@ 261106.2
current
'use strict';

const {
  FunctionPrototypeBind,
  ObjectDefineProperty,
  SafeMap,
  Symbol,
} = primordials;

// Private symbols
const kFd = Symbol('kFd');
const kEntry = Symbol('kEntry');

// VFS FDs use bit 30 set to avoid conflicts with real OS fds.
// Real fds are small non-negative integers; VFS fds start at 0x40000000.
const VFS_FD_MASK = 0x40000000;
let nextFd = 0;

// Global registry of open virtual file descriptors
const openFDs = new SafeMap();

/**
 * Represents an open virtual file descriptor.
 * Wraps a VirtualFileHandle from the provider.
 */
class VirtualFD {
  /**
   * @param {number} fd The file descriptor number
   * @param {VirtualFileHandle} entry The virtual file handle
   */
  constructor(fd, entry) {
    this[kFd] = fd;
    this[kEntry] = entry;
  }

  /**
   * Gets the file descriptor number.
   * @returns {number}
   */
  get fd() {
    return this[kFd];
  }

  /**
   * Gets the file handle.
   * @returns {VirtualFileHandle}
   */
  get entry() {
    return this[kEntry];
  }

  getAsyncId() {
    return this[kFd];
  }

  async close() {
    await this[kEntry].close();
    closeVirtualFd(this[kFd]);
  }

  closeSync() {
    this[kEntry].closeSync();
    closeVirtualFd(this[kFd]);
  }
}

const vfsFileHandleMethods = [
  'appendFile', 'chmod', 'chown', 'datasync', 'sync', 'read', 'readv',
  'readFile', 'stat', 'truncate', 'utimes', 'write', 'writev', 'writeFile',
];
let FileHandle;

function createVfsFileHandle(vfd) {
  FileHandle ??= require('internal/fs/promises').FileHandle;
  const fileHandle = new FileHandle(vfd);
  const entry = vfd.entry;
  for (let i = 0; i < vfsFileHandleMethods.length; i++) {
    const method = vfsFileHandleMethods[i];
    ObjectDefineProperty(fileHandle, method, {
      __proto__: null,
      configurable: true,
      value: FunctionPrototypeBind(entry[method], entry),
      writable: true,
    });
  }
  return fileHandle;
}

/**
 * Opens a virtual file and returns its file descriptor.
 * @param {VirtualFileHandle} entry The virtual file handle
 * @returns {number} The file descriptor
 */
function openVirtualFd(entry) {
  const fd = VFS_FD_MASK | nextFd++;
  const vfd = new VirtualFD(fd, entry);
  openFDs.set(fd, vfd);
  return fd;
}

/**
 * Gets a VirtualFD by its file descriptor number.
 * @param {number} fd The file descriptor number
 * @returns {VirtualFD|undefined}
 */
function getVirtualFd(fd) {
  return openFDs.get(fd);
}

/**
 * Closes a virtual file descriptor.
 * @param {number} fd The file descriptor number
 * @returns {boolean} True if the fd was found and closed
 */
function closeVirtualFd(fd) {
  return openFDs.delete(fd);
}

module.exports = {
  VFS_FD_MASK,
  VirtualFD,
  createVfsFileHandle,
  openVirtualFd,
  getVirtualFd,
  closeVirtualFd,
};