Files: e6f6f8953f02f539bb377ecd4fc0a5eb4db2f900 / index.js
4115 bytesRaw
1 | var pull = require('pull-stream') |
2 | var Buffered = require('pull-buffered') |
3 | var xtend = require('xtend') |
4 | var headers = require('./headers') |
5 | |
6 | var mixinPax = function (header, pax) { |
7 | if (pax.path) header.name = pax.path |
8 | if (pax.linkpath) header.linkname = pax.linkpath |
9 | if (pax.size) header.size = parseInt(pax.size, 10) |
10 | header.pax = pax |
11 | return header |
12 | } |
13 | |
14 | module.exports = function (opts) { |
15 | var b = Buffered() |
16 | var gnuLongPath, gnuLongLinkPath, pax, paxGlobal |
17 | opts = opts || {} |
18 | var _cb |
19 | var ended |
20 | var locked = false |
21 | |
22 | function drainOverflow(size, cb) { |
23 | var len = 512 - (size % 512) |
24 | if (!len) return cb() |
25 | b.chunks(len)(null, function (end, data) { |
26 | if (end && end !== true) return cb(end) |
27 | cb() |
28 | }) |
29 | } |
30 | |
31 | var readNextHeader = b.chunks(512) |
32 | function readEntry(cb) { |
33 | if (locked) return _cb = cb |
34 | if (ended) return cb(ended) |
35 | readNextHeader(null, function (end, data) { |
36 | if (end) return cb(ended = end) |
37 | var header |
38 | try { header = headers.decode(data, opts.filenameEncoding) } |
39 | catch (err) { return cb(err) } |
40 | if (!header) return readEntry(cb) |
41 | |
42 | if (header.type === 'gnu-long-path') { |
43 | return b.chunks(header.size)(null, function (end, data) { |
44 | if (end) return cb(end) |
45 | gnuLongPath = headers.decodeLongPath(data, opts.filenameEncoding) |
46 | drainOverflow(header.size, function (err) { |
47 | if (err) return cb(err) |
48 | readEntry(cb) |
49 | }) |
50 | }) |
51 | } |
52 | |
53 | if (header.type === 'gnu-long-link-path') { |
54 | return b.chunks(header.size)(null, function (end, data) { |
55 | if (end) return cb(end) |
56 | gnuLongLinkPath = headers.decodeLongPath(data, opts.filenameEncoding) |
57 | drainOverflow(header.size, function (err) { |
58 | if (err) return cb(err) |
59 | readEntry(cb) |
60 | }) |
61 | }) |
62 | } |
63 | |
64 | if (header.type === 'pax-global-header') { |
65 | return b.chunks(header.size)(null, function (end, data) { |
66 | if (end) return cb(end) |
67 | paxGlobal = headers.decodePax(data) |
68 | drainOverflow(header.size, function (err) { |
69 | if (err) return cb(err) |
70 | readEntry(cb) |
71 | }) |
72 | }) |
73 | } |
74 | |
75 | if (header.type === 'pax-header') { |
76 | return b.chunks(header.size)(null, function (end, data) { |
77 | if (end) return cb(end) |
78 | pax = headers.decodePax(data) |
79 | if (paxGlobal) pax = xtend(paxGlobal, pax) |
80 | drainOverflow(header.size, function (err) { |
81 | if (err) return cb(err) |
82 | readEntry(cb) |
83 | }) |
84 | }) |
85 | } |
86 | |
87 | if (gnuLongPath) { |
88 | header.name = gnuLongPath |
89 | gnuLongPath = null |
90 | } |
91 | |
92 | if (gnuLongLinkPath) { |
93 | header.linkname = gnuLongLinkPath |
94 | gnuLongLinkPath = null |
95 | } |
96 | |
97 | if (pax) { |
98 | header = mixinPax(header, pax) |
99 | pax = null |
100 | } |
101 | |
102 | if (!header.size || header.type === 'directory') { |
103 | return cb(null, { |
104 | header: header, |
105 | read: pull.empty() |
106 | }) |
107 | } |
108 | |
109 | locked = true |
110 | var overflow = 512 - header.size % 512 |
111 | var readBody = b.take(header.size) |
112 | var readOverflow = function () { |
113 | pull( |
114 | b.take(overflow), |
115 | pull.drain(null, function (err) { |
116 | if (err) ended = err |
117 | locked = false |
118 | var cb1 |
119 | if (_cb) { |
120 | var cb1 = _cb |
121 | _cb = null |
122 | readEntry(cb1) |
123 | } |
124 | }) |
125 | ) |
126 | } |
127 | var readBodyWrapped = function (abort, cb) { |
128 | if (abort) return pull( |
129 | readBody, |
130 | pull.drain(null, function (err) { |
131 | if (err) return cb(err) |
132 | cb() |
133 | readOverflow() |
134 | }) |
135 | ) |
136 | readBody(null, function (end, data) { |
137 | if (end) readOverflow() |
138 | cb(end, data) |
139 | }) |
140 | } |
141 | cb(null, { |
142 | header: header, |
143 | read: readBodyWrapped |
144 | }) |
145 | }) |
146 | } |
147 | |
148 | return function (read) { |
149 | b(read) |
150 | return function (abort, cb) { |
151 | if (abort) return read(abort, cb) |
152 | readEntry(cb) |
153 | } |
154 | } |
155 | } |
156 |
Built with git-ssb-web