zip-lib 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +380 -377
- package/fs.d.ts +19 -0
- package/{lib/fs.js → fs.js} +98 -16
- package/package.json +43 -45
- package/{lib/unzip.js → unzip.js} +25 -7
- package/{lib/zip.js → zip.js} +3 -3
- package/lib/util.js +0 -48
- /package/{lib/cancelable.d.ts → cancelable.d.ts} +0 -0
- /package/{lib/cancelable.js → cancelable.js} +0 -0
- /package/{lib/index.d.ts → index.d.ts} +0 -0
- /package/{lib/index.js → index.js} +0 -0
- /package/{lib/unzip.d.ts → unzip.d.ts} +0 -0
- /package/{lib/zip.d.ts → zip.d.ts} +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2019 Ouga
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Ouga
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,378 +1,381 @@
|
|
|
1
|
-
# zip-lib
|
|
2
|
-
zip and unzip library for node.
|
|
3
|
-
|
|
4
|
-
[](https://www.npmjs.org/package/zip-lib)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* [
|
|
18
|
-
|
|
19
|
-
- [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
path/to/folder
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
path/to/target.zip
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
├──
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
zip.
|
|
138
|
-
// Adds a
|
|
139
|
-
zip.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
path/to/folder
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
path/to/target.zip
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
1
|
+
# zip-lib
|
|
2
|
+
zip and unzip library for node.
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.org/package/zip-lib)
|
|
5
|
+
[](https://github.com/fpsqdb/zip-lib/blob/master/LICENSE)
|
|
6
|
+

|
|
7
|
+
[](https://github.com/fpsqdb/zip-lib/actions?query=workflow%3Atest)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm install zip-lib
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
* [Zip](#Zip)
|
|
18
|
+
- [Zip single file](#zip-single-file)
|
|
19
|
+
- [Zip single folder](#zip-single-folder)
|
|
20
|
+
* [Unzip](#unzip)
|
|
21
|
+
* [Advanced usage](#advance-usage)
|
|
22
|
+
- [Sets the compression level](#sets-the-compression-level)
|
|
23
|
+
- [Zip multiple files and folders](#zip-multiple-files-and-folders)
|
|
24
|
+
- [Zip with metadata](#zip-with-metadata)
|
|
25
|
+
- [Unzip with entry callback](#unzip-with-entry-callback)
|
|
26
|
+
- [Unzip and exclude specified entries](#unzip-and-exclude-specified-entries)
|
|
27
|
+
- [Cancel zip](#cancel-zip)
|
|
28
|
+
- [Cancel unzip](#cancel-unzip)
|
|
29
|
+
* [API](#api)
|
|
30
|
+
- Method: [archiveFile](#archivefile)
|
|
31
|
+
- Method: [archiveFolder](#archivefolder)
|
|
32
|
+
- Method: [extract](#extract)
|
|
33
|
+
- Class: [Zip](#class-zip)
|
|
34
|
+
- Class: [Unzip](#class-unzip)
|
|
35
|
+
- Options: [IZipOptions](#izipoptions)
|
|
36
|
+
- Options: [IExtractOptions](#iextractoptions)
|
|
37
|
+
|
|
38
|
+
## Zip
|
|
39
|
+
You can use **zip-lib** to compress files or folders.
|
|
40
|
+
|
|
41
|
+
### Zip single file
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const zl = require("zip-lib");
|
|
45
|
+
|
|
46
|
+
zl.archiveFile("path/to/file.txt", "path/to/target.zip").then(function () {
|
|
47
|
+
console.log("done");
|
|
48
|
+
}, function (err) {
|
|
49
|
+
console.log(err);
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Zip single folder
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
const zl = require("zip-lib");
|
|
57
|
+
|
|
58
|
+
zl.archiveFolder("path/to/folder", "path/to/target.zip").then(function () {
|
|
59
|
+
console.log("done");
|
|
60
|
+
}, function (err) {
|
|
61
|
+
console.log(err);
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Unzip
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const zl = require("zip-lib");
|
|
69
|
+
|
|
70
|
+
zl.extract("path/to/target.zip", "path/to/target").then(function () {
|
|
71
|
+
console.log("done");
|
|
72
|
+
}, function (err) {
|
|
73
|
+
console.log(err);
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Advanced usage
|
|
78
|
+
|
|
79
|
+
### Sets the compression level
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
const zl = require("zip-lib");
|
|
83
|
+
|
|
84
|
+
zl.archiveFolder("path/to/folder", "path/to/target.zip", { compressionLevel: 9 }).then(function () {
|
|
85
|
+
console.log("done");
|
|
86
|
+
}, function (err) {
|
|
87
|
+
console.log(err);
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Zip multiple files and folders
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const zl = require("zip-lib");
|
|
95
|
+
|
|
96
|
+
const zip = new zl.Zip();
|
|
97
|
+
// Adds a file from the file system
|
|
98
|
+
zip.addFile("path/to/file.txt");
|
|
99
|
+
// Adds a folder from the file system, putting its contents at the root of archive
|
|
100
|
+
zip.addFolder("path/to/folder");
|
|
101
|
+
// Generate zip file.
|
|
102
|
+
zip.archive("path/to/target.zip").then(function () {
|
|
103
|
+
console.log("done");
|
|
104
|
+
}, function (err) {
|
|
105
|
+
console.log(err);
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The `path/to/folder` directory is as follows:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
path/to/folder
|
|
113
|
+
.
|
|
114
|
+
├── dir1
|
|
115
|
+
│ ├── file.ext
|
|
116
|
+
├── dir2
|
|
117
|
+
└── file_in_root.ext
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
And the generated `path/to/target.zip` archive file directory will be as follows:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
path/to/target.zip
|
|
124
|
+
.
|
|
125
|
+
├── file.txt
|
|
126
|
+
├── dir1
|
|
127
|
+
│ ├── file.ext
|
|
128
|
+
├── dir2
|
|
129
|
+
└── file_in_root.ext
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Zip with metadata
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
const zl = require("zip-lib");
|
|
136
|
+
|
|
137
|
+
const zip = new zl.Zip();
|
|
138
|
+
// Adds a file from the file system
|
|
139
|
+
zip.addFile("path/to/file.txt", "renamedFile.txt");
|
|
140
|
+
zip.addFile("path/to/file2.txt", "folder/file.txt");
|
|
141
|
+
// Adds a folder from the file system, and naming it `new folder` within the archive
|
|
142
|
+
zip.addFolder("path/to/folder", "new folder");
|
|
143
|
+
// Generate zip file.
|
|
144
|
+
zip.archive("path/to/target.zip").then(function () {
|
|
145
|
+
console.log("done");
|
|
146
|
+
}, function (err) {
|
|
147
|
+
console.log(err);
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The `path/to/folder` directory is as follows:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
path/to/folder
|
|
155
|
+
.
|
|
156
|
+
├── dir1
|
|
157
|
+
│ ├── file.ext
|
|
158
|
+
├── dir2
|
|
159
|
+
└── file_in_root.ext
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
And the generated `path/to/target.zip` archive file directory will be as follows:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
path/to/target.zip
|
|
166
|
+
.
|
|
167
|
+
├── renamedFile.txt
|
|
168
|
+
├── folder
|
|
169
|
+
│ ├── file.txt
|
|
170
|
+
│── new folder
|
|
171
|
+
├── dir1
|
|
172
|
+
│ ├── file.ext
|
|
173
|
+
├── dir2
|
|
174
|
+
└── file_in_root.ext
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Unzip with entry callback
|
|
178
|
+
Using `onEntry` callback we can know the current progress of extracting and control the extraction operation. See [IExtractOptions](#iextractoptions).
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
const zl = require("zip-lib");
|
|
182
|
+
|
|
183
|
+
const unzip = new zl.Unzip({
|
|
184
|
+
// Called before an item is extracted.
|
|
185
|
+
onEntry: function (event) {
|
|
186
|
+
console.log(event.entryCount, event.entryName);
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
|
|
190
|
+
console.log("done");
|
|
191
|
+
}, function (err) {
|
|
192
|
+
console.log(err);
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Unzip and exclude specified entries
|
|
197
|
+
The following code shows how to exclude the `__MACOSX` folder in the zip file when extracting. See [IExtractOptions](#iextractoptions).
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const zl = require("zip-lib");
|
|
201
|
+
|
|
202
|
+
const unzip = new zl.Unzip({
|
|
203
|
+
// Called before an item is extracted.
|
|
204
|
+
onEntry: function (event) {
|
|
205
|
+
if (/^__MACOSX\//.test(event.entryName)) {
|
|
206
|
+
// entry name starts with __MACOSX/
|
|
207
|
+
event.preventDefault();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
|
|
212
|
+
console.log("done");
|
|
213
|
+
}, function (err) {
|
|
214
|
+
console.log(err);
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Cancel zip
|
|
219
|
+
If the `cancel` method is called after the archive is complete, nothing will happen.
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
const zl = require("zip-lib");
|
|
223
|
+
|
|
224
|
+
const zip = new zl.Zip();
|
|
225
|
+
zip.addFile("path/to/file.txt");
|
|
226
|
+
zip.archive("path/to/target.zip").then(function () {
|
|
227
|
+
console.log("done");
|
|
228
|
+
}, function (err) {
|
|
229
|
+
if (err.name === "Canceled") {
|
|
230
|
+
console.log("cancel");
|
|
231
|
+
} else {
|
|
232
|
+
console.log(err);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Cancel zip
|
|
237
|
+
zip.cancel();
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Cancel unzip
|
|
241
|
+
If the `cancel` method is called after the extract is complete, nothing will happen.
|
|
242
|
+
|
|
243
|
+
```js
|
|
244
|
+
const zl = require("zip-lib");
|
|
245
|
+
|
|
246
|
+
const unzip = new zl.Unzip();
|
|
247
|
+
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
|
|
248
|
+
console.log("done");
|
|
249
|
+
}, function (err) {
|
|
250
|
+
if (err.name === "Canceled") {
|
|
251
|
+
console.log("cancel");
|
|
252
|
+
} else {
|
|
253
|
+
console.log(err);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// cancel
|
|
258
|
+
unzip.cancel();
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## API
|
|
262
|
+
|
|
263
|
+
### Method: archiveFile <a id="archivefile"></a>
|
|
264
|
+
|
|
265
|
+
**archiveFile(file, zipFile, [options])**
|
|
266
|
+
|
|
267
|
+
Compress a single file to zip.
|
|
268
|
+
|
|
269
|
+
- `file`: String
|
|
270
|
+
- `zipFile`: String
|
|
271
|
+
- `options?`: [IZipOptions](#izipoptions) (optional)
|
|
272
|
+
|
|
273
|
+
Returns: `Promise<viod>`
|
|
274
|
+
|
|
275
|
+
### Method: archiveFolder <a id="archivefolder"></a>
|
|
276
|
+
|
|
277
|
+
**archiveFolder(folder, zipFile, [options])**
|
|
278
|
+
|
|
279
|
+
Compress all the contents of the specified folder to zip.
|
|
280
|
+
|
|
281
|
+
- `folder`: String
|
|
282
|
+
- `zipFile`: String
|
|
283
|
+
- `options?`: [IZipOptions](#izipoptions) (optional)
|
|
284
|
+
|
|
285
|
+
Returns: `Promise<void>`
|
|
286
|
+
|
|
287
|
+
### Method: extract <a id="extract"></a>
|
|
288
|
+
|
|
289
|
+
**extract(zipFile, targetFolder, [options])**
|
|
290
|
+
|
|
291
|
+
Extract the zip file to the specified location.
|
|
292
|
+
|
|
293
|
+
- `zipFile`: String
|
|
294
|
+
- `targetFolder`: String
|
|
295
|
+
- `options?`: [IExtractOptions](#iextractoptions) (optional)
|
|
296
|
+
|
|
297
|
+
Returns: `Promise<void>`
|
|
298
|
+
|
|
299
|
+
### Class: Zip<a id="class-zip"></a>
|
|
300
|
+
Compress files or folders to a zip file.
|
|
301
|
+
|
|
302
|
+
**Constructor: new Zip([options])**
|
|
303
|
+
|
|
304
|
+
- `options?`: [IZipOptions](#izipoptions)
|
|
305
|
+
|
|
306
|
+
**Method: addFile(file, [metadataPath])**
|
|
307
|
+
|
|
308
|
+
Adds a file from the file system at realPath into the zipfile as metadataPath.
|
|
309
|
+
|
|
310
|
+
- `file`: String
|
|
311
|
+
- `metadataPath?`: String (optional) - Typically metadataPath would be calculated as path.relative(root, realPath). A valid metadataPath must not start with `/` or `/[A-Za-z]:\//`, and must not contain `..`.
|
|
312
|
+
|
|
313
|
+
Returns: `void`
|
|
314
|
+
|
|
315
|
+
**Method: addFolder(folder, [metadataPath])**
|
|
316
|
+
|
|
317
|
+
Adds a folder from the file system at realPath into the zipfile as metadataPath.
|
|
318
|
+
|
|
319
|
+
- `folder`: String
|
|
320
|
+
- `metadataPath?`: String (optional) - Typically metadataPath would be calculated as path.relative(root, realPath). A valid metadataPath must not start with `/` or `/[A-Za-z]:\//`, and must not contain `..`.
|
|
321
|
+
|
|
322
|
+
Returns: `void`
|
|
323
|
+
|
|
324
|
+
**Method: archive(zipFile)**
|
|
325
|
+
|
|
326
|
+
Generate zip file.
|
|
327
|
+
|
|
328
|
+
- `zipFile`: String
|
|
329
|
+
|
|
330
|
+
Returns: `Promise<viod>`
|
|
331
|
+
|
|
332
|
+
**Method: cancel()**
|
|
333
|
+
|
|
334
|
+
Cancel compression. If the `cancel` method is called after the archive is complete, nothing will happen.
|
|
335
|
+
|
|
336
|
+
Returns: `void`
|
|
337
|
+
|
|
338
|
+
### Class: Unzip<a id="class-unzip"></a>
|
|
339
|
+
Extract the zip file.
|
|
340
|
+
|
|
341
|
+
**Constructor: new Unzip([options])**
|
|
342
|
+
|
|
343
|
+
- `options?`: [IZipOptions](#izipoptions) (optional)
|
|
344
|
+
|
|
345
|
+
**Method: extract(zipFile, targetFolder)**
|
|
346
|
+
|
|
347
|
+
Extract the zip file to the specified location.
|
|
348
|
+
|
|
349
|
+
- `zipFile`: String
|
|
350
|
+
- `targetFolder`: String
|
|
351
|
+
|
|
352
|
+
Returns: `Promise<void>`
|
|
353
|
+
|
|
354
|
+
**Method: cancel()**
|
|
355
|
+
|
|
356
|
+
If the `cancel` method is called after the extract is complete, nothing will happen.
|
|
357
|
+
|
|
358
|
+
Returns: `void`
|
|
359
|
+
|
|
360
|
+
### Options: IZipOptions <a id="izipoptions"></a>
|
|
361
|
+
|
|
362
|
+
Object
|
|
363
|
+
- `followSymlinks?`: Boolean (optional) - Indicates how to handle when the given path is a symbolic link. The default value is `false`.<br>`true`: add the target of the symbolic link to the zip.<br>`false`: add symbolic link itself to the zip.
|
|
364
|
+
- `compressionLevel?`: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 - Sets the compression level. The default value is `6`.<br>`0`: the file data will be stored.<br>`1-9`: the file data will be deflated.
|
|
365
|
+
|
|
366
|
+
### Options: IExtractOptions <a id="iextractoptions"></a>
|
|
367
|
+
|
|
368
|
+
Object
|
|
369
|
+
- `overwrite?`: String (optional) - If it is true, the target directory will be deleted before extract. The default value is `false`.
|
|
370
|
+
- `symlinkAsFileOnWindows?`: Boolean (optional) - Extract symbolic links as files on Windows. This value is only available on Windows and ignored on other platforms. The default value is `true`.<br>If `true`, the symlink in the zip will be extracted as a normal file on Windows.<br>If `false`, the symlink in the zip will be extracted as a symlink correctly on Windows, but an `EPERM` error will be thrown under non-administrators.
|
|
371
|
+
|
|
372
|
+
> ⚠**WARNING:** On Windows, the default security policy allows only administrators to create symbolic links. If you set `symlinkAsFileOnWindows` to `false` and the zip contains symlink, be sure to run the code under the administrator, otherwise an `EPERM` error will be thrown.
|
|
373
|
+
|
|
374
|
+
- `onEntry?`: Function (optional) - Called before an item is extracted.<br>Arguments:
|
|
375
|
+
- `event`: Object - Represents an event that an entry is about to be extracted.
|
|
376
|
+
- `entryName`: String (readonly) - Entry name.
|
|
377
|
+
- `entryCount`: Number (readonly) - Total number of entries.
|
|
378
|
+
- `preventDefault()`: Function - Prevent extracting current entry. This method can be used to prevent extraction of the current item. By calling this method we can control which items can be extracted.
|
|
379
|
+
|
|
380
|
+
# License
|
|
378
381
|
Licensed under the [MIT](https://github.com/fpsqdb/zip-lib/blob/master/LICENSE) license.
|
package/fs.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FileEntry {
|
|
2
|
+
path: string;
|
|
3
|
+
isSymbolicLink: boolean;
|
|
4
|
+
type: FileType;
|
|
5
|
+
mtime: Date;
|
|
6
|
+
mode: number;
|
|
7
|
+
}
|
|
8
|
+
export type FileType = "file" | "dir";
|
|
9
|
+
export declare function realpath(target: string): Promise<string>;
|
|
10
|
+
export declare function readdirp(folder: string): Promise<FileEntry[]>;
|
|
11
|
+
export declare function getFileEntry(target: string): Promise<FileEntry>;
|
|
12
|
+
export declare function ensureFolder(folder: string): Promise<{
|
|
13
|
+
isDirectory: boolean;
|
|
14
|
+
isSymbolicLink: boolean;
|
|
15
|
+
realpath?: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function pathExists(target: string): Promise<boolean>;
|
|
18
|
+
export declare function rimraf(target: string): Promise<void>;
|
|
19
|
+
export declare function isRootPath(target: string): boolean;
|
package/{lib/fs.js → fs.js}
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.realpath = realpath;
|
|
3
4
|
exports.readdirp = readdirp;
|
|
4
5
|
exports.getFileEntry = getFileEntry;
|
|
5
6
|
exports.ensureFolder = ensureFolder;
|
|
@@ -7,10 +8,17 @@ exports.pathExists = pathExists;
|
|
|
7
8
|
exports.rimraf = rimraf;
|
|
8
9
|
exports.isRootPath = isRootPath;
|
|
9
10
|
const path = require("path");
|
|
10
|
-
const
|
|
11
|
+
const fs = require("fs/promises");
|
|
12
|
+
const util = require("node:util");
|
|
13
|
+
const fsSync = require("fs");
|
|
14
|
+
async function realpath(target) {
|
|
15
|
+
// fs.promises.realpath has a bug with long path on Windows.
|
|
16
|
+
// https://github.com/nodejs/node/issues/51031
|
|
17
|
+
return util.promisify(fsSync.realpath)(target);
|
|
18
|
+
}
|
|
11
19
|
async function readdirp(folder) {
|
|
12
20
|
const result = [];
|
|
13
|
-
const files = await
|
|
21
|
+
const files = await fs.readdir(folder);
|
|
14
22
|
for (const item of files) {
|
|
15
23
|
const file = path.join(folder, item);
|
|
16
24
|
const entry = await getFileEntry(file);
|
|
@@ -28,7 +36,7 @@ async function readdirp(folder) {
|
|
|
28
36
|
return result;
|
|
29
37
|
}
|
|
30
38
|
async function getFileEntry(target) {
|
|
31
|
-
const stat = await
|
|
39
|
+
const stat = await fs.lstat(target);
|
|
32
40
|
let isSymbolicLink = false;
|
|
33
41
|
let fileType = "file";
|
|
34
42
|
if (stat.isDirectory()) {
|
|
@@ -40,7 +48,7 @@ async function getFileEntry(target) {
|
|
|
40
48
|
// If the path is a link, we must instead use fs.stat() to find out if the
|
|
41
49
|
// link is a directory or not because lstat will always return the stat of
|
|
42
50
|
// the link which is always a file.
|
|
43
|
-
const actualStat = await
|
|
51
|
+
const actualStat = await fs.stat(target);
|
|
44
52
|
if (actualStat.isDirectory()) {
|
|
45
53
|
fileType = "dir";
|
|
46
54
|
}
|
|
@@ -57,10 +65,14 @@ async function getFileEntry(target) {
|
|
|
57
65
|
async function ensureFolder(folder) {
|
|
58
66
|
// stop at root
|
|
59
67
|
if (folder === path.dirname(folder)) {
|
|
60
|
-
return Promise.resolve(
|
|
68
|
+
return Promise.resolve({
|
|
69
|
+
isDirectory: true,
|
|
70
|
+
isSymbolicLink: false
|
|
71
|
+
});
|
|
61
72
|
}
|
|
62
73
|
try {
|
|
63
|
-
await mkdir(folder);
|
|
74
|
+
const result = await mkdir(folder);
|
|
75
|
+
return result;
|
|
64
76
|
}
|
|
65
77
|
catch (error) {
|
|
66
78
|
// ENOENT: a parent folder does not exist yet, continue
|
|
@@ -75,7 +87,7 @@ async function ensureFolder(folder) {
|
|
|
75
87
|
}
|
|
76
88
|
async function pathExists(target) {
|
|
77
89
|
try {
|
|
78
|
-
await
|
|
90
|
+
await fs.access(target);
|
|
79
91
|
return true;
|
|
80
92
|
}
|
|
81
93
|
catch (error) {
|
|
@@ -88,23 +100,23 @@ async function rimraf(target) {
|
|
|
88
100
|
return Promise.reject(new Error(`Refuse to recursively delete root, path: "${target}"`));
|
|
89
101
|
}
|
|
90
102
|
try {
|
|
91
|
-
const stat = await
|
|
103
|
+
const stat = await fs.lstat(target);
|
|
92
104
|
// Folder delete (recursive) - NOT for symbolic links though!
|
|
93
105
|
if (stat.isDirectory() && !stat.isSymbolicLink()) {
|
|
94
106
|
// Children
|
|
95
|
-
const children = await
|
|
107
|
+
const children = await fs.readdir(target);
|
|
96
108
|
await Promise.all(children.map(child => rimraf(path.join(target, child))));
|
|
97
109
|
// Folder
|
|
98
|
-
await
|
|
110
|
+
await fs.rmdir(target);
|
|
99
111
|
}
|
|
100
112
|
// Single file delete
|
|
101
113
|
else {
|
|
102
114
|
// chmod as needed to allow for unlink
|
|
103
115
|
const mode = stat.mode;
|
|
104
116
|
if (!(mode & 128)) { // 128 === 0200
|
|
105
|
-
await
|
|
117
|
+
await fs.chmod(target, mode | 128);
|
|
106
118
|
}
|
|
107
|
-
return
|
|
119
|
+
return fs.unlink(target);
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
catch (error) {
|
|
@@ -115,7 +127,11 @@ async function rimraf(target) {
|
|
|
115
127
|
}
|
|
116
128
|
async function mkdir(folder) {
|
|
117
129
|
try {
|
|
118
|
-
await
|
|
130
|
+
await fs.mkdir(folder, 0o777);
|
|
131
|
+
return {
|
|
132
|
+
isDirectory: true,
|
|
133
|
+
isSymbolicLink: false,
|
|
134
|
+
};
|
|
119
135
|
}
|
|
120
136
|
catch (error) {
|
|
121
137
|
// ENOENT: a parent folder does not exist yet or folder name is invalid.
|
|
@@ -125,15 +141,81 @@ async function mkdir(folder) {
|
|
|
125
141
|
// Any other error: check if folder exists and
|
|
126
142
|
// return normally in that case if its a folder
|
|
127
143
|
try {
|
|
128
|
-
const fileStat = await
|
|
129
|
-
if (
|
|
130
|
-
|
|
144
|
+
const fileStat = await fs.lstat(folder);
|
|
145
|
+
if (fileStat.isSymbolicLink()) {
|
|
146
|
+
const realFilePath = await realpath(folder);
|
|
147
|
+
const realFileStat = await fs.lstat(realFilePath);
|
|
148
|
+
if (!realFileStat.isDirectory()) {
|
|
149
|
+
return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
isDirectory: false,
|
|
153
|
+
isSymbolicLink: true,
|
|
154
|
+
realpath: realFilePath,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
if (!fileStat.isDirectory()) {
|
|
159
|
+
return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
isDirectory: true,
|
|
163
|
+
isSymbolicLink: false,
|
|
164
|
+
};
|
|
131
165
|
}
|
|
132
166
|
}
|
|
133
167
|
catch (statError) {
|
|
134
168
|
throw error; // rethrow original error
|
|
135
169
|
}
|
|
136
170
|
}
|
|
171
|
+
// // Any other error: check if folder exists and
|
|
172
|
+
// // return normally in that case if its a folder
|
|
173
|
+
// try {
|
|
174
|
+
// if (folder.includes("dirlink")) {
|
|
175
|
+
// console.log("tttttt11111", folder);
|
|
176
|
+
// }
|
|
177
|
+
// const fileStat = await fs.lstat(folder);
|
|
178
|
+
// if (folder.includes("dirlink")) {
|
|
179
|
+
// console.log("tttttt22222", fileStat);
|
|
180
|
+
// }
|
|
181
|
+
// if (fileStat.isSymbolicLink()) {
|
|
182
|
+
// console.log("kkkkkkkkk", fileStat);
|
|
183
|
+
// const realFilePath = await realpath(folder);
|
|
184
|
+
// const realFileStat = await fs.lstat(realFilePath);
|
|
185
|
+
// if (!realFileStat.isDirectory()) {
|
|
186
|
+
// return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
187
|
+
// }
|
|
188
|
+
// return {
|
|
189
|
+
// isDirectory: false,
|
|
190
|
+
// isSymbolicLink: true,
|
|
191
|
+
// realpath: realFilePath,
|
|
192
|
+
// }
|
|
193
|
+
// } else {
|
|
194
|
+
// if (!fileStat.isDirectory()) {
|
|
195
|
+
// return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
|
|
196
|
+
// }
|
|
197
|
+
// return {
|
|
198
|
+
// isDirectory: true,
|
|
199
|
+
// isSymbolicLink: false,
|
|
200
|
+
// }
|
|
201
|
+
// }
|
|
202
|
+
// } catch (statError) {
|
|
203
|
+
// if (folder.includes("dirlink")) {
|
|
204
|
+
// console.log("yyyyy", statError);
|
|
205
|
+
// }
|
|
206
|
+
// // ignore
|
|
207
|
+
// }
|
|
208
|
+
// if (folder.includes("dirlink")) {
|
|
209
|
+
// console.log("kkkkkkkkk22222", folder);
|
|
210
|
+
// }
|
|
211
|
+
// await fs.mkdir(folder, { recursive: true, mode: 0o777 });
|
|
212
|
+
// if (folder.includes("dirlink")) {
|
|
213
|
+
// console.log("kkkkkkkkk3333333", folder);
|
|
214
|
+
// }
|
|
215
|
+
// return {
|
|
216
|
+
// isDirectory: true,
|
|
217
|
+
// isSymbolicLink: false,
|
|
218
|
+
// };
|
|
137
219
|
}
|
|
138
220
|
// "A"
|
|
139
221
|
const charA = 65;
|
package/package.json
CHANGED
|
@@ -1,45 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "zip-lib",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "zip and unzip library for node",
|
|
5
|
-
"main": "lib/index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"compile": "rimraf ./
|
|
8
|
-
"release": "rimraf ./lib && tsc -p ./src/tsconfig.release.json",
|
|
9
|
-
"compile-test": "rimraf ./test/out && tsc -p ./test/src/tsconfig.json",
|
|
10
|
-
"test": "node ./test/src/before.js && mocha ./test/out --timeout 10000"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"@types/
|
|
38
|
-
"@types/
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "zip-lib",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "zip and unzip library for node",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"compile": "rimraf ./dist && tsc -p ./src/tsconfig.json",
|
|
8
|
+
"release": "rimraf ./lib && tsc -p ./src/tsconfig.release.json && node ./build.mjs",
|
|
9
|
+
"compile-test": "rimraf ./test/out && tsc -p ./test/src/tsconfig.json",
|
|
10
|
+
"test": "npm run compile && npm run compile-test && node ./test/src/before.js && mocha ./test/out --timeout 10000"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/fpsqdb/zip-lib.git"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"zip",
|
|
21
|
+
"folder",
|
|
22
|
+
"unzip",
|
|
23
|
+
"archive",
|
|
24
|
+
"extract",
|
|
25
|
+
"promise",
|
|
26
|
+
"async"
|
|
27
|
+
],
|
|
28
|
+
"author": "fpsqdb",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"yauzl": "^3.2.0",
|
|
32
|
+
"yazl": "^3.3.1"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/mocha": "^10.0.10",
|
|
36
|
+
"@types/node": "^18.19.86",
|
|
37
|
+
"@types/yauzl": "^2.10.3",
|
|
38
|
+
"@types/yazl": "^2.4.6",
|
|
39
|
+
"mocha": "^11.1.0",
|
|
40
|
+
"rimraf": "^6.0.1",
|
|
41
|
+
"typescript": "^5.8.3"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -4,8 +4,8 @@ exports.Unzip = void 0;
|
|
|
4
4
|
const yauzl = require("yauzl");
|
|
5
5
|
const exfs = require("./fs");
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
|
+
const fs = require("fs/promises");
|
|
7
8
|
const path = require("path");
|
|
8
|
-
const util = require("./util");
|
|
9
9
|
const cancelable_1 = require("./cancelable");
|
|
10
10
|
class EntryEvent {
|
|
11
11
|
/**
|
|
@@ -40,6 +40,7 @@ class EntryContext {
|
|
|
40
40
|
this._realTargetFolder = _realTargetFolder;
|
|
41
41
|
this.symlinkAsFileOnWindows = symlinkAsFileOnWindows;
|
|
42
42
|
this._symlinkFileNames = [];
|
|
43
|
+
this._symlinkFolders = [];
|
|
43
44
|
}
|
|
44
45
|
get decodeEntryFileName() {
|
|
45
46
|
return this._decodeEntryFileName;
|
|
@@ -56,20 +57,31 @@ class EntryContext {
|
|
|
56
57
|
get symlinkFileNames() {
|
|
57
58
|
return this._symlinkFileNames;
|
|
58
59
|
}
|
|
60
|
+
get symlinkFolders() {
|
|
61
|
+
return this._symlinkFolders;
|
|
62
|
+
}
|
|
59
63
|
getFilePath() {
|
|
60
64
|
return path.join(this.targetFolder, this.decodeEntryFileName);
|
|
61
65
|
}
|
|
62
66
|
async isOutsideTargetFolder(tpath) {
|
|
63
|
-
if (this.symlinkFileNames.length === 0
|
|
67
|
+
if (this.symlinkFileNames.length === 0 &&
|
|
68
|
+
this.symlinkFolders.length === 0) {
|
|
64
69
|
return false;
|
|
65
70
|
}
|
|
66
71
|
if (process.platform === "win32" &&
|
|
67
72
|
this.symlinkAsFileOnWindows) {
|
|
68
73
|
return false;
|
|
69
74
|
}
|
|
75
|
+
for (const { folder, realpath } of this.symlinkFolders) {
|
|
76
|
+
if (tpath.includes(folder)) {
|
|
77
|
+
if (realpath.indexOf(this.realTargetFolder) !== 0) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
70
82
|
for (const fileName of this.symlinkFileNames) {
|
|
71
83
|
if (tpath.includes(fileName)) {
|
|
72
|
-
const realFilePath = await
|
|
84
|
+
const realFilePath = await exfs.realpath(tpath);
|
|
73
85
|
if (realFilePath.indexOf(this.realTargetFolder) !== 0) {
|
|
74
86
|
return true;
|
|
75
87
|
}
|
|
@@ -106,7 +118,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
106
118
|
return Promise.reject(this.canceledError());
|
|
107
119
|
}
|
|
108
120
|
await exfs.ensureFolder(targetFolder);
|
|
109
|
-
const realTargetFolder = await
|
|
121
|
+
const realTargetFolder = await exfs.realpath(targetFolder);
|
|
110
122
|
const zfile = await this.openZip(zipFile, token);
|
|
111
123
|
this.zipFile = zfile;
|
|
112
124
|
zfile.readEntry();
|
|
@@ -240,7 +252,13 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
240
252
|
async extractEntry(zfile, entry, entryContext, token) {
|
|
241
253
|
const filePath = entryContext.getFilePath();
|
|
242
254
|
const fileDir = path.dirname(filePath);
|
|
243
|
-
await exfs.ensureFolder(fileDir);
|
|
255
|
+
const folderStat = await exfs.ensureFolder(fileDir);
|
|
256
|
+
if (folderStat.isSymbolicLink) {
|
|
257
|
+
entryContext.symlinkFolders.push({
|
|
258
|
+
folder: fileDir,
|
|
259
|
+
realpath: folderStat.realpath,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
244
262
|
const outside = await entryContext.isOutsideTargetFolder(fileDir);
|
|
245
263
|
if (outside) {
|
|
246
264
|
const error = new Error(`Refuse to write file outside "${entryContext.targetFolder}", file: "${filePath}"`);
|
|
@@ -317,7 +335,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
317
335
|
targetPath = path.join(path.dirname(des), linkContent);
|
|
318
336
|
}
|
|
319
337
|
try {
|
|
320
|
-
const stat = await
|
|
338
|
+
const stat = await fs.stat(targetPath);
|
|
321
339
|
if (stat.isDirectory()) {
|
|
322
340
|
linkType = "dir";
|
|
323
341
|
}
|
|
@@ -327,7 +345,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
327
345
|
}
|
|
328
346
|
}
|
|
329
347
|
}
|
|
330
|
-
await
|
|
348
|
+
await fs.symlink(linkContent, des, linkType);
|
|
331
349
|
}
|
|
332
350
|
isOverwrite() {
|
|
333
351
|
if (this.options &&
|
package/{lib/zip.js → zip.js}
RENAMED
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Zip = void 0;
|
|
4
4
|
const yazl = require("yazl");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
|
+
const fs = require("fs/promises");
|
|
6
7
|
const exfs = require("./fs");
|
|
7
8
|
const path = require("path");
|
|
8
|
-
const util = require("./util");
|
|
9
9
|
const cancelable_1 = require("./cancelable");
|
|
10
10
|
/**
|
|
11
11
|
* Compress files or folders to a zip file.
|
|
@@ -120,7 +120,7 @@ class Zip extends cancelable_1.Cancelable {
|
|
|
120
120
|
if (entry.isSymbolicLink) {
|
|
121
121
|
if (this.followSymlink()) {
|
|
122
122
|
if (entry.type === "dir") {
|
|
123
|
-
const realPath = await
|
|
123
|
+
const realPath = await exfs.realpath(file.path);
|
|
124
124
|
await this.walkDir([{ path: realPath, metadataPath: file.metadataPath }], token);
|
|
125
125
|
}
|
|
126
126
|
else {
|
|
@@ -160,7 +160,7 @@ class Zip extends cancelable_1.Cancelable {
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
async addSymlink(zip, file, metadataPath) {
|
|
163
|
-
const linkTarget = await
|
|
163
|
+
const linkTarget = await fs.readlink(file.path);
|
|
164
164
|
zip.addBuffer(Buffer.from(linkTarget), metadataPath, Object.assign(Object.assign({}, this.getYazlOption()), { mtime: file.mtime, mode: file.mode }));
|
|
165
165
|
}
|
|
166
166
|
async walkDir(folders, token) {
|
package/lib/util.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unlink = unlink;
|
|
4
|
-
exports.mkdir = mkdir;
|
|
5
|
-
exports.realpath = realpath;
|
|
6
|
-
exports.stat = stat;
|
|
7
|
-
exports.lstat = lstat;
|
|
8
|
-
exports.chmod = chmod;
|
|
9
|
-
exports.readdir = readdir;
|
|
10
|
-
exports.access = access;
|
|
11
|
-
exports.rmdir = rmdir;
|
|
12
|
-
exports.symlink = symlink;
|
|
13
|
-
exports.readlink = readlink;
|
|
14
|
-
const fs = require("fs");
|
|
15
|
-
const util = require("util");
|
|
16
|
-
function unlink(path) {
|
|
17
|
-
return util.promisify(fs.unlink)(path);
|
|
18
|
-
}
|
|
19
|
-
function mkdir(path, mode) {
|
|
20
|
-
return util.promisify(fs.mkdir)(path, mode);
|
|
21
|
-
}
|
|
22
|
-
function realpath(path) {
|
|
23
|
-
return util.promisify(fs.realpath)(path);
|
|
24
|
-
}
|
|
25
|
-
function stat(path) {
|
|
26
|
-
return util.promisify(fs.stat)(path);
|
|
27
|
-
}
|
|
28
|
-
function lstat(path) {
|
|
29
|
-
return util.promisify(fs.lstat)(path);
|
|
30
|
-
}
|
|
31
|
-
function chmod(path, mode) {
|
|
32
|
-
return util.promisify(fs.chmod)(path, mode);
|
|
33
|
-
}
|
|
34
|
-
function readdir(path) {
|
|
35
|
-
return util.promisify(fs.readdir)(path);
|
|
36
|
-
}
|
|
37
|
-
function access(path, mode) {
|
|
38
|
-
return util.promisify(fs.access)(path, mode);
|
|
39
|
-
}
|
|
40
|
-
function rmdir(path) {
|
|
41
|
-
return util.promisify(fs.rmdir)(path);
|
|
42
|
-
}
|
|
43
|
-
function symlink(target, path, type) {
|
|
44
|
-
return util.promisify(fs.symlink)(target, path, type);
|
|
45
|
-
}
|
|
46
|
-
function readlink(path) {
|
|
47
|
-
return util.promisify(fs.readlink)(path);
|
|
48
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|