11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayPrototypePush,
51cb0ef41Sopenharmony_ci  ArrayPrototypeShift,
61cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
71cb0ef41Sopenharmony_ci  ObjectDefineProperty,
81cb0ef41Sopenharmony_ci  PromiseReject,
91cb0ef41Sopenharmony_ci  Symbol,
101cb0ef41Sopenharmony_ci  SymbolAsyncIterator,
111cb0ef41Sopenharmony_ci} = primordials;
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciconst pathModule = require('path');
141cb0ef41Sopenharmony_ciconst binding = internalBinding('fs');
151cb0ef41Sopenharmony_ciconst dirBinding = internalBinding('fs_dir');
161cb0ef41Sopenharmony_ciconst {
171cb0ef41Sopenharmony_ci  codes: {
181cb0ef41Sopenharmony_ci    ERR_DIR_CLOSED,
191cb0ef41Sopenharmony_ci    ERR_DIR_CONCURRENT_OPERATION,
201cb0ef41Sopenharmony_ci    ERR_MISSING_ARGS,
211cb0ef41Sopenharmony_ci  },
221cb0ef41Sopenharmony_ci} = require('internal/errors');
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst { FSReqCallback } = binding;
251cb0ef41Sopenharmony_ciconst internalUtil = require('internal/util');
261cb0ef41Sopenharmony_ciconst {
271cb0ef41Sopenharmony_ci  getDirent,
281cb0ef41Sopenharmony_ci  getOptions,
291cb0ef41Sopenharmony_ci  getValidatedPath,
301cb0ef41Sopenharmony_ci  handleErrorFromBinding,
311cb0ef41Sopenharmony_ci} = require('internal/fs/utils');
321cb0ef41Sopenharmony_ciconst {
331cb0ef41Sopenharmony_ci  validateFunction,
341cb0ef41Sopenharmony_ci  validateUint32,
351cb0ef41Sopenharmony_ci} = require('internal/validators');
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciconst kDirHandle = Symbol('kDirHandle');
381cb0ef41Sopenharmony_ciconst kDirPath = Symbol('kDirPath');
391cb0ef41Sopenharmony_ciconst kDirBufferedEntries = Symbol('kDirBufferedEntries');
401cb0ef41Sopenharmony_ciconst kDirClosed = Symbol('kDirClosed');
411cb0ef41Sopenharmony_ciconst kDirOptions = Symbol('kDirOptions');
421cb0ef41Sopenharmony_ciconst kDirReadImpl = Symbol('kDirReadImpl');
431cb0ef41Sopenharmony_ciconst kDirReadPromisified = Symbol('kDirReadPromisified');
441cb0ef41Sopenharmony_ciconst kDirClosePromisified = Symbol('kDirClosePromisified');
451cb0ef41Sopenharmony_ciconst kDirOperationQueue = Symbol('kDirOperationQueue');
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciclass Dir {
481cb0ef41Sopenharmony_ci  constructor(handle, path, options) {
491cb0ef41Sopenharmony_ci    if (handle == null) throw new ERR_MISSING_ARGS('handle');
501cb0ef41Sopenharmony_ci    this[kDirHandle] = handle;
511cb0ef41Sopenharmony_ci    this[kDirBufferedEntries] = [];
521cb0ef41Sopenharmony_ci    this[kDirPath] = path;
531cb0ef41Sopenharmony_ci    this[kDirClosed] = false;
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci    // Either `null` or an Array of pending operations (= functions to be called
561cb0ef41Sopenharmony_ci    // once the current operation is done).
571cb0ef41Sopenharmony_ci    this[kDirOperationQueue] = null;
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci    this[kDirOptions] = {
601cb0ef41Sopenharmony_ci      bufferSize: 32,
611cb0ef41Sopenharmony_ci      ...getOptions(options, {
621cb0ef41Sopenharmony_ci        encoding: 'utf8',
631cb0ef41Sopenharmony_ci      }),
641cb0ef41Sopenharmony_ci    };
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci    validateUint32(this[kDirOptions].bufferSize, 'options.bufferSize', true);
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci    this[kDirReadPromisified] = FunctionPrototypeBind(
691cb0ef41Sopenharmony_ci      internalUtil.promisify(this[kDirReadImpl]), this, false);
701cb0ef41Sopenharmony_ci    this[kDirClosePromisified] = FunctionPrototypeBind(
711cb0ef41Sopenharmony_ci      internalUtil.promisify(this.close), this);
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  get path() {
751cb0ef41Sopenharmony_ci    return this[kDirPath];
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  read(callback) {
791cb0ef41Sopenharmony_ci    return this[kDirReadImpl](true, callback);
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  [kDirReadImpl](maybeSync, callback) {
831cb0ef41Sopenharmony_ci    if (this[kDirClosed] === true) {
841cb0ef41Sopenharmony_ci      throw new ERR_DIR_CLOSED();
851cb0ef41Sopenharmony_ci    }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci    if (callback === undefined) {
881cb0ef41Sopenharmony_ci      return this[kDirReadPromisified]();
891cb0ef41Sopenharmony_ci    }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    if (this[kDirOperationQueue] !== null) {
941cb0ef41Sopenharmony_ci      ArrayPrototypePush(this[kDirOperationQueue], () => {
951cb0ef41Sopenharmony_ci        this[kDirReadImpl](maybeSync, callback);
961cb0ef41Sopenharmony_ci      });
971cb0ef41Sopenharmony_ci      return;
981cb0ef41Sopenharmony_ci    }
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci    if (this[kDirBufferedEntries].length > 0) {
1011cb0ef41Sopenharmony_ci      try {
1021cb0ef41Sopenharmony_ci        const dirent = ArrayPrototypeShift(this[kDirBufferedEntries]);
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci        if (this[kDirOptions].recursive && dirent.isDirectory()) {
1051cb0ef41Sopenharmony_ci          this.readSyncRecursive(dirent);
1061cb0ef41Sopenharmony_ci        }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci        if (maybeSync)
1091cb0ef41Sopenharmony_ci          process.nextTick(callback, null, dirent);
1101cb0ef41Sopenharmony_ci        else
1111cb0ef41Sopenharmony_ci          callback(null, dirent);
1121cb0ef41Sopenharmony_ci        return;
1131cb0ef41Sopenharmony_ci      } catch (error) {
1141cb0ef41Sopenharmony_ci        return callback(error);
1151cb0ef41Sopenharmony_ci      }
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    const req = new FSReqCallback();
1191cb0ef41Sopenharmony_ci    req.oncomplete = (err, result) => {
1201cb0ef41Sopenharmony_ci      process.nextTick(() => {
1211cb0ef41Sopenharmony_ci        const queue = this[kDirOperationQueue];
1221cb0ef41Sopenharmony_ci        this[kDirOperationQueue] = null;
1231cb0ef41Sopenharmony_ci        for (const op of queue) op();
1241cb0ef41Sopenharmony_ci      });
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci      if (err || result === null) {
1271cb0ef41Sopenharmony_ci        return callback(err, result);
1281cb0ef41Sopenharmony_ci      }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci      try {
1311cb0ef41Sopenharmony_ci        this.processReadResult(this[kDirPath], result);
1321cb0ef41Sopenharmony_ci        const dirent = ArrayPrototypeShift(this[kDirBufferedEntries]);
1331cb0ef41Sopenharmony_ci        if (this[kDirOptions].recursive && dirent.isDirectory()) {
1341cb0ef41Sopenharmony_ci          this.readSyncRecursive(dirent);
1351cb0ef41Sopenharmony_ci        }
1361cb0ef41Sopenharmony_ci        callback(null, dirent);
1371cb0ef41Sopenharmony_ci      } catch (error) {
1381cb0ef41Sopenharmony_ci        callback(error);
1391cb0ef41Sopenharmony_ci      }
1401cb0ef41Sopenharmony_ci    };
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci    this[kDirOperationQueue] = [];
1431cb0ef41Sopenharmony_ci    this[kDirHandle].read(
1441cb0ef41Sopenharmony_ci      this[kDirOptions].encoding,
1451cb0ef41Sopenharmony_ci      this[kDirOptions].bufferSize,
1461cb0ef41Sopenharmony_ci      req,
1471cb0ef41Sopenharmony_ci    );
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  processReadResult(path, result) {
1511cb0ef41Sopenharmony_ci    for (let i = 0; i < result.length; i += 2) {
1521cb0ef41Sopenharmony_ci      ArrayPrototypePush(
1531cb0ef41Sopenharmony_ci        this[kDirBufferedEntries],
1541cb0ef41Sopenharmony_ci        getDirent(
1551cb0ef41Sopenharmony_ci          path,
1561cb0ef41Sopenharmony_ci          result[i],
1571cb0ef41Sopenharmony_ci          result[i + 1],
1581cb0ef41Sopenharmony_ci          true, // Quirk to not introduce a breaking change.
1591cb0ef41Sopenharmony_ci        ),
1601cb0ef41Sopenharmony_ci      );
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  readSyncRecursive(dirent) {
1651cb0ef41Sopenharmony_ci    const ctx = { path: dirent.path };
1661cb0ef41Sopenharmony_ci    const handle = dirBinding.opendir(
1671cb0ef41Sopenharmony_ci      pathModule.toNamespacedPath(dirent.path),
1681cb0ef41Sopenharmony_ci      this[kDirOptions].encoding,
1691cb0ef41Sopenharmony_ci      undefined,
1701cb0ef41Sopenharmony_ci      ctx,
1711cb0ef41Sopenharmony_ci    );
1721cb0ef41Sopenharmony_ci    handleErrorFromBinding(ctx);
1731cb0ef41Sopenharmony_ci    const result = handle.read(
1741cb0ef41Sopenharmony_ci      this[kDirOptions].encoding,
1751cb0ef41Sopenharmony_ci      this[kDirOptions].bufferSize,
1761cb0ef41Sopenharmony_ci      undefined,
1771cb0ef41Sopenharmony_ci      ctx,
1781cb0ef41Sopenharmony_ci    );
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci    if (result) {
1811cb0ef41Sopenharmony_ci      this.processReadResult(dirent.path, result);
1821cb0ef41Sopenharmony_ci    }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci    handle.close(undefined, ctx);
1851cb0ef41Sopenharmony_ci    handleErrorFromBinding(ctx);
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  readSync() {
1891cb0ef41Sopenharmony_ci    if (this[kDirClosed] === true) {
1901cb0ef41Sopenharmony_ci      throw new ERR_DIR_CLOSED();
1911cb0ef41Sopenharmony_ci    }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci    if (this[kDirOperationQueue] !== null) {
1941cb0ef41Sopenharmony_ci      throw new ERR_DIR_CONCURRENT_OPERATION();
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci    if (this[kDirBufferedEntries].length > 0) {
1981cb0ef41Sopenharmony_ci      const dirent = ArrayPrototypeShift(this[kDirBufferedEntries]);
1991cb0ef41Sopenharmony_ci      if (this[kDirOptions].recursive && dirent.isDirectory()) {
2001cb0ef41Sopenharmony_ci        this.readSyncRecursive(dirent);
2011cb0ef41Sopenharmony_ci      }
2021cb0ef41Sopenharmony_ci      return dirent;
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci    const ctx = { path: this[kDirPath] };
2061cb0ef41Sopenharmony_ci    const result = this[kDirHandle].read(
2071cb0ef41Sopenharmony_ci      this[kDirOptions].encoding,
2081cb0ef41Sopenharmony_ci      this[kDirOptions].bufferSize,
2091cb0ef41Sopenharmony_ci      undefined,
2101cb0ef41Sopenharmony_ci      ctx,
2111cb0ef41Sopenharmony_ci    );
2121cb0ef41Sopenharmony_ci    handleErrorFromBinding(ctx);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    if (result === null) {
2151cb0ef41Sopenharmony_ci      return result;
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    this.processReadResult(this[kDirPath], result);
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci    const dirent = ArrayPrototypeShift(this[kDirBufferedEntries]);
2211cb0ef41Sopenharmony_ci    if (this[kDirOptions].recursive && dirent.isDirectory()) {
2221cb0ef41Sopenharmony_ci      this.readSyncRecursive(dirent);
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci    return dirent;
2251cb0ef41Sopenharmony_ci  }
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  close(callback) {
2281cb0ef41Sopenharmony_ci    // Promise
2291cb0ef41Sopenharmony_ci    if (callback === undefined) {
2301cb0ef41Sopenharmony_ci      if (this[kDirClosed] === true) {
2311cb0ef41Sopenharmony_ci        return PromiseReject(new ERR_DIR_CLOSED());
2321cb0ef41Sopenharmony_ci      }
2331cb0ef41Sopenharmony_ci      return this[kDirClosePromisified]();
2341cb0ef41Sopenharmony_ci    }
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci    // callback
2371cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci    if (this[kDirClosed] === true) {
2401cb0ef41Sopenharmony_ci      process.nextTick(callback, new ERR_DIR_CLOSED());
2411cb0ef41Sopenharmony_ci      return;
2421cb0ef41Sopenharmony_ci    }
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci    if (this[kDirOperationQueue] !== null) {
2451cb0ef41Sopenharmony_ci      ArrayPrototypePush(this[kDirOperationQueue], () => {
2461cb0ef41Sopenharmony_ci        this.close(callback);
2471cb0ef41Sopenharmony_ci      });
2481cb0ef41Sopenharmony_ci      return;
2491cb0ef41Sopenharmony_ci    }
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci    this[kDirClosed] = true;
2521cb0ef41Sopenharmony_ci    const req = new FSReqCallback();
2531cb0ef41Sopenharmony_ci    req.oncomplete = callback;
2541cb0ef41Sopenharmony_ci    this[kDirHandle].close(req);
2551cb0ef41Sopenharmony_ci  }
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  closeSync() {
2581cb0ef41Sopenharmony_ci    if (this[kDirClosed] === true) {
2591cb0ef41Sopenharmony_ci      throw new ERR_DIR_CLOSED();
2601cb0ef41Sopenharmony_ci    }
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci    if (this[kDirOperationQueue] !== null) {
2631cb0ef41Sopenharmony_ci      throw new ERR_DIR_CONCURRENT_OPERATION();
2641cb0ef41Sopenharmony_ci    }
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci    this[kDirClosed] = true;
2671cb0ef41Sopenharmony_ci    const ctx = { path: this[kDirPath] };
2681cb0ef41Sopenharmony_ci    const result = this[kDirHandle].close(undefined, ctx);
2691cb0ef41Sopenharmony_ci    handleErrorFromBinding(ctx);
2701cb0ef41Sopenharmony_ci    return result;
2711cb0ef41Sopenharmony_ci  }
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  async* entries() {
2741cb0ef41Sopenharmony_ci    try {
2751cb0ef41Sopenharmony_ci      while (true) {
2761cb0ef41Sopenharmony_ci        const result = await this[kDirReadPromisified]();
2771cb0ef41Sopenharmony_ci        if (result === null) {
2781cb0ef41Sopenharmony_ci          break;
2791cb0ef41Sopenharmony_ci        }
2801cb0ef41Sopenharmony_ci        yield result;
2811cb0ef41Sopenharmony_ci      }
2821cb0ef41Sopenharmony_ci    } finally {
2831cb0ef41Sopenharmony_ci      await this[kDirClosePromisified]();
2841cb0ef41Sopenharmony_ci    }
2851cb0ef41Sopenharmony_ci  }
2861cb0ef41Sopenharmony_ci}
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ciObjectDefineProperty(Dir.prototype, SymbolAsyncIterator, {
2891cb0ef41Sopenharmony_ci  __proto__: null,
2901cb0ef41Sopenharmony_ci  value: Dir.prototype.entries,
2911cb0ef41Sopenharmony_ci  enumerable: false,
2921cb0ef41Sopenharmony_ci  writable: true,
2931cb0ef41Sopenharmony_ci  configurable: true,
2941cb0ef41Sopenharmony_ci});
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_cifunction opendir(path, options, callback) {
2971cb0ef41Sopenharmony_ci  callback = typeof options === 'function' ? options : callback;
2981cb0ef41Sopenharmony_ci  validateFunction(callback, 'callback');
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  path = getValidatedPath(path);
3011cb0ef41Sopenharmony_ci  options = getOptions(options, {
3021cb0ef41Sopenharmony_ci    encoding: 'utf8',
3031cb0ef41Sopenharmony_ci  });
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci  function opendirCallback(error, handle) {
3061cb0ef41Sopenharmony_ci    if (error) {
3071cb0ef41Sopenharmony_ci      callback(error);
3081cb0ef41Sopenharmony_ci    } else {
3091cb0ef41Sopenharmony_ci      callback(null, new Dir(handle, path, options));
3101cb0ef41Sopenharmony_ci    }
3111cb0ef41Sopenharmony_ci  }
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  const req = new FSReqCallback();
3141cb0ef41Sopenharmony_ci  req.oncomplete = opendirCallback;
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  dirBinding.opendir(
3171cb0ef41Sopenharmony_ci    pathModule.toNamespacedPath(path),
3181cb0ef41Sopenharmony_ci    options.encoding,
3191cb0ef41Sopenharmony_ci    req,
3201cb0ef41Sopenharmony_ci  );
3211cb0ef41Sopenharmony_ci}
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_cifunction opendirSync(path, options) {
3241cb0ef41Sopenharmony_ci  path = getValidatedPath(path);
3251cb0ef41Sopenharmony_ci  options = getOptions(options, {
3261cb0ef41Sopenharmony_ci    encoding: 'utf8',
3271cb0ef41Sopenharmony_ci  });
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  const ctx = { path };
3301cb0ef41Sopenharmony_ci  const handle = dirBinding.opendir(
3311cb0ef41Sopenharmony_ci    pathModule.toNamespacedPath(path),
3321cb0ef41Sopenharmony_ci    options.encoding,
3331cb0ef41Sopenharmony_ci    undefined,
3341cb0ef41Sopenharmony_ci    ctx,
3351cb0ef41Sopenharmony_ci  );
3361cb0ef41Sopenharmony_ci  handleErrorFromBinding(ctx);
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  return new Dir(handle, path, options);
3391cb0ef41Sopenharmony_ci}
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_cimodule.exports = {
3421cb0ef41Sopenharmony_ci  Dir,
3431cb0ef41Sopenharmony_ci  opendir,
3441cb0ef41Sopenharmony_ci  opendirSync,
3451cb0ef41Sopenharmony_ci};
346