HEX
Server: nginx/1.18.0
System: Linux test-ipsremont 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
User: ips (1000)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //var/www/quadcode.com/node_modules/directory-tree/lib/directory-tree.js
'use strict';

const FS = require('fs');
const PATH = require('path');
const constants = {
  DIRECTORY: 'directory',
  FILE: 'file'
}

function safeReadDirSync (path) {
  let dirData = {};
  try {
    dirData = FS.readdirSync(path);
  } catch(ex) {
    if (ex.code == "EACCES" || ex.code == "EPERM") {
      //User does not have permissions, ignore directory
      return null;
    }
    else throw ex;
  }
  return dirData;
}

/**
 * Normalizes windows style paths by replacing double backslahes with single forward slahes (unix style).
 * @param  {string} path
 * @return {string}
 */
function normalizePath(path) {
  return path.replace(/\\/g, '/');
}

/**
 * Tests if the supplied parameter is of type RegExp
 * @param  {any}  regExp
 * @return {Boolean}
 */
function isRegExp(regExp) {
  return typeof regExp === "object" && regExp.constructor == RegExp;
}

/**
 * Collects the files and folders for a directory path into an Object, subject
 * to the options supplied, and invoking optional
 * @param  {String} path
 * @param  {Object} options
 * @param  {function} onEachFile
 * @param  {function} onEachDirectory
 * @return {Object}
 */
function directoryTree (path, options, onEachFile, onEachDirectory, currentDepth = 0) {
  options = options || {};

  if (options.depth !== undefined && options.attributes && options.attributes.indexOf('size') !== -1) {
    throw new Error('usage of size attribute with depth option is prohibited');
  }

  const name = PATH.basename(path);
  path = options.normalizePath ? normalizePath(path) : path;
  const item = { path, name };
  let stats;
  let lstat;

  try {
    stats = FS.statSync(path);
    lstat = FS.lstatSync(path);
  }
  catch (e) { return null }

  // Skip if it matches the exclude regex
  if (options.exclude) {
    const excludes =  isRegExp(options.exclude) ? [options.exclude] : options.exclude;
    if (excludes.some((exclusion) => exclusion.test(path))) {
      return null;
    }
  }

  if (lstat.isSymbolicLink()) {
    item.isSymbolicLink = true;
    // Skip if symbolic links should not be followed
    if (options.followSymlinks === false)
      return null;
    // Initialize the symbolic links array to avoid infinite loops
    if (!options.symlinks)
      options = { ...options, symlinks: [] };
    // Skip if a cyclic symbolic link has been found
    if (options.symlinks.find(ino => ino === lstat.ino)) {
      return null;
    } else {
      options.symlinks.push(lstat.ino);
    }
  }

  if (stats.isFile()) {

    const ext = PATH.extname(path).toLowerCase();

    // Skip if it does not match the extension regex
    if (options.extensions && !options.extensions.test(ext))
      return null;


    if (options.attributes) {
      options.attributes.forEach((attribute) => {
        switch (attribute) {
          case 'extension':
            item.extension = ext;
            break;
          case 'type':
            item.type = constants.FILE;
            break;
          default:
            item[attribute] = stats[attribute];
            break;
        }
      });
    }

    if (onEachFile) {
      onEachFile(item, path, stats);
    }
  }
  else if (stats.isDirectory()) {
    let dirData = safeReadDirSync(path);
    if (dirData === null) return null;

    if (options.depth === undefined || options.depth > currentDepth) {
      item.children = dirData
          .map(child => directoryTree(PATH.join(path, child), options, onEachFile, onEachDirectory, currentDepth + 1))
          .filter(e => !!e);
    }

    if (options.attributes) {
      options.attributes.forEach((attribute) => {
        switch (attribute) {
          case 'size':
            item.size = item.children.reduce((prev, cur) => prev + cur.size, 0);
            break;
          case 'type':
            item.type = constants.DIRECTORY;
            break;
          case 'extension':
            break;
          default:
            item[attribute] = stats[attribute];
            break;
        }
        
      });
    }

    if (onEachDirectory) {
      onEachDirectory(item, path, stats);
    }
  } else {
    return null; // Or set item.size = 0 for devices, FIFO and sockets ?
  }
  return item;
}

module.exports = directoryTree;