function map_directory()

in scripts/sandpit/harden_directory.php [122:197]


function map_directory($dir) {
  try {
    if (Filesystem::pathExists($dir.'/.git')) {
      list($list) = execx(
        '(cd %s && git ls-tree -r --full-tree --abbrev=40 HEAD)',
        $dir);
      $list = trim($list);
      $list = explode("\n", $list);

      $map = array();
      foreach ($list as $line) {
        $matches = null;
        $regexp  = '/^(\d{6}) (\w+) ([a-z0-9]{40})\t(.*)$/';
        if (!preg_match($regexp, $line, $matches)) {
          throw new Exception(pht("Unable to parse line '%s'!", $line));
        }
        $flag = $matches[1];
        $type = $matches[2];
        $hash = $matches[3];
        $file = $matches[4];
        if ($type === 'commit') {
          // Deal with Git submodules.
          $submap = map_directory($dir.'/'.$file);
          foreach ($submap as $subfile => $info) {
            $map[$file.'/'.$subfile] = $info;
          }
        } else {
          $mask = (int)base_convert($flag, 8, 10);
          $type = 'file';
          if ($mask & 0111) {
            echo pht('EXEC: %s', $file)."\n";
            $type = 'exec';
          } else if (($mask & 0120000) === 0120000) {
            $type = 'link';
          }
          $map[$file] = array(
            'hash' => $hash,
            'type' => $type,
          );
        }
      }
      return $map;
    }
  } catch (Exception $ex) {
    phlog($ex);
    // Just drop down and go with the non-git approach.
  }

  $files = id(new FileFinder($dir))
    ->withType('f')
    ->excludePath('*/.git/*')
    ->excludePath('*/.svn/*')
    ->find();
  foreach ($files as $file) {
    if (!strncmp($file, './', 2)) {
      $file = substr($file, 2);
    }
    $data = Filesystem::readFile($dir.'/'.$file);
    $len  = strlen($data);
    $hash = sha1("blob {$len}\0{$data}");

    $type = 'file';
    if (is_link($dir.'/'.$file)) {
      $type = 'link';
    } else if (is_executable($dir.'/'.$file)) {
      $type = 'exec';
    }

    $map[$file] = array(
      'hash' => $hash,
      'type' => $type,
    );
  }

  return $map;
}