extract.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Set the umask, so that it works the same everywhere.
  2. process.umask(parseInt('22', 8))
  3. var tap = require("tap")
  4. , tar = require("../tar.js")
  5. , fs = require("fs")
  6. , path = require("path")
  7. , file = path.resolve(__dirname, "fixtures/c.tar")
  8. , target = path.resolve(__dirname, "tmp/extract-test")
  9. , index = 0
  10. , fstream = require("fstream")
  11. , ee = 0
  12. , expectEntries =
  13. [ { path: 'c.txt',
  14. mode: '644',
  15. type: '0',
  16. depth: undefined,
  17. size: 513,
  18. linkpath: '',
  19. nlink: undefined,
  20. dev: undefined,
  21. ino: undefined },
  22. { path: 'cc.txt',
  23. mode: '644',
  24. type: '0',
  25. depth: undefined,
  26. size: 513,
  27. linkpath: '',
  28. nlink: undefined,
  29. dev: undefined,
  30. ino: undefined },
  31. { path: 'r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  32. mode: '644',
  33. type: '0',
  34. depth: undefined,
  35. size: 100,
  36. linkpath: '',
  37. nlink: undefined,
  38. dev: undefined,
  39. ino: undefined },
  40. { path: 'Ω.txt',
  41. mode: '644',
  42. type: '0',
  43. depth: undefined,
  44. size: 2,
  45. linkpath: '',
  46. nlink: undefined,
  47. dev: undefined,
  48. ino: undefined },
  49. { path: 'Ω.txt',
  50. mode: '644',
  51. type: '0',
  52. depth: undefined,
  53. size: 2,
  54. linkpath: '',
  55. nlink: 1,
  56. dev: 234881026,
  57. ino: 51693379 },
  58. { path: '200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  59. mode: '644',
  60. type: '0',
  61. depth: undefined,
  62. size: 200,
  63. linkpath: '',
  64. nlink: 1,
  65. dev: 234881026,
  66. ino: 51681874 },
  67. { path: '200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  68. mode: '644',
  69. type: '0',
  70. depth: undefined,
  71. size: 201,
  72. linkpath: '',
  73. nlink: undefined,
  74. dev: undefined,
  75. ino: undefined },
  76. { path: '200LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL',
  77. mode: '777',
  78. type: '2',
  79. depth: undefined,
  80. size: 0,
  81. linkpath: '200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  82. nlink: undefined,
  83. dev: undefined,
  84. ino: undefined },
  85. { path: '200-hard',
  86. mode: '644',
  87. type: '0',
  88. depth: undefined,
  89. size: 200,
  90. linkpath: '',
  91. nlink: 2,
  92. dev: 234881026,
  93. ino: 51681874 },
  94. { path: '200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  95. mode: '644',
  96. type: '1',
  97. depth: undefined,
  98. size: 0,
  99. linkpath: path.resolve(target, '200-hard'),
  100. nlink: 2,
  101. dev: 234881026,
  102. ino: 51681874 } ]
  103. , ef = 0
  104. , expectFiles =
  105. [ { path: '',
  106. mode: '40755',
  107. type: 'Directory',
  108. depth: 0,
  109. linkpath: undefined },
  110. { path: '/200-hard',
  111. mode: '100644',
  112. type: 'File',
  113. depth: 1,
  114. size: 200,
  115. linkpath: undefined,
  116. nlink: 2 },
  117. { path: '/200LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL',
  118. mode: '120777',
  119. type: 'SymbolicLink',
  120. depth: 1,
  121. size: 200,
  122. linkpath: '200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  123. nlink: 1 },
  124. { path: '/200ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  125. mode: '100644',
  126. type: 'Link',
  127. depth: 1,
  128. size: 200,
  129. linkpath: path.join(target, '200-hard'),
  130. nlink: 2 },
  131. { path: '/c.txt',
  132. mode: '100644',
  133. type: 'File',
  134. depth: 1,
  135. size: 513,
  136. linkpath: undefined,
  137. nlink: 1 },
  138. { path: '/cc.txt',
  139. mode: '100644',
  140. type: 'File',
  141. depth: 1,
  142. size: 513,
  143. linkpath: undefined,
  144. nlink: 1 },
  145. { path: '/r',
  146. mode: '40755',
  147. type: 'Directory',
  148. depth: 1,
  149. linkpath: undefined },
  150. { path: '/r/e',
  151. mode: '40755',
  152. type: 'Directory',
  153. depth: 2,
  154. linkpath: undefined },
  155. { path: '/r/e/a',
  156. mode: '40755',
  157. type: 'Directory',
  158. depth: 3,
  159. linkpath: undefined },
  160. { path: '/r/e/a/l',
  161. mode: '40755',
  162. type: 'Directory',
  163. depth: 4,
  164. linkpath: undefined },
  165. { path: '/r/e/a/l/l',
  166. mode: '40755',
  167. type: 'Directory',
  168. depth: 5,
  169. linkpath: undefined },
  170. { path: '/r/e/a/l/l/y',
  171. mode: '40755',
  172. type: 'Directory',
  173. depth: 6,
  174. linkpath: undefined },
  175. { path: '/r/e/a/l/l/y/-',
  176. mode: '40755',
  177. type: 'Directory',
  178. depth: 7,
  179. linkpath: undefined },
  180. { path: '/r/e/a/l/l/y/-/d',
  181. mode: '40755',
  182. type: 'Directory',
  183. depth: 8,
  184. linkpath: undefined },
  185. { path: '/r/e/a/l/l/y/-/d/e',
  186. mode: '40755',
  187. type: 'Directory',
  188. depth: 9,
  189. linkpath: undefined },
  190. { path: '/r/e/a/l/l/y/-/d/e/e',
  191. mode: '40755',
  192. type: 'Directory',
  193. depth: 10,
  194. linkpath: undefined },
  195. { path: '/r/e/a/l/l/y/-/d/e/e/p',
  196. mode: '40755',
  197. type: 'Directory',
  198. depth: 11,
  199. linkpath: undefined },
  200. { path: '/r/e/a/l/l/y/-/d/e/e/p/-',
  201. mode: '40755',
  202. type: 'Directory',
  203. depth: 12,
  204. linkpath: undefined },
  205. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f',
  206. mode: '40755',
  207. type: 'Directory',
  208. depth: 13,
  209. linkpath: undefined },
  210. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o',
  211. mode: '40755',
  212. type: 'Directory',
  213. depth: 14,
  214. linkpath: undefined },
  215. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l',
  216. mode: '40755',
  217. type: 'Directory',
  218. depth: 15,
  219. linkpath: undefined },
  220. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d',
  221. mode: '40755',
  222. type: 'Directory',
  223. depth: 16,
  224. linkpath: undefined },
  225. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e',
  226. mode: '40755',
  227. type: 'Directory',
  228. depth: 17,
  229. linkpath: undefined },
  230. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r',
  231. mode: '40755',
  232. type: 'Directory',
  233. depth: 18,
  234. linkpath: undefined },
  235. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-',
  236. mode: '40755',
  237. type: 'Directory',
  238. depth: 19,
  239. linkpath: undefined },
  240. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p',
  241. mode: '40755',
  242. type: 'Directory',
  243. depth: 20,
  244. linkpath: undefined },
  245. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a',
  246. mode: '40755',
  247. type: 'Directory',
  248. depth: 21,
  249. linkpath: undefined },
  250. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t',
  251. mode: '40755',
  252. type: 'Directory',
  253. depth: 22,
  254. linkpath: undefined },
  255. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h',
  256. mode: '40755',
  257. type: 'Directory',
  258. depth: 23,
  259. linkpath: undefined },
  260. { path: '/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
  261. mode: '100644',
  262. type: 'File',
  263. depth: 24,
  264. size: 100,
  265. linkpath: undefined,
  266. nlink: 1 },
  267. { path: '/Ω.txt',
  268. mode: '100644',
  269. type: 'File',
  270. depth: 1,
  271. size: 2,
  272. linkpath: undefined,
  273. nlink: 1 } ]
  274. // The extract class basically just pipes the input
  275. // to a Reader, and then to a fstream.DirWriter
  276. // So, this is as much a test of fstream.Reader and fstream.Writer
  277. // as it is of tar.Extract, but it sort of makes sense.
  278. tap.test("preclean", function (t) {
  279. require("rimraf").sync(__dirname + "/tmp/extract-test")
  280. t.pass("cleaned!")
  281. t.end()
  282. })
  283. tap.test("extract test", function (t) {
  284. var extract = tar.Extract(target)
  285. var inp = fs.createReadStream(file)
  286. // give it a weird buffer size to try to break in odd places
  287. inp.bufferSize = 1234
  288. inp.pipe(extract)
  289. extract.on("end", function () {
  290. t.equal(ee, expectEntries.length, "should see "+ee+" entries")
  291. // should get no more entries after end
  292. extract.removeAllListeners("entry")
  293. extract.on("entry", function (e) {
  294. t.fail("Should not get entries after end!")
  295. })
  296. next()
  297. })
  298. extract.on("entry", function (entry) {
  299. var found =
  300. { path: entry.path
  301. , mode: entry.props.mode.toString(8)
  302. , type: entry.props.type
  303. , depth: entry.props.depth
  304. , size: entry.props.size
  305. , linkpath: entry.props.linkpath
  306. , nlink: entry.props.nlink
  307. , dev: entry.props.dev
  308. , ino: entry.props.ino
  309. }
  310. var wanted = expectEntries[ee ++]
  311. t.equivalent(found, wanted, "tar entry " + ee + " " + wanted.path)
  312. })
  313. function next () {
  314. var r = fstream.Reader({ path: target
  315. , type: "Directory"
  316. // this is just to encourage consistency
  317. , sort: "alpha" })
  318. r.on("ready", function () {
  319. foundEntry(r)
  320. })
  321. r.on("end", finish)
  322. function foundEntry (entry) {
  323. var p = entry.path.substr(target.length)
  324. var found =
  325. { path: p
  326. , mode: entry.props.mode.toString(8)
  327. , type: entry.props.type
  328. , depth: entry.props.depth
  329. , size: entry.props.size
  330. , linkpath: entry.props.linkpath
  331. , nlink: entry.props.nlink
  332. }
  333. var wanted = expectFiles[ef ++]
  334. t.has(found, wanted, "unpacked file " + ef + " " + wanted.path)
  335. entry.on("entry", foundEntry)
  336. }
  337. function finish () {
  338. t.equal(ef, expectFiles.length, "should have "+ef+" items")
  339. t.end()
  340. }
  341. }
  342. })