zip-lib 1.2.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +296 -205
- package/lib/fs.d.ts +1 -0
- package/lib/fs.js +74 -61
- package/lib/index.d.ts +21 -2
- package/lib/index.js +27 -24
- package/lib/unzip.d.ts +22 -10
- package/lib/unzip.js +207 -135
- package/lib/zip.d.ts +25 -13
- package/lib/zip.js +154 -66
- package/package.json +3 -3
package/lib/unzip.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.Unzip = void 0;
|
|
|
4
4
|
const node_fs_1 = require("node:fs");
|
|
5
5
|
const fs = require("node:fs/promises");
|
|
6
6
|
const path = require("node:path");
|
|
7
|
+
const promises_1 = require("node:stream/promises");
|
|
7
8
|
const yauzl = require("yauzl");
|
|
8
9
|
const cancelable_1 = require("./cancelable");
|
|
9
10
|
const exfs = require("./fs");
|
|
@@ -41,6 +42,7 @@ class EntryContext {
|
|
|
41
42
|
this.symlinkAsFileOnWindows = symlinkAsFileOnWindows;
|
|
42
43
|
this._symlinkFileNames = [];
|
|
43
44
|
this._symlinkFolders = [];
|
|
45
|
+
this._inspectedFolders = [];
|
|
44
46
|
this._ensuredFolders = [];
|
|
45
47
|
}
|
|
46
48
|
get decodeEntryFileName() {
|
|
@@ -67,10 +69,25 @@ class EntryContext {
|
|
|
67
69
|
getFilePath() {
|
|
68
70
|
return path.resolve(path.join(this.targetFolder, this.decodeEntryFileName));
|
|
69
71
|
}
|
|
72
|
+
async inspectFolder(folder) {
|
|
73
|
+
if (this._inspectedFolders.includes(folder) || folder === path.dirname(folder)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
await this.inspectFolder(path.dirname(folder));
|
|
77
|
+
const folderStat = await exfs.statFolder(folder);
|
|
78
|
+
if (!folderStat) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (folderStat.isSymbolicLink) {
|
|
82
|
+
this.addSymlinkFolder(folder, folderStat.realpath);
|
|
83
|
+
}
|
|
84
|
+
this._inspectedFolders.push(folder);
|
|
85
|
+
}
|
|
70
86
|
async ensureFolder(folder) {
|
|
71
87
|
if (this._ensuredFolders.includes(folder)) {
|
|
72
88
|
return;
|
|
73
89
|
}
|
|
90
|
+
await this.inspectFolder(path.dirname(folder));
|
|
74
91
|
const folderStat = await exfs.ensureFolder(folder);
|
|
75
92
|
if (folderStat.isSymbolicLink) {
|
|
76
93
|
this.addSymlinkFolder(folder, folderStat.realpath);
|
|
@@ -117,98 +134,133 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
117
134
|
super();
|
|
118
135
|
this.options = options;
|
|
119
136
|
}
|
|
120
|
-
|
|
121
|
-
* Extract the zip file to the specified location.
|
|
122
|
-
* @param zipFile
|
|
123
|
-
* @param targetFolder
|
|
124
|
-
* @param options
|
|
125
|
-
*/
|
|
126
|
-
async extract(zipFile, targetFolder) {
|
|
127
|
-
let extractedEntriesCount = 0;
|
|
137
|
+
async extract(zipFileOrBuffer, targetFolder) {
|
|
128
138
|
const token = new cancelable_1.CancellationToken();
|
|
129
139
|
this.token = token;
|
|
140
|
+
try {
|
|
141
|
+
const { zfile, realTargetFolder } = await this.prepareExtraction(zipFileOrBuffer, targetFolder, token);
|
|
142
|
+
this.zipFile = zfile;
|
|
143
|
+
await this.processEntries(zfile, targetFolder, realTargetFolder, token);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
if (this.token === token) {
|
|
147
|
+
this.token = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async prepareExtraction(zipFileOrBuffer, targetFolder, token) {
|
|
130
152
|
if (this.isOverwrite()) {
|
|
131
153
|
await exfs.rimraf(targetFolder);
|
|
132
154
|
}
|
|
133
155
|
if (token.isCancelled) {
|
|
134
|
-
|
|
156
|
+
throw this.canceledError();
|
|
135
157
|
}
|
|
136
158
|
await exfs.ensureFolder(targetFolder);
|
|
137
159
|
const realTargetFolder = await exfs.realpath(targetFolder);
|
|
138
|
-
const zfile = await this.openZip(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
160
|
+
const zfile = await this.openZip(zipFileOrBuffer, token);
|
|
161
|
+
return { zfile, realTargetFolder };
|
|
162
|
+
}
|
|
163
|
+
async processEntries(zfile, targetFolder, realTargetFolder, token) {
|
|
164
|
+
return await new Promise((resolve, reject) => {
|
|
165
|
+
let extractedEntriesCount = 0;
|
|
142
166
|
let anyError = null;
|
|
143
167
|
const total = zfile.entryCount;
|
|
168
|
+
const entryContext = new EntryContext(targetFolder, realTargetFolder, this.symlinkToFile());
|
|
169
|
+
const entryEvent = new EntryEvent(total);
|
|
170
|
+
const settle = this.createPromiseSettler(resolve, reject);
|
|
171
|
+
const disposeCancel = token.onCancelled(() => {
|
|
172
|
+
this.closeZip(zfile);
|
|
173
|
+
settle.reject(this.canceledError());
|
|
174
|
+
});
|
|
144
175
|
zfile.once("error", (err) => {
|
|
145
|
-
|
|
146
|
-
|
|
176
|
+
disposeCancel();
|
|
177
|
+
anyError = this.wrapError(err, token.isCancelled);
|
|
178
|
+
this.closeZip(zfile);
|
|
179
|
+
settle.reject(anyError);
|
|
147
180
|
});
|
|
148
181
|
zfile.once("close", () => {
|
|
149
|
-
|
|
182
|
+
disposeCancel();
|
|
183
|
+
if (this.zipFile === zfile) {
|
|
184
|
+
this.zipFile = null;
|
|
185
|
+
}
|
|
150
186
|
if (anyError) {
|
|
151
|
-
|
|
187
|
+
settle.reject(this.wrapError(anyError, token.isCancelled));
|
|
152
188
|
}
|
|
153
|
-
else {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// If the zip content is empty, it will not receive the
|
|
158
|
-
|
|
159
|
-
c(void 0);
|
|
160
|
-
}
|
|
189
|
+
else if (token.isCancelled) {
|
|
190
|
+
settle.reject(this.canceledError());
|
|
191
|
+
}
|
|
192
|
+
else if (extractedEntriesCount >= total) {
|
|
193
|
+
// If the zip content is empty, it will not receive the zfile.on("entry") event.
|
|
194
|
+
settle.resolve();
|
|
161
195
|
}
|
|
162
196
|
});
|
|
163
|
-
// Because openZip is an asynchronous method, openZip may not be completed when calling cancel,
|
|
164
|
-
// so we need to check if it has been canceled after the openZip method returns.
|
|
165
|
-
if (token.isCancelled) {
|
|
166
|
-
this.closeZip();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const entryContext = new EntryContext(targetFolder, realTargetFolder, this.symlinkToFile());
|
|
170
|
-
const entryEvent = new EntryEvent(total);
|
|
171
197
|
zfile.on("entry", async (entry) => {
|
|
172
|
-
// use UTF-8 in all situations
|
|
173
|
-
// see https://github.com/thejoshwolfe/yauzl/issues/84
|
|
174
|
-
const rawName = entry.fileName.toString("utf8");
|
|
175
|
-
// allow backslash
|
|
176
|
-
const fileName = rawName.replace(/\\/g, "/");
|
|
177
|
-
// Because `decodeStrings` is `false`, we need to manually verify the entryname
|
|
178
|
-
// see https://github.com/thejoshwolfe/yauzl#validatefilenamefilename
|
|
179
|
-
const errorMessage = yauzl.validateFileName(fileName);
|
|
180
|
-
if (errorMessage != null) {
|
|
181
|
-
anyError = new Error(errorMessage);
|
|
182
|
-
this.closeZip();
|
|
183
|
-
e(anyError);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
entryEvent.entryName = fileName;
|
|
187
|
-
this.onEntryCallback(entryEvent);
|
|
188
|
-
entryContext.decodeEntryFileName = fileName;
|
|
189
198
|
try {
|
|
190
|
-
|
|
191
|
-
entryEvent.reset();
|
|
192
|
-
zfile.readEntry();
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
await this.handleEntry(zfile, entry, entryContext, token);
|
|
196
|
-
}
|
|
199
|
+
await this.handleZipEntry(zfile, entry, entryContext, entryEvent, token);
|
|
197
200
|
extractedEntriesCount++;
|
|
198
|
-
if (extractedEntriesCount
|
|
199
|
-
|
|
201
|
+
if (extractedEntriesCount >= total) {
|
|
202
|
+
settle.resolve();
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
catch (error) {
|
|
203
206
|
anyError = this.wrapError(error, token.isCancelled);
|
|
204
|
-
this.closeZip();
|
|
205
|
-
|
|
207
|
+
this.closeZip(zfile);
|
|
208
|
+
settle.reject(anyError);
|
|
206
209
|
}
|
|
207
210
|
});
|
|
211
|
+
this.readNextEntry(zfile, token);
|
|
208
212
|
});
|
|
209
213
|
}
|
|
214
|
+
readNextEntry(zfile, token) {
|
|
215
|
+
if (token.isCancelled) {
|
|
216
|
+
this.closeZip(zfile);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
zfile.readEntry();
|
|
220
|
+
}
|
|
221
|
+
createPromiseSettler(resolve, reject) {
|
|
222
|
+
let settled = false;
|
|
223
|
+
return {
|
|
224
|
+
resolve: () => {
|
|
225
|
+
if (settled) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
settled = true;
|
|
229
|
+
resolve();
|
|
230
|
+
},
|
|
231
|
+
reject: (error) => {
|
|
232
|
+
if (settled) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
settled = true;
|
|
236
|
+
reject(error);
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
async handleZipEntry(zfile, entry, entryContext, entryEvent, token) {
|
|
241
|
+
// use UTF-8 in all situations
|
|
242
|
+
// see https://github.com/thejoshwolfe/yauzl/issues/84
|
|
243
|
+
const rawName = entry.fileName.toString("utf8");
|
|
244
|
+
// allow backslash
|
|
245
|
+
const fileName = rawName.replace(/\\/g, "/");
|
|
246
|
+
// Because decodeStrings is false, we need to manually verify the entry name
|
|
247
|
+
// see https://github.com/thejoshwolfe/yauzl#validatefilenamefilename
|
|
248
|
+
const errorMessage = yauzl.validateFileName(fileName);
|
|
249
|
+
if (errorMessage != null) {
|
|
250
|
+
throw new Error(errorMessage);
|
|
251
|
+
}
|
|
252
|
+
entryEvent.entryName = fileName;
|
|
253
|
+
this.onEntryCallback(entryEvent);
|
|
254
|
+
entryContext.decodeEntryFileName = fileName;
|
|
255
|
+
if (entryEvent.isPrevented) {
|
|
256
|
+
entryEvent.reset();
|
|
257
|
+
this.readNextEntry(zfile, token);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
await this.handleEntry(zfile, entry, entryContext, token);
|
|
261
|
+
}
|
|
210
262
|
/**
|
|
211
|
-
* Cancel
|
|
263
|
+
* Cancel extraction.
|
|
212
264
|
* If the cancel method is called after the extract is complete, nothing will happen.
|
|
213
265
|
*/
|
|
214
266
|
cancel() {
|
|
@@ -218,35 +270,50 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
218
270
|
}
|
|
219
271
|
this.closeZip();
|
|
220
272
|
}
|
|
221
|
-
closeZip() {
|
|
222
|
-
|
|
223
|
-
|
|
273
|
+
closeZip(zfile) {
|
|
274
|
+
const target = zfile !== null && zfile !== void 0 ? zfile : this.zipFile;
|
|
275
|
+
if (target) {
|
|
276
|
+
target.close();
|
|
277
|
+
}
|
|
278
|
+
if (!zfile || this.zipFile === zfile) {
|
|
224
279
|
this.zipFile = null;
|
|
225
280
|
}
|
|
226
281
|
}
|
|
227
|
-
openZip(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
282
|
+
async openZip(zipFileOrBuffer, token) {
|
|
283
|
+
const options = {
|
|
284
|
+
lazyEntries: true,
|
|
285
|
+
// see https://github.com/thejoshwolfe/yauzl/issues/84
|
|
286
|
+
decodeStrings: false,
|
|
287
|
+
};
|
|
288
|
+
try {
|
|
289
|
+
return await new Promise((resolve, reject) => {
|
|
290
|
+
const callback = (err, zfile) => {
|
|
291
|
+
if (err) {
|
|
292
|
+
reject(this.wrapError(err, token.isCancelled));
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
resolve(zfile);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
if (typeof zipFileOrBuffer === "string") {
|
|
299
|
+
yauzl.open(zipFileOrBuffer, options, callback);
|
|
236
300
|
}
|
|
237
301
|
else {
|
|
238
|
-
|
|
302
|
+
yauzl.fromBuffer(zipFileOrBuffer, options, callback);
|
|
239
303
|
}
|
|
240
304
|
});
|
|
241
|
-
}
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
throw this.wrapError(error, token.isCancelled);
|
|
308
|
+
}
|
|
242
309
|
}
|
|
243
310
|
async handleEntry(zfile, entry, entryContext, token) {
|
|
244
311
|
if (/\/$/.test(entryContext.decodeEntryFileName)) {
|
|
245
312
|
// Directory file names end with '/'.
|
|
246
|
-
// Note that
|
|
313
|
+
// Note that entries for directories themselves are optional.
|
|
247
314
|
// An entry's fileName implicitly requires its parent directories to exist.
|
|
248
315
|
await exfs.ensureFolder(entryContext.getFilePath());
|
|
249
|
-
|
|
316
|
+
this.readNextEntry(zfile, token);
|
|
250
317
|
}
|
|
251
318
|
else {
|
|
252
319
|
// file entry
|
|
@@ -254,13 +321,13 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
254
321
|
}
|
|
255
322
|
}
|
|
256
323
|
openZipFileStream(zfile, entry, token) {
|
|
257
|
-
return new Promise((
|
|
324
|
+
return new Promise((resolve, reject) => {
|
|
258
325
|
zfile.openReadStream(entry, (err, readStream) => {
|
|
259
326
|
if (err) {
|
|
260
|
-
|
|
327
|
+
reject(this.wrapError(err, token.isCancelled));
|
|
261
328
|
}
|
|
262
329
|
else {
|
|
263
|
-
|
|
330
|
+
resolve(readStream);
|
|
264
331
|
}
|
|
265
332
|
});
|
|
266
333
|
});
|
|
@@ -268,7 +335,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
268
335
|
async extractEntry(zfile, entry, entryContext, token) {
|
|
269
336
|
const filePath = entryContext.getFilePath();
|
|
270
337
|
const fileDir = path.dirname(filePath);
|
|
271
|
-
await entryContext.
|
|
338
|
+
await entryContext.inspectFolder(fileDir);
|
|
272
339
|
const outside = await entryContext.isOutsideTargetFolder(fileDir);
|
|
273
340
|
if (outside) {
|
|
274
341
|
const error = new Error(`Refuse to write file outside "${entryContext.targetFolder}", file: "${filePath}"`);
|
|
@@ -277,64 +344,69 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
277
344
|
}
|
|
278
345
|
const readStream = await this.openZipFileStream(zfile, entry, token);
|
|
279
346
|
await this.writeEntryToFile(readStream, entry, entryContext, token);
|
|
280
|
-
|
|
347
|
+
this.readNextEntry(zfile, token);
|
|
281
348
|
}
|
|
282
349
|
async writeEntryToFile(readStream, entry, entryContext, token) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
350
|
+
var _a;
|
|
351
|
+
try {
|
|
352
|
+
const filePath = entryContext.getFilePath();
|
|
353
|
+
const mode = this.modeFromEntry(entry);
|
|
354
|
+
// see https://unix.stackexchange.com/questions/193465/what-file-mode-is-a-symlink
|
|
355
|
+
const isSymlink = (mode & 0o170000) === 0o120000;
|
|
356
|
+
if (isSymlink) {
|
|
357
|
+
entryContext.symlinkFileNames.push(path.resolve(path.join(entryContext.targetFolder, entryContext.decodeEntryFileName)));
|
|
288
358
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const mode = this.modeFromEntry(entry);
|
|
297
|
-
// see https://unix.stackexchange.com/questions/193465/what-file-mode-is-a-symlink
|
|
298
|
-
const isSymlink = (mode & 0o170000) === 0o120000;
|
|
299
|
-
if (isSymlink) {
|
|
300
|
-
entryContext.symlinkFileNames.push(path.resolve(path.join(entryContext.targetFolder, entryContext.decodeEntryFileName)));
|
|
359
|
+
if (isSymlink && !this.symlinkToFile()) {
|
|
360
|
+
const linkContent = await this.readStreamContent(readStream, token);
|
|
361
|
+
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.safeSymlinksOnly) &&
|
|
362
|
+
entryContext.isSymlinkTargetOutsideTargetFolder(linkContent, filePath)) {
|
|
363
|
+
const error = new Error(`Dangerous link path was refused : "${entryContext.targetFolder}", file: "${filePath}", target: "${linkContent}". Set safeSymlinksOnly to false to allow writing through this symlink.`);
|
|
364
|
+
error.name = "AF_ILLEGAL_TARGET";
|
|
365
|
+
throw error;
|
|
301
366
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.safeSymlinksOnly) &&
|
|
315
|
-
entryContext.isSymlinkTargetOutsideTargetFolder(linkContent, filePath)) {
|
|
316
|
-
const error = new Error(`Dangerous link path was refused : "${entryContext.targetFolder}", file: "${filePath}", target: "${linkContent}"`);
|
|
317
|
-
error.name = "AF_ILLEGAL_TARGET";
|
|
318
|
-
e(error);
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
this.createSymlink(linkContent, filePath).then(c, e);
|
|
322
|
-
}
|
|
323
|
-
});
|
|
367
|
+
await entryContext.ensureFolder(path.dirname(filePath));
|
|
368
|
+
await this.createSymlink(linkContent, filePath);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
await entryContext.ensureFolder(path.dirname(filePath));
|
|
372
|
+
const fileStream = (0, node_fs_1.createWriteStream)(filePath, { mode });
|
|
373
|
+
const pipelinePromise = (0, promises_1.pipeline)(readStream, fileStream);
|
|
374
|
+
const disposeCancel = token.onCancelled(() => {
|
|
375
|
+
fileStream.destroy(this.canceledError());
|
|
376
|
+
});
|
|
377
|
+
try {
|
|
378
|
+
await pipelinePromise;
|
|
324
379
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
fileStream.once("close", () => c());
|
|
328
|
-
fileStream.once("error", (err) => {
|
|
329
|
-
e(this.wrapError(err, token.isCancelled));
|
|
330
|
-
});
|
|
331
|
-
readStream.pipe(fileStream);
|
|
380
|
+
finally {
|
|
381
|
+
disposeCancel();
|
|
332
382
|
}
|
|
333
383
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
throw this.wrapError(error, token.isCancelled);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async readStreamContent(readStream, token) {
|
|
390
|
+
let linkContent = "";
|
|
391
|
+
const readPromise = new Promise((resolve, reject) => {
|
|
392
|
+
readStream.on("data", (chunk) => {
|
|
393
|
+
linkContent += typeof chunk === "string" ? chunk : chunk.toString();
|
|
394
|
+
});
|
|
395
|
+
readStream.once("end", resolve);
|
|
396
|
+
readStream.once("error", (err) => {
|
|
397
|
+
reject(this.wrapError(err, token.isCancelled));
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
const disposeCancel = token.onCancelled(() => {
|
|
401
|
+
readStream.destroy(this.canceledError());
|
|
337
402
|
});
|
|
403
|
+
try {
|
|
404
|
+
await readPromise;
|
|
405
|
+
return linkContent;
|
|
406
|
+
}
|
|
407
|
+
finally {
|
|
408
|
+
disposeCancel();
|
|
409
|
+
}
|
|
338
410
|
}
|
|
339
411
|
modeFromEntry(entry) {
|
|
340
412
|
const attr = entry.externalFileAttributes >> 16 || 33188;
|
|
@@ -342,7 +414,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
342
414
|
.map((mask) => attr & mask)
|
|
343
415
|
.reduce((a, b) => a + b, attr & 61440 /* S_IFMT */);
|
|
344
416
|
}
|
|
345
|
-
async createSymlink(linkContent,
|
|
417
|
+
async createSymlink(linkContent, filePath) {
|
|
346
418
|
let linkType = "file";
|
|
347
419
|
if (process.platform === "win32") {
|
|
348
420
|
if (/\/$/.test(linkContent)) {
|
|
@@ -351,7 +423,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
351
423
|
else {
|
|
352
424
|
let targetPath = linkContent;
|
|
353
425
|
if (!path.isAbsolute(linkContent)) {
|
|
354
|
-
targetPath = path.join(path.dirname(
|
|
426
|
+
targetPath = path.join(path.dirname(filePath), linkContent);
|
|
355
427
|
}
|
|
356
428
|
try {
|
|
357
429
|
const stat = await fs.stat(targetPath);
|
|
@@ -364,7 +436,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
364
436
|
}
|
|
365
437
|
}
|
|
366
438
|
}
|
|
367
|
-
await fs.symlink(linkContent,
|
|
439
|
+
await fs.symlink(linkContent, filePath, linkType);
|
|
368
440
|
}
|
|
369
441
|
isOverwrite() {
|
|
370
442
|
var _a;
|
package/lib/zip.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Cancelable } from "./cancelable";
|
|
2
2
|
export interface IZipOptions {
|
|
3
3
|
/**
|
|
4
|
-
* Indicates how to handle
|
|
4
|
+
* Indicates how to handle the given path when it is a symbolic link.
|
|
5
5
|
*
|
|
6
6
|
* `true`: add the target of the symbolic link to the zip.
|
|
7
7
|
*
|
|
8
|
-
* `false`: add symbolic link itself to the zip.
|
|
8
|
+
* `false`: add the symbolic link itself to the zip.
|
|
9
9
|
*
|
|
10
10
|
* The default value is `false`.
|
|
11
11
|
*/
|
|
@@ -13,7 +13,7 @@ export interface IZipOptions {
|
|
|
13
13
|
/**
|
|
14
14
|
* Sets the compression level.
|
|
15
15
|
*
|
|
16
|
-
* 0
|
|
16
|
+
* `0`: the file data will be stored; otherwise, the file data will be deflated.
|
|
17
17
|
*
|
|
18
18
|
* The default value is `6`.
|
|
19
19
|
*/
|
|
@@ -28,31 +28,43 @@ export declare class Zip extends Cancelable {
|
|
|
28
28
|
*
|
|
29
29
|
*/
|
|
30
30
|
constructor(options?: IZipOptions | undefined);
|
|
31
|
-
private yazlFile;
|
|
32
|
-
private isPipe;
|
|
33
|
-
private zipStream;
|
|
34
31
|
private zipFiles;
|
|
35
32
|
private zipFolders;
|
|
36
33
|
private token;
|
|
34
|
+
private activeArchive;
|
|
37
35
|
/**
|
|
38
|
-
* Adds a file from the file system at realPath
|
|
36
|
+
* Adds a file from the file system at `realPath` to the zip file as `metadataPath`.
|
|
39
37
|
* @param file
|
|
40
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath)
|
|
38
|
+
* @param metadataPath Typically, `metadataPath` would be calculated as `path.relative(root, realPath)`.
|
|
41
39
|
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
42
40
|
*/
|
|
43
41
|
addFile(file: string, metadataPath?: string): void;
|
|
44
42
|
/**
|
|
45
|
-
* Adds a folder from the file system at realPath
|
|
43
|
+
* Adds a folder from the file system at `realPath` to the zip file as `metadataPath`.
|
|
46
44
|
* @param folder
|
|
47
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath)
|
|
45
|
+
* @param metadataPath Typically, `metadataPath` would be calculated as `path.relative(root, realPath)`.
|
|
48
46
|
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
49
47
|
*/
|
|
50
48
|
addFolder(folder: string, metadataPath?: string): void;
|
|
51
49
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
50
|
+
* Zips the content and returns it as a single Buffer.
|
|
51
|
+
*
|
|
52
|
+
* @returns A promise that resolves to the zipped Buffer.
|
|
53
|
+
*/
|
|
54
|
+
archive(): Promise<Buffer>;
|
|
55
|
+
/**
|
|
56
|
+
* Zips the content and saves it directly to the specified file path.
|
|
57
|
+
*
|
|
58
|
+
* @param zipFile The absolute or relative path where the .zip file will be created.
|
|
59
|
+
* @returns A promise that resolves when the file has been fully written.
|
|
54
60
|
*/
|
|
55
61
|
archive(zipFile: string): Promise<void>;
|
|
62
|
+
private prepareArchive;
|
|
63
|
+
private bindArchiveOutput;
|
|
64
|
+
private archiveToFile;
|
|
65
|
+
private archiveToBuffer;
|
|
66
|
+
private createPromiseSettler;
|
|
67
|
+
private addQueuedEntries;
|
|
56
68
|
/**
|
|
57
69
|
* Cancel compression.
|
|
58
70
|
* If the cancel method is called after the archive is complete, nothing will happen.
|
|
@@ -62,7 +74,7 @@ export declare class Zip extends Cancelable {
|
|
|
62
74
|
private addFileStream;
|
|
63
75
|
private addSymlink;
|
|
64
76
|
private walkDir;
|
|
65
|
-
private
|
|
77
|
+
private stop;
|
|
66
78
|
private followSymlink;
|
|
67
79
|
/**
|
|
68
80
|
* Retrieves the yazl options based on the current settings.
|