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