1'use strict'; 2 3const { 4 MathMin, 5} = primordials; 6 7const { 8 constants: { 9 kReadFileBufferLength, 10 kReadFileUnknownBufferLength, 11 } 12} = require('internal/fs/utils'); 13 14const { Buffer } = require('buffer'); 15 16const { FSReqCallback, close, read } = internalBinding('fs'); 17 18const { hideStackFrames } = require('internal/errors'); 19 20 21let DOMException; 22const lazyDOMException = hideStackFrames((message, name) => { 23 if (DOMException === undefined) 24 DOMException = internalBinding('messaging').DOMException; 25 return new DOMException(message, name); 26}); 27 28function readFileAfterRead(err, bytesRead) { 29 const context = this.context; 30 31 if (err) 32 return context.close(err); 33 34 context.pos += bytesRead; 35 36 if (context.pos === context.size || bytesRead === 0) { 37 context.close(); 38 } else { 39 if (context.size === 0) { 40 // Unknown size, just read until we don't get bytes. 41 const buffer = bytesRead === kReadFileUnknownBufferLength ? 42 context.buffer : context.buffer.slice(0, bytesRead); 43 context.buffers.push(buffer); 44 } 45 context.read(); 46 } 47} 48 49function readFileAfterClose(err) { 50 const context = this.context; 51 const callback = context.callback; 52 let buffer = null; 53 54 if (context.err || err) 55 return callback(context.err || err); 56 57 try { 58 if (context.size === 0) 59 buffer = Buffer.concat(context.buffers, context.pos); 60 else if (context.pos < context.size) 61 buffer = context.buffer.slice(0, context.pos); 62 else 63 buffer = context.buffer; 64 65 if (context.encoding) 66 buffer = buffer.toString(context.encoding); 67 } catch (err) { 68 return callback(err); 69 } 70 71 callback(null, buffer); 72} 73 74class ReadFileContext { 75 constructor(callback, encoding) { 76 this.fd = undefined; 77 this.isUserFd = undefined; 78 this.size = 0; 79 this.callback = callback; 80 this.buffers = null; 81 this.buffer = null; 82 this.pos = 0; 83 this.encoding = encoding; 84 this.err = null; 85 this.signal = undefined; 86 } 87 88 read() { 89 let buffer; 90 let offset; 91 let length; 92 93 if (this.signal && this.signal.aborted) { 94 return this.close( 95 lazyDOMException('The operation was aborted', 'AbortError') 96 ); 97 } 98 if (this.size === 0) { 99 buffer = Buffer.allocUnsafeSlow(kReadFileUnknownBufferLength); 100 offset = 0; 101 length = kReadFileUnknownBufferLength; 102 this.buffer = buffer; 103 } else { 104 buffer = this.buffer; 105 offset = this.pos; 106 length = MathMin(kReadFileBufferLength, this.size - this.pos); 107 } 108 109 const req = new FSReqCallback(); 110 req.oncomplete = readFileAfterRead; 111 req.context = this; 112 113 read(this.fd, buffer, offset, length, -1, req); 114 } 115 116 close(err) { 117 if (this.isUserFd) { 118 process.nextTick(function tick(context) { 119 readFileAfterClose.call({ context }, null); 120 }, this); 121 return; 122 } 123 124 const req = new FSReqCallback(); 125 req.oncomplete = readFileAfterClose; 126 req.context = this; 127 this.err = err; 128 129 close(this.fd, req); 130 } 131} 132 133module.exports = ReadFileContext; 134