c4e43c57c45638e212a953d7474e1f49fcd145d98bc4b65c0698a8374df1ca8c8b747680965efef9de409968b5031fd6ad5fc046eb2e006e3766f373d68a7e 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. "use strict";
  2. // parse a 512-byte header block to a data object, or vice-versa
  3. // encode returns `true` if a pax extended header is needed, because
  4. // the data could not be faithfully encoded in a simple header.
  5. // (Also, check header.needPax to see if it needs a pax header.)
  6. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  7. if (k2 === undefined) k2 = k;
  8. var desc = Object.getOwnPropertyDescriptor(m, k);
  9. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  10. desc = { enumerable: true, get: function() { return m[k]; } };
  11. }
  12. Object.defineProperty(o, k2, desc);
  13. }) : (function(o, m, k, k2) {
  14. if (k2 === undefined) k2 = k;
  15. o[k2] = m[k];
  16. }));
  17. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  18. Object.defineProperty(o, "default", { enumerable: true, value: v });
  19. }) : function(o, v) {
  20. o["default"] = v;
  21. });
  22. var __importStar = (this && this.__importStar) || function (mod) {
  23. if (mod && mod.__esModule) return mod;
  24. var result = {};
  25. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  26. __setModuleDefault(result, mod);
  27. return result;
  28. };
  29. Object.defineProperty(exports, "__esModule", { value: true });
  30. exports.Header = void 0;
  31. const node_path_1 = require("node:path");
  32. const large = __importStar(require("./large-numbers.js"));
  33. const types = __importStar(require("./types.js"));
  34. class Header {
  35. cksumValid = false;
  36. needPax = false;
  37. nullBlock = false;
  38. block;
  39. path;
  40. mode;
  41. uid;
  42. gid;
  43. size;
  44. cksum;
  45. #type = 'Unsupported';
  46. linkpath;
  47. uname;
  48. gname;
  49. devmaj = 0;
  50. devmin = 0;
  51. atime;
  52. ctime;
  53. mtime;
  54. charset;
  55. comment;
  56. constructor(data, off = 0, ex, gex) {
  57. if (Buffer.isBuffer(data)) {
  58. this.decode(data, off || 0, ex, gex);
  59. }
  60. else if (data) {
  61. this.#slurp(data);
  62. }
  63. }
  64. decode(buf, off, ex, gex) {
  65. if (!off) {
  66. off = 0;
  67. }
  68. if (!buf || !(buf.length >= off + 512)) {
  69. throw new Error('need 512 bytes for header');
  70. }
  71. this.path = decString(buf, off, 100);
  72. this.mode = decNumber(buf, off + 100, 8);
  73. this.uid = decNumber(buf, off + 108, 8);
  74. this.gid = decNumber(buf, off + 116, 8);
  75. this.size = decNumber(buf, off + 124, 12);
  76. this.mtime = decDate(buf, off + 136, 12);
  77. this.cksum = decNumber(buf, off + 148, 12);
  78. // if we have extended or global extended headers, apply them now
  79. // See https://github.com/npm/node-tar/pull/187
  80. // Apply global before local, so it overrides
  81. if (gex)
  82. this.#slurp(gex, true);
  83. if (ex)
  84. this.#slurp(ex);
  85. // old tar versions marked dirs as a file with a trailing /
  86. const t = decString(buf, off + 156, 1);
  87. if (types.isCode(t)) {
  88. this.#type = t || '0';
  89. }
  90. if (this.#type === '0' && this.path.slice(-1) === '/') {
  91. this.#type = '5';
  92. }
  93. // tar implementations sometimes incorrectly put the stat(dir).size
  94. // as the size in the tarball, even though Directory entries are
  95. // not able to have any body at all. In the very rare chance that
  96. // it actually DOES have a body, we weren't going to do anything with
  97. // it anyway, and it'll just be a warning about an invalid header.
  98. if (this.#type === '5') {
  99. this.size = 0;
  100. }
  101. this.linkpath = decString(buf, off + 157, 100);
  102. if (buf.subarray(off + 257, off + 265).toString() ===
  103. 'ustar\u000000') {
  104. this.uname = decString(buf, off + 265, 32);
  105. this.gname = decString(buf, off + 297, 32);
  106. /* c8 ignore start */
  107. this.devmaj = decNumber(buf, off + 329, 8) ?? 0;
  108. this.devmin = decNumber(buf, off + 337, 8) ?? 0;
  109. /* c8 ignore stop */
  110. if (buf[off + 475] !== 0) {
  111. // definitely a prefix, definitely >130 chars.
  112. const prefix = decString(buf, off + 345, 155);
  113. this.path = prefix + '/' + this.path;
  114. }
  115. else {
  116. const prefix = decString(buf, off + 345, 130);
  117. if (prefix) {
  118. this.path = prefix + '/' + this.path;
  119. }
  120. this.atime = decDate(buf, off + 476, 12);
  121. this.ctime = decDate(buf, off + 488, 12);
  122. }
  123. }
  124. let sum = 8 * 0x20;
  125. for (let i = off; i < off + 148; i++) {
  126. sum += buf[i];
  127. }
  128. for (let i = off + 156; i < off + 512; i++) {
  129. sum += buf[i];
  130. }
  131. this.cksumValid = sum === this.cksum;
  132. if (this.cksum === undefined && sum === 8 * 0x20) {
  133. this.nullBlock = true;
  134. }
  135. }
  136. #slurp(ex, gex = false) {
  137. Object.assign(this, Object.fromEntries(Object.entries(ex).filter(([k, v]) => {
  138. // we slurp in everything except for the path attribute in
  139. // a global extended header, because that's weird. Also, any
  140. // null/undefined values are ignored.
  141. return !(v === null ||
  142. v === undefined ||
  143. (k === 'path' && gex) ||
  144. (k === 'linkpath' && gex) ||
  145. k === 'global');
  146. })));
  147. }
  148. encode(buf, off = 0) {
  149. if (!buf) {
  150. buf = this.block = Buffer.alloc(512);
  151. }
  152. if (this.#type === 'Unsupported') {
  153. this.#type = '0';
  154. }
  155. if (!(buf.length >= off + 512)) {
  156. throw new Error('need 512 bytes for header');
  157. }
  158. const prefixSize = this.ctime || this.atime ? 130 : 155;
  159. const split = splitPrefix(this.path || '', prefixSize);
  160. const path = split[0];
  161. const prefix = split[1];
  162. this.needPax = !!split[2];
  163. this.needPax = encString(buf, off, 100, path) || this.needPax;
  164. this.needPax =
  165. encNumber(buf, off + 100, 8, this.mode) || this.needPax;
  166. this.needPax =
  167. encNumber(buf, off + 108, 8, this.uid) || this.needPax;
  168. this.needPax =
  169. encNumber(buf, off + 116, 8, this.gid) || this.needPax;
  170. this.needPax =
  171. encNumber(buf, off + 124, 12, this.size) || this.needPax;
  172. this.needPax =
  173. encDate(buf, off + 136, 12, this.mtime) || this.needPax;
  174. buf[off + 156] = this.#type.charCodeAt(0);
  175. this.needPax =
  176. encString(buf, off + 157, 100, this.linkpath) || this.needPax;
  177. buf.write('ustar\u000000', off + 257, 8);
  178. this.needPax =
  179. encString(buf, off + 265, 32, this.uname) || this.needPax;
  180. this.needPax =
  181. encString(buf, off + 297, 32, this.gname) || this.needPax;
  182. this.needPax =
  183. encNumber(buf, off + 329, 8, this.devmaj) || this.needPax;
  184. this.needPax =
  185. encNumber(buf, off + 337, 8, this.devmin) || this.needPax;
  186. this.needPax =
  187. encString(buf, off + 345, prefixSize, prefix) || this.needPax;
  188. if (buf[off + 475] !== 0) {
  189. this.needPax =
  190. encString(buf, off + 345, 155, prefix) || this.needPax;
  191. }
  192. else {
  193. this.needPax =
  194. encString(buf, off + 345, 130, prefix) || this.needPax;
  195. this.needPax =
  196. encDate(buf, off + 476, 12, this.atime) || this.needPax;
  197. this.needPax =
  198. encDate(buf, off + 488, 12, this.ctime) || this.needPax;
  199. }
  200. let sum = 8 * 0x20;
  201. for (let i = off; i < off + 148; i++) {
  202. sum += buf[i];
  203. }
  204. for (let i = off + 156; i < off + 512; i++) {
  205. sum += buf[i];
  206. }
  207. this.cksum = sum;
  208. encNumber(buf, off + 148, 8, this.cksum);
  209. this.cksumValid = true;
  210. return this.needPax;
  211. }
  212. get type() {
  213. return (this.#type === 'Unsupported' ?
  214. this.#type
  215. : types.name.get(this.#type));
  216. }
  217. get typeKey() {
  218. return this.#type;
  219. }
  220. set type(type) {
  221. const c = String(types.code.get(type));
  222. if (types.isCode(c) || c === 'Unsupported') {
  223. this.#type = c;
  224. }
  225. else if (types.isCode(type)) {
  226. this.#type = type;
  227. }
  228. else {
  229. throw new TypeError('invalid entry type: ' + type);
  230. }
  231. }
  232. }
  233. exports.Header = Header;
  234. const splitPrefix = (p, prefixSize) => {
  235. const pathSize = 100;
  236. let pp = p;
  237. let prefix = '';
  238. let ret = undefined;
  239. const root = node_path_1.posix.parse(p).root || '.';
  240. if (Buffer.byteLength(pp) < pathSize) {
  241. ret = [pp, prefix, false];
  242. }
  243. else {
  244. // first set prefix to the dir, and path to the base
  245. prefix = node_path_1.posix.dirname(pp);
  246. pp = node_path_1.posix.basename(pp);
  247. do {
  248. if (Buffer.byteLength(pp) <= pathSize &&
  249. Buffer.byteLength(prefix) <= prefixSize) {
  250. // both fit!
  251. ret = [pp, prefix, false];
  252. }
  253. else if (Buffer.byteLength(pp) > pathSize &&
  254. Buffer.byteLength(prefix) <= prefixSize) {
  255. // prefix fits in prefix, but path doesn't fit in path
  256. ret = [pp.slice(0, pathSize - 1), prefix, true];
  257. }
  258. else {
  259. // make path take a bit from prefix
  260. pp = node_path_1.posix.join(node_path_1.posix.basename(prefix), pp);
  261. prefix = node_path_1.posix.dirname(prefix);
  262. }
  263. } while (prefix !== root && ret === undefined);
  264. // at this point, found no resolution, just truncate
  265. if (!ret) {
  266. ret = [p.slice(0, pathSize - 1), '', true];
  267. }
  268. }
  269. return ret;
  270. };
  271. const decString = (buf, off, size) => buf
  272. .subarray(off, off + size)
  273. .toString('utf8')
  274. .replace(/\0.*/, '');
  275. const decDate = (buf, off, size) => numToDate(decNumber(buf, off, size));
  276. const numToDate = (num) => num === undefined ? undefined : new Date(num * 1000);
  277. const decNumber = (buf, off, size) => Number(buf[off]) & 0x80 ?
  278. large.parse(buf.subarray(off, off + size))
  279. : decSmallNumber(buf, off, size);
  280. const nanUndef = (value) => (isNaN(value) ? undefined : value);
  281. const decSmallNumber = (buf, off, size) => nanUndef(parseInt(buf
  282. .subarray(off, off + size)
  283. .toString('utf8')
  284. .replace(/\0.*$/, '')
  285. .trim(), 8));
  286. // the maximum encodable as a null-terminated octal, by field size
  287. const MAXNUM = {
  288. 12: 0o77777777777,
  289. 8: 0o7777777,
  290. };
  291. const encNumber = (buf, off, size, num) => num === undefined ? false
  292. : num > MAXNUM[size] || num < 0 ?
  293. (large.encode(num, buf.subarray(off, off + size)), true)
  294. : (encSmallNumber(buf, off, size, num), false);
  295. const encSmallNumber = (buf, off, size, num) => buf.write(octalString(num, size), off, size, 'ascii');
  296. const octalString = (num, size) => padOctal(Math.floor(num).toString(8), size);
  297. const padOctal = (str, size) => (str.length === size - 1 ?
  298. str
  299. : new Array(size - str.length - 1).join('0') + str + ' ') + '\0';
  300. const encDate = (buf, off, size, date) => date === undefined ? false : (encNumber(buf, off, size, date.getTime() / 1000));
  301. // enough to fill the longest string we've got
  302. const NULLS = new Array(156).join('\0');
  303. // pad with nulls, return true if it's longer or non-ascii
  304. const encString = (buf, off, size, str) => str === undefined ? false : ((buf.write(str + NULLS, off, size, 'utf8'),
  305. str.length !== Buffer.byteLength(str) || str.length > size));
  306. //# sourceMappingURL=header.js.map