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;
}