codekingpro/portable-devtools
114k
1import { Minipass } from 'minipass';
2import { normalizeWindowsPath } from './normalize-windows-path.js';
3export class ReadEntry extends Minipass {
4 extended;
5 globalExtended;
6 header;
7 startBlockSize;
8 blockRemain;
9 remain;
10 type;
11 meta = false;
12 ignore = false;
13 path;
14 mode;
15 uid;
16 gid;
17 uname;
18 gname;
19 size = 0;
20 mtime;
21 atime;
22 ctime;
23 linkpath;
24 dev;
25 ino;
26 nlink;
27 invalid = false;
28 absolute;
29 unsupported = false;
30 constructor(header, ex, gex) {
31 super({});
32 // read entries always start life paused. this is to avoid the
33 // situation where Minipass's auto-ending empty streams results
34 // in an entry ending before we're ready for it.
35 this.pause();
36 this.extended = ex;
37 this.globalExtended = gex;
38 this.header = header;
39 /* c8 ignore start */
40 this.remain = header.size ?? 0;
41 /* c8 ignore stop */
42 this.startBlockSize = 512 * Math.ceil(this.remain / 512);
43 this.blockRemain = this.startBlockSize;
44 this.type = header.type;
45 switch (this.type) {
46 case 'File':
47 case 'OldFile':
48 case 'Link':
49 case 'SymbolicLink':
50 case 'CharacterDevice':
51 case 'BlockDevice':
52 case 'Directory':
53 case 'FIFO':
54 case 'ContiguousFile':
55 case 'GNUDumpDir':
56 break;
57 case 'NextFileHasLongLinkpath':
58 case 'NextFileHasLongPath':
59 case 'OldGnuLongPath':
60 case 'GlobalExtendedHeader':
61 case 'ExtendedHeader':
62 case 'OldExtendedHeader':
63 this.meta = true;
64 break;
65 // NOTE: gnutar and bsdtar treat unrecognized types as 'File'
66 // it may be worth doing the same, but with a warning.
67 default:
68 this.ignore = true;
69 }
70 /* c8 ignore start */
71 if (!header.path) {
72 throw new Error('no path provided for tar.ReadEntry');
73 }
74 /* c8 ignore stop */
75 this.path = normalizeWindowsPath(header.path);
76 this.mode = header.mode;
77 if (this.mode) {
78 this.mode = this.mode & 0o7777;
79 }
80 this.uid = header.uid;
81 this.gid = header.gid;
82 this.uname = header.uname;
83 this.gname = header.gname;
84 this.size = this.remain;
85 this.mtime = header.mtime;
86 this.atime = header.atime;
87 this.ctime = header.ctime;
88 /* c8 ignore start */
89 this.linkpath =
90 header.linkpath ?
91 normalizeWindowsPath(header.linkpath)
92 : undefined;
93 /* c8 ignore stop */
94 this.uname = header.uname;
95 this.gname = header.gname;
96 if (ex) {
97 this.#slurp(ex);
98 }
99 if (gex) {
100 this.#slurp(gex, true);
101 }
102 }
103 write(data) {
104 const writeLen = data.length;
105 if (writeLen > this.blockRemain) {
106 throw new Error('writing more to entry than is appropriate');
107 }
108 const r = this.remain;
109 const br = this.blockRemain;
110 this.remain = Math.max(0, r - writeLen);
111 this.blockRemain = Math.max(0, br - writeLen);
112 if (this.ignore) {
113 return true;
114 }
115 if (r >= writeLen) {
116 return super.write(data);
117 }
118 // r < writeLen
119 return super.write(data.subarray(0, r));
120 }
121 #slurp(ex, gex = false) {
122 if (ex.path)
123 ex.path = normalizeWindowsPath(ex.path);
124 if (ex.linkpath)
125 ex.linkpath = normalizeWindowsPath(ex.linkpath);
126 Object.assign(this, Object.fromEntries(Object.entries(ex).filter(([k, v]) => {
127 // we slurp in everything except for the path attribute in
128 // a global extended header, because that's weird. Also, any
129 // null/undefined values are ignored.
130 return !(v === null ||
131 v === undefined ||
132 (k === 'path' && gex));
133 })));
134 }
135}
136//# sourceMappingURL=read-entry.js.map