• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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