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