Skip to content

Commit 0dcc5b2

Browse files
committed
chore: track fs state on WriteEntry class, not in arguments
1 parent adf3511 commit 0dcc5b2

1 file changed

Lines changed: 75 additions & 45 deletions

File tree

lib/write-entry.js

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
5252
this.noMtime = !!opt.noMtime
5353
this.mtime = opt.mtime || null
5454

55+
this.fd = null
56+
this.blockLen = null
57+
this.blockRemain = null
58+
this.buf = null
59+
this.offset = null
60+
this.length = null
61+
this.pos = null
62+
this.remain = null
63+
5564
if (typeof opt.onwarn === 'function')
5665
this.on('warn', opt.onwarn)
5766

@@ -208,75 +217,89 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
208217
}
209218

210219
[ONOPENFILE] (fd) {
211-
const blockLen = 512 * Math.ceil(this.stat.size / 512)
212-
const bufLen = Math.min(blockLen, this.maxReadSize)
213-
const buf = Buffer.allocUnsafe(bufLen)
214-
this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
220+
this.fd = fd
221+
this.blockLen = 512 * Math.ceil(this.stat.size / 512)
222+
this.blockRemain = this.blockLen
223+
const bufLen = Math.min(this.blockLen, this.maxReadSize)
224+
this.buf = Buffer.allocUnsafe(bufLen)
225+
this.offset = 0
226+
this.pos = 0
227+
this.remain = this.stat.size
228+
this.length = this.buf.length
229+
this[READ](this.stat.size)
215230
}
216231

217-
[READ] (fd, buf, offset, length, pos, remain, blockRemain) {
232+
[READ] () {
233+
const { fd, buf, offset, length, pos } = this
218234
fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
219-
if (er)
220-
return this[CLOSE](fd, _ => this.emit('error', er))
221-
this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
235+
if (er) {
236+
// ignoring the error from close(2) is a bad practice, but at
237+
// this point we already have an error, don't need another one
238+
return this[CLOSE](() => this.emit('error', er))
239+
}
240+
this[ONREAD](bytesRead)
222241
})
223242
}
224243

225-
[CLOSE] (fd, cb) {
226-
fs.close(fd, cb)
244+
[CLOSE] (cb) {
245+
fs.close(this.fd, cb)
227246
}
228247

229-
[ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
230-
if (bytesRead <= 0 && remain > 0) {
248+
[ONREAD] (bytesRead) {
249+
if (bytesRead <= 0 && this.remain > 0) {
231250
const er = new Error('encountered unexpected EOF')
232251
er.path = this.absolute
233252
er.syscall = 'read'
234253
er.code = 'EOF'
235-
this[CLOSE](fd, _ => _)
236-
return this.emit('error', er)
254+
return this[CLOSE](() => this.emit('error', er))
237255
}
238256

239-
if (bytesRead > remain) {
257+
if (bytesRead > this.remain) {
240258
const er = new Error('did not encounter expected EOF')
241259
er.path = this.absolute
242260
er.syscall = 'read'
243261
er.code = 'EOF'
244-
this[CLOSE](fd, _ => _)
245-
return this.emit('error', er)
262+
return this[CLOSE](() => this.emit('error', er))
246263
}
247264

248265
// null out the rest of the buffer, if we could fit the block padding
249-
if (bytesRead === remain) {
250-
for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
251-
buf[i + offset] = 0
252-
bytesRead ++
253-
remain ++
266+
// at the end of this loop, we've incremented bytesRead and this.remain
267+
// to be incremented up to the blockRemain level, as if we had expected
268+
// to get a null-padded file, and read it until the end. then we will
269+
// decrement both remain and blockRemain by bytesRead, and know that we
270+
// reached the expected EOF, without any null buffer to append.
271+
if (bytesRead === this.remain) {
272+
for (let i = bytesRead; i < this.length && bytesRead < this.blockRemain; i++) {
273+
this.buf[i + this.offset] = 0
274+
bytesRead++
275+
this.remain++
254276
}
255277
}
256278

257-
const writeBuf = offset === 0 && bytesRead === buf.length ?
258-
buf : buf.slice(offset, offset + bytesRead)
259-
remain -= bytesRead
260-
blockRemain -= bytesRead
261-
pos += bytesRead
262-
offset += bytesRead
279+
const writeBuf = this.offset === 0 && bytesRead === this.buf.length ?
280+
this.buf : this.buf.slice(this.offset, this.offset + bytesRead)
281+
this.remain -= bytesRead
282+
this.blockRemain -= bytesRead
283+
this.pos += bytesRead
284+
this.offset += bytesRead
263285

264286
this.write(writeBuf)
265287

266-
if (!remain) {
267-
if (blockRemain)
268-
this.write(Buffer.alloc(blockRemain))
269-
this.end()
270-
this[CLOSE](fd, _ => _)
271-
return
288+
if (!this.remain) {
289+
if (this.blockRemain)
290+
this.write(Buffer.alloc(this.blockRemain))
291+
return this[CLOSE](/* istanbul ignore next - legacy */
292+
er => er ? this.emit('error', er) : this.end())
272293
}
273294

274-
if (offset >= length) {
275-
buf = Buffer.allocUnsafe(length)
276-
offset = 0
295+
if (this.offset >= this.length) {
296+
// if we only have a smaller bit left to read, alloc a smaller buffer
297+
// otherwise, keep it the same length it was before.
298+
this.buf = Buffer.allocUnsafe(Math.min(this.blockRemain, this.buf.length))
299+
this.offset = 0
277300
}
278-
length = buf.length - offset
279-
this[READ](fd, buf, offset, length, pos, remain, blockRemain)
301+
this.length = this.buf.length - this.offset
302+
this[READ]()
280303
}
281304
})
282305

@@ -297,20 +320,27 @@ class WriteEntrySync extends WriteEntry {
297320
this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
298321
}
299322

300-
[READ] (fd, buf, offset, length, pos, remain, blockRemain) {
323+
[READ] () {
301324
let threw = true
302325
try {
326+
const { fd, buf, offset, length, pos } = this
303327
const bytesRead = fs.readSync(fd, buf, offset, length, pos)
304-
this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
328+
this[ONREAD](bytesRead)
305329
threw = false
306330
} finally {
307-
if (threw)
308-
try { this[CLOSE](fd) } catch (er) {}
331+
// ignoring the error from close(2) is a bad practice, but at
332+
// this point we already have an error, don't need another one
333+
if (threw) {
334+
try {
335+
this[CLOSE](() => {})
336+
} catch (er) {}
337+
}
309338
}
310339
}
311340

312-
[CLOSE] (fd) {
313-
fs.closeSync(fd)
341+
[CLOSE] (cb) {
342+
fs.closeSync(this.fd)
343+
cb()
314344
}
315345
}
316346

0 commit comments

Comments
 (0)