0caa7b3d5ece47344a7411dfa0087a459d5cc23b999d3c93de5276d5fd004a5244b170e64a363507feb3a902269be3f7d359d11625c0560b26633846fd3a72 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Minipass } from 'minipass';
  2. import { normalizeWindowsPath } from './normalize-windows-path.js';
  3. export 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