tar-xz 0.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/LICENSE +165 -0
- package/README.md +201 -0
- package/lib/browser/create.d.ts +27 -0
- package/lib/browser/create.d.ts.map +1 -0
- package/lib/browser/create.js +113 -0
- package/lib/browser/create.js.map +1 -0
- package/lib/browser/extract.d.ts +24 -0
- package/lib/browser/extract.d.ts.map +1 -0
- package/lib/browser/extract.js +112 -0
- package/lib/browser/extract.js.map +1 -0
- package/lib/browser/index.d.ts +7 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +7 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/list.d.ts +23 -0
- package/lib/browser/list.d.ts.map +1 -0
- package/lib/browser/list.js +81 -0
- package/lib/browser/list.js.map +1 -0
- package/lib/index.browser.d.ts +12 -0
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js +14 -0
- package/lib/index.browser.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +14 -0
- package/lib/index.js.map +1 -0
- package/lib/node/create.d.ts +22 -0
- package/lib/node/create.d.ts.map +1 -0
- package/lib/node/create.js +155 -0
- package/lib/node/create.js.map +1 -0
- package/lib/node/extract.d.ts +30 -0
- package/lib/node/extract.d.ts.map +1 -0
- package/lib/node/extract.js +274 -0
- package/lib/node/extract.js.map +1 -0
- package/lib/node/index.d.ts +7 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +7 -0
- package/lib/node/index.js.map +1 -0
- package/lib/node/list.d.ts +20 -0
- package/lib/node/list.d.ts.map +1 -0
- package/lib/node/list.js +115 -0
- package/lib/node/list.js.map +1 -0
- package/lib/tar/checksum.d.ts +40 -0
- package/lib/tar/checksum.d.ts.map +1 -0
- package/lib/tar/checksum.js +91 -0
- package/lib/tar/checksum.js.map +1 -0
- package/lib/tar/format.d.ts +87 -0
- package/lib/tar/format.d.ts.map +1 -0
- package/lib/tar/format.js +244 -0
- package/lib/tar/format.js.map +1 -0
- package/lib/tar/index.d.ts +8 -0
- package/lib/tar/index.d.ts.map +1 -0
- package/lib/tar/index.js +6 -0
- package/lib/tar/index.js.map +1 -0
- package/lib/tar/pax.d.ts +82 -0
- package/lib/tar/pax.d.ts.map +1 -0
- package/lib/tar/pax.js +185 -0
- package/lib/tar/pax.js.map +1 -0
- package/lib/types.d.ts +144 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +26 -0
- package/lib/types.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js TAR extraction with XZ decompression
|
|
3
|
+
*/
|
|
4
|
+
import { createReadStream, promises as fs } from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import { Writable } from 'node:stream';
|
|
7
|
+
import { pipeline } from 'node:stream/promises';
|
|
8
|
+
import { createUnxz } from 'node-liblzma';
|
|
9
|
+
import { applyPaxAttributes, BLOCK_SIZE, calculatePadding, isEmptyBlock, parseHeader, parsePaxData, } from '../tar/index.js';
|
|
10
|
+
import { TarEntryType } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Transform stream that unpacks TAR format
|
|
13
|
+
*/
|
|
14
|
+
class TarUnpack extends Writable {
|
|
15
|
+
buffer = Buffer.alloc(0);
|
|
16
|
+
currentEntry = null;
|
|
17
|
+
bytesRemaining = 0;
|
|
18
|
+
paddingRemaining = 0;
|
|
19
|
+
contentChunks = [];
|
|
20
|
+
paxAttrs = null;
|
|
21
|
+
emptyBlockCount = 0;
|
|
22
|
+
entries = [];
|
|
23
|
+
_write(chunk, _encoding, callback) {
|
|
24
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
25
|
+
try {
|
|
26
|
+
this.processBuffer();
|
|
27
|
+
callback();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
callback(error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
processBuffer() {
|
|
34
|
+
while (this.buffer.length > 0) {
|
|
35
|
+
// Handle padding
|
|
36
|
+
if (this.paddingRemaining > 0) {
|
|
37
|
+
const skip = Math.min(this.paddingRemaining, this.buffer.length);
|
|
38
|
+
this.buffer = this.buffer.subarray(skip);
|
|
39
|
+
this.paddingRemaining -= skip;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Handle file content
|
|
43
|
+
if (this.bytesRemaining > 0 && this.currentEntry) {
|
|
44
|
+
const readSize = Math.min(this.bytesRemaining, this.buffer.length);
|
|
45
|
+
this.contentChunks.push(this.buffer.subarray(0, readSize));
|
|
46
|
+
this.buffer = this.buffer.subarray(readSize);
|
|
47
|
+
this.bytesRemaining -= readSize;
|
|
48
|
+
// Entry complete
|
|
49
|
+
if (this.bytesRemaining === 0) {
|
|
50
|
+
const content = Buffer.concat(this.contentChunks);
|
|
51
|
+
this.entries.push({ ...this.currentEntry, content });
|
|
52
|
+
// Calculate padding
|
|
53
|
+
this.paddingRemaining = calculatePadding(this.currentEntry.size);
|
|
54
|
+
this.currentEntry = null;
|
|
55
|
+
this.contentChunks = [];
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Need a full block for header
|
|
60
|
+
if (this.buffer.length < BLOCK_SIZE) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
const headerBlock = this.buffer.subarray(0, BLOCK_SIZE);
|
|
64
|
+
this.buffer = this.buffer.subarray(BLOCK_SIZE);
|
|
65
|
+
// Check for end-of-archive
|
|
66
|
+
if (isEmptyBlock(headerBlock)) {
|
|
67
|
+
this.emptyBlockCount++;
|
|
68
|
+
if (this.emptyBlockCount >= 2) {
|
|
69
|
+
// End of archive
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
this.emptyBlockCount = 0;
|
|
75
|
+
// Parse header
|
|
76
|
+
let entry = parseHeader(headerBlock);
|
|
77
|
+
if (!entry) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Handle PAX headers
|
|
81
|
+
if (entry.type === TarEntryType.PAX_HEADER) {
|
|
82
|
+
// Read PAX data
|
|
83
|
+
const paxSize = entry.size;
|
|
84
|
+
const paxPadding = calculatePadding(paxSize);
|
|
85
|
+
const totalNeeded = paxSize + paxPadding;
|
|
86
|
+
if (this.buffer.length < totalNeeded) {
|
|
87
|
+
// Put header back and wait for more data
|
|
88
|
+
this.buffer = Buffer.concat([headerBlock, this.buffer]);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
const paxData = this.buffer.subarray(0, paxSize);
|
|
92
|
+
this.buffer = this.buffer.subarray(paxSize + paxPadding);
|
|
93
|
+
this.paxAttrs = parsePaxData(paxData);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (entry.type === TarEntryType.PAX_GLOBAL) {
|
|
97
|
+
// Skip global PAX headers (we don't support them yet)
|
|
98
|
+
const skipSize = entry.size + calculatePadding(entry.size);
|
|
99
|
+
if (this.buffer.length < skipSize) {
|
|
100
|
+
this.buffer = Buffer.concat([headerBlock, this.buffer]);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
this.buffer = this.buffer.subarray(skipSize);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// Apply PAX attributes if present
|
|
107
|
+
if (this.paxAttrs) {
|
|
108
|
+
entry = applyPaxAttributes(entry, this.paxAttrs);
|
|
109
|
+
this.paxAttrs = null;
|
|
110
|
+
}
|
|
111
|
+
// Handle directories (no content)
|
|
112
|
+
if (entry.type === TarEntryType.DIRECTORY) {
|
|
113
|
+
this.entries.push({ ...entry, content: Buffer.alloc(0) });
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// Handle symlinks (no content)
|
|
117
|
+
if (entry.type === TarEntryType.SYMLINK || entry.type === TarEntryType.HARDLINK) {
|
|
118
|
+
this.entries.push({ ...entry, content: Buffer.alloc(0) });
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
// Regular file - prepare to read content
|
|
122
|
+
if (entry.size > 0) {
|
|
123
|
+
this.currentEntry = entry;
|
|
124
|
+
this.bytesRemaining = entry.size;
|
|
125
|
+
this.contentChunks = [];
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
this.entries.push({ ...entry, content: Buffer.alloc(0) });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
_final(callback) {
|
|
133
|
+
if (this.bytesRemaining > 0) {
|
|
134
|
+
callback(new Error(`Unexpected end of archive, ${this.bytesRemaining} bytes remaining`));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
callback();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Strip leading path components from a path
|
|
143
|
+
*/
|
|
144
|
+
function stripPath(filePath, strip) {
|
|
145
|
+
if (strip <= 0) {
|
|
146
|
+
return filePath;
|
|
147
|
+
}
|
|
148
|
+
const parts = filePath.split('/');
|
|
149
|
+
return parts.slice(strip).join('/');
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Validate that a path doesn't escape the target directory (path traversal protection)
|
|
153
|
+
* @throws Error if path traversal is detected
|
|
154
|
+
*/
|
|
155
|
+
function validatePath(destPath, cwd) {
|
|
156
|
+
const resolvedDest = path.resolve(destPath);
|
|
157
|
+
const resolvedCwd = path.resolve(cwd);
|
|
158
|
+
// Ensure the destination path starts with the cwd (no escape via ../)
|
|
159
|
+
if (!resolvedDest.startsWith(resolvedCwd + path.sep) && resolvedDest !== resolvedCwd) {
|
|
160
|
+
throw new Error(`Path traversal detected: ${destPath} escapes ${cwd}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Extract a tar.xz archive
|
|
165
|
+
*
|
|
166
|
+
* @param options - Extraction options
|
|
167
|
+
* @returns Promise with list of extracted entries
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* await extract({
|
|
172
|
+
* file: 'archive.tar.xz',
|
|
173
|
+
* cwd: '/dest',
|
|
174
|
+
* strip: 1
|
|
175
|
+
* });
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export async function extract(options) {
|
|
179
|
+
const { file, cwd = process.cwd(), strip = 0, filter, preserveOwner = false } = options;
|
|
180
|
+
// Create decompression and unpacking streams
|
|
181
|
+
const inputStream = createReadStream(file);
|
|
182
|
+
const unxzStream = createUnxz();
|
|
183
|
+
const tarUnpack = new TarUnpack();
|
|
184
|
+
// Run pipeline
|
|
185
|
+
await pipeline(inputStream, unxzStream, tarUnpack);
|
|
186
|
+
// Extract files
|
|
187
|
+
const extractedEntries = [];
|
|
188
|
+
for (const entry of tarUnpack.entries) {
|
|
189
|
+
// Apply strip
|
|
190
|
+
const strippedName = stripPath(entry.name, strip);
|
|
191
|
+
if (!strippedName) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
// Apply filter
|
|
195
|
+
const entryForFilter = { ...entry, name: strippedName };
|
|
196
|
+
if (filter && !filter(entryForFilter)) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const destPath = path.join(cwd, strippedName);
|
|
200
|
+
// Validate path doesn't escape cwd (path traversal protection)
|
|
201
|
+
validatePath(destPath, cwd);
|
|
202
|
+
// Ensure parent directory exists
|
|
203
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
204
|
+
if (entry.type === TarEntryType.DIRECTORY) {
|
|
205
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
206
|
+
}
|
|
207
|
+
else if (entry.type === TarEntryType.SYMLINK) {
|
|
208
|
+
try {
|
|
209
|
+
await fs.unlink(destPath);
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Ignore if doesn't exist
|
|
213
|
+
}
|
|
214
|
+
await fs.symlink(entry.linkname, destPath);
|
|
215
|
+
}
|
|
216
|
+
else if (entry.type === TarEntryType.HARDLINK) {
|
|
217
|
+
const linkDest = path.join(cwd, stripPath(entry.linkname, strip));
|
|
218
|
+
try {
|
|
219
|
+
await fs.unlink(destPath);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Ignore if doesn't exist
|
|
223
|
+
}
|
|
224
|
+
await fs.link(linkDest, destPath);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
// Regular file
|
|
228
|
+
await fs.writeFile(destPath, entry.content);
|
|
229
|
+
}
|
|
230
|
+
// Set permissions
|
|
231
|
+
try {
|
|
232
|
+
await fs.chmod(destPath, entry.mode);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Ignore permission errors
|
|
236
|
+
}
|
|
237
|
+
// Set ownership if requested and running as root
|
|
238
|
+
if (preserveOwner && process.getuid?.() === 0) {
|
|
239
|
+
try {
|
|
240
|
+
await fs.chown(destPath, entry.uid, entry.gid);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Ignore ownership errors
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Set modification time
|
|
247
|
+
try {
|
|
248
|
+
const mtime = new Date(entry.mtime * 1000);
|
|
249
|
+
await fs.utimes(destPath, mtime, mtime);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Ignore time errors
|
|
253
|
+
}
|
|
254
|
+
extractedEntries.push(entryForFilter);
|
|
255
|
+
}
|
|
256
|
+
return extractedEntries;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Extract archive to memory (no disk writes)
|
|
260
|
+
*/
|
|
261
|
+
export async function extractToMemory(file, options = {}) {
|
|
262
|
+
const { strip = 0, filter } = options;
|
|
263
|
+
const inputStream = createReadStream(file);
|
|
264
|
+
const unxzStream = createUnxz();
|
|
265
|
+
const tarUnpack = new TarUnpack();
|
|
266
|
+
await pipeline(inputStream, unxzStream, tarUnpack);
|
|
267
|
+
return tarUnpack.entries
|
|
268
|
+
.map((entry) => ({
|
|
269
|
+
...entry,
|
|
270
|
+
name: stripPath(entry.name, strip),
|
|
271
|
+
}))
|
|
272
|
+
.filter((entry) => entry.name && (!filter || filter(entry)));
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/node/extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js TAR listing with XZ decompression
|
|
3
|
+
*/
|
|
4
|
+
import { type ListOptions, type TarEntry } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* List contents of a tar.xz archive
|
|
7
|
+
*
|
|
8
|
+
* @param options - List options
|
|
9
|
+
* @returns Promise with list of entries
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const entries = await list({ file: 'archive.tar.xz' });
|
|
14
|
+
* for (const entry of entries) {
|
|
15
|
+
* console.log(entry.name, entry.size);
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function list(options: ListOptions): Promise<TarEntry[]>;
|
|
20
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/node/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAsG5E;;;;;;;;;;;;;GAaG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAUpE"}
|
package/lib/node/list.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js TAR listing with XZ decompression
|
|
3
|
+
*/
|
|
4
|
+
import { createReadStream } from 'node:fs';
|
|
5
|
+
import { Writable } from 'node:stream';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { createUnxz } from 'node-liblzma';
|
|
8
|
+
import { applyPaxAttributes, BLOCK_SIZE, calculatePadding, isEmptyBlock, parseHeader, parsePaxData, } from '../tar/index.js';
|
|
9
|
+
import { TarEntryType } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Writable stream that lists TAR entries without extracting content
|
|
12
|
+
*/
|
|
13
|
+
class TarList extends Writable {
|
|
14
|
+
buffer = Buffer.alloc(0);
|
|
15
|
+
bytesToSkip = 0;
|
|
16
|
+
paxAttrs = null;
|
|
17
|
+
emptyBlockCount = 0;
|
|
18
|
+
entries = [];
|
|
19
|
+
_write(chunk, _encoding, callback) {
|
|
20
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
21
|
+
try {
|
|
22
|
+
this.processBuffer();
|
|
23
|
+
callback();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
callback(error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
processBuffer() {
|
|
30
|
+
while (this.buffer.length > 0) {
|
|
31
|
+
// Skip content and padding
|
|
32
|
+
if (this.bytesToSkip > 0) {
|
|
33
|
+
const skip = Math.min(this.bytesToSkip, this.buffer.length);
|
|
34
|
+
this.buffer = this.buffer.subarray(skip);
|
|
35
|
+
this.bytesToSkip -= skip;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Need a full block for header
|
|
39
|
+
if (this.buffer.length < BLOCK_SIZE) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
const headerBlock = this.buffer.subarray(0, BLOCK_SIZE);
|
|
43
|
+
this.buffer = this.buffer.subarray(BLOCK_SIZE);
|
|
44
|
+
// Check for end-of-archive
|
|
45
|
+
if (isEmptyBlock(headerBlock)) {
|
|
46
|
+
this.emptyBlockCount++;
|
|
47
|
+
if (this.emptyBlockCount >= 2) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
this.emptyBlockCount = 0;
|
|
53
|
+
// Parse header
|
|
54
|
+
let entry = parseHeader(headerBlock);
|
|
55
|
+
if (!entry) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Handle PAX headers
|
|
59
|
+
if (entry.type === TarEntryType.PAX_HEADER) {
|
|
60
|
+
const paxSize = entry.size;
|
|
61
|
+
const paxPadding = calculatePadding(paxSize);
|
|
62
|
+
const totalNeeded = paxSize + paxPadding;
|
|
63
|
+
if (this.buffer.length < totalNeeded) {
|
|
64
|
+
this.buffer = Buffer.concat([headerBlock, this.buffer]);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
const paxData = this.buffer.subarray(0, paxSize);
|
|
68
|
+
this.buffer = this.buffer.subarray(paxSize + paxPadding);
|
|
69
|
+
this.paxAttrs = parsePaxData(paxData);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (entry.type === TarEntryType.PAX_GLOBAL) {
|
|
73
|
+
this.bytesToSkip = entry.size + calculatePadding(entry.size);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Apply PAX attributes if present
|
|
77
|
+
if (this.paxAttrs) {
|
|
78
|
+
entry = applyPaxAttributes(entry, this.paxAttrs);
|
|
79
|
+
this.paxAttrs = null;
|
|
80
|
+
}
|
|
81
|
+
// Add entry to list
|
|
82
|
+
this.entries.push(entry);
|
|
83
|
+
// Skip content
|
|
84
|
+
if (entry.size > 0) {
|
|
85
|
+
this.bytesToSkip = entry.size + calculatePadding(entry.size);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
_final(callback) {
|
|
90
|
+
callback();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* List contents of a tar.xz archive
|
|
95
|
+
*
|
|
96
|
+
* @param options - List options
|
|
97
|
+
* @returns Promise with list of entries
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* const entries = await list({ file: 'archive.tar.xz' });
|
|
102
|
+
* for (const entry of entries) {
|
|
103
|
+
* console.log(entry.name, entry.size);
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export async function list(options) {
|
|
108
|
+
const { file } = options;
|
|
109
|
+
const inputStream = createReadStream(file);
|
|
110
|
+
const unxzStream = createUnxz();
|
|
111
|
+
const tarList = new TarList();
|
|
112
|
+
await pipeline(inputStream, unxzStream, tarList);
|
|
113
|
+
return tarList.entries;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/node/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TAR header checksum calculation
|
|
3
|
+
*
|
|
4
|
+
* The checksum is a simple sum of all bytes in the header block,
|
|
5
|
+
* with the 8-byte checksum field (bytes 148-155) treated as spaces (0x20).
|
|
6
|
+
*/
|
|
7
|
+
/** Offset of checksum field in TAR header */
|
|
8
|
+
export declare const CHECKSUM_OFFSET = 148;
|
|
9
|
+
/** Length of checksum field */
|
|
10
|
+
export declare const CHECKSUM_LENGTH = 8;
|
|
11
|
+
/**
|
|
12
|
+
* Calculate TAR header checksum
|
|
13
|
+
*
|
|
14
|
+
* @param header - 512-byte TAR header block
|
|
15
|
+
* @returns Checksum value (sum of unsigned bytes, checksum field as spaces)
|
|
16
|
+
*/
|
|
17
|
+
export declare function calculateChecksum(header: Uint8Array): number;
|
|
18
|
+
/**
|
|
19
|
+
* Verify TAR header checksum
|
|
20
|
+
*
|
|
21
|
+
* @param header - 512-byte TAR header block
|
|
22
|
+
* @returns true if checksum is valid
|
|
23
|
+
*/
|
|
24
|
+
export declare function verifyChecksum(header: Uint8Array): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Write checksum to TAR header
|
|
27
|
+
*
|
|
28
|
+
* @param header - 512-byte TAR header block (will be modified)
|
|
29
|
+
*/
|
|
30
|
+
export declare function writeChecksum(header: Uint8Array): void;
|
|
31
|
+
/**
|
|
32
|
+
* Parse octal number from header field
|
|
33
|
+
*
|
|
34
|
+
* @param header - Header buffer
|
|
35
|
+
* @param offset - Field offset
|
|
36
|
+
* @param length - Field length
|
|
37
|
+
* @returns Parsed number
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseOctal(header: Uint8Array, offset: number, length: number): number;
|
|
40
|
+
//# sourceMappingURL=checksum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../../src/tar/checksum.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6CAA6C;AAC7C,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,+BAA+B;AAC/B,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAiB5D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAK1D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAgBtD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAsBrF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TAR header checksum calculation
|
|
3
|
+
*
|
|
4
|
+
* The checksum is a simple sum of all bytes in the header block,
|
|
5
|
+
* with the 8-byte checksum field (bytes 148-155) treated as spaces (0x20).
|
|
6
|
+
*/
|
|
7
|
+
/** Offset of checksum field in TAR header */
|
|
8
|
+
export const CHECKSUM_OFFSET = 148;
|
|
9
|
+
/** Length of checksum field */
|
|
10
|
+
export const CHECKSUM_LENGTH = 8;
|
|
11
|
+
/**
|
|
12
|
+
* Calculate TAR header checksum
|
|
13
|
+
*
|
|
14
|
+
* @param header - 512-byte TAR header block
|
|
15
|
+
* @returns Checksum value (sum of unsigned bytes, checksum field as spaces)
|
|
16
|
+
*/
|
|
17
|
+
export function calculateChecksum(header) {
|
|
18
|
+
if (header.length !== 512) {
|
|
19
|
+
throw new Error(`Invalid TAR header length: ${header.length}, expected 512`);
|
|
20
|
+
}
|
|
21
|
+
let sum = 0;
|
|
22
|
+
for (let i = 0; i < 512; i++) {
|
|
23
|
+
// Treat checksum field (bytes 148-155) as spaces (0x20 = 32)
|
|
24
|
+
if (i >= CHECKSUM_OFFSET && i < CHECKSUM_OFFSET + CHECKSUM_LENGTH) {
|
|
25
|
+
sum += 0x20;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
sum += header[i];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return sum;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Verify TAR header checksum
|
|
35
|
+
*
|
|
36
|
+
* @param header - 512-byte TAR header block
|
|
37
|
+
* @returns true if checksum is valid
|
|
38
|
+
*/
|
|
39
|
+
export function verifyChecksum(header) {
|
|
40
|
+
const calculated = calculateChecksum(header);
|
|
41
|
+
const stored = parseOctal(header, CHECKSUM_OFFSET, CHECKSUM_LENGTH);
|
|
42
|
+
return calculated === stored;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Write checksum to TAR header
|
|
46
|
+
*
|
|
47
|
+
* @param header - 512-byte TAR header block (will be modified)
|
|
48
|
+
*/
|
|
49
|
+
export function writeChecksum(header) {
|
|
50
|
+
// First, fill checksum field with spaces
|
|
51
|
+
for (let i = 0; i < CHECKSUM_LENGTH; i++) {
|
|
52
|
+
header[CHECKSUM_OFFSET + i] = 0x20;
|
|
53
|
+
}
|
|
54
|
+
// Calculate checksum
|
|
55
|
+
const checksum = calculateChecksum(header);
|
|
56
|
+
// Write checksum as 6-digit octal, space, null
|
|
57
|
+
const octalStr = checksum.toString(8).padStart(6, '0');
|
|
58
|
+
for (let i = 0; i < 6; i++) {
|
|
59
|
+
header[CHECKSUM_OFFSET + i] = octalStr.charCodeAt(i);
|
|
60
|
+
}
|
|
61
|
+
header[CHECKSUM_OFFSET + 6] = 0x00; // null terminator
|
|
62
|
+
header[CHECKSUM_OFFSET + 7] = 0x20; // space
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse octal number from header field
|
|
66
|
+
*
|
|
67
|
+
* @param header - Header buffer
|
|
68
|
+
* @param offset - Field offset
|
|
69
|
+
* @param length - Field length
|
|
70
|
+
* @returns Parsed number
|
|
71
|
+
*/
|
|
72
|
+
export function parseOctal(header, offset, length) {
|
|
73
|
+
let str = '';
|
|
74
|
+
for (let i = 0; i < length; i++) {
|
|
75
|
+
const byte = header[offset + i];
|
|
76
|
+
// Stop at null or space
|
|
77
|
+
if (byte === 0 || byte === 0x20) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
str += String.fromCharCode(byte);
|
|
81
|
+
}
|
|
82
|
+
if (str.length === 0) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
const value = Number.parseInt(str, 8);
|
|
86
|
+
if (Number.isNaN(value)) {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=checksum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.js","sourceRoot":"","sources":["../../src/tar/checksum.ts"],"names":[],"mappings":"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"}
|