source: node_modules/tar-stream/pack.js@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 5.5 KB
RevLine 
[81bc7da]1var constants = require('fs-constants')
2var eos = require('end-of-stream')
3var inherits = require('inherits')
4var alloc = Buffer.alloc
5
6var Readable = require('readable-stream').Readable
7var Writable = require('readable-stream').Writable
8var StringDecoder = require('string_decoder').StringDecoder
9
10var headers = require('./headers')
11
12var DMODE = parseInt('755', 8)
13var FMODE = parseInt('644', 8)
14
15var END_OF_TAR = alloc(1024)
16
17var noop = function () {}
18
19var overflow = function (self, size) {
20 size &= 511
21 if (size) self.push(END_OF_TAR.slice(0, 512 - size))
22}
23
24function modeToType (mode) {
25 switch (mode & constants.S_IFMT) {
26 case constants.S_IFBLK: return 'block-device'
27 case constants.S_IFCHR: return 'character-device'
28 case constants.S_IFDIR: return 'directory'
29 case constants.S_IFIFO: return 'fifo'
30 case constants.S_IFLNK: return 'symlink'
31 }
32
33 return 'file'
34}
35
36var Sink = function (to) {
37 Writable.call(this)
38 this.written = 0
39 this._to = to
40 this._destroyed = false
41}
42
43inherits(Sink, Writable)
44
45Sink.prototype._write = function (data, enc, cb) {
46 this.written += data.length
47 if (this._to.push(data)) return cb()
48 this._to._drain = cb
49}
50
51Sink.prototype.destroy = function () {
52 if (this._destroyed) return
53 this._destroyed = true
54 this.emit('close')
55}
56
57var LinkSink = function () {
58 Writable.call(this)
59 this.linkname = ''
60 this._decoder = new StringDecoder('utf-8')
61 this._destroyed = false
62}
63
64inherits(LinkSink, Writable)
65
66LinkSink.prototype._write = function (data, enc, cb) {
67 this.linkname += this._decoder.write(data)
68 cb()
69}
70
71LinkSink.prototype.destroy = function () {
72 if (this._destroyed) return
73 this._destroyed = true
74 this.emit('close')
75}
76
77var Void = function () {
78 Writable.call(this)
79 this._destroyed = false
80}
81
82inherits(Void, Writable)
83
84Void.prototype._write = function (data, enc, cb) {
85 cb(new Error('No body allowed for this entry'))
86}
87
88Void.prototype.destroy = function () {
89 if (this._destroyed) return
90 this._destroyed = true
91 this.emit('close')
92}
93
94var Pack = function (opts) {
95 if (!(this instanceof Pack)) return new Pack(opts)
96 Readable.call(this, opts)
97
98 this._drain = noop
99 this._finalized = false
100 this._finalizing = false
101 this._destroyed = false
102 this._stream = null
103}
104
105inherits(Pack, Readable)
106
107Pack.prototype.entry = function (header, buffer, callback) {
108 if (this._stream) throw new Error('already piping an entry')
109 if (this._finalized || this._destroyed) return
110
111 if (typeof buffer === 'function') {
112 callback = buffer
113 buffer = null
114 }
115
116 if (!callback) callback = noop
117
118 var self = this
119
120 if (!header.size || header.type === 'symlink') header.size = 0
121 if (!header.type) header.type = modeToType(header.mode)
122 if (!header.mode) header.mode = header.type === 'directory' ? DMODE : FMODE
123 if (!header.uid) header.uid = 0
124 if (!header.gid) header.gid = 0
125 if (!header.mtime) header.mtime = new Date()
126
127 if (typeof buffer === 'string') buffer = Buffer.from(buffer)
128 if (Buffer.isBuffer(buffer)) {
129 header.size = buffer.length
130 this._encode(header)
131 var ok = this.push(buffer)
132 overflow(self, header.size)
133 if (ok) process.nextTick(callback)
134 else this._drain = callback
135 return new Void()
136 }
137
138 if (header.type === 'symlink' && !header.linkname) {
139 var linkSink = new LinkSink()
140 eos(linkSink, function (err) {
141 if (err) { // stream was closed
142 self.destroy()
143 return callback(err)
144 }
145
146 header.linkname = linkSink.linkname
147 self._encode(header)
148 callback()
149 })
150
151 return linkSink
152 }
153
154 this._encode(header)
155
156 if (header.type !== 'file' && header.type !== 'contiguous-file') {
157 process.nextTick(callback)
158 return new Void()
159 }
160
161 var sink = new Sink(this)
162
163 this._stream = sink
164
165 eos(sink, function (err) {
166 self._stream = null
167
168 if (err) { // stream was closed
169 self.destroy()
170 return callback(err)
171 }
172
173 if (sink.written !== header.size) { // corrupting tar
174 self.destroy()
175 return callback(new Error('size mismatch'))
176 }
177
178 overflow(self, header.size)
179 if (self._finalizing) self.finalize()
180 callback()
181 })
182
183 return sink
184}
185
186Pack.prototype.finalize = function () {
187 if (this._stream) {
188 this._finalizing = true
189 return
190 }
191
192 if (this._finalized) return
193 this._finalized = true
194 this.push(END_OF_TAR)
195 this.push(null)
196}
197
198Pack.prototype.destroy = function (err) {
199 if (this._destroyed) return
200 this._destroyed = true
201
202 if (err) this.emit('error', err)
203 this.emit('close')
204 if (this._stream && this._stream.destroy) this._stream.destroy()
205}
206
207Pack.prototype._encode = function (header) {
208 if (!header.pax) {
209 var buf = headers.encode(header)
210 if (buf) {
211 this.push(buf)
212 return
213 }
214 }
215 this._encodePax(header)
216}
217
218Pack.prototype._encodePax = function (header) {
219 var paxHeader = headers.encodePax({
220 name: header.name,
221 linkname: header.linkname,
222 pax: header.pax
223 })
224
225 var newHeader = {
226 name: 'PaxHeader',
227 mode: header.mode,
228 uid: header.uid,
229 gid: header.gid,
230 size: paxHeader.length,
231 mtime: header.mtime,
232 type: 'pax-header',
233 linkname: header.linkname && 'PaxHeader',
234 uname: header.uname,
235 gname: header.gname,
236 devmajor: header.devmajor,
237 devminor: header.devminor
238 }
239
240 this.push(headers.encode(newHeader))
241 this.push(paxHeader)
242 overflow(this, paxHeader.length)
243
244 newHeader.size = header.size
245 newHeader.type = header.type
246 this.push(headers.encode(newHeader))
247}
248
249Pack.prototype._read = function (n) {
250 var drain = this._drain
251 this._drain = noop
252 drain()
253}
254
255module.exports = Pack
Note: See TracBrowser for help on using the repository browser.