@holydeck/cli 2026.9.2
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 +21 -0
- package/README.md +234 -0
- package/dist/BrowserWebSocketTransport-H3D6MINS.js +12 -0
- package/dist/BrowserWebSocketTransport-H3D6MINS.js.map +1 -0
- package/dist/LaunchOptions-42ZS55HH.js +12 -0
- package/dist/LaunchOptions-42ZS55HH.js.map +1 -0
- package/dist/NodeWebSocketTransport-BXHQGXRM.js +15 -0
- package/dist/NodeWebSocketTransport-BXHQGXRM.js.map +1 -0
- package/dist/bidi-25S23FWJ.js +18358 -0
- package/dist/bidi-25S23FWJ.js.map +1 -0
- package/dist/chunk-2BLOYUSF.js +795 -0
- package/dist/chunk-2BLOYUSF.js.map +1 -0
- package/dist/chunk-43CZTS57.js +38 -0
- package/dist/chunk-43CZTS57.js.map +1 -0
- package/dist/chunk-DIBLSFAG.js +34 -0
- package/dist/chunk-DIBLSFAG.js.map +1 -0
- package/dist/chunk-IEJ3OX3N.js +52 -0
- package/dist/chunk-IEJ3OX3N.js.map +1 -0
- package/dist/chunk-JM4YIWBN.js +3796 -0
- package/dist/chunk-JM4YIWBN.js.map +1 -0
- package/dist/chunk-NP3DTWF7.js +23282 -0
- package/dist/chunk-NP3DTWF7.js.map +1 -0
- package/dist/chunk-SWG4X375.js +51 -0
- package/dist/chunk-SWG4X375.js.map +1 -0
- package/dist/chunk-UC6TFXMD.js +2821 -0
- package/dist/chunk-UC6TFXMD.js.map +1 -0
- package/dist/chunk-V4BIHFVZ.js +2287 -0
- package/dist/chunk-V4BIHFVZ.js.map +1 -0
- package/dist/chunk-V77AQPDK.js +20 -0
- package/dist/chunk-V77AQPDK.js.map +1 -0
- package/dist/chunk-XAENXL52.js +101 -0
- package/dist/chunk-XAENXL52.js.map +1 -0
- package/dist/cli.js +64101 -0
- package/dist/cli.js.map +1 -0
- package/dist/dist-3ZE2HBJQ.js +20447 -0
- package/dist/dist-3ZE2HBJQ.js.map +1 -0
- package/dist/dist-575AQY5L.js +1161 -0
- package/dist/dist-575AQY5L.js.map +1 -0
- package/dist/dist-DL5M2SDJ.js +117 -0
- package/dist/dist-DL5M2SDJ.js.map +1 -0
- package/dist/dist-OMWR53J4.js +4713 -0
- package/dist/dist-OMWR53J4.js.map +1 -0
- package/dist/dist-UT6HKKCD.js +281 -0
- package/dist/dist-UT6HKKCD.js.map +1 -0
- package/dist/fs-P6GYHPGZ.js +1685 -0
- package/dist/fs-P6GYHPGZ.js.map +1 -0
- package/dist/helpers-64DWIL6C.js +21 -0
- package/dist/helpers-64DWIL6C.js.map +1 -0
- package/dist/main-IQ64YDOJ.js +61 -0
- package/dist/main-IQ64YDOJ.js.map +1 -0
- package/dist/puppeteer-RDWY6FSG.js +2386 -0
- package/dist/puppeteer-RDWY6FSG.js.map +1 -0
- package/dist/yargs-KMQWKLG6.js +3264 -0
- package/dist/yargs-KMQWKLG6.js.map +1 -0
- package/dist/yauzl-7KG7KPPF.js +1355 -0
- package/dist/yauzl-7KG7KPPF.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,1685 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __holydeckCreateRequire } from 'node:module';
|
|
3
|
+
const require = __holydeckCreateRequire(import.meta.url);
|
|
4
|
+
import "./chunk-IEJ3OX3N.js";
|
|
5
|
+
|
|
6
|
+
// ../../node_modules/.pnpm/modern-tar@0.8.5/node_modules/modern-tar/dist/packer-kJPaRbFA.js
|
|
7
|
+
var FILE = "file";
|
|
8
|
+
var LINK = "link";
|
|
9
|
+
var SYMLINK = "symlink";
|
|
10
|
+
var DIRECTORY = "directory";
|
|
11
|
+
var TYPEFLAG = {
|
|
12
|
+
file: "0",
|
|
13
|
+
link: "1",
|
|
14
|
+
symlink: "2",
|
|
15
|
+
"character-device": "3",
|
|
16
|
+
"block-device": "4",
|
|
17
|
+
directory: "5",
|
|
18
|
+
fifo: "6",
|
|
19
|
+
"pax-header": "x",
|
|
20
|
+
"pax-global-header": "g",
|
|
21
|
+
"gnu-long-name": "L",
|
|
22
|
+
"gnu-long-link-name": "K"
|
|
23
|
+
};
|
|
24
|
+
var FLAGTYPE = {
|
|
25
|
+
"0": FILE,
|
|
26
|
+
"1": LINK,
|
|
27
|
+
"2": SYMLINK,
|
|
28
|
+
"3": "character-device",
|
|
29
|
+
"4": "block-device",
|
|
30
|
+
"5": DIRECTORY,
|
|
31
|
+
"6": "fifo",
|
|
32
|
+
x: "pax-header",
|
|
33
|
+
g: "pax-global-header",
|
|
34
|
+
L: "gnu-long-name",
|
|
35
|
+
K: "gnu-long-link-name"
|
|
36
|
+
};
|
|
37
|
+
var ZERO_BLOCK = /* @__PURE__ */ new Uint8Array(512);
|
|
38
|
+
var EMPTY = /* @__PURE__ */ new Uint8Array(0);
|
|
39
|
+
var encoder = new TextEncoder();
|
|
40
|
+
var decoder = new TextDecoder();
|
|
41
|
+
function writeString(view, offset, size, value) {
|
|
42
|
+
if (!value) return;
|
|
43
|
+
for (let i = 0; i < value.length && i < size; i++) {
|
|
44
|
+
const charCode = value.charCodeAt(i);
|
|
45
|
+
if (charCode > 127) {
|
|
46
|
+
encoder.encodeInto(value, view.subarray(offset, offset + size));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
view[offset + i] = charCode;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function writeOctal(view, offset, size, value) {
|
|
53
|
+
if (value === void 0) return;
|
|
54
|
+
let remaining = value;
|
|
55
|
+
for (let i = offset + size - 2; i >= offset; i--) {
|
|
56
|
+
view[i] = 48 + remaining % 8;
|
|
57
|
+
remaining = Math.floor(remaining / 8);
|
|
58
|
+
}
|
|
59
|
+
if (remaining === 0 && value % 1 === 0) return;
|
|
60
|
+
encoder.encodeInto(value.toString(8).padStart(size - 1, "0"), view.subarray(offset, offset + size - 1));
|
|
61
|
+
}
|
|
62
|
+
function readString(view, offset, size) {
|
|
63
|
+
if (view[offset] === 0) return "";
|
|
64
|
+
const end = view.indexOf(0, offset);
|
|
65
|
+
const sliceEnd = end === -1 || end > offset + size ? offset + size : end;
|
|
66
|
+
return decoder.decode(view.subarray(offset, sliceEnd));
|
|
67
|
+
}
|
|
68
|
+
function readOctal(view, offset, size) {
|
|
69
|
+
let value = 0;
|
|
70
|
+
const end = offset + size;
|
|
71
|
+
for (let i = offset; i < end; i++) {
|
|
72
|
+
const charCode = view[i];
|
|
73
|
+
if (charCode === 0) break;
|
|
74
|
+
if (charCode === 32) continue;
|
|
75
|
+
value = value * 8 + (charCode - 48);
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
function readNumeric(view, offset, size) {
|
|
80
|
+
if (view[offset] & 128) {
|
|
81
|
+
let result = 0;
|
|
82
|
+
result = view[offset] & 127;
|
|
83
|
+
for (let i = 1; i < size; i++) result = result * 256 + view[offset + i];
|
|
84
|
+
if (!Number.isSafeInteger(result)) throw new Error("TAR number too large");
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
return readOctal(view, offset, size);
|
|
88
|
+
}
|
|
89
|
+
var isBodyless = (header) => header.type === "directory" || header.type === "symlink" || header.type === "link" || header.type === "character-device" || header.type === "block-device" || header.type === "fifo";
|
|
90
|
+
async function normalizeBody(body) {
|
|
91
|
+
if (body === null || body === void 0) return EMPTY;
|
|
92
|
+
if (body instanceof Uint8Array) return body;
|
|
93
|
+
if (typeof body === "string") return encoder.encode(body);
|
|
94
|
+
if (body instanceof ArrayBuffer) return new Uint8Array(body);
|
|
95
|
+
if (body instanceof Blob) return new Uint8Array(await body.arrayBuffer());
|
|
96
|
+
throw new TypeError("Unsupported content type for entry body.");
|
|
97
|
+
}
|
|
98
|
+
var stripPath = (p, n) => {
|
|
99
|
+
const parts = p.split("/").filter(Boolean);
|
|
100
|
+
return n >= parts.length ? "" : parts.slice(n).join("/");
|
|
101
|
+
};
|
|
102
|
+
function transformHeader(header, options) {
|
|
103
|
+
const { strip, filter, map } = options;
|
|
104
|
+
if (!strip && !filter && !map) return header;
|
|
105
|
+
const h = { ...header };
|
|
106
|
+
if (strip && strip > 0) {
|
|
107
|
+
const newName = stripPath(h.name, strip);
|
|
108
|
+
if (!newName) return null;
|
|
109
|
+
h.name = h.type === "directory" && !newName.endsWith("/") ? `${newName}/` : newName;
|
|
110
|
+
if (h.linkname) {
|
|
111
|
+
const isAbsolute2 = h.linkname.startsWith("/");
|
|
112
|
+
if (isAbsolute2 || h.type === "link") {
|
|
113
|
+
const stripped = stripPath(h.linkname, strip);
|
|
114
|
+
h.linkname = isAbsolute2 ? `/${stripped}` || "/" : stripped;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (filter?.(h) === false) return null;
|
|
119
|
+
const result = map ? map(h) : h;
|
|
120
|
+
if (result && (!result.name?.trim() || result.name === "." || result.name === "/")) return null;
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
var INITIAL_CAPACITY = 256;
|
|
124
|
+
function createChunkQueue() {
|
|
125
|
+
let chunks = new Array(INITIAL_CAPACITY);
|
|
126
|
+
let capacityMask = chunks.length - 1;
|
|
127
|
+
let head = 0;
|
|
128
|
+
let tail = 0;
|
|
129
|
+
let totalAvailable = 0;
|
|
130
|
+
const consumeFromHead = (count) => {
|
|
131
|
+
const chunk = chunks[head];
|
|
132
|
+
if (count === chunk.length) {
|
|
133
|
+
chunks[head] = EMPTY;
|
|
134
|
+
head = head + 1 & capacityMask;
|
|
135
|
+
} else chunks[head] = chunk.subarray(count);
|
|
136
|
+
totalAvailable -= count;
|
|
137
|
+
if (totalAvailable === 0 && chunks.length > INITIAL_CAPACITY) {
|
|
138
|
+
chunks = new Array(INITIAL_CAPACITY);
|
|
139
|
+
capacityMask = 255;
|
|
140
|
+
head = 0;
|
|
141
|
+
tail = 0;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
function pull(bytes, callback) {
|
|
145
|
+
if (callback) {
|
|
146
|
+
let fed = 0;
|
|
147
|
+
let remaining2 = Math.min(bytes, totalAvailable);
|
|
148
|
+
while (remaining2 > 0) {
|
|
149
|
+
const chunk = chunks[head];
|
|
150
|
+
const toFeed = Math.min(remaining2, chunk.length);
|
|
151
|
+
const segment = toFeed === chunk.length ? chunk : chunk.subarray(0, toFeed);
|
|
152
|
+
consumeFromHead(toFeed);
|
|
153
|
+
remaining2 -= toFeed;
|
|
154
|
+
fed += toFeed;
|
|
155
|
+
if (!callback(segment)) break;
|
|
156
|
+
}
|
|
157
|
+
return fed;
|
|
158
|
+
}
|
|
159
|
+
if (totalAvailable < bytes) return null;
|
|
160
|
+
if (bytes === 0) return EMPTY;
|
|
161
|
+
const firstChunk = chunks[head];
|
|
162
|
+
if (firstChunk.length >= bytes) {
|
|
163
|
+
const view = firstChunk.length === bytes ? firstChunk : firstChunk.subarray(0, bytes);
|
|
164
|
+
consumeFromHead(bytes);
|
|
165
|
+
return view;
|
|
166
|
+
}
|
|
167
|
+
const result = new Uint8Array(bytes);
|
|
168
|
+
let copied = 0;
|
|
169
|
+
let remaining = bytes;
|
|
170
|
+
while (remaining > 0) {
|
|
171
|
+
const chunk = chunks[head];
|
|
172
|
+
const toCopy = Math.min(remaining, chunk.length);
|
|
173
|
+
result.set(toCopy === chunk.length ? chunk : chunk.subarray(0, toCopy), copied);
|
|
174
|
+
copied += toCopy;
|
|
175
|
+
remaining -= toCopy;
|
|
176
|
+
consumeFromHead(toCopy);
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
push: (chunk) => {
|
|
182
|
+
if (chunk.length === 0) return;
|
|
183
|
+
let nextTail = tail + 1 & capacityMask;
|
|
184
|
+
if (nextTail === head) {
|
|
185
|
+
const oldLen = chunks.length;
|
|
186
|
+
const newLen = oldLen * 2;
|
|
187
|
+
const newChunks = new Array(newLen);
|
|
188
|
+
const count = tail - head + oldLen & oldLen - 1;
|
|
189
|
+
if (head < tail) for (let i = 0; i < count; i++) newChunks[i] = chunks[head + i];
|
|
190
|
+
else {
|
|
191
|
+
const firstPart = oldLen - head;
|
|
192
|
+
for (let i = 0; i < firstPart; i++) newChunks[i] = chunks[head + i];
|
|
193
|
+
for (let i = 0; i < tail; i++) newChunks[firstPart + i] = chunks[i];
|
|
194
|
+
}
|
|
195
|
+
chunks = newChunks;
|
|
196
|
+
capacityMask = newLen - 1;
|
|
197
|
+
head = 0;
|
|
198
|
+
tail = count;
|
|
199
|
+
nextTail = tail + 1 & capacityMask;
|
|
200
|
+
}
|
|
201
|
+
chunks[tail] = chunk;
|
|
202
|
+
tail = nextTail;
|
|
203
|
+
totalAvailable += chunk.length;
|
|
204
|
+
},
|
|
205
|
+
available: () => totalAvailable,
|
|
206
|
+
peek: (bytes) => {
|
|
207
|
+
if (totalAvailable < bytes) return null;
|
|
208
|
+
if (bytes === 0) return EMPTY;
|
|
209
|
+
const firstChunk = chunks[head];
|
|
210
|
+
if (firstChunk.length >= bytes) return firstChunk.length === bytes ? firstChunk : firstChunk.subarray(0, bytes);
|
|
211
|
+
const result = new Uint8Array(bytes);
|
|
212
|
+
let copied = 0;
|
|
213
|
+
let index = head;
|
|
214
|
+
while (copied < bytes) {
|
|
215
|
+
const chunk = chunks[index];
|
|
216
|
+
const toCopy = Math.min(bytes - copied, chunk.length);
|
|
217
|
+
if (toCopy === chunk.length) result.set(chunk, copied);
|
|
218
|
+
else result.set(chunk.subarray(0, toCopy), copied);
|
|
219
|
+
copied += toCopy;
|
|
220
|
+
index = index + 1 & capacityMask;
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
},
|
|
224
|
+
discard: (bytes) => {
|
|
225
|
+
if (bytes > totalAvailable) throw new Error("Too many bytes consumed");
|
|
226
|
+
if (bytes === 0) return;
|
|
227
|
+
let remaining = bytes;
|
|
228
|
+
while (remaining > 0) {
|
|
229
|
+
const chunk = chunks[head];
|
|
230
|
+
const toConsume = Math.min(remaining, chunk.length);
|
|
231
|
+
consumeFromHead(toConsume);
|
|
232
|
+
remaining -= toConsume;
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
pull
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
var CHECKSUM_SPACE = 32;
|
|
239
|
+
var ASCII_ZERO = 48;
|
|
240
|
+
function validateChecksum(block) {
|
|
241
|
+
const stored = readOctal(block, 148, 8);
|
|
242
|
+
let sum = 0;
|
|
243
|
+
for (let i = 0; i < block.length; i++) if (i >= 148 && i < 156) sum += CHECKSUM_SPACE;
|
|
244
|
+
else sum += block[i];
|
|
245
|
+
return stored === sum;
|
|
246
|
+
}
|
|
247
|
+
function writeChecksum(block) {
|
|
248
|
+
block.fill(CHECKSUM_SPACE, 148, 156);
|
|
249
|
+
let checksum = 0;
|
|
250
|
+
for (let i = block.length; i > 0; ) checksum += block[--i];
|
|
251
|
+
for (let i = 153; i >= 148; i--) {
|
|
252
|
+
block[i] = (checksum & 7) + ASCII_ZERO;
|
|
253
|
+
checksum >>= 3;
|
|
254
|
+
}
|
|
255
|
+
block[154] = 0;
|
|
256
|
+
block[155] = CHECKSUM_SPACE;
|
|
257
|
+
}
|
|
258
|
+
var USTAR_SPLIT_MAX_SIZE = 256;
|
|
259
|
+
var NON_ASCII = /[^\x00-\x7f]/;
|
|
260
|
+
function isUtf8TooLong(value, limit) {
|
|
261
|
+
if (value.length * 3 <= limit) return false;
|
|
262
|
+
if (value.length > limit) return true;
|
|
263
|
+
if (!NON_ASCII.test(value)) return false;
|
|
264
|
+
return encoder.encode(value).length > limit;
|
|
265
|
+
}
|
|
266
|
+
function generatePax(header) {
|
|
267
|
+
const paxRecords = {};
|
|
268
|
+
if (isUtf8TooLong(header.name, 100)) {
|
|
269
|
+
if (findUstarSplit(header.name) === null) paxRecords.path = header.name;
|
|
270
|
+
}
|
|
271
|
+
if (header.linkname && isUtf8TooLong(header.linkname, 100)) paxRecords.linkpath = header.linkname;
|
|
272
|
+
if (header.uname && isUtf8TooLong(header.uname, 32)) paxRecords.uname = header.uname;
|
|
273
|
+
if (header.gname && isUtf8TooLong(header.gname, 32)) paxRecords.gname = header.gname;
|
|
274
|
+
if (header.uid != null && header.uid > 2097151) paxRecords.uid = String(header.uid);
|
|
275
|
+
if (header.gid != null && header.gid > 2097151) paxRecords.gid = String(header.gid);
|
|
276
|
+
if (header.size != null && header.size > 8589934591) paxRecords.size = String(header.size);
|
|
277
|
+
if (header.pax) Object.assign(paxRecords, header.pax);
|
|
278
|
+
const paxEntries = Object.entries(paxRecords);
|
|
279
|
+
if (paxEntries.length === 0) return null;
|
|
280
|
+
const paxBody = encoder.encode(paxEntries.map(([key, value]) => {
|
|
281
|
+
const record = `${key}=${value}
|
|
282
|
+
`;
|
|
283
|
+
const partLength = encoder.encode(record).length + 1;
|
|
284
|
+
let totalLength = partLength + String(partLength).length;
|
|
285
|
+
totalLength = partLength + String(totalLength).length;
|
|
286
|
+
return `${totalLength} ${record}`;
|
|
287
|
+
}).join(""));
|
|
288
|
+
return {
|
|
289
|
+
paxHeader: createTarHeader({
|
|
290
|
+
name: decoder.decode(encoder.encode(`PaxHeader/${header.name}`).slice(0, 100)),
|
|
291
|
+
size: paxBody.length,
|
|
292
|
+
type: "pax-header",
|
|
293
|
+
mode: 420,
|
|
294
|
+
mtime: header.mtime,
|
|
295
|
+
uname: header.uname,
|
|
296
|
+
gname: header.gname,
|
|
297
|
+
uid: header.uid,
|
|
298
|
+
gid: header.gid
|
|
299
|
+
}),
|
|
300
|
+
paxBody
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function findUstarSplit(path2) {
|
|
304
|
+
if (!isUtf8TooLong(path2, 100) || isUtf8TooLong(path2, USTAR_SPLIT_MAX_SIZE)) return null;
|
|
305
|
+
for (let i = path2.length - 1; i > 0; i--) {
|
|
306
|
+
if (path2[i] !== "/") continue;
|
|
307
|
+
const prefix = path2.slice(0, i);
|
|
308
|
+
const name = path2.slice(i + 1);
|
|
309
|
+
if (!isUtf8TooLong(prefix, 155) && !isUtf8TooLong(name, 100)) return {
|
|
310
|
+
prefix,
|
|
311
|
+
name
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
function createTarHeader(header) {
|
|
317
|
+
const view = /* @__PURE__ */ new Uint8Array(512);
|
|
318
|
+
const size = isBodyless(header) ? 0 : header.size ?? 0;
|
|
319
|
+
let name = header.name;
|
|
320
|
+
let prefix = "";
|
|
321
|
+
if (!header.pax?.path) {
|
|
322
|
+
const split = findUstarSplit(name);
|
|
323
|
+
if (split) {
|
|
324
|
+
name = split.name;
|
|
325
|
+
prefix = split.prefix;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
writeString(view, 0, 100, name);
|
|
329
|
+
writeOctal(view, 100, 8, header.mode ?? (header.type === "directory" ? 493 : 420));
|
|
330
|
+
writeOctal(view, 108, 8, header.uid ?? 0);
|
|
331
|
+
writeOctal(view, 116, 8, header.gid ?? 0);
|
|
332
|
+
writeOctal(view, 124, 12, size);
|
|
333
|
+
writeOctal(view, 136, 12, Math.floor((header.mtime?.getTime() ?? Date.now()) / 1e3));
|
|
334
|
+
writeString(view, 156, 1, TYPEFLAG[header.type ?? "file"]);
|
|
335
|
+
writeString(view, 157, 100, header.linkname);
|
|
336
|
+
writeString(view, 257, 6, "ustar\0");
|
|
337
|
+
writeString(view, 263, 2, "00");
|
|
338
|
+
writeString(view, 265, 32, header.uname);
|
|
339
|
+
writeString(view, 297, 32, header.gname);
|
|
340
|
+
writeString(view, 345, 155, prefix);
|
|
341
|
+
writeChecksum(view);
|
|
342
|
+
return view;
|
|
343
|
+
}
|
|
344
|
+
function parseUstarHeader(block, strict) {
|
|
345
|
+
if (strict && !validateChecksum(block)) throw new Error("Invalid tar header checksum.");
|
|
346
|
+
const typeflag = readString(block, 156, 1);
|
|
347
|
+
const header = {
|
|
348
|
+
name: readString(block, 0, 100),
|
|
349
|
+
mode: readOctal(block, 100, 8),
|
|
350
|
+
uid: readNumeric(block, 108, 8),
|
|
351
|
+
gid: readNumeric(block, 116, 8),
|
|
352
|
+
size: readNumeric(block, 124, 12),
|
|
353
|
+
mtime: /* @__PURE__ */ new Date(readNumeric(block, 136, 12) * 1e3),
|
|
354
|
+
type: FLAGTYPE[typeflag] || "file",
|
|
355
|
+
linkname: readString(block, 157, 100)
|
|
356
|
+
};
|
|
357
|
+
const magic = readString(block, 257, 6);
|
|
358
|
+
if (magic.trim() === "ustar") {
|
|
359
|
+
header.uname = readString(block, 265, 32);
|
|
360
|
+
header.gname = readString(block, 297, 32);
|
|
361
|
+
}
|
|
362
|
+
if (magic === "ustar") header.prefix = readString(block, 345, 155);
|
|
363
|
+
return header;
|
|
364
|
+
}
|
|
365
|
+
var PAX_MAPPING = {
|
|
366
|
+
path: ["name", (v) => v],
|
|
367
|
+
linkpath: ["linkname", (v) => v],
|
|
368
|
+
size: ["size", (v) => /^\d+$/.test(v) && Number.isSafeInteger(+v) ? +v : NaN],
|
|
369
|
+
mtime: ["mtime", parseFloat],
|
|
370
|
+
uid: ["uid", (v) => parseInt(v, 10)],
|
|
371
|
+
gid: ["gid", (v) => parseInt(v, 10)],
|
|
372
|
+
uname: ["uname", (v) => v],
|
|
373
|
+
gname: ["gname", (v) => v]
|
|
374
|
+
};
|
|
375
|
+
function parsePax(buffer) {
|
|
376
|
+
const overrides = /* @__PURE__ */ Object.create(null);
|
|
377
|
+
const pax = /* @__PURE__ */ Object.create(null);
|
|
378
|
+
let isPax = false;
|
|
379
|
+
let offset = 0;
|
|
380
|
+
while (offset < buffer.length) {
|
|
381
|
+
const spaceIndex = buffer.indexOf(32, offset);
|
|
382
|
+
if (spaceIndex === -1) break;
|
|
383
|
+
const length = parseInt(decoder.decode(buffer.subarray(offset, spaceIndex)), 10);
|
|
384
|
+
if (!(length > 0)) break;
|
|
385
|
+
const recordEnd = offset + length;
|
|
386
|
+
const recordStr = decoder.decode(buffer.subarray(spaceIndex + 1, recordEnd - 1));
|
|
387
|
+
const equalsIndex = recordStr.indexOf("=");
|
|
388
|
+
if (equalsIndex > 0) {
|
|
389
|
+
const key = recordStr.slice(0, equalsIndex);
|
|
390
|
+
const value = recordStr.slice(equalsIndex + 1);
|
|
391
|
+
pax[key] = value;
|
|
392
|
+
isPax = true;
|
|
393
|
+
if (Object.hasOwn(PAX_MAPPING, key)) {
|
|
394
|
+
const [targetKey, parser] = PAX_MAPPING[key];
|
|
395
|
+
const parsedValue = parser(value);
|
|
396
|
+
if (typeof parsedValue === "string" || !Number.isNaN(parsedValue)) overrides[targetKey] = parsedValue;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
offset = recordEnd;
|
|
400
|
+
}
|
|
401
|
+
if (isPax) overrides.pax = pax;
|
|
402
|
+
return overrides;
|
|
403
|
+
}
|
|
404
|
+
function applyOverrides(header, overrides) {
|
|
405
|
+
if (overrides.name !== void 0) header.name = overrides.name;
|
|
406
|
+
if (overrides.linkname !== void 0) header.linkname = overrides.linkname;
|
|
407
|
+
if (overrides.size !== void 0) header.size = overrides.size;
|
|
408
|
+
if (overrides.mtime !== void 0) header.mtime = /* @__PURE__ */ new Date(overrides.mtime * 1e3);
|
|
409
|
+
if (overrides.uid !== void 0) header.uid = overrides.uid;
|
|
410
|
+
if (overrides.gid !== void 0) header.gid = overrides.gid;
|
|
411
|
+
if (overrides.uname !== void 0) header.uname = overrides.uname;
|
|
412
|
+
if (overrides.gname !== void 0) header.gname = overrides.gname;
|
|
413
|
+
if (overrides.pax) header.pax = Object.assign({}, header.pax ?? {}, overrides.pax);
|
|
414
|
+
}
|
|
415
|
+
function getMetaParser(type) {
|
|
416
|
+
switch (type) {
|
|
417
|
+
case "pax-global-header":
|
|
418
|
+
case "pax-header":
|
|
419
|
+
return parsePax;
|
|
420
|
+
case "gnu-long-name":
|
|
421
|
+
return (data) => ({ name: readString(data, 0, data.length) });
|
|
422
|
+
case "gnu-long-link-name":
|
|
423
|
+
return (data) => ({ linkname: readString(data, 0, data.length) });
|
|
424
|
+
default:
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function getHeaderBlocks(header) {
|
|
429
|
+
const base = createTarHeader(header);
|
|
430
|
+
const pax = generatePax(header);
|
|
431
|
+
if (!pax) return [base];
|
|
432
|
+
const paxPadding = -pax.paxBody.length & 511;
|
|
433
|
+
const paddingBlocks = paxPadding > 0 ? [ZERO_BLOCK.subarray(0, paxPadding)] : [];
|
|
434
|
+
return [
|
|
435
|
+
pax.paxHeader,
|
|
436
|
+
pax.paxBody,
|
|
437
|
+
...paddingBlocks,
|
|
438
|
+
base
|
|
439
|
+
];
|
|
440
|
+
}
|
|
441
|
+
var STATE_HEADER = 0;
|
|
442
|
+
var STATE_BODY = 1;
|
|
443
|
+
var MAX_META_SIZE = 8388608;
|
|
444
|
+
var truncateErr = /* @__PURE__ */ new Error("Tar archive is truncated.");
|
|
445
|
+
function createUnpacker(options = {}) {
|
|
446
|
+
const strict = options.strict ?? false;
|
|
447
|
+
const { available, peek, push, discard, pull } = createChunkQueue();
|
|
448
|
+
let state = STATE_HEADER;
|
|
449
|
+
let ended = false;
|
|
450
|
+
let done = false;
|
|
451
|
+
let eof = false;
|
|
452
|
+
let currentEntry = null;
|
|
453
|
+
const paxGlobals = {};
|
|
454
|
+
let nextEntryOverrides = {};
|
|
455
|
+
const unpacker = {
|
|
456
|
+
isEntryActive: () => state === STATE_BODY,
|
|
457
|
+
isBodyComplete: () => !currentEntry || currentEntry.remaining === 0,
|
|
458
|
+
canFinish: () => !currentEntry || available() >= currentEntry.remaining + currentEntry.padding,
|
|
459
|
+
bodyBytes: () => currentEntry && currentEntry.remaining > 0 ? Math.min(currentEntry.remaining, available()) : 0,
|
|
460
|
+
available,
|
|
461
|
+
write(chunk) {
|
|
462
|
+
if (ended) throw new Error("Archive already ended.");
|
|
463
|
+
push(chunk);
|
|
464
|
+
},
|
|
465
|
+
end() {
|
|
466
|
+
ended = true;
|
|
467
|
+
},
|
|
468
|
+
readHeader() {
|
|
469
|
+
if (state !== STATE_HEADER) throw new Error("Cannot read header while an entry is active");
|
|
470
|
+
if (done) return void 0;
|
|
471
|
+
while (!done) {
|
|
472
|
+
if (available() < 512) {
|
|
473
|
+
if (ended) {
|
|
474
|
+
if (available() > 0 && strict) throw truncateErr;
|
|
475
|
+
done = true;
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
const headerBlock = peek(512);
|
|
481
|
+
if (isZeroBlock(headerBlock)) {
|
|
482
|
+
if (available() < 1024) {
|
|
483
|
+
if (ended) {
|
|
484
|
+
if (strict) throw truncateErr;
|
|
485
|
+
done = true;
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
if (isZeroBlock(peek(1024).subarray(512))) {
|
|
491
|
+
discard(1024);
|
|
492
|
+
done = true;
|
|
493
|
+
eof = true;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (strict) throw new Error("Invalid tar header.");
|
|
497
|
+
discard(512);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
let internalHeader;
|
|
501
|
+
try {
|
|
502
|
+
internalHeader = parseUstarHeader(headerBlock, strict);
|
|
503
|
+
} catch (err) {
|
|
504
|
+
if (strict) throw err;
|
|
505
|
+
discard(512);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
const metaParser = getMetaParser(internalHeader.type);
|
|
509
|
+
if (metaParser) {
|
|
510
|
+
if (internalHeader.size > MAX_META_SIZE) throw new Error("Tar metadata entry exceeds maximum size.");
|
|
511
|
+
const paddedSize = internalHeader.size + (-internalHeader.size & 511);
|
|
512
|
+
if (available() < 512 + paddedSize) {
|
|
513
|
+
if (ended && strict) throw truncateErr;
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
discard(512);
|
|
517
|
+
const overrides = metaParser(pull(paddedSize).subarray(0, internalHeader.size));
|
|
518
|
+
if (nextEntryOverrides.pax) nextEntryOverrides = {};
|
|
519
|
+
const target = internalHeader.type === "pax-global-header" ? paxGlobals : nextEntryOverrides;
|
|
520
|
+
for (const key in overrides) target[key] = overrides[key];
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
discard(512);
|
|
524
|
+
const header = internalHeader;
|
|
525
|
+
if (internalHeader.prefix) header.name = `${internalHeader.prefix}/${header.name}`;
|
|
526
|
+
applyOverrides(header, paxGlobals);
|
|
527
|
+
applyOverrides(header, nextEntryOverrides);
|
|
528
|
+
let archiveSize = header.size;
|
|
529
|
+
if (isBodyless(header)) {
|
|
530
|
+
archiveSize = 0;
|
|
531
|
+
header.size = 0;
|
|
532
|
+
} else if (header.name.endsWith("/") && header.type === "file") {
|
|
533
|
+
header.type = DIRECTORY;
|
|
534
|
+
header.size = 0;
|
|
535
|
+
}
|
|
536
|
+
nextEntryOverrides = {};
|
|
537
|
+
currentEntry = {
|
|
538
|
+
header,
|
|
539
|
+
remaining: archiveSize,
|
|
540
|
+
padding: -archiveSize & 511
|
|
541
|
+
};
|
|
542
|
+
state = STATE_BODY;
|
|
543
|
+
return header;
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
streamBody(callback) {
|
|
547
|
+
if (state !== STATE_BODY || !currentEntry || currentEntry.remaining === 0) return 0;
|
|
548
|
+
const bytesToFeed = Math.min(currentEntry.remaining, available());
|
|
549
|
+
if (bytesToFeed === 0) return 0;
|
|
550
|
+
const fed = pull(bytesToFeed, callback);
|
|
551
|
+
currentEntry.remaining -= fed;
|
|
552
|
+
return fed;
|
|
553
|
+
},
|
|
554
|
+
skipPadding() {
|
|
555
|
+
if (state !== STATE_BODY || !currentEntry) return true;
|
|
556
|
+
if (currentEntry.remaining > 0) throw new Error("Body not fully consumed");
|
|
557
|
+
if (available() < currentEntry.padding) return false;
|
|
558
|
+
discard(currentEntry.padding);
|
|
559
|
+
currentEntry = null;
|
|
560
|
+
state = STATE_HEADER;
|
|
561
|
+
return true;
|
|
562
|
+
},
|
|
563
|
+
skipEntry() {
|
|
564
|
+
if (state !== STATE_BODY || !currentEntry) return true;
|
|
565
|
+
const toDiscard = Math.min(currentEntry.remaining, available());
|
|
566
|
+
if (toDiscard > 0) {
|
|
567
|
+
discard(toDiscard);
|
|
568
|
+
currentEntry.remaining -= toDiscard;
|
|
569
|
+
}
|
|
570
|
+
if (currentEntry.remaining > 0) return false;
|
|
571
|
+
return unpacker.skipPadding();
|
|
572
|
+
},
|
|
573
|
+
validateEOF() {
|
|
574
|
+
if (strict) {
|
|
575
|
+
if (!eof) throw truncateErr;
|
|
576
|
+
if (available() > 0) {
|
|
577
|
+
if (pull(available()).some((byte) => byte !== 0)) throw new Error("Invalid EOF.");
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
return unpacker;
|
|
583
|
+
}
|
|
584
|
+
function isZeroBlock(block) {
|
|
585
|
+
if (block[0] !== 0) return false;
|
|
586
|
+
if (block.byteOffset % 8 === 0) {
|
|
587
|
+
const view = new BigUint64Array(block.buffer, block.byteOffset, block.length / 8);
|
|
588
|
+
for (let i = 0; i < view.length; i++) if (view[i] !== 0n) return false;
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
for (let i = 0; i < block.length; i++) if (block[i] !== 0) return false;
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
var EOF_BUFFER = /* @__PURE__ */ new Uint8Array(1024);
|
|
595
|
+
function createTarPacker(onData) {
|
|
596
|
+
let currentHeader = null;
|
|
597
|
+
let bytesWritten = 0;
|
|
598
|
+
let finalized = false;
|
|
599
|
+
const fail = (message) => {
|
|
600
|
+
throw new Error(message);
|
|
601
|
+
};
|
|
602
|
+
return {
|
|
603
|
+
add(header) {
|
|
604
|
+
if (finalized) fail("No new tar entries after finalize.");
|
|
605
|
+
if (currentHeader !== null) fail("Previous entry must be completed before adding a new one");
|
|
606
|
+
const size = isBodyless(header) ? 0 : header.size;
|
|
607
|
+
if (!Number.isSafeInteger(size) || size < 0) fail("Invalid tar entry size.");
|
|
608
|
+
const headerBlocks = getHeaderBlocks({
|
|
609
|
+
...header,
|
|
610
|
+
size
|
|
611
|
+
});
|
|
612
|
+
for (const block of headerBlocks) onData(block);
|
|
613
|
+
currentHeader = {
|
|
614
|
+
...header,
|
|
615
|
+
size
|
|
616
|
+
};
|
|
617
|
+
bytesWritten = 0;
|
|
618
|
+
},
|
|
619
|
+
write(chunk) {
|
|
620
|
+
if (!currentHeader) fail("No active tar entry.");
|
|
621
|
+
if (finalized) fail("Cannot write data after finalize.");
|
|
622
|
+
const newTotal = bytesWritten + chunk.length;
|
|
623
|
+
if (newTotal > currentHeader.size) fail(`"${currentHeader.name}" exceeds given size of ${currentHeader.size} bytes.`);
|
|
624
|
+
bytesWritten = newTotal;
|
|
625
|
+
onData(chunk);
|
|
626
|
+
},
|
|
627
|
+
endEntry() {
|
|
628
|
+
if (!currentHeader) fail("No active entry to end.");
|
|
629
|
+
if (finalized) fail("Cannot end entry after finalize.");
|
|
630
|
+
if (bytesWritten !== currentHeader.size) fail(`Size mismatch for "${currentHeader.name}".`);
|
|
631
|
+
const paddingSize = -currentHeader.size & 511;
|
|
632
|
+
if (paddingSize > 0) onData(new Uint8Array(paddingSize));
|
|
633
|
+
currentHeader = null;
|
|
634
|
+
bytesWritten = 0;
|
|
635
|
+
},
|
|
636
|
+
finalize() {
|
|
637
|
+
if (finalized) fail("Archive has already been finalized");
|
|
638
|
+
if (currentHeader !== null) fail("Cannot finalize while an entry is still active");
|
|
639
|
+
onData(EOF_BUFFER);
|
|
640
|
+
finalized = true;
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// ../../node_modules/.pnpm/modern-tar@0.8.5/node_modules/modern-tar/dist/fs/index.js
|
|
646
|
+
import * as fs from "fs";
|
|
647
|
+
import * as fsp from "fs/promises";
|
|
648
|
+
import { cpus } from "os";
|
|
649
|
+
import * as path from "path";
|
|
650
|
+
import { Readable, Writable } from "stream";
|
|
651
|
+
function validateBounds(targetPath, destDir, errorMessage) {
|
|
652
|
+
const target = path.resolve(targetPath);
|
|
653
|
+
const dest = path.resolve(destDir);
|
|
654
|
+
if (target !== dest && !target.startsWith(dest + path.sep)) throw new Error(errorMessage);
|
|
655
|
+
}
|
|
656
|
+
var win32Reserved = {
|
|
657
|
+
":": "\uF03A",
|
|
658
|
+
"<": "\uF03C",
|
|
659
|
+
">": "\uF03E",
|
|
660
|
+
"|": "\uF07C",
|
|
661
|
+
"?": "\uF03F",
|
|
662
|
+
"*": "\uF02A",
|
|
663
|
+
'"': "\uF022"
|
|
664
|
+
};
|
|
665
|
+
var pathAlias = /\/\/|(?:^|\/)\.(?:\/|$)/;
|
|
666
|
+
function normalizeName(name) {
|
|
667
|
+
const path2 = name.replace(/\\/g, "/");
|
|
668
|
+
if (path2.split("/").includes("..") || /^[a-zA-Z]:\.\./.test(path2)) throw new Error(`${name} points outside extraction directory`);
|
|
669
|
+
let relative2 = path2;
|
|
670
|
+
if (/^[a-zA-Z]:/.test(relative2)) relative2 = relative2.replace(/^[a-zA-Z]:[/\\]?/, "");
|
|
671
|
+
else if (relative2.startsWith("/")) relative2 = relative2.replace(/^\/+/, "");
|
|
672
|
+
if (process.platform === "win32") return relative2.replace(/[<>:"|?*]/g, (char) => win32Reserved[char]);
|
|
673
|
+
return relative2;
|
|
674
|
+
}
|
|
675
|
+
var normalizeHeaderName = (s) => {
|
|
676
|
+
const name = normalizeName(s.replace(/[\\/]+$/, ""));
|
|
677
|
+
return pathAlias.test(name) ? path.posix.normalize(name) : name;
|
|
678
|
+
};
|
|
679
|
+
var BIGINT_STAT = { bigint: true };
|
|
680
|
+
var WITH_FILE_TYPES = { withFileTypes: true };
|
|
681
|
+
var packTarSources = packTar;
|
|
682
|
+
function packTar(sources, options = {}) {
|
|
683
|
+
const results = /* @__PURE__ */ new Map();
|
|
684
|
+
const fileHandles = /* @__PURE__ */ new Map();
|
|
685
|
+
const bodyStreams = /* @__PURE__ */ new Set();
|
|
686
|
+
let resume = null;
|
|
687
|
+
let drain = null;
|
|
688
|
+
let resumeWriter = null;
|
|
689
|
+
let cancelError;
|
|
690
|
+
const unblock = () => {
|
|
691
|
+
const resolve2 = resume;
|
|
692
|
+
resume = null;
|
|
693
|
+
drain = null;
|
|
694
|
+
resolve2?.();
|
|
695
|
+
};
|
|
696
|
+
const wakeWriter = () => {
|
|
697
|
+
resumeWriter?.();
|
|
698
|
+
resumeWriter = null;
|
|
699
|
+
};
|
|
700
|
+
const destroyBody = (body, reason) => {
|
|
701
|
+
bodyStreams.delete(body);
|
|
702
|
+
body.destroy(reason);
|
|
703
|
+
};
|
|
704
|
+
const closeHandle = (handle) => {
|
|
705
|
+
const closing = fileHandles.get(handle);
|
|
706
|
+
if (closing !== null) return closing;
|
|
707
|
+
const promise = handle.close().finally(() => fileHandles.delete(handle));
|
|
708
|
+
fileHandles.set(handle, promise);
|
|
709
|
+
return promise;
|
|
710
|
+
};
|
|
711
|
+
const stop = async (reason) => {
|
|
712
|
+
for (const body of bodyStreams) destroyBody(body, reason);
|
|
713
|
+
const closing = Promise.allSettled([...fileHandles.keys()].map(closeHandle));
|
|
714
|
+
results.clear();
|
|
715
|
+
wakeWriter();
|
|
716
|
+
for (const result of await closing) if (result.status === "rejected") throw result.reason;
|
|
717
|
+
};
|
|
718
|
+
const stream = new Readable({
|
|
719
|
+
highWaterMark: 8388608,
|
|
720
|
+
read: unblock,
|
|
721
|
+
destroy(error, callback) {
|
|
722
|
+
cancelError = error ?? AbortSignal.abort().reason;
|
|
723
|
+
unblock();
|
|
724
|
+
stop(cancelError).then(() => callback(error), (closeError) => callback(error ?? closeError));
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
const onError = (error) => stream.destroy(error);
|
|
728
|
+
const packer = createTarPacker((chunk) => {
|
|
729
|
+
if (stream.destroyed) throw cancelError;
|
|
730
|
+
if (!stream.push(Buffer.from(chunk)) && !drain) drain = new Promise((resolve2) => {
|
|
731
|
+
resume = resolve2;
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
(async () => {
|
|
735
|
+
const { dereference = false, filter, map, baseDir, concurrency = cpus().length || 8 } = options;
|
|
736
|
+
let directoryPath;
|
|
737
|
+
let realBaseDir;
|
|
738
|
+
let jobs;
|
|
739
|
+
if (typeof sources === "string") {
|
|
740
|
+
const source = path.resolve(sources);
|
|
741
|
+
directoryPath = source;
|
|
742
|
+
const before = await fsp.stat(source, BIGINT_STAT);
|
|
743
|
+
if (stream.destroyed) return;
|
|
744
|
+
const entries = await fsp.readdir(source, WITH_FILE_TYPES);
|
|
745
|
+
if (stream.destroyed) return;
|
|
746
|
+
const after = await fsp.stat(source, BIGINT_STAT);
|
|
747
|
+
if (stream.destroyed) return;
|
|
748
|
+
jobs = before.dev === after.dev && before.ino === after.ino ? entries.map((entry) => ({
|
|
749
|
+
type: entry.isDirectory() ? DIRECTORY : FILE,
|
|
750
|
+
source: path.join(source, entry.name),
|
|
751
|
+
target: entry.name
|
|
752
|
+
})) : [];
|
|
753
|
+
} else jobs = sources.map((source) => ({ ...source }));
|
|
754
|
+
const seenHardlinks = /* @__PURE__ */ new Map();
|
|
755
|
+
let jobIndex = 0;
|
|
756
|
+
let writeIndex = 0;
|
|
757
|
+
let activeWorkers = 0;
|
|
758
|
+
let allJobsQueued = false;
|
|
759
|
+
const writeStreamBody = async (body) => {
|
|
760
|
+
try {
|
|
761
|
+
for await (const chunk of body) {
|
|
762
|
+
if (stream.destroyed) return;
|
|
763
|
+
packer.write(chunk instanceof Uint8Array ? chunk : Buffer.from(chunk));
|
|
764
|
+
if (drain) await drain;
|
|
765
|
+
}
|
|
766
|
+
} finally {
|
|
767
|
+
body.off("error", onError);
|
|
768
|
+
bodyStreams.delete(body);
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
const writer = async () => {
|
|
772
|
+
const readBufferSmall = Buffer.alloc(65536);
|
|
773
|
+
let readBufferLarge = null;
|
|
774
|
+
while (true) {
|
|
775
|
+
if (stream.destroyed) return;
|
|
776
|
+
if (allJobsQueued && writeIndex >= jobs.length) break;
|
|
777
|
+
if (!results.has(writeIndex)) {
|
|
778
|
+
await new Promise((resolve2) => {
|
|
779
|
+
resumeWriter = resolve2;
|
|
780
|
+
});
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
const result = results.get(writeIndex);
|
|
784
|
+
results.delete(writeIndex);
|
|
785
|
+
if (!result) {
|
|
786
|
+
writeIndex++;
|
|
787
|
+
controller();
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
if (result.hardlinkId) {
|
|
791
|
+
const originalName = result.header.name;
|
|
792
|
+
const hardlinkTarget = seenHardlinks.get(result.hardlinkId);
|
|
793
|
+
if (hardlinkTarget) {
|
|
794
|
+
if (result.body && !(result.body instanceof Uint8Array) && !(result.body instanceof Readable)) await closeHandle(result.body.handle);
|
|
795
|
+
result.body = void 0;
|
|
796
|
+
result.header.type = LINK;
|
|
797
|
+
result.header.linkname = hardlinkTarget.originalName;
|
|
798
|
+
result.header.size = 0;
|
|
799
|
+
}
|
|
800
|
+
if (map) result.header = map(result.header);
|
|
801
|
+
if (hardlinkTarget) {
|
|
802
|
+
if (result.header.linkname === hardlinkTarget.originalName) result.header.linkname = hardlinkTarget.mappedName;
|
|
803
|
+
} else seenHardlinks.set(result.hardlinkId, {
|
|
804
|
+
originalName,
|
|
805
|
+
mappedName: result.header.name
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
packer.add(result.header);
|
|
809
|
+
if (drain) await drain;
|
|
810
|
+
if (stream.destroyed) return;
|
|
811
|
+
if (result.body) if (result.body instanceof Uint8Array) {
|
|
812
|
+
if (result.body.length > 0) {
|
|
813
|
+
packer.write(result.body);
|
|
814
|
+
if (drain) await drain;
|
|
815
|
+
}
|
|
816
|
+
} else if (result.body instanceof Readable) await writeStreamBody(result.body);
|
|
817
|
+
else {
|
|
818
|
+
const { handle, size } = result.body;
|
|
819
|
+
const readBuffer = size > 1048576 ? readBufferLarge ??= Buffer.alloc(1048576) : readBufferSmall;
|
|
820
|
+
try {
|
|
821
|
+
let bytesLeft = size;
|
|
822
|
+
while (bytesLeft > 0 && !stream.destroyed) {
|
|
823
|
+
const { bytesRead } = await handle.read(readBuffer, 0, Math.min(bytesLeft, readBuffer.length), null);
|
|
824
|
+
if (bytesRead === 0) break;
|
|
825
|
+
packer.write(readBuffer.subarray(0, bytesRead));
|
|
826
|
+
bytesLeft -= bytesRead;
|
|
827
|
+
if (drain) await drain;
|
|
828
|
+
}
|
|
829
|
+
} finally {
|
|
830
|
+
await closeHandle(handle);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (stream.destroyed) return;
|
|
834
|
+
packer.endEntry();
|
|
835
|
+
if (drain) await drain;
|
|
836
|
+
writeIndex++;
|
|
837
|
+
controller();
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
const controller = () => {
|
|
841
|
+
if (stream.destroyed || allJobsQueued) return;
|
|
842
|
+
while (activeWorkers < concurrency && jobIndex < jobs.length && jobIndex - writeIndex < concurrency) {
|
|
843
|
+
activeWorkers++;
|
|
844
|
+
const currentIndex = jobIndex++;
|
|
845
|
+
processJob(jobs[currentIndex], currentIndex).catch(onError).finally(() => {
|
|
846
|
+
activeWorkers--;
|
|
847
|
+
controller();
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
if (activeWorkers === 0 && jobIndex >= jobs.length) {
|
|
851
|
+
allJobsQueued = true;
|
|
852
|
+
wakeWriter();
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
const processJob = async (job, index) => {
|
|
856
|
+
let jobResult = null;
|
|
857
|
+
const target = normalizeName(job.target);
|
|
858
|
+
try {
|
|
859
|
+
if (job.type === "content" || job.type === "stream") {
|
|
860
|
+
let body2;
|
|
861
|
+
let size;
|
|
862
|
+
const isDir = target.endsWith("/");
|
|
863
|
+
if (job.type === "stream") {
|
|
864
|
+
if (!isDir && job.size <= 0 || isDir && job.size !== 0) throw new Error(isDir ? "Streams for directories must have size 0." : "Streams require a positive size.");
|
|
865
|
+
size = job.size;
|
|
866
|
+
} else {
|
|
867
|
+
const content = await normalizeBody(job.content);
|
|
868
|
+
size = content.length;
|
|
869
|
+
body2 = content;
|
|
870
|
+
}
|
|
871
|
+
const stat3 = {
|
|
872
|
+
size: isDir ? 0 : size,
|
|
873
|
+
isFile: () => !isDir,
|
|
874
|
+
isDirectory: () => isDir,
|
|
875
|
+
isSymbolicLink: () => false,
|
|
876
|
+
mode: job.mode,
|
|
877
|
+
mtime: job.mtime ?? /* @__PURE__ */ new Date(),
|
|
878
|
+
uid: job.uid ?? 0,
|
|
879
|
+
gid: job.gid ?? 0
|
|
880
|
+
};
|
|
881
|
+
if (stream.destroyed) return;
|
|
882
|
+
if (filter && !filter(target, stat3)) return;
|
|
883
|
+
if (stream.destroyed) return;
|
|
884
|
+
let header2 = {
|
|
885
|
+
name: target,
|
|
886
|
+
type: isDir ? DIRECTORY : FILE,
|
|
887
|
+
size: isDir ? 0 : size,
|
|
888
|
+
mode: stat3.mode,
|
|
889
|
+
mtime: stat3.mtime,
|
|
890
|
+
uid: stat3.uid,
|
|
891
|
+
gid: stat3.gid,
|
|
892
|
+
uname: job.uname,
|
|
893
|
+
gname: job.gname
|
|
894
|
+
};
|
|
895
|
+
if (map) header2 = map(header2);
|
|
896
|
+
if (stream.destroyed) return;
|
|
897
|
+
if (!isDir && job.type === "stream") {
|
|
898
|
+
body2 = job.content instanceof Readable ? job.content : Readable.fromWeb(job.content);
|
|
899
|
+
body2.once("error", onError);
|
|
900
|
+
bodyStreams.add(body2);
|
|
901
|
+
}
|
|
902
|
+
jobResult = {
|
|
903
|
+
header: header2,
|
|
904
|
+
body: isDir ? void 0 : body2
|
|
905
|
+
};
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
let source = job.source;
|
|
909
|
+
let stat2 = await fsp.lstat(source, BIGINT_STAT);
|
|
910
|
+
if (stream.destroyed) return;
|
|
911
|
+
if (dereference && stat2.isSymbolicLink()) {
|
|
912
|
+
source = await fsp.realpath(source);
|
|
913
|
+
if (stream.destroyed) return;
|
|
914
|
+
realBaseDir ??= await fsp.realpath(baseDir ?? directoryPath ?? process.cwd());
|
|
915
|
+
if (stream.destroyed) return;
|
|
916
|
+
const relativeToBase = path.relative(realBaseDir, source);
|
|
917
|
+
if (relativeToBase === ".." || relativeToBase.startsWith(".." + path.sep) || path.isAbsolute(relativeToBase)) return;
|
|
918
|
+
stat2 = await fsp.lstat(source, BIGINT_STAT);
|
|
919
|
+
if (stat2.isSymbolicLink()) return;
|
|
920
|
+
}
|
|
921
|
+
if (stream.destroyed) return;
|
|
922
|
+
if (filter && !filter(job.source, stat2)) return;
|
|
923
|
+
if (stream.destroyed) return;
|
|
924
|
+
let header = {
|
|
925
|
+
name: target,
|
|
926
|
+
size: 0,
|
|
927
|
+
mode: (job.mode ?? Number(stat2.mode)) & 4095,
|
|
928
|
+
mtime: job.mtime === void 0 ? stat2.mtime : new Date(job.mtime.getTime()),
|
|
929
|
+
uid: job.uid ?? Number(stat2.uid),
|
|
930
|
+
gid: job.gid ?? Number(stat2.gid),
|
|
931
|
+
uname: job.uname,
|
|
932
|
+
gname: job.gname,
|
|
933
|
+
type: FILE
|
|
934
|
+
};
|
|
935
|
+
let body;
|
|
936
|
+
let hardlinkId;
|
|
937
|
+
if (stat2.isDirectory()) {
|
|
938
|
+
header.type = DIRECTORY;
|
|
939
|
+
header.name = target.endsWith("/") ? target : `${target}/`;
|
|
940
|
+
try {
|
|
941
|
+
const entries = await fsp.readdir(source, WITH_FILE_TYPES);
|
|
942
|
+
if (stream.destroyed) return;
|
|
943
|
+
const after = await fsp.lstat(source, BIGINT_STAT);
|
|
944
|
+
if (stream.destroyed || !after.isDirectory() || stat2.dev !== after.dev || stat2.ino !== after.ino) return;
|
|
945
|
+
for (const d of entries) jobs.push({
|
|
946
|
+
type: d.isDirectory() ? DIRECTORY : FILE,
|
|
947
|
+
source: path.join(source, d.name),
|
|
948
|
+
target: `${header.name}${d.name}`,
|
|
949
|
+
mtime: job.mtime,
|
|
950
|
+
uid: job.uid,
|
|
951
|
+
gid: job.gid,
|
|
952
|
+
uname: job.uname,
|
|
953
|
+
gname: job.gname,
|
|
954
|
+
mode: job.mode
|
|
955
|
+
});
|
|
956
|
+
} catch (error) {
|
|
957
|
+
const code = error.code;
|
|
958
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
|
|
959
|
+
}
|
|
960
|
+
} else if (stat2.isSymbolicLink()) {
|
|
961
|
+
header.type = SYMLINK;
|
|
962
|
+
header.linkname = await fsp.readlink(job.source);
|
|
963
|
+
} else if (stat2.isFile()) {
|
|
964
|
+
header.size = Number(stat2.size);
|
|
965
|
+
let handleToClose;
|
|
966
|
+
if (stat2.nlink > 1n && (process.platform !== "win32" || stat2.dev !== 0n && stat2.ino !== -1n)) hardlinkId = `${stat2.dev}:${stat2.ino}`;
|
|
967
|
+
try {
|
|
968
|
+
let after;
|
|
969
|
+
try {
|
|
970
|
+
if (header.size === 0) after = await fsp.lstat(source, BIGINT_STAT);
|
|
971
|
+
else {
|
|
972
|
+
handleToClose = await fsp.open(source, fs.constants.O_NOFOLLOW ?? 0);
|
|
973
|
+
fileHandles.set(handleToClose, null);
|
|
974
|
+
}
|
|
975
|
+
} catch (error) {
|
|
976
|
+
const code = error.code;
|
|
977
|
+
if (code === "ELOOP" || code === "ENOENT") return;
|
|
978
|
+
throw error;
|
|
979
|
+
}
|
|
980
|
+
if (stream.destroyed) return;
|
|
981
|
+
if (after) {
|
|
982
|
+
if (!after.isFile() || stat2.dev !== after.dev || stat2.ino !== after.ino) return;
|
|
983
|
+
} else {
|
|
984
|
+
const { dev, ino } = await handleToClose.stat(BIGINT_STAT);
|
|
985
|
+
if (stream.destroyed) return;
|
|
986
|
+
if (stat2.dev !== dev || stat2.ino !== ino) return;
|
|
987
|
+
}
|
|
988
|
+
if (header.size > 0) {
|
|
989
|
+
const handle = handleToClose;
|
|
990
|
+
if (header.size < 32768) {
|
|
991
|
+
const buffer = Buffer.allocUnsafe(header.size);
|
|
992
|
+
let offset = 0;
|
|
993
|
+
while (offset < buffer.length && !stream.destroyed) {
|
|
994
|
+
const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, offset);
|
|
995
|
+
if (bytesRead === 0) break;
|
|
996
|
+
offset += bytesRead;
|
|
997
|
+
}
|
|
998
|
+
body = offset === buffer.length ? buffer : buffer.subarray(0, offset);
|
|
999
|
+
} else {
|
|
1000
|
+
body = {
|
|
1001
|
+
handle,
|
|
1002
|
+
size: header.size
|
|
1003
|
+
};
|
|
1004
|
+
handleToClose = void 0;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
} finally {
|
|
1008
|
+
if (handleToClose) await closeHandle(handleToClose);
|
|
1009
|
+
}
|
|
1010
|
+
} else return;
|
|
1011
|
+
if (stream.destroyed) return;
|
|
1012
|
+
if (hardlinkId) jobResult = {
|
|
1013
|
+
header,
|
|
1014
|
+
body,
|
|
1015
|
+
hardlinkId
|
|
1016
|
+
};
|
|
1017
|
+
else {
|
|
1018
|
+
if (map) header = map(header);
|
|
1019
|
+
jobResult = {
|
|
1020
|
+
header,
|
|
1021
|
+
body
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
} finally {
|
|
1025
|
+
if (stream.destroyed) {
|
|
1026
|
+
if (jobResult?.body instanceof Readable) destroyBody(jobResult.body, cancelError);
|
|
1027
|
+
else if (jobResult?.body && !(jobResult.body instanceof Uint8Array)) await closeHandle(jobResult.body.handle);
|
|
1028
|
+
} else {
|
|
1029
|
+
results.set(index, jobResult);
|
|
1030
|
+
if (index === writeIndex) wakeWriter();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
controller();
|
|
1035
|
+
await writer();
|
|
1036
|
+
if (!stream.destroyed) {
|
|
1037
|
+
packer.finalize();
|
|
1038
|
+
stream.push(null);
|
|
1039
|
+
}
|
|
1040
|
+
})().catch(onError);
|
|
1041
|
+
return stream;
|
|
1042
|
+
}
|
|
1043
|
+
var createOperationQueue = (concurrency) => {
|
|
1044
|
+
let active = 0;
|
|
1045
|
+
const tasks = [];
|
|
1046
|
+
let head = 0;
|
|
1047
|
+
let idle = null;
|
|
1048
|
+
let resolveIdle = null;
|
|
1049
|
+
const ensureIdle = () => idle ??= new Promise((resolve2) => resolveIdle = resolve2);
|
|
1050
|
+
const flush = () => {
|
|
1051
|
+
while (active < concurrency && head < tasks.length) {
|
|
1052
|
+
const task = tasks[head++];
|
|
1053
|
+
active++;
|
|
1054
|
+
task().finally(() => {
|
|
1055
|
+
active--;
|
|
1056
|
+
flush();
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
if (head === tasks.length) {
|
|
1060
|
+
tasks.length = 0;
|
|
1061
|
+
head = 0;
|
|
1062
|
+
if (active === 0 && resolveIdle) {
|
|
1063
|
+
resolveIdle();
|
|
1064
|
+
idle = null;
|
|
1065
|
+
resolveIdle = null;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
return {
|
|
1070
|
+
add(op) {
|
|
1071
|
+
const wasIdle = active === 0 && head === tasks.length;
|
|
1072
|
+
return new Promise((resolve2, reject) => {
|
|
1073
|
+
tasks.push(() => Promise.resolve().then(op).then(resolve2, reject));
|
|
1074
|
+
if (wasIdle) ensureIdle();
|
|
1075
|
+
flush();
|
|
1076
|
+
});
|
|
1077
|
+
},
|
|
1078
|
+
onIdle() {
|
|
1079
|
+
return active === 0 && head === tasks.length ? Promise.resolve() : ensureIdle();
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
var BATCH_BYTES = 262144;
|
|
1084
|
+
var BUFFER_LIMIT = 8388608;
|
|
1085
|
+
var MAX_WRITE_VECTORS = 1024;
|
|
1086
|
+
var CREATE_FLAGS = fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_TRUNC | (fs.constants.O_NOFOLLOW ?? 0) | fs.constants.O_EXCL;
|
|
1087
|
+
var STATE_OPENING = 1;
|
|
1088
|
+
var STATE_OPEN = 2;
|
|
1089
|
+
var STATE_CLOSED = 3;
|
|
1090
|
+
var STATE_FAILED = 4;
|
|
1091
|
+
var DRAINED_PROMISE = Promise.resolve();
|
|
1092
|
+
var discardFile = (fd) => fs.ftruncate(fd, 0, () => fs.close(fd));
|
|
1093
|
+
function createFileSink(path2, { mode = 438, mtime } = {}, onError) {
|
|
1094
|
+
let state = STATE_OPENING;
|
|
1095
|
+
let flushing = false;
|
|
1096
|
+
let fd = null;
|
|
1097
|
+
let queue = [];
|
|
1098
|
+
let spare = [];
|
|
1099
|
+
let bytes = 0;
|
|
1100
|
+
let storedError = null;
|
|
1101
|
+
let failedFd = null;
|
|
1102
|
+
let endPromise = null;
|
|
1103
|
+
let endResolve = null;
|
|
1104
|
+
let endReject = null;
|
|
1105
|
+
let drainPromise = null;
|
|
1106
|
+
let drainResolve = null;
|
|
1107
|
+
let drainReject = null;
|
|
1108
|
+
const settleDrain = (error) => {
|
|
1109
|
+
if (!drainPromise) return;
|
|
1110
|
+
const resolve2 = drainResolve;
|
|
1111
|
+
const reject = drainReject;
|
|
1112
|
+
drainPromise = null;
|
|
1113
|
+
drainResolve = null;
|
|
1114
|
+
drainReject = null;
|
|
1115
|
+
if (error) reject?.(error);
|
|
1116
|
+
else resolve2?.();
|
|
1117
|
+
};
|
|
1118
|
+
const resetBuffers = () => {
|
|
1119
|
+
bytes = 0;
|
|
1120
|
+
queue.length = 0;
|
|
1121
|
+
spare.length = 0;
|
|
1122
|
+
};
|
|
1123
|
+
const finish = () => {
|
|
1124
|
+
if (state === STATE_FAILED) return;
|
|
1125
|
+
state = STATE_CLOSED;
|
|
1126
|
+
endResolve?.();
|
|
1127
|
+
settleDrain();
|
|
1128
|
+
};
|
|
1129
|
+
const fail = (error) => {
|
|
1130
|
+
if (storedError) return;
|
|
1131
|
+
storedError = error;
|
|
1132
|
+
state = STATE_FAILED;
|
|
1133
|
+
const writePending = flushing;
|
|
1134
|
+
resetBuffers();
|
|
1135
|
+
const fdToClose = fd;
|
|
1136
|
+
fd = null;
|
|
1137
|
+
if (fdToClose !== null) if (writePending) failedFd = fdToClose;
|
|
1138
|
+
else discardFile(fdToClose);
|
|
1139
|
+
flushing = false;
|
|
1140
|
+
if (endReject) endReject(error);
|
|
1141
|
+
else onError?.(error);
|
|
1142
|
+
settleDrain(error);
|
|
1143
|
+
};
|
|
1144
|
+
const close2 = () => {
|
|
1145
|
+
if (fd === null) {
|
|
1146
|
+
finish();
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
const fdToClose = fd;
|
|
1150
|
+
fd = null;
|
|
1151
|
+
if (mtime) fs.futimes(fdToClose, mtime, mtime, (err) => {
|
|
1152
|
+
if (state !== STATE_OPEN) {
|
|
1153
|
+
fs.close(fdToClose);
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (err) {
|
|
1157
|
+
fs.close(fdToClose, () => fail(err));
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
fs.close(fdToClose, (closeErr) => {
|
|
1161
|
+
if (state !== STATE_OPEN) return;
|
|
1162
|
+
if (closeErr) fail(closeErr);
|
|
1163
|
+
else finish();
|
|
1164
|
+
});
|
|
1165
|
+
});
|
|
1166
|
+
else fs.close(fdToClose, (err) => {
|
|
1167
|
+
if (state !== STATE_OPEN) return;
|
|
1168
|
+
if (err) fail(err);
|
|
1169
|
+
else finish();
|
|
1170
|
+
});
|
|
1171
|
+
};
|
|
1172
|
+
const flush = () => {
|
|
1173
|
+
if (flushing || queue.length === 0 || state !== STATE_OPEN) return;
|
|
1174
|
+
flushing = true;
|
|
1175
|
+
let bufs = queue;
|
|
1176
|
+
queue = spare;
|
|
1177
|
+
spare = bufs;
|
|
1178
|
+
queue.length = 0;
|
|
1179
|
+
let pendingBytes = bytes;
|
|
1180
|
+
const onDone = (err, written = 0) => {
|
|
1181
|
+
if (state !== STATE_OPEN) {
|
|
1182
|
+
if (failedFd !== null) {
|
|
1183
|
+
const fdToClose = failedFd;
|
|
1184
|
+
failedFd = null;
|
|
1185
|
+
discardFile(fdToClose);
|
|
1186
|
+
}
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
if (err) {
|
|
1190
|
+
flushing = false;
|
|
1191
|
+
fail(err);
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
if (written <= 0 || written > pendingBytes) {
|
|
1195
|
+
flushing = false;
|
|
1196
|
+
fail(/* @__PURE__ */ new Error("File write made no progress."));
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
bytes -= written;
|
|
1200
|
+
pendingBytes -= written;
|
|
1201
|
+
if (pendingBytes > 0) {
|
|
1202
|
+
let skipped = written;
|
|
1203
|
+
let index = 0;
|
|
1204
|
+
while (skipped >= bufs[index].length) skipped -= bufs[index++].length;
|
|
1205
|
+
bufs = bufs.slice(index);
|
|
1206
|
+
if (skipped > 0) bufs[0] = bufs[0].subarray(skipped);
|
|
1207
|
+
if (bufs.length === 1) {
|
|
1208
|
+
const buf = bufs[0];
|
|
1209
|
+
fs.write(fd, buf, 0, buf.length, null, onDone);
|
|
1210
|
+
} else fs.writev(fd, bufs, onDone);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
flushing = false;
|
|
1214
|
+
spare.length = 0;
|
|
1215
|
+
if (bytes < BUFFER_LIMIT) settleDrain();
|
|
1216
|
+
if (queue.length > 0) flush();
|
|
1217
|
+
else if (endResolve) close2();
|
|
1218
|
+
};
|
|
1219
|
+
if (bufs.length === 1) {
|
|
1220
|
+
const buf = bufs[0];
|
|
1221
|
+
fs.write(fd, buf, 0, buf.length, null, onDone);
|
|
1222
|
+
} else fs.writev(fd, bufs, onDone);
|
|
1223
|
+
};
|
|
1224
|
+
const onOpen = (err, openFd) => {
|
|
1225
|
+
if (err) return fail(err);
|
|
1226
|
+
if (state >= STATE_CLOSED) {
|
|
1227
|
+
fs.close(openFd);
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
fd = openFd;
|
|
1231
|
+
state = STATE_OPEN;
|
|
1232
|
+
if (endResolve) if (queue.length > 0) flush();
|
|
1233
|
+
else close2();
|
|
1234
|
+
else if (bytes >= BATCH_BYTES || queue.length >= MAX_WRITE_VECTORS) flush();
|
|
1235
|
+
else settleDrain();
|
|
1236
|
+
};
|
|
1237
|
+
const write2 = (chunk) => {
|
|
1238
|
+
if (state >= STATE_CLOSED || endResolve) return false;
|
|
1239
|
+
queue.push(chunk);
|
|
1240
|
+
bytes += chunk.length;
|
|
1241
|
+
if (state === STATE_OPEN && !flushing && (bytes >= BATCH_BYTES || queue.length >= MAX_WRITE_VECTORS)) flush();
|
|
1242
|
+
return bytes < BUFFER_LIMIT && queue.length < MAX_WRITE_VECTORS;
|
|
1243
|
+
};
|
|
1244
|
+
const waitDrain = () => {
|
|
1245
|
+
if (storedError) return Promise.reject(storedError);
|
|
1246
|
+
if (state === STATE_OPENING || state === STATE_OPEN && (bytes >= BUFFER_LIMIT || queue.length >= MAX_WRITE_VECTORS)) return drainPromise ??= new Promise((resolve2, reject) => {
|
|
1247
|
+
drainResolve = resolve2;
|
|
1248
|
+
drainReject = reject;
|
|
1249
|
+
});
|
|
1250
|
+
return DRAINED_PROMISE;
|
|
1251
|
+
};
|
|
1252
|
+
const end = () => {
|
|
1253
|
+
if (storedError) return Promise.reject(storedError);
|
|
1254
|
+
if (state >= STATE_CLOSED) return DRAINED_PROMISE;
|
|
1255
|
+
if (endPromise) return endPromise;
|
|
1256
|
+
endPromise = new Promise((resolve2, reject) => {
|
|
1257
|
+
endResolve = resolve2;
|
|
1258
|
+
endReject = reject;
|
|
1259
|
+
if (state === STATE_OPEN && !flushing) if (queue.length > 0) flush();
|
|
1260
|
+
else close2();
|
|
1261
|
+
});
|
|
1262
|
+
return endPromise;
|
|
1263
|
+
};
|
|
1264
|
+
const destroy = (error) => {
|
|
1265
|
+
if (error) {
|
|
1266
|
+
fail(error);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
if (state >= STATE_CLOSED) return;
|
|
1270
|
+
resetBuffers();
|
|
1271
|
+
flushing = false;
|
|
1272
|
+
if (fd !== null) {
|
|
1273
|
+
const fdToClose = fd;
|
|
1274
|
+
fd = null;
|
|
1275
|
+
fs.close(fdToClose);
|
|
1276
|
+
}
|
|
1277
|
+
finish();
|
|
1278
|
+
};
|
|
1279
|
+
fs.open(path2, CREATE_FLAGS, mode, (err, openFd) => {
|
|
1280
|
+
if (err?.code !== "EEXIST") return onOpen(err, openFd);
|
|
1281
|
+
if (state !== STATE_OPENING) return;
|
|
1282
|
+
fs.rm(path2, { force: true }, (rmErr) => {
|
|
1283
|
+
if (rmErr) return fail(rmErr);
|
|
1284
|
+
if (state !== STATE_OPENING) return;
|
|
1285
|
+
fs.open(path2, CREATE_FLAGS, mode, onOpen);
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1288
|
+
return {
|
|
1289
|
+
write: write2,
|
|
1290
|
+
end,
|
|
1291
|
+
destroy,
|
|
1292
|
+
waitDrain
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
var createCache = () => {
|
|
1296
|
+
const m = /* @__PURE__ */ new Map();
|
|
1297
|
+
return {
|
|
1298
|
+
get(k) {
|
|
1299
|
+
const v = m.get(k);
|
|
1300
|
+
if (m.delete(k)) m.set(k, v);
|
|
1301
|
+
return v;
|
|
1302
|
+
},
|
|
1303
|
+
set(k, v) {
|
|
1304
|
+
if (m.set(k, v).size > 1e4) m.delete(m.keys().next().value);
|
|
1305
|
+
},
|
|
1306
|
+
clear() {
|
|
1307
|
+
m.clear();
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
};
|
|
1311
|
+
var ENOENT = "ENOENT";
|
|
1312
|
+
var MAX_SYMLINKS = 64;
|
|
1313
|
+
var linkSep = process.platform === "win32" ? /[/\\]/ : "/";
|
|
1314
|
+
var linkParts = (linkname) => linkname.split(linkSep).filter((part) => part && part !== ".");
|
|
1315
|
+
var createPathCache = (destDirPath, options, opQueue, concurrency) => {
|
|
1316
|
+
const { maxDepth = 1024, dmode } = options;
|
|
1317
|
+
const dirPromises = createCache();
|
|
1318
|
+
const pathConflicts = /* @__PURE__ */ new Map();
|
|
1319
|
+
const deferredLinks = [];
|
|
1320
|
+
let symlinks;
|
|
1321
|
+
const realDirCache = createCache();
|
|
1322
|
+
const initializeDestDir = async (destDirPath2) => {
|
|
1323
|
+
const symbolic = path.resolve(destDirPath2);
|
|
1324
|
+
try {
|
|
1325
|
+
await fsp.mkdir(symbolic, { recursive: true });
|
|
1326
|
+
} catch (err) {
|
|
1327
|
+
if (err.code === ENOENT) {
|
|
1328
|
+
const parentDir = path.dirname(symbolic);
|
|
1329
|
+
if (parentDir === symbolic) throw err;
|
|
1330
|
+
await fsp.mkdir(parentDir, { recursive: true });
|
|
1331
|
+
await fsp.mkdir(symbolic, { recursive: true });
|
|
1332
|
+
} else throw err;
|
|
1333
|
+
}
|
|
1334
|
+
try {
|
|
1335
|
+
return {
|
|
1336
|
+
symbolic,
|
|
1337
|
+
real: await fsp.realpath(symbolic)
|
|
1338
|
+
};
|
|
1339
|
+
} catch (err) {
|
|
1340
|
+
if (err.code === ENOENT) return {
|
|
1341
|
+
symbolic,
|
|
1342
|
+
real: symbolic
|
|
1343
|
+
};
|
|
1344
|
+
throw err;
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
const destDirPromise = initializeDestDir(destDirPath);
|
|
1348
|
+
destDirPromise.catch(() => {
|
|
1349
|
+
});
|
|
1350
|
+
const getRealDir = async (dirPath, errorMessage) => {
|
|
1351
|
+
const destDir = await destDirPromise;
|
|
1352
|
+
if (dirPath === destDir.symbolic) return destDir.real;
|
|
1353
|
+
let promise = realDirCache.get(dirPath);
|
|
1354
|
+
if (!promise) {
|
|
1355
|
+
promise = fsp.realpath(dirPath).then((realPath) => {
|
|
1356
|
+
validateBounds(realPath, destDir.real, errorMessage);
|
|
1357
|
+
return realPath;
|
|
1358
|
+
});
|
|
1359
|
+
realDirCache.set(dirPath, promise);
|
|
1360
|
+
}
|
|
1361
|
+
return promise;
|
|
1362
|
+
};
|
|
1363
|
+
const prepareDirectory = async (dirPath, mode) => {
|
|
1364
|
+
let promise = dirPromises.get(dirPath);
|
|
1365
|
+
if (promise) return promise;
|
|
1366
|
+
promise = (async () => {
|
|
1367
|
+
if (dirPath === (await destDirPromise).symbolic) return;
|
|
1368
|
+
await prepareDirectory(path.dirname(dirPath));
|
|
1369
|
+
try {
|
|
1370
|
+
const stat2 = await fsp.lstat(dirPath);
|
|
1371
|
+
if (stat2.isDirectory()) return;
|
|
1372
|
+
if (stat2.isSymbolicLink()) try {
|
|
1373
|
+
const realPath = await getRealDir(dirPath, `Symlink "${dirPath}" points outside the extraction directory.`);
|
|
1374
|
+
if ((await fsp.stat(realPath)).isDirectory()) return;
|
|
1375
|
+
} catch (err) {
|
|
1376
|
+
if (err.code === ENOENT) throw new Error(`Symlink "${dirPath}" points outside the extraction directory.`);
|
|
1377
|
+
throw err;
|
|
1378
|
+
}
|
|
1379
|
+
throw new Error(`"${dirPath}" is not a valid directory component.`);
|
|
1380
|
+
} catch (err) {
|
|
1381
|
+
if (err.code === ENOENT) {
|
|
1382
|
+
await fsp.mkdir(dirPath, { mode: mode ?? options.dmode });
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
throw err;
|
|
1386
|
+
}
|
|
1387
|
+
})();
|
|
1388
|
+
dirPromises.set(dirPath, promise);
|
|
1389
|
+
return promise;
|
|
1390
|
+
};
|
|
1391
|
+
return {
|
|
1392
|
+
async ready() {
|
|
1393
|
+
await destDirPromise;
|
|
1394
|
+
},
|
|
1395
|
+
async preparePath(header) {
|
|
1396
|
+
const { name, linkname, type, mode, mtime } = header;
|
|
1397
|
+
const normalizedName = normalizeHeaderName(name);
|
|
1398
|
+
const destDir = await destDirPromise;
|
|
1399
|
+
const outPath = path.join(destDir.symbolic, normalizedName);
|
|
1400
|
+
if (maxDepth !== Infinity) {
|
|
1401
|
+
let depth = 1;
|
|
1402
|
+
for (const char of normalizedName) if (char === "/" && ++depth > maxDepth) throw new Error("Tar exceeds max specified depth.");
|
|
1403
|
+
}
|
|
1404
|
+
const prevOp = pathConflicts.get(normalizedName);
|
|
1405
|
+
if (prevOp) {
|
|
1406
|
+
if (prevOp === "directory" && type !== "directory" || prevOp !== "directory" && type === "directory") throw new Error(`Path conflict ${type} over existing ${prevOp} at "${name}"`);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
const parentDir = path.dirname(outPath);
|
|
1410
|
+
switch (type) {
|
|
1411
|
+
case DIRECTORY: {
|
|
1412
|
+
pathConflicts.set(normalizedName, DIRECTORY);
|
|
1413
|
+
const safeMode = mode === void 0 ? void 0 : mode & 511;
|
|
1414
|
+
await prepareDirectory(outPath, dmode ?? safeMode);
|
|
1415
|
+
if (mtime) await fsp.lutimes(outPath, mtime, mtime).catch(() => {
|
|
1416
|
+
});
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
case FILE:
|
|
1420
|
+
pathConflicts.set(normalizedName, FILE);
|
|
1421
|
+
await prepareDirectory(parentDir);
|
|
1422
|
+
return path.join(await getRealDir(parentDir, `File "${name}" points outside the extraction directory.`), path.basename(outPath));
|
|
1423
|
+
case SYMLINK: {
|
|
1424
|
+
pathConflicts.set(normalizedName, SYMLINK);
|
|
1425
|
+
if (!linkname) return;
|
|
1426
|
+
validateBounds(path.resolve(parentDir, linkname), destDir.symbolic, `Symlink "${linkname}" points outside the extraction directory.`);
|
|
1427
|
+
await prepareDirectory(parentDir);
|
|
1428
|
+
const realParentDir = await fsp.realpath(parentDir);
|
|
1429
|
+
validateBounds(realParentDir, destDir.real, "Symlink parent changed.");
|
|
1430
|
+
validateBounds(path.resolve(realParentDir, linkname), destDir.real, `Symlink "${linkname}" points outside the extraction directory.`);
|
|
1431
|
+
const realOutPath = path.join(realParentDir, path.basename(outPath));
|
|
1432
|
+
try {
|
|
1433
|
+
await fsp.symlink(linkname, realOutPath);
|
|
1434
|
+
} catch (err) {
|
|
1435
|
+
if (err.code !== "EEXIST") throw err;
|
|
1436
|
+
await fsp.rm(realOutPath, { force: true });
|
|
1437
|
+
if (await fsp.realpath(parentDir) !== realParentDir) throw new Error("Symlink parent changed.");
|
|
1438
|
+
await fsp.symlink(linkname, realOutPath);
|
|
1439
|
+
}
|
|
1440
|
+
(symlinks ??= []).push([normalizedName, linkname]);
|
|
1441
|
+
dirPromises.clear();
|
|
1442
|
+
realDirCache.clear();
|
|
1443
|
+
if (mtime) await fsp.lutimes(outPath, mtime, mtime).catch(() => {
|
|
1444
|
+
});
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
case LINK: {
|
|
1448
|
+
pathConflicts.set(normalizedName, LINK);
|
|
1449
|
+
if (!linkname) return;
|
|
1450
|
+
if (path.isAbsolute(linkname)) throw new Error(`Hardlink "${linkname}" points outside the extraction directory.`);
|
|
1451
|
+
const linkTarget = path.join(destDir.symbolic, linkname);
|
|
1452
|
+
validateBounds(linkTarget, destDir.symbolic, `Hardlink "${linkname}" points outside the extraction directory.`);
|
|
1453
|
+
await prepareDirectory(parentDir);
|
|
1454
|
+
if (linkTarget !== outPath) deferredLinks.push({
|
|
1455
|
+
linkTarget,
|
|
1456
|
+
outPath
|
|
1457
|
+
});
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
default:
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
},
|
|
1464
|
+
async checkSymlinks() {
|
|
1465
|
+
if (!symlinks) return;
|
|
1466
|
+
const { symbolic: dest, real } = await destDirPromise;
|
|
1467
|
+
const realPrefix = real + path.sep;
|
|
1468
|
+
const root = path.parse(real).root;
|
|
1469
|
+
const depth = linkParts(real.slice(root.length)).length;
|
|
1470
|
+
const targetParts = (linkname, resolvedParts, message) => {
|
|
1471
|
+
if (!path.isAbsolute(linkname)) return linkParts(linkname);
|
|
1472
|
+
validateBounds(linkname, real, message);
|
|
1473
|
+
resolvedParts.length = 0;
|
|
1474
|
+
const parts = linkParts(linkname.slice(root.length));
|
|
1475
|
+
parts.splice(0, depth);
|
|
1476
|
+
return parts;
|
|
1477
|
+
};
|
|
1478
|
+
const getSymlinkError = async ([name, storedLinkname]) => {
|
|
1479
|
+
const outPath = path.join(dest, name);
|
|
1480
|
+
try {
|
|
1481
|
+
try {
|
|
1482
|
+
const resolved = await fsp.realpath(outPath);
|
|
1483
|
+
if (resolved !== real && !resolved.startsWith(realPrefix)) throw new Error(`Symlink "${storedLinkname}" points outside the extraction directory.`);
|
|
1484
|
+
return;
|
|
1485
|
+
} catch (err) {
|
|
1486
|
+
if (err.code !== ENOENT) throw err;
|
|
1487
|
+
}
|
|
1488
|
+
if (!(await fsp.lstat(outPath)).isSymbolicLink()) return;
|
|
1489
|
+
const linkname = await fsp.readlink(outPath);
|
|
1490
|
+
const message = `Symlink "${linkname}" points outside the extraction directory.`;
|
|
1491
|
+
const realParent = await fsp.realpath(path.dirname(outPath));
|
|
1492
|
+
validateBounds(realParent, real, message);
|
|
1493
|
+
const resolvedParts = linkParts(path.relative(real, realParent));
|
|
1494
|
+
const pendingParts = targetParts(linkname, resolvedParts, message);
|
|
1495
|
+
let followedSymlinks = 0;
|
|
1496
|
+
for (let i = 0; i < pendingParts.length; i++) {
|
|
1497
|
+
const part = pendingParts[i];
|
|
1498
|
+
if (part === "..") {
|
|
1499
|
+
if (!resolvedParts.length) throw new Error(message);
|
|
1500
|
+
resolvedParts.pop();
|
|
1501
|
+
continue;
|
|
1502
|
+
}
|
|
1503
|
+
resolvedParts.push(part);
|
|
1504
|
+
const nextPath = path.join(real, ...resolvedParts);
|
|
1505
|
+
let nextStat;
|
|
1506
|
+
try {
|
|
1507
|
+
nextStat = await fsp.lstat(nextPath);
|
|
1508
|
+
} catch (err) {
|
|
1509
|
+
if (err.code === ENOENT) continue;
|
|
1510
|
+
throw err;
|
|
1511
|
+
}
|
|
1512
|
+
if (!nextStat.isSymbolicLink()) continue;
|
|
1513
|
+
if (++followedSymlinks > MAX_SYMLINKS) throw new Error(message);
|
|
1514
|
+
const nextLink = await fsp.readlink(nextPath);
|
|
1515
|
+
resolvedParts.pop();
|
|
1516
|
+
pendingParts.splice(i + 1, 0, ...targetParts(nextLink, resolvedParts, message));
|
|
1517
|
+
}
|
|
1518
|
+
} catch (err) {
|
|
1519
|
+
if (err.code !== ENOENT) return err;
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
for (let start = 0; start < symlinks.length; start += concurrency) {
|
|
1523
|
+
const batch = symlinks.slice(start, start + concurrency);
|
|
1524
|
+
const errors = await Promise.all(batch.map((symlink2) => opQueue.add(() => getSymlinkError(symlink2))));
|
|
1525
|
+
for (const [i, error] of errors.entries()) {
|
|
1526
|
+
if (error === void 0) continue;
|
|
1527
|
+
await fsp.rm(path.join(dest, batch[i][0]), { force: true });
|
|
1528
|
+
throw error;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
},
|
|
1532
|
+
async applyLinks() {
|
|
1533
|
+
const destRoot = (await destDirPromise).real;
|
|
1534
|
+
for (const { linkTarget, outPath } of deferredLinks) try {
|
|
1535
|
+
const realTargetDir = await fsp.realpath(path.dirname(linkTarget));
|
|
1536
|
+
validateBounds(realTargetDir, destRoot, `Hardlink "${linkTarget}" points outside the extraction directory.`);
|
|
1537
|
+
const realTarget = path.join(realTargetDir, path.basename(linkTarget));
|
|
1538
|
+
const [targetResult, outDirResult] = await Promise.allSettled([opQueue.add(() => fsp.lstat(realTarget)), opQueue.add(() => fsp.realpath(path.dirname(outPath)))]);
|
|
1539
|
+
if (targetResult.status === "rejected") throw targetResult.reason;
|
|
1540
|
+
const targetStat = targetResult.value;
|
|
1541
|
+
if (targetStat.isSymbolicLink()) throw new Error(`Hardlink "${linkTarget}" is a symlink.`);
|
|
1542
|
+
if (outDirResult.status === "rejected") throw outDirResult.reason;
|
|
1543
|
+
const realOutDir = outDirResult.value;
|
|
1544
|
+
validateBounds(realOutDir, destRoot, `Hardlink "${outPath}" points outside the extraction directory.`);
|
|
1545
|
+
const realOutPath = path.join(realOutDir, path.basename(outPath));
|
|
1546
|
+
try {
|
|
1547
|
+
await fsp.link(realTarget, realOutPath);
|
|
1548
|
+
} catch (err) {
|
|
1549
|
+
const code = err.code;
|
|
1550
|
+
if (code !== "EEXIST" && code !== ENOENT) throw err;
|
|
1551
|
+
try {
|
|
1552
|
+
const outStat = await fsp.lstat(realOutPath);
|
|
1553
|
+
if (outStat.dev === targetStat.dev && outStat.ino === targetStat.ino) continue;
|
|
1554
|
+
await fsp.rm(realOutPath, { force: true });
|
|
1555
|
+
} catch (err2) {
|
|
1556
|
+
if (err2.code !== ENOENT) throw err2;
|
|
1557
|
+
}
|
|
1558
|
+
await fsp.link(realTarget, realOutPath);
|
|
1559
|
+
}
|
|
1560
|
+
const linkStat = await fsp.lstat(realOutPath);
|
|
1561
|
+
if (linkStat.dev !== targetStat.dev || linkStat.ino !== targetStat.ino) {
|
|
1562
|
+
await fsp.rm(realOutPath, { force: true });
|
|
1563
|
+
throw new Error(`Hardlink target "${linkTarget}" changed during creation for link at "${outPath}".`);
|
|
1564
|
+
}
|
|
1565
|
+
} catch (err) {
|
|
1566
|
+
if (err.code === ENOENT) throw new Error(`Hardlink target "${linkTarget}" does not exist for link at "${outPath}".`);
|
|
1567
|
+
throw err;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
};
|
|
1572
|
+
function unpackTar(directoryPath, options = {}) {
|
|
1573
|
+
const unpacker = createUnpacker(options);
|
|
1574
|
+
const concurrency = options.concurrency || cpus().length || 8;
|
|
1575
|
+
const opQueue = createOperationQueue(concurrency);
|
|
1576
|
+
let cancelError;
|
|
1577
|
+
const pathCache = createPathCache(directoryPath, options, opQueue, concurrency);
|
|
1578
|
+
let currentFileStream = null;
|
|
1579
|
+
const fileStreams = /* @__PURE__ */ new Set();
|
|
1580
|
+
let needsDrain = false;
|
|
1581
|
+
const writeCurrent = (chunk) => {
|
|
1582
|
+
const writeOk = currentFileStream.write(chunk);
|
|
1583
|
+
if (!writeOk) needsDrain = true;
|
|
1584
|
+
return writeOk;
|
|
1585
|
+
};
|
|
1586
|
+
const onFileError = (err) => {
|
|
1587
|
+
if (!writable.destroyed) writable.destroy(err);
|
|
1588
|
+
};
|
|
1589
|
+
const closeCurrent = () => {
|
|
1590
|
+
const stream = currentFileStream;
|
|
1591
|
+
currentFileStream = null;
|
|
1592
|
+
opQueue.add(() => stream.end()).then(() => fileStreams.delete(stream), (err) => {
|
|
1593
|
+
fileStreams.delete(stream);
|
|
1594
|
+
onFileError(err);
|
|
1595
|
+
});
|
|
1596
|
+
};
|
|
1597
|
+
const writable = new Writable({
|
|
1598
|
+
async write(chunk, _, cb) {
|
|
1599
|
+
let pendingFileOpens;
|
|
1600
|
+
let writeError;
|
|
1601
|
+
try {
|
|
1602
|
+
unpacker.write(chunk);
|
|
1603
|
+
if (unpacker.isEntryActive()) {
|
|
1604
|
+
if (currentFileStream) {
|
|
1605
|
+
while (!unpacker.isBodyComplete()) {
|
|
1606
|
+
needsDrain = false;
|
|
1607
|
+
const fed = unpacker.streamBody(writeCurrent);
|
|
1608
|
+
if (needsDrain) await currentFileStream.waitDrain();
|
|
1609
|
+
else if (fed === 0) return;
|
|
1610
|
+
}
|
|
1611
|
+
if (!unpacker.skipPadding()) return;
|
|
1612
|
+
closeCurrent();
|
|
1613
|
+
} else if (!unpacker.skipEntry()) return;
|
|
1614
|
+
}
|
|
1615
|
+
while (true) {
|
|
1616
|
+
const header = unpacker.readHeader();
|
|
1617
|
+
if (header === void 0 || header === null) return;
|
|
1618
|
+
const transformedHeader = transformHeader(header, options);
|
|
1619
|
+
if (!transformedHeader) {
|
|
1620
|
+
if (!unpacker.skipEntry()) return;
|
|
1621
|
+
continue;
|
|
1622
|
+
}
|
|
1623
|
+
const outPath = await opQueue.add(() => pathCache.preparePath(transformedHeader));
|
|
1624
|
+
if (cancelError) throw cancelError;
|
|
1625
|
+
if (outPath) {
|
|
1626
|
+
const safeMode = transformedHeader.mode === void 0 ? void 0 : transformedHeader.mode & 511;
|
|
1627
|
+
currentFileStream = createFileSink(outPath, {
|
|
1628
|
+
mode: options.fmode ?? safeMode,
|
|
1629
|
+
mtime: transformedHeader.mtime ?? void 0
|
|
1630
|
+
}, onFileError);
|
|
1631
|
+
fileStreams.add(currentFileStream);
|
|
1632
|
+
(pendingFileOpens ??= []).push(currentFileStream.waitDrain().catch((error) => error));
|
|
1633
|
+
while (!unpacker.isBodyComplete()) {
|
|
1634
|
+
needsDrain = false;
|
|
1635
|
+
const fed = unpacker.streamBody(writeCurrent);
|
|
1636
|
+
if (needsDrain) await currentFileStream.waitDrain();
|
|
1637
|
+
else if (fed === 0) return;
|
|
1638
|
+
}
|
|
1639
|
+
if (!unpacker.skipPadding()) return;
|
|
1640
|
+
closeCurrent();
|
|
1641
|
+
} else if (!unpacker.skipEntry()) return;
|
|
1642
|
+
}
|
|
1643
|
+
} catch (err) {
|
|
1644
|
+
writeError = err;
|
|
1645
|
+
} finally {
|
|
1646
|
+
const openError = pendingFileOpens ? (await Promise.all(pendingFileOpens)).find((error) => error) : void 0;
|
|
1647
|
+
cb(cancelError ?? openError ?? writeError);
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
async final(cb) {
|
|
1651
|
+
try {
|
|
1652
|
+
unpacker.end();
|
|
1653
|
+
unpacker.validateEOF();
|
|
1654
|
+
if (currentFileStream) closeCurrent();
|
|
1655
|
+
await pathCache.ready();
|
|
1656
|
+
await opQueue.onIdle();
|
|
1657
|
+
if (cancelError) throw cancelError;
|
|
1658
|
+
await pathCache.checkSymlinks();
|
|
1659
|
+
await pathCache.applyLinks();
|
|
1660
|
+
cb();
|
|
1661
|
+
} catch (err) {
|
|
1662
|
+
cb(err);
|
|
1663
|
+
}
|
|
1664
|
+
},
|
|
1665
|
+
destroy(error, callback) {
|
|
1666
|
+
const hasWork = fileStreams.size > 0 || writable.writableLength > 0 || writable.writableEnded && !writable.writableFinished;
|
|
1667
|
+
if (!error && !hasWork) {
|
|
1668
|
+
callback(null);
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
cancelError = error ?? AbortSignal.abort().reason;
|
|
1672
|
+
for (const stream of fileStreams) stream.destroy(cancelError);
|
|
1673
|
+
fileStreams.clear();
|
|
1674
|
+
currentFileStream = null;
|
|
1675
|
+
callback(cancelError);
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
return writable;
|
|
1679
|
+
}
|
|
1680
|
+
export {
|
|
1681
|
+
packTar,
|
|
1682
|
+
packTarSources,
|
|
1683
|
+
unpackTar
|
|
1684
|
+
};
|
|
1685
|
+
//# sourceMappingURL=fs-P6GYHPGZ.js.map
|