@nocobase/plugin-logger 0.18.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/LogsDownloader.d.ts +2 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +1 -0
- package/dist/client/locale/index.d.ts +3 -0
- package/dist/externalVersion.js +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.d.ts +10 -0
- package/dist/locale/en-US.js +31 -0
- package/dist/locale/zh-CN.d.ts +10 -0
- package/dist/locale/zh-CN.js +31 -0
- package/dist/node_modules/tar-fs/LICENSE +21 -0
- package/dist/node_modules/tar-fs/index.js +1 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/constants.js +14 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/extract.js +406 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/headers.js +321 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/index.js +2 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/pack.js +287 -0
- package/dist/node_modules/tar-fs/node_modules/tar-stream/package.json +35 -0
- package/dist/node_modules/tar-fs/package.json +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +33 -0
- package/dist/server/plugin.d.ts +11 -0
- package/dist/server/plugin.js +61 -0
- package/dist/server/resourcer/logger.d.ts +9 -0
- package/dist/server/resourcer/logger.js +114 -0
- package/package.json +21 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
const { Writable, Readable, getStreamError } = require('streamx')
|
|
2
|
+
const FIFO = require('fast-fifo')
|
|
3
|
+
const b4a = require('b4a')
|
|
4
|
+
const headers = require('./headers')
|
|
5
|
+
|
|
6
|
+
const EMPTY = b4a.alloc(0)
|
|
7
|
+
|
|
8
|
+
class BufferList {
|
|
9
|
+
constructor () {
|
|
10
|
+
this.buffered = 0
|
|
11
|
+
this.shifted = 0
|
|
12
|
+
this.queue = new FIFO()
|
|
13
|
+
|
|
14
|
+
this._offset = 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
push (buffer) {
|
|
18
|
+
this.buffered += buffer.byteLength
|
|
19
|
+
this.queue.push(buffer)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
shiftFirst (size) {
|
|
23
|
+
return this._buffered === 0 ? null : this._next(size)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
shift (size) {
|
|
27
|
+
if (size > this.buffered) return null
|
|
28
|
+
if (size === 0) return EMPTY
|
|
29
|
+
|
|
30
|
+
let chunk = this._next(size)
|
|
31
|
+
|
|
32
|
+
if (size === chunk.byteLength) return chunk // likely case
|
|
33
|
+
|
|
34
|
+
const chunks = [chunk]
|
|
35
|
+
|
|
36
|
+
while ((size -= chunk.byteLength) > 0) {
|
|
37
|
+
chunk = this._next(size)
|
|
38
|
+
chunks.push(chunk)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return b4a.concat(chunks)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_next (size) {
|
|
45
|
+
const buf = this.queue.peek()
|
|
46
|
+
const rem = buf.byteLength - this._offset
|
|
47
|
+
|
|
48
|
+
if (size >= rem) {
|
|
49
|
+
const sub = this._offset ? buf.subarray(this._offset, buf.byteLength) : buf
|
|
50
|
+
this.queue.shift()
|
|
51
|
+
this._offset = 0
|
|
52
|
+
this.buffered -= rem
|
|
53
|
+
this.shifted += rem
|
|
54
|
+
return sub
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.buffered -= size
|
|
58
|
+
this.shifted += size
|
|
59
|
+
|
|
60
|
+
return buf.subarray(this._offset, (this._offset += size))
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
class Source extends Readable {
|
|
65
|
+
constructor (self, header, offset) {
|
|
66
|
+
super()
|
|
67
|
+
|
|
68
|
+
this.header = header
|
|
69
|
+
this.offset = offset
|
|
70
|
+
|
|
71
|
+
this._parent = self
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
_read (cb) {
|
|
75
|
+
if (this.header.size === 0) {
|
|
76
|
+
this.push(null)
|
|
77
|
+
}
|
|
78
|
+
if (this._parent._stream === this) {
|
|
79
|
+
this._parent._update()
|
|
80
|
+
}
|
|
81
|
+
cb(null)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
_predestroy () {
|
|
85
|
+
this._parent.destroy(getStreamError(this))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
_detach () {
|
|
89
|
+
if (this._parent._stream === this) {
|
|
90
|
+
this._parent._stream = null
|
|
91
|
+
this._parent._missing = overflow(this.header.size)
|
|
92
|
+
this._parent._update()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_destroy (cb) {
|
|
97
|
+
this._detach()
|
|
98
|
+
cb(null)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
class Extract extends Writable {
|
|
103
|
+
constructor (opts) {
|
|
104
|
+
super(opts)
|
|
105
|
+
|
|
106
|
+
if (!opts) opts = {}
|
|
107
|
+
|
|
108
|
+
this._buffer = new BufferList()
|
|
109
|
+
this._offset = 0
|
|
110
|
+
this._header = null
|
|
111
|
+
this._stream = null
|
|
112
|
+
this._missing = 0
|
|
113
|
+
this._longHeader = false
|
|
114
|
+
this._callback = noop
|
|
115
|
+
this._locked = false
|
|
116
|
+
this._finished = false
|
|
117
|
+
this._pax = null
|
|
118
|
+
this._paxGlobal = null
|
|
119
|
+
this._gnuLongPath = null
|
|
120
|
+
this._gnuLongLinkPath = null
|
|
121
|
+
this._filenameEncoding = opts.filenameEncoding || 'utf-8'
|
|
122
|
+
this._allowUnknownFormat = !!opts.allowUnknownFormat
|
|
123
|
+
this._unlockBound = this._unlock.bind(this)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
_unlock (err) {
|
|
127
|
+
this._locked = false
|
|
128
|
+
|
|
129
|
+
if (err) {
|
|
130
|
+
this.destroy(err)
|
|
131
|
+
this._continueWrite(err)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this._update()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_consumeHeader () {
|
|
139
|
+
if (this._locked) return false
|
|
140
|
+
|
|
141
|
+
this._offset = this._buffer.shifted
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
this._header = headers.decode(this._buffer.shift(512), this._filenameEncoding, this._allowUnknownFormat)
|
|
145
|
+
} catch (err) {
|
|
146
|
+
this._continueWrite(err)
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!this._header) return true
|
|
151
|
+
|
|
152
|
+
switch (this._header.type) {
|
|
153
|
+
case 'gnu-long-path':
|
|
154
|
+
case 'gnu-long-link-path':
|
|
155
|
+
case 'pax-global-header':
|
|
156
|
+
case 'pax-header':
|
|
157
|
+
this._longHeader = true
|
|
158
|
+
this._missing = this._header.size
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this._locked = true
|
|
163
|
+
this._applyLongHeaders()
|
|
164
|
+
|
|
165
|
+
if (this._header.size === 0 || this._header.type === 'directory') {
|
|
166
|
+
this.emit('entry', this._header, this._createStream(), this._unlockBound)
|
|
167
|
+
return true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this._stream = this._createStream()
|
|
171
|
+
this._missing = this._header.size
|
|
172
|
+
|
|
173
|
+
this.emit('entry', this._header, this._stream, this._unlockBound)
|
|
174
|
+
return true
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
_applyLongHeaders () {
|
|
178
|
+
if (this._gnuLongPath) {
|
|
179
|
+
this._header.name = this._gnuLongPath
|
|
180
|
+
this._gnuLongPath = null
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (this._gnuLongLinkPath) {
|
|
184
|
+
this._header.linkname = this._gnuLongLinkPath
|
|
185
|
+
this._gnuLongLinkPath = null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (this._pax) {
|
|
189
|
+
if (this._pax.path) this._header.name = this._pax.path
|
|
190
|
+
if (this._pax.linkpath) this._header.linkname = this._pax.linkpath
|
|
191
|
+
if (this._pax.size) this._header.size = parseInt(this._pax.size, 10)
|
|
192
|
+
this._header.pax = this._pax
|
|
193
|
+
this._pax = null
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
_decodeLongHeader (buf) {
|
|
198
|
+
switch (this._header.type) {
|
|
199
|
+
case 'gnu-long-path':
|
|
200
|
+
this._gnuLongPath = headers.decodeLongPath(buf, this._filenameEncoding)
|
|
201
|
+
break
|
|
202
|
+
case 'gnu-long-link-path':
|
|
203
|
+
this._gnuLongLinkPath = headers.decodeLongPath(buf, this._filenameEncoding)
|
|
204
|
+
break
|
|
205
|
+
case 'pax-global-header':
|
|
206
|
+
this._paxGlobal = headers.decodePax(buf)
|
|
207
|
+
break
|
|
208
|
+
case 'pax-header':
|
|
209
|
+
this._pax = this._paxGlobal === null
|
|
210
|
+
? headers.decodePax(buf)
|
|
211
|
+
: Object.assign({}, this._paxGlobal, headers.decodePax(buf))
|
|
212
|
+
break
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
_consumeLongHeader () {
|
|
217
|
+
this._longHeader = false
|
|
218
|
+
this._missing = overflow(this._header.size)
|
|
219
|
+
|
|
220
|
+
const buf = this._buffer.shift(this._header.size)
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
this._decodeLongHeader(buf)
|
|
224
|
+
} catch (err) {
|
|
225
|
+
this._continueWrite(err)
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return true
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
_consumeStream () {
|
|
233
|
+
const buf = this._buffer.shiftFirst(this._missing)
|
|
234
|
+
if (buf === null) return false
|
|
235
|
+
|
|
236
|
+
this._missing -= buf.byteLength
|
|
237
|
+
const drained = this._stream.push(buf)
|
|
238
|
+
|
|
239
|
+
if (this._missing === 0) {
|
|
240
|
+
this._stream.push(null)
|
|
241
|
+
if (drained) this._stream._detach()
|
|
242
|
+
return drained && this._locked === false
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return drained
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_createStream () {
|
|
249
|
+
return new Source(this, this._header, this._offset)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
_update () {
|
|
253
|
+
while (this._buffer.buffered > 0 && !this.destroying) {
|
|
254
|
+
if (this._missing > 0) {
|
|
255
|
+
if (this._stream !== null) {
|
|
256
|
+
if (this._consumeStream() === false) return
|
|
257
|
+
continue
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (this._longHeader === true) {
|
|
261
|
+
if (this._missing > this._buffer.buffered) break
|
|
262
|
+
if (this._consumeLongHeader() === false) return false
|
|
263
|
+
continue
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const ignore = this._buffer.shiftFirst(this._missing)
|
|
267
|
+
if (ignore !== null) this._missing -= ignore.byteLength
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (this._buffer.buffered < 512) break
|
|
272
|
+
if (this._stream !== null || this._consumeHeader() === false) return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
this._continueWrite(null)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
_continueWrite (err) {
|
|
279
|
+
const cb = this._callback
|
|
280
|
+
this._callback = noop
|
|
281
|
+
cb(err)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
_write (data, cb) {
|
|
285
|
+
this._callback = cb
|
|
286
|
+
this._buffer.push(data)
|
|
287
|
+
this._update()
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
_final (cb) {
|
|
291
|
+
this._finished = this._missing === 0 && this._buffer.buffered === 0
|
|
292
|
+
cb(this._finished ? null : new Error('Unexpected end of data'))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
_predestroy () {
|
|
296
|
+
this._continueWrite(null)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
_destroy (cb) {
|
|
300
|
+
if (this._stream) this._stream.destroy(getStreamError(this))
|
|
301
|
+
cb(null)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
[Symbol.asyncIterator] () {
|
|
305
|
+
let error = null
|
|
306
|
+
|
|
307
|
+
let promiseResolve = null
|
|
308
|
+
let promiseReject = null
|
|
309
|
+
|
|
310
|
+
let entryStream = null
|
|
311
|
+
let entryCallback = null
|
|
312
|
+
|
|
313
|
+
const extract = this
|
|
314
|
+
|
|
315
|
+
this.on('entry', onentry)
|
|
316
|
+
this.on('error', (err) => { error = err })
|
|
317
|
+
this.on('close', onclose)
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
[Symbol.asyncIterator] () {
|
|
321
|
+
return this
|
|
322
|
+
},
|
|
323
|
+
next () {
|
|
324
|
+
return new Promise(onnext)
|
|
325
|
+
},
|
|
326
|
+
return () {
|
|
327
|
+
return destroy(null)
|
|
328
|
+
},
|
|
329
|
+
throw (err) {
|
|
330
|
+
return destroy(err)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function consumeCallback (err) {
|
|
335
|
+
if (!entryCallback) return
|
|
336
|
+
const cb = entryCallback
|
|
337
|
+
entryCallback = null
|
|
338
|
+
cb(err)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function onnext (resolve, reject) {
|
|
342
|
+
if (error) {
|
|
343
|
+
return reject(error)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (entryStream) {
|
|
347
|
+
resolve({ value: entryStream, done: false })
|
|
348
|
+
entryStream = null
|
|
349
|
+
return
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
promiseResolve = resolve
|
|
353
|
+
promiseReject = reject
|
|
354
|
+
|
|
355
|
+
consumeCallback(null)
|
|
356
|
+
|
|
357
|
+
if (extract._finished && promiseResolve) {
|
|
358
|
+
promiseResolve({ value: undefined, done: true })
|
|
359
|
+
promiseResolve = promiseReject = null
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function onentry (header, stream, callback) {
|
|
364
|
+
entryCallback = callback
|
|
365
|
+
stream.on('error', noop) // no way around this due to tick sillyness
|
|
366
|
+
|
|
367
|
+
if (promiseResolve) {
|
|
368
|
+
promiseResolve({ value: stream, done: false })
|
|
369
|
+
promiseResolve = promiseReject = null
|
|
370
|
+
} else {
|
|
371
|
+
entryStream = stream
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function onclose () {
|
|
376
|
+
consumeCallback(error)
|
|
377
|
+
if (!promiseResolve) return
|
|
378
|
+
if (error) promiseReject(error)
|
|
379
|
+
else promiseResolve({ value: undefined, done: true })
|
|
380
|
+
promiseResolve = promiseReject = null
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function destroy (err) {
|
|
384
|
+
extract.destroy(err)
|
|
385
|
+
consumeCallback(err)
|
|
386
|
+
return new Promise((resolve, reject) => {
|
|
387
|
+
if (extract.destroyed) return resolve({ value: undefined, done: true })
|
|
388
|
+
extract.once('close', function () {
|
|
389
|
+
if (err) reject(err)
|
|
390
|
+
else resolve({ value: undefined, done: true })
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
module.exports = function extract (opts) {
|
|
398
|
+
return new Extract(opts)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function noop () {}
|
|
402
|
+
|
|
403
|
+
function overflow (size) {
|
|
404
|
+
size &= 511
|
|
405
|
+
return size && 512 - size
|
|
406
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
const b4a = require('b4a')
|
|
2
|
+
|
|
3
|
+
const ZEROS = '0000000000000000000'
|
|
4
|
+
const SEVENS = '7777777777777777777'
|
|
5
|
+
const ZERO_OFFSET = '0'.charCodeAt(0)
|
|
6
|
+
const USTAR_MAGIC = b4a.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x00]) // ustar\x00
|
|
7
|
+
const USTAR_VER = b4a.from([ZERO_OFFSET, ZERO_OFFSET])
|
|
8
|
+
const GNU_MAGIC = b4a.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x20]) // ustar\x20
|
|
9
|
+
const GNU_VER = b4a.from([0x20, 0x00])
|
|
10
|
+
const MASK = 0o7777
|
|
11
|
+
const MAGIC_OFFSET = 257
|
|
12
|
+
const VERSION_OFFSET = 263
|
|
13
|
+
|
|
14
|
+
exports.decodeLongPath = function decodeLongPath (buf, encoding) {
|
|
15
|
+
return decodeStr(buf, 0, buf.length, encoding)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.encodePax = function encodePax (opts) { // TODO: encode more stuff in pax
|
|
19
|
+
let result = ''
|
|
20
|
+
if (opts.name) result += addLength(' path=' + opts.name + '\n')
|
|
21
|
+
if (opts.linkname) result += addLength(' linkpath=' + opts.linkname + '\n')
|
|
22
|
+
const pax = opts.pax
|
|
23
|
+
if (pax) {
|
|
24
|
+
for (const key in pax) {
|
|
25
|
+
result += addLength(' ' + key + '=' + pax[key] + '\n')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return b4a.from(result)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.decodePax = function decodePax (buf) {
|
|
32
|
+
const result = {}
|
|
33
|
+
|
|
34
|
+
while (buf.length) {
|
|
35
|
+
let i = 0
|
|
36
|
+
while (i < buf.length && buf[i] !== 32) i++
|
|
37
|
+
const len = parseInt(buf.subarray(0, i).toString(), 10)
|
|
38
|
+
if (!len) return result
|
|
39
|
+
|
|
40
|
+
const b = b4a.toString(buf.subarray(i + 1, len - 1))
|
|
41
|
+
const keyIndex = b.indexOf('=')
|
|
42
|
+
if (keyIndex === -1) return result
|
|
43
|
+
result[b.slice(0, keyIndex)] = b.slice(keyIndex + 1)
|
|
44
|
+
|
|
45
|
+
buf = buf.subarray(len)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.encode = function encode (opts) {
|
|
52
|
+
const buf = b4a.alloc(512)
|
|
53
|
+
let name = opts.name
|
|
54
|
+
let prefix = ''
|
|
55
|
+
|
|
56
|
+
if (opts.typeflag === 5 && name[name.length - 1] !== '/') name += '/'
|
|
57
|
+
if (b4a.byteLength(name) !== name.length) return null // utf-8
|
|
58
|
+
|
|
59
|
+
while (b4a.byteLength(name) > 100) {
|
|
60
|
+
const i = name.indexOf('/')
|
|
61
|
+
if (i === -1) return null
|
|
62
|
+
prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i)
|
|
63
|
+
name = name.slice(i + 1)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (b4a.byteLength(name) > 100 || b4a.byteLength(prefix) > 155) return null
|
|
67
|
+
if (opts.linkname && b4a.byteLength(opts.linkname) > 100) return null
|
|
68
|
+
|
|
69
|
+
b4a.write(buf, name)
|
|
70
|
+
b4a.write(buf, encodeOct(opts.mode & MASK, 6), 100)
|
|
71
|
+
b4a.write(buf, encodeOct(opts.uid, 6), 108)
|
|
72
|
+
b4a.write(buf, encodeOct(opts.gid, 6), 116)
|
|
73
|
+
encodeSize(opts.size, buf, 124)
|
|
74
|
+
b4a.write(buf, encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136)
|
|
75
|
+
|
|
76
|
+
buf[156] = ZERO_OFFSET + toTypeflag(opts.type)
|
|
77
|
+
|
|
78
|
+
if (opts.linkname) b4a.write(buf, opts.linkname, 157)
|
|
79
|
+
|
|
80
|
+
b4a.copy(USTAR_MAGIC, buf, MAGIC_OFFSET)
|
|
81
|
+
b4a.copy(USTAR_VER, buf, VERSION_OFFSET)
|
|
82
|
+
if (opts.uname) b4a.write(buf, opts.uname, 265)
|
|
83
|
+
if (opts.gname) b4a.write(buf, opts.gname, 297)
|
|
84
|
+
b4a.write(buf, encodeOct(opts.devmajor || 0, 6), 329)
|
|
85
|
+
b4a.write(buf, encodeOct(opts.devminor || 0, 6), 337)
|
|
86
|
+
|
|
87
|
+
if (prefix) b4a.write(buf, prefix, 345)
|
|
88
|
+
|
|
89
|
+
b4a.write(buf, encodeOct(cksum(buf), 6), 148)
|
|
90
|
+
|
|
91
|
+
return buf
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.decode = function decode (buf, filenameEncoding, allowUnknownFormat) {
|
|
95
|
+
let typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET
|
|
96
|
+
|
|
97
|
+
let name = decodeStr(buf, 0, 100, filenameEncoding)
|
|
98
|
+
const mode = decodeOct(buf, 100, 8)
|
|
99
|
+
const uid = decodeOct(buf, 108, 8)
|
|
100
|
+
const gid = decodeOct(buf, 116, 8)
|
|
101
|
+
const size = decodeOct(buf, 124, 12)
|
|
102
|
+
const mtime = decodeOct(buf, 136, 12)
|
|
103
|
+
const type = toType(typeflag)
|
|
104
|
+
const linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100, filenameEncoding)
|
|
105
|
+
const uname = decodeStr(buf, 265, 32)
|
|
106
|
+
const gname = decodeStr(buf, 297, 32)
|
|
107
|
+
const devmajor = decodeOct(buf, 329, 8)
|
|
108
|
+
const devminor = decodeOct(buf, 337, 8)
|
|
109
|
+
|
|
110
|
+
const c = cksum(buf)
|
|
111
|
+
|
|
112
|
+
// checksum is still initial value if header was null.
|
|
113
|
+
if (c === 8 * 32) return null
|
|
114
|
+
|
|
115
|
+
// valid checksum
|
|
116
|
+
if (c !== decodeOct(buf, 148, 8)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?')
|
|
117
|
+
|
|
118
|
+
if (isUSTAR(buf)) {
|
|
119
|
+
// ustar (posix) format.
|
|
120
|
+
// prepend prefix, if present.
|
|
121
|
+
if (buf[345]) name = decodeStr(buf, 345, 155, filenameEncoding) + '/' + name
|
|
122
|
+
} else if (isGNU(buf)) {
|
|
123
|
+
// 'gnu'/'oldgnu' format. Similar to ustar, but has support for incremental and
|
|
124
|
+
// multi-volume tarballs.
|
|
125
|
+
} else {
|
|
126
|
+
if (!allowUnknownFormat) {
|
|
127
|
+
throw new Error('Invalid tar header: unknown format.')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// to support old tar versions that use trailing / to indicate dirs
|
|
132
|
+
if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
name,
|
|
136
|
+
mode,
|
|
137
|
+
uid,
|
|
138
|
+
gid,
|
|
139
|
+
size,
|
|
140
|
+
mtime: new Date(1000 * mtime),
|
|
141
|
+
type,
|
|
142
|
+
linkname,
|
|
143
|
+
uname,
|
|
144
|
+
gname,
|
|
145
|
+
devmajor,
|
|
146
|
+
devminor,
|
|
147
|
+
pax: null
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function isUSTAR (buf) {
|
|
152
|
+
return b4a.equals(USTAR_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isGNU (buf) {
|
|
156
|
+
return b4a.equals(GNU_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)) &&
|
|
157
|
+
b4a.equals(GNU_VER, buf.subarray(VERSION_OFFSET, VERSION_OFFSET + 2))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function clamp (index, len, defaultValue) {
|
|
161
|
+
if (typeof index !== 'number') return defaultValue
|
|
162
|
+
index = ~~index // Coerce to integer.
|
|
163
|
+
if (index >= len) return len
|
|
164
|
+
if (index >= 0) return index
|
|
165
|
+
index += len
|
|
166
|
+
if (index >= 0) return index
|
|
167
|
+
return 0
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function toType (flag) {
|
|
171
|
+
switch (flag) {
|
|
172
|
+
case 0:
|
|
173
|
+
return 'file'
|
|
174
|
+
case 1:
|
|
175
|
+
return 'link'
|
|
176
|
+
case 2:
|
|
177
|
+
return 'symlink'
|
|
178
|
+
case 3:
|
|
179
|
+
return 'character-device'
|
|
180
|
+
case 4:
|
|
181
|
+
return 'block-device'
|
|
182
|
+
case 5:
|
|
183
|
+
return 'directory'
|
|
184
|
+
case 6:
|
|
185
|
+
return 'fifo'
|
|
186
|
+
case 7:
|
|
187
|
+
return 'contiguous-file'
|
|
188
|
+
case 72:
|
|
189
|
+
return 'pax-header'
|
|
190
|
+
case 55:
|
|
191
|
+
return 'pax-global-header'
|
|
192
|
+
case 27:
|
|
193
|
+
return 'gnu-long-link-path'
|
|
194
|
+
case 28:
|
|
195
|
+
case 30:
|
|
196
|
+
return 'gnu-long-path'
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return null
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function toTypeflag (flag) {
|
|
203
|
+
switch (flag) {
|
|
204
|
+
case 'file':
|
|
205
|
+
return 0
|
|
206
|
+
case 'link':
|
|
207
|
+
return 1
|
|
208
|
+
case 'symlink':
|
|
209
|
+
return 2
|
|
210
|
+
case 'character-device':
|
|
211
|
+
return 3
|
|
212
|
+
case 'block-device':
|
|
213
|
+
return 4
|
|
214
|
+
case 'directory':
|
|
215
|
+
return 5
|
|
216
|
+
case 'fifo':
|
|
217
|
+
return 6
|
|
218
|
+
case 'contiguous-file':
|
|
219
|
+
return 7
|
|
220
|
+
case 'pax-header':
|
|
221
|
+
return 72
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return 0
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function indexOf (block, num, offset, end) {
|
|
228
|
+
for (; offset < end; offset++) {
|
|
229
|
+
if (block[offset] === num) return offset
|
|
230
|
+
}
|
|
231
|
+
return end
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function cksum (block) {
|
|
235
|
+
let sum = 8 * 32
|
|
236
|
+
for (let i = 0; i < 148; i++) sum += block[i]
|
|
237
|
+
for (let j = 156; j < 512; j++) sum += block[j]
|
|
238
|
+
return sum
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function encodeOct (val, n) {
|
|
242
|
+
val = val.toString(8)
|
|
243
|
+
if (val.length > n) return SEVENS.slice(0, n) + ' '
|
|
244
|
+
return ZEROS.slice(0, n - val.length) + val + ' '
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function encodeSizeBin (num, buf, off) {
|
|
248
|
+
buf[off] = 0x80
|
|
249
|
+
for (let i = 11; i > 0; i--) {
|
|
250
|
+
buf[off + i] = num & 0xff
|
|
251
|
+
num = Math.floor(num / 0x100)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function encodeSize (num, buf, off) {
|
|
256
|
+
if (num.toString(8).length > 11) {
|
|
257
|
+
encodeSizeBin(num, buf, off)
|
|
258
|
+
} else {
|
|
259
|
+
b4a.write(buf, encodeOct(num, 11), off)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Copied from the node-tar repo and modified to meet
|
|
264
|
+
* tar-stream coding standard.
|
|
265
|
+
*
|
|
266
|
+
* Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349
|
|
267
|
+
*/
|
|
268
|
+
function parse256 (buf) {
|
|
269
|
+
// first byte MUST be either 80 or FF
|
|
270
|
+
// 80 for positive, FF for 2's comp
|
|
271
|
+
let positive
|
|
272
|
+
if (buf[0] === 0x80) positive = true
|
|
273
|
+
else if (buf[0] === 0xFF) positive = false
|
|
274
|
+
else return null
|
|
275
|
+
|
|
276
|
+
// build up a base-256 tuple from the least sig to the highest
|
|
277
|
+
const tuple = []
|
|
278
|
+
let i
|
|
279
|
+
for (i = buf.length - 1; i > 0; i--) {
|
|
280
|
+
const byte = buf[i]
|
|
281
|
+
if (positive) tuple.push(byte)
|
|
282
|
+
else tuple.push(0xFF - byte)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let sum = 0
|
|
286
|
+
const l = tuple.length
|
|
287
|
+
for (i = 0; i < l; i++) {
|
|
288
|
+
sum += tuple[i] * Math.pow(256, i)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return positive ? sum : -1 * sum
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function decodeOct (val, offset, length) {
|
|
295
|
+
val = val.subarray(offset, offset + length)
|
|
296
|
+
offset = 0
|
|
297
|
+
|
|
298
|
+
// If prefixed with 0x80 then parse as a base-256 integer
|
|
299
|
+
if (val[offset] & 0x80) {
|
|
300
|
+
return parse256(val)
|
|
301
|
+
} else {
|
|
302
|
+
// Older versions of tar can prefix with spaces
|
|
303
|
+
while (offset < val.length && val[offset] === 32) offset++
|
|
304
|
+
const end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)
|
|
305
|
+
while (offset < end && val[offset] === 0) offset++
|
|
306
|
+
if (end === offset) return 0
|
|
307
|
+
return parseInt(val.subarray(offset, end).toString(), 8)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function decodeStr (val, offset, length, encoding) {
|
|
312
|
+
return b4a.toString(val.subarray(offset, indexOf(val, 0, offset, offset + length)), encoding)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function addLength (str) {
|
|
316
|
+
const len = b4a.byteLength(str)
|
|
317
|
+
let digits = Math.floor(Math.log(len) / Math.log(10)) + 1
|
|
318
|
+
if (len + digits >= Math.pow(10, digits)) digits++
|
|
319
|
+
|
|
320
|
+
return (len + digits) + str
|
|
321
|
+
}
|