tar-vern 0.3.0 → 1.1.0
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/README_pack.md +40 -6
- package/dist/extractor.d.ts +21 -0
- package/dist/extractor.d.ts.map +1 -0
- package/dist/index.cjs +377 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +365 -30
- package/dist/index.js.map +1 -1
- package/dist/packer.d.ts +2 -1
- package/dist/packer.d.ts.map +1 -1
- package/dist/types.d.ts +27 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +34 -8
- package/dist/utils.d.ts.map +1 -1
- package/package.json +19 -3
- package/LICENSE +0 -21
- package/README.md +0 -212
- package/dist/generated/packageMetadata.d.ts +0 -16
- package/dist/generated/packageMetadata.d.ts.map +0 -1
package/dist/index.js
CHANGED
@@ -1,24 +1,30 @@
|
|
1
1
|
/*!
|
2
2
|
* name: tar-vern
|
3
|
-
* version:
|
3
|
+
* version: 1.1.0
|
4
4
|
* description: Tape archiver library for Typescript
|
5
5
|
* author: Kouji Matsui (@kekyo@mi.kekyo.net)
|
6
6
|
* license: MIT
|
7
7
|
* repository.url: https://github.com/kekyo/tar-vern.git
|
8
|
+
* git.commit.hash: 6d4ff13b538b16545ccc55b2e74f8e5f73999a34
|
8
9
|
*/
|
9
10
|
import { Readable } from "stream";
|
10
|
-
import { createGzip } from "zlib";
|
11
|
+
import { createGzip, createGunzip } from "zlib";
|
11
12
|
import { createReadStream, createWriteStream } from "fs";
|
12
|
-
import { stat } from "fs/promises";
|
13
|
+
import { stat, mkdir, writeFile, readdir } from "fs/promises";
|
14
|
+
import { pipeline } from "stream/promises";
|
15
|
+
import { join, dirname } from "path";
|
16
|
+
const MAX_NAME = 100;
|
17
|
+
const MAX_PREFIX = 155;
|
13
18
|
const getUName = (candidateName, candidateId, reflectStat) => {
|
14
19
|
return candidateName ?? (reflectStat === "all" ? candidateId.toString() : "root");
|
15
20
|
};
|
16
21
|
const getBuffer = (data) => {
|
17
22
|
return Buffer.isBuffer(data) ? data : Buffer.from(data, "utf8");
|
18
23
|
};
|
19
|
-
const createDirectoryItem = async (path, reflectStat, options) => {
|
24
|
+
const createDirectoryItem = async (path, reflectStat, options, signal) => {
|
20
25
|
const rs = reflectStat ?? "none";
|
21
26
|
if (rs !== "none" && options?.directoryPath) {
|
27
|
+
signal?.throwIfAborted();
|
22
28
|
const stats = await stat(options.directoryPath);
|
23
29
|
const mode = options?.mode ?? stats.mode;
|
24
30
|
const uid = options?.uid ?? stats.uid;
|
@@ -55,7 +61,8 @@ const createDirectoryItem = async (path, reflectStat, options) => {
|
|
55
61
|
};
|
56
62
|
}
|
57
63
|
};
|
58
|
-
const createFileItem = async (path, content, options) => {
|
64
|
+
const createFileItem = async (path, content, options, signal) => {
|
65
|
+
signal?.throwIfAborted();
|
59
66
|
const mode = options?.mode ?? 420;
|
60
67
|
const uid = options?.uid ?? 0;
|
61
68
|
const gid = options?.gid ?? 0;
|
@@ -74,7 +81,7 @@ const createFileItem = async (path, content, options) => {
|
|
74
81
|
content
|
75
82
|
};
|
76
83
|
};
|
77
|
-
const createReadableFileItem = async (path, readable, options) => {
|
84
|
+
const createReadableFileItem = async (path, readable, options, signal) => {
|
78
85
|
const mode = options?.mode ?? 420;
|
79
86
|
const uid = options?.uid ?? 0;
|
80
87
|
const gid = options?.gid ?? 0;
|
@@ -86,6 +93,7 @@ const createReadableFileItem = async (path, readable, options) => {
|
|
86
93
|
const chunks = [];
|
87
94
|
length = 0;
|
88
95
|
for await (const chunk of readable) {
|
96
|
+
signal?.throwIfAborted();
|
89
97
|
const buffer = getBuffer(chunk);
|
90
98
|
chunks.push(buffer);
|
91
99
|
length += buffer.length;
|
@@ -102,7 +110,7 @@ const createReadableFileItem = async (path, readable, options) => {
|
|
102
110
|
content: {
|
103
111
|
kind: "readable",
|
104
112
|
length,
|
105
|
-
readable: Readable.from(chunks)
|
113
|
+
readable: Readable.from(chunks, { signal })
|
106
114
|
}
|
107
115
|
};
|
108
116
|
} else {
|
@@ -123,7 +131,7 @@ const createReadableFileItem = async (path, readable, options) => {
|
|
123
131
|
};
|
124
132
|
}
|
125
133
|
};
|
126
|
-
const createGeneratorFileItem = async (path, generator, options) => {
|
134
|
+
const createGeneratorFileItem = async (path, generator, options, signal) => {
|
127
135
|
const mode = options?.mode ?? 420;
|
128
136
|
const uid = options?.uid ?? 0;
|
129
137
|
const gid = options?.gid ?? 0;
|
@@ -135,6 +143,7 @@ const createGeneratorFileItem = async (path, generator, options) => {
|
|
135
143
|
const chunks = [];
|
136
144
|
length = 0;
|
137
145
|
for await (const chunk of generator) {
|
146
|
+
signal?.throwIfAborted();
|
138
147
|
const buffer = getBuffer(chunk);
|
139
148
|
chunks.push(buffer);
|
140
149
|
length += buffer.length;
|
@@ -151,7 +160,7 @@ const createGeneratorFileItem = async (path, generator, options) => {
|
|
151
160
|
content: {
|
152
161
|
kind: "readable",
|
153
162
|
length,
|
154
|
-
readable: Readable.from(chunks)
|
163
|
+
readable: Readable.from(chunks, { signal })
|
155
164
|
}
|
156
165
|
};
|
157
166
|
} else {
|
@@ -172,10 +181,11 @@ const createGeneratorFileItem = async (path, generator, options) => {
|
|
172
181
|
};
|
173
182
|
}
|
174
183
|
};
|
175
|
-
const createReadFileItem = async (path, filePath, reflectStat, options) => {
|
184
|
+
const createReadFileItem = async (path, filePath, reflectStat, options, signal) => {
|
176
185
|
const rs = reflectStat ?? "exceptName";
|
186
|
+
signal?.throwIfAborted();
|
177
187
|
const stats = await stat(filePath);
|
178
|
-
const reader = createReadStream(filePath);
|
188
|
+
const reader = createReadStream(filePath, { signal });
|
179
189
|
const mode = options?.mode ?? (rs !== "none" ? stats.mode : void 0);
|
180
190
|
const uid = options?.uid ?? (rs !== "none" ? stats.uid : void 0);
|
181
191
|
const gid = options?.gid ?? (rs !== "none" ? stats.gid : void 0);
|
@@ -190,16 +200,85 @@ const createReadFileItem = async (path, filePath, reflectStat, options) => {
|
|
190
200
|
uid,
|
191
201
|
gid,
|
192
202
|
date
|
193
|
-
});
|
203
|
+
}, signal);
|
204
|
+
};
|
205
|
+
const storeReaderToFile = async (reader, path, signal) => {
|
206
|
+
const writer = createWriteStream(path, { signal });
|
207
|
+
await pipeline(reader, writer, { signal });
|
194
208
|
};
|
195
|
-
const
|
196
|
-
const
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
209
|
+
const getAllFilesInDirectory = async (baseDir, signal) => {
|
210
|
+
const collectFiles = async (currentDir, relativePath) => {
|
211
|
+
signal?.throwIfAborted();
|
212
|
+
try {
|
213
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
214
|
+
const result = [];
|
215
|
+
const tasks = entries.map(async (entry) => {
|
216
|
+
signal?.throwIfAborted();
|
217
|
+
const entryRelativePath = join(relativePath, entry.name);
|
218
|
+
if (entry.isDirectory()) {
|
219
|
+
const entryFullPath = join(currentDir, entry.name);
|
220
|
+
const directoryContents = await collectFiles(entryFullPath, entryRelativePath);
|
221
|
+
return [entryRelativePath, ...directoryContents];
|
222
|
+
} else {
|
223
|
+
return [entryRelativePath];
|
224
|
+
}
|
225
|
+
});
|
226
|
+
const allResults = await Promise.all(tasks);
|
227
|
+
for (const entryResults of allResults) {
|
228
|
+
result.push(...entryResults);
|
229
|
+
}
|
230
|
+
return result;
|
231
|
+
} catch (error) {
|
232
|
+
console.warn(`Warning: Could not read directory ${currentDir}:`, error);
|
233
|
+
return [];
|
234
|
+
}
|
235
|
+
};
|
236
|
+
return await collectFiles(baseDir, "");
|
237
|
+
};
|
238
|
+
const createEntryItemGenerator = async function* (baseDir, relativePaths, reflectStat, signal) {
|
239
|
+
const rs = reflectStat ?? "exceptName";
|
240
|
+
const pathsToProcess = relativePaths ?? await getAllFilesInDirectory(baseDir, signal);
|
241
|
+
for (const relativePath of pathsToProcess) {
|
242
|
+
signal?.throwIfAborted();
|
243
|
+
const fsPath = join(baseDir, relativePath);
|
244
|
+
try {
|
245
|
+
signal?.throwIfAborted();
|
246
|
+
const stats = await stat(fsPath);
|
247
|
+
if (stats.isDirectory()) {
|
248
|
+
yield await createDirectoryItem(relativePath, rs, {
|
249
|
+
directoryPath: fsPath
|
250
|
+
}, signal);
|
251
|
+
} else if (stats.isFile()) {
|
252
|
+
yield await createReadFileItem(relativePath, fsPath, rs, void 0, signal);
|
253
|
+
}
|
254
|
+
} catch (error) {
|
255
|
+
console.warn(`Warning: Could not access ${fsPath}:`, error);
|
256
|
+
continue;
|
257
|
+
}
|
258
|
+
}
|
259
|
+
};
|
260
|
+
const extractTo = async (iterator, basePath, signal) => {
|
261
|
+
for await (const entry of iterator) {
|
262
|
+
signal?.throwIfAborted();
|
263
|
+
const targetPath = join(basePath, entry.path);
|
264
|
+
if (entry.kind === "directory") {
|
265
|
+
try {
|
266
|
+
signal?.throwIfAborted();
|
267
|
+
await mkdir(targetPath, { recursive: true, mode: entry.mode });
|
268
|
+
} catch (error) {
|
269
|
+
if (error.code !== "EEXIST") {
|
270
|
+
throw error;
|
271
|
+
}
|
272
|
+
}
|
273
|
+
} else if (entry.kind === "file") {
|
274
|
+
const parentDir = dirname(targetPath);
|
275
|
+
signal?.throwIfAborted();
|
276
|
+
await mkdir(parentDir, { recursive: true });
|
277
|
+
const fileEntry = entry;
|
278
|
+
const content = await fileEntry.getContent("buffer");
|
279
|
+
await writeFile(targetPath, content, { mode: entry.mode, signal });
|
280
|
+
}
|
281
|
+
}
|
203
282
|
};
|
204
283
|
const utf8ByteLength = (str) => {
|
205
284
|
return Buffer.byteLength(str, "utf8");
|
@@ -217,8 +296,6 @@ const truncateUtf8Safe = (str, maxBytes) => {
|
|
217
296
|
}
|
218
297
|
return str.slice(0, i);
|
219
298
|
};
|
220
|
-
const MAX_NAME = 100;
|
221
|
-
const MAX_PREFIX = 155;
|
222
299
|
const splitPath = (path) => {
|
223
300
|
if (utf8ByteLength(path) <= MAX_NAME) {
|
224
301
|
return { prefix: "", name: path };
|
@@ -299,10 +376,11 @@ const createTarPacker = (entryItemGenerator, compressionType, signal) => {
|
|
299
376
|
const totalPaddedContentBytes = getPaddedBytes(contentBytes);
|
300
377
|
yield totalPaddedContentBytes;
|
301
378
|
} else {
|
379
|
+
const content = entryItemContent;
|
302
380
|
const tarHeaderBytes = createTarHeader(
|
303
381
|
"file",
|
304
382
|
entryItem.path,
|
305
|
-
|
383
|
+
content.length,
|
306
384
|
entryItem.mode,
|
307
385
|
entryItem.uname,
|
308
386
|
entryItem.gname,
|
@@ -312,10 +390,10 @@ const createTarPacker = (entryItemGenerator, compressionType, signal) => {
|
|
312
390
|
);
|
313
391
|
yield tarHeaderBytes;
|
314
392
|
let position = 0;
|
315
|
-
switch (
|
393
|
+
switch (content.kind) {
|
316
394
|
// Content is a generator
|
317
395
|
case "generator": {
|
318
|
-
for await (const contentBytes of
|
396
|
+
for await (const contentBytes of content.generator) {
|
319
397
|
signal?.throwIfAborted();
|
320
398
|
yield contentBytes;
|
321
399
|
position += contentBytes.length;
|
@@ -324,9 +402,9 @@ const createTarPacker = (entryItemGenerator, compressionType, signal) => {
|
|
324
402
|
}
|
325
403
|
// Content is a readable stream
|
326
404
|
case "readable": {
|
327
|
-
for await (const
|
405
|
+
for await (const chunk of content.readable) {
|
328
406
|
signal?.throwIfAborted();
|
329
|
-
const contentBytes = getBuffer(
|
407
|
+
const contentBytes = getBuffer(chunk);
|
330
408
|
yield contentBytes;
|
331
409
|
position += contentBytes.length;
|
332
410
|
}
|
@@ -364,25 +442,282 @@ const createTarPacker = (entryItemGenerator, compressionType, signal) => {
|
|
364
442
|
switch (ct) {
|
365
443
|
// No compression
|
366
444
|
case "none": {
|
367
|
-
return Readable.from(entryItemIterator());
|
445
|
+
return Readable.from(entryItemIterator(), { signal });
|
368
446
|
}
|
369
447
|
// Gzip compression
|
370
448
|
case "gzip": {
|
371
449
|
const gzipStream = createGzip({ level: 9 });
|
372
|
-
const entryItemStream = Readable.from(entryItemIterator());
|
450
|
+
const entryItemStream = Readable.from(entryItemIterator(), { signal });
|
373
451
|
entryItemStream.pipe(gzipStream);
|
374
452
|
return gzipStream;
|
375
453
|
}
|
376
454
|
}
|
377
455
|
};
|
456
|
+
const parseOctalBytes = (buffer, offset, length) => {
|
457
|
+
const str = buffer.subarray(offset, offset + length).toString("ascii").replace(/\0/g, "").trim();
|
458
|
+
return str ? parseInt(str, 8) : 0;
|
459
|
+
};
|
460
|
+
const parseString = (buffer, offset, length) => {
|
461
|
+
return buffer.subarray(offset, offset + length).toString("utf8").replace(/\0/g, "").trim();
|
462
|
+
};
|
463
|
+
const readExactBytes = async (iterator, size, signal) => {
|
464
|
+
const chunks = [];
|
465
|
+
let totalRead = 0;
|
466
|
+
while (totalRead < size) {
|
467
|
+
signal?.throwIfAborted();
|
468
|
+
const { value, done } = await iterator.next();
|
469
|
+
if (done) {
|
470
|
+
if (totalRead === 0) {
|
471
|
+
return void 0;
|
472
|
+
} else {
|
473
|
+
throw new Error(`Unexpected end of stream: expected ${size} bytes, got ${totalRead} bytes`);
|
474
|
+
}
|
475
|
+
}
|
476
|
+
const chunk = getBuffer(value);
|
477
|
+
const needed = size - totalRead;
|
478
|
+
if (chunk.length <= needed) {
|
479
|
+
chunks.push(chunk);
|
480
|
+
totalRead += chunk.length;
|
481
|
+
} else {
|
482
|
+
chunks.push(chunk.subarray(0, needed));
|
483
|
+
await iterator.return?.(chunk.subarray(needed));
|
484
|
+
totalRead = size;
|
485
|
+
}
|
486
|
+
}
|
487
|
+
return Buffer.concat(chunks, size);
|
488
|
+
};
|
489
|
+
const skipExactBytes = async (iterator, size, signal) => {
|
490
|
+
let totalSkipped = 0;
|
491
|
+
while (totalSkipped < size) {
|
492
|
+
signal?.throwIfAborted();
|
493
|
+
const { value, done } = await iterator.next();
|
494
|
+
if (done) {
|
495
|
+
throw new Error(`Unexpected end of stream: expected to skip ${size} bytes, skipped ${totalSkipped} bytes`);
|
496
|
+
}
|
497
|
+
const chunk = getBuffer(value);
|
498
|
+
const needed = size - totalSkipped;
|
499
|
+
if (chunk.length <= needed) {
|
500
|
+
totalSkipped += chunk.length;
|
501
|
+
} else {
|
502
|
+
await iterator.return?.(chunk.subarray(needed));
|
503
|
+
totalSkipped = size;
|
504
|
+
}
|
505
|
+
}
|
506
|
+
};
|
507
|
+
const skipPaddingBytesTo512Boundary = async (iterator, contentSize, signal) => {
|
508
|
+
const padding = (512 - contentSize % 512) % 512;
|
509
|
+
if (padding > 0) {
|
510
|
+
await skipExactBytes(iterator, padding, signal);
|
511
|
+
}
|
512
|
+
};
|
513
|
+
const parseTarHeader = (buffer) => {
|
514
|
+
if (buffer.every((b) => b === 0)) {
|
515
|
+
return void 0;
|
516
|
+
}
|
517
|
+
const name = parseString(buffer, 0, 100);
|
518
|
+
const mode = parseOctalBytes(buffer, 100, 8);
|
519
|
+
const uid = parseOctalBytes(buffer, 108, 8);
|
520
|
+
const gid = parseOctalBytes(buffer, 116, 8);
|
521
|
+
const size = parseOctalBytes(buffer, 124, 12);
|
522
|
+
const mtime = new Date(parseOctalBytes(buffer, 136, 12) * 1e3);
|
523
|
+
const checksum = parseOctalBytes(buffer, 148, 8);
|
524
|
+
const typeflag = parseString(buffer, 156, 1);
|
525
|
+
const magic = parseString(buffer, 257, 6);
|
526
|
+
const uname = parseString(buffer, 265, 32);
|
527
|
+
const gname = parseString(buffer, 297, 32);
|
528
|
+
const prefix = parseString(buffer, 345, 155);
|
529
|
+
if (magic !== "ustar") {
|
530
|
+
throw new Error(`Invalid tar format: magic="${magic}"`);
|
531
|
+
}
|
532
|
+
let calculatedSum = 0;
|
533
|
+
for (let i = 0; i < 512; i++) {
|
534
|
+
if (i >= 148 && i < 156) {
|
535
|
+
calculatedSum += 32;
|
536
|
+
} else {
|
537
|
+
calculatedSum += buffer[i];
|
538
|
+
}
|
539
|
+
}
|
540
|
+
if (calculatedSum !== checksum) {
|
541
|
+
throw new Error(`Invalid checksum: expected ${checksum}, got ${calculatedSum}`);
|
542
|
+
}
|
543
|
+
let path = prefix ? `${prefix}/${name}` : name;
|
544
|
+
if (path.endsWith("/")) {
|
545
|
+
path = path.slice(0, -1);
|
546
|
+
}
|
547
|
+
const kind = typeflag === "5" ? "directory" : "file";
|
548
|
+
return {
|
549
|
+
kind,
|
550
|
+
path,
|
551
|
+
size,
|
552
|
+
mode,
|
553
|
+
uid,
|
554
|
+
gid,
|
555
|
+
mtime,
|
556
|
+
uname: uname || uid.toString(),
|
557
|
+
gname: gname || gid.toString(),
|
558
|
+
checksum,
|
559
|
+
consumed: false
|
560
|
+
};
|
561
|
+
};
|
562
|
+
const createBufferedAsyncIterator = (iterable, signal) => {
|
563
|
+
const buffer = [];
|
564
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
565
|
+
return {
|
566
|
+
next: async () => {
|
567
|
+
signal?.throwIfAborted();
|
568
|
+
if (buffer.length > 0) {
|
569
|
+
return { value: buffer.shift(), done: false };
|
570
|
+
}
|
571
|
+
return iterator.next();
|
572
|
+
},
|
573
|
+
return: async (value) => {
|
574
|
+
if (value !== void 0) {
|
575
|
+
buffer.unshift(value);
|
576
|
+
}
|
577
|
+
return { value: void 0, done: false };
|
578
|
+
}
|
579
|
+
};
|
580
|
+
};
|
581
|
+
const createReadableFromIterator = (iterator, size, signal, consumedRef) => {
|
582
|
+
const generator = async function* () {
|
583
|
+
let remainingBytes = size;
|
584
|
+
while (remainingBytes > 0) {
|
585
|
+
signal?.throwIfAborted();
|
586
|
+
const { value, done } = await iterator.next();
|
587
|
+
if (done) {
|
588
|
+
throw new Error(`Unexpected end of stream: expected ${size} bytes, remaining ${remainingBytes} bytes`);
|
589
|
+
}
|
590
|
+
const chunk = getBuffer(value);
|
591
|
+
if (chunk.length <= remainingBytes) {
|
592
|
+
remainingBytes -= chunk.length;
|
593
|
+
yield chunk;
|
594
|
+
} else {
|
595
|
+
const needed = chunk.subarray(0, remainingBytes);
|
596
|
+
const excess = chunk.subarray(remainingBytes);
|
597
|
+
remainingBytes = 0;
|
598
|
+
await iterator.return?.(excess);
|
599
|
+
yield needed;
|
600
|
+
break;
|
601
|
+
}
|
602
|
+
}
|
603
|
+
await skipPaddingBytesTo512Boundary(iterator, size, signal);
|
604
|
+
consumedRef.consumed = true;
|
605
|
+
};
|
606
|
+
return Readable.from(generator(), { signal });
|
607
|
+
};
|
608
|
+
const createTarExtractor = async function* (readable, compressionType, signal) {
|
609
|
+
const ct = compressionType ?? "none";
|
610
|
+
let inputStream;
|
611
|
+
switch (ct) {
|
612
|
+
case "gzip":
|
613
|
+
const gunzip = createGunzip();
|
614
|
+
readable.pipe(gunzip);
|
615
|
+
inputStream = gunzip;
|
616
|
+
break;
|
617
|
+
case "none":
|
618
|
+
default:
|
619
|
+
inputStream = readable;
|
620
|
+
break;
|
621
|
+
}
|
622
|
+
const iterator = createBufferedAsyncIterator(inputStream, signal);
|
623
|
+
let header;
|
624
|
+
while (true) {
|
625
|
+
signal?.throwIfAborted();
|
626
|
+
if (header?.kind === "file" && !header.consumed) {
|
627
|
+
await skipExactBytes(iterator, header.size, signal);
|
628
|
+
await skipPaddingBytesTo512Boundary(iterator, header.size, signal);
|
629
|
+
header.consumed = true;
|
630
|
+
}
|
631
|
+
let headerBuffer;
|
632
|
+
try {
|
633
|
+
headerBuffer = await readExactBytes(iterator, 512, signal);
|
634
|
+
} catch (error) {
|
635
|
+
if (error instanceof Error && error.message.includes("Unexpected end of stream")) {
|
636
|
+
throw new Error("Invalid tar format: incomplete header");
|
637
|
+
}
|
638
|
+
throw error;
|
639
|
+
}
|
640
|
+
if (headerBuffer === void 0) {
|
641
|
+
break;
|
642
|
+
}
|
643
|
+
header = parseTarHeader(headerBuffer);
|
644
|
+
if (!header) {
|
645
|
+
const secondBlock = await readExactBytes(iterator, 512, signal);
|
646
|
+
if (secondBlock === void 0 || secondBlock.every((b) => b === 0)) {
|
647
|
+
break;
|
648
|
+
}
|
649
|
+
throw new Error("Invalid tar format: expected terminator block");
|
650
|
+
}
|
651
|
+
if (header.kind === "directory") {
|
652
|
+
yield {
|
653
|
+
kind: "directory",
|
654
|
+
path: header.path,
|
655
|
+
mode: header.mode,
|
656
|
+
uid: header.uid,
|
657
|
+
gid: header.gid,
|
658
|
+
uname: header.uname,
|
659
|
+
gname: header.gname,
|
660
|
+
date: header.mtime
|
661
|
+
};
|
662
|
+
} else {
|
663
|
+
const currentHeader = header;
|
664
|
+
yield {
|
665
|
+
kind: "file",
|
666
|
+
path: currentHeader.path,
|
667
|
+
mode: currentHeader.mode,
|
668
|
+
uid: currentHeader.uid,
|
669
|
+
gid: currentHeader.gid,
|
670
|
+
uname: currentHeader.uname,
|
671
|
+
gname: currentHeader.gname,
|
672
|
+
date: currentHeader.mtime,
|
673
|
+
getContent: async (type) => {
|
674
|
+
if (currentHeader.consumed) {
|
675
|
+
throw new Error("Content has already been consumed. Multiple calls to getContent are not supported.");
|
676
|
+
}
|
677
|
+
switch (type) {
|
678
|
+
// For string
|
679
|
+
case "string": {
|
680
|
+
const dataBuffer = await readExactBytes(iterator, currentHeader.size, signal);
|
681
|
+
if (dataBuffer === void 0) {
|
682
|
+
throw new Error(`Unexpected end of stream while reading file data for ${currentHeader.path}`);
|
683
|
+
}
|
684
|
+
await skipPaddingBytesTo512Boundary(iterator, currentHeader.size, signal);
|
685
|
+
currentHeader.consumed = true;
|
686
|
+
return dataBuffer.toString("utf8");
|
687
|
+
}
|
688
|
+
// For buffer
|
689
|
+
case "buffer": {
|
690
|
+
const dataBuffer = await readExactBytes(iterator, currentHeader.size, signal);
|
691
|
+
if (dataBuffer === void 0) {
|
692
|
+
throw new Error(`Unexpected end of stream while reading file data for ${currentHeader.path}`);
|
693
|
+
}
|
694
|
+
await skipPaddingBytesTo512Boundary(iterator, currentHeader.size, signal);
|
695
|
+
currentHeader.consumed = true;
|
696
|
+
return dataBuffer;
|
697
|
+
}
|
698
|
+
// For Readble stream
|
699
|
+
case "readable": {
|
700
|
+
const readable2 = createReadableFromIterator(iterator, currentHeader.size, signal, currentHeader);
|
701
|
+
return readable2;
|
702
|
+
}
|
703
|
+
default:
|
704
|
+
throw new Error(`Unsupported content type: ${type}`);
|
705
|
+
}
|
706
|
+
}
|
707
|
+
};
|
708
|
+
}
|
709
|
+
}
|
710
|
+
};
|
378
711
|
export {
|
379
712
|
createDirectoryItem,
|
713
|
+
createEntryItemGenerator,
|
380
714
|
createFileItem,
|
381
715
|
createGeneratorFileItem,
|
382
716
|
createReadFileItem,
|
383
717
|
createReadableFileItem,
|
718
|
+
createTarExtractor,
|
384
719
|
createTarPacker,
|
385
|
-
|
720
|
+
extractTo,
|
386
721
|
storeReaderToFile
|
387
722
|
};
|
388
723
|
//# sourceMappingURL=index.js.map
|