2017-09-05 20:09:00 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
*
|
2018-02-17 02:24:55 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-09-05 20:09:00 +00:00
|
|
|
*/
|
|
|
|
|
2016-08-01 11:37:34 +00:00
|
|
|
const path = require('path');
|
|
|
|
const fs = require('fs');
|
|
|
|
|
2016-09-12 22:08:06 +00:00
|
|
|
/**
|
2016-09-15 12:22:07 +00:00
|
|
|
* Find and resolve symlinks in `lookupFolder`.
|
|
|
|
* Ignore any descendants of the paths in `ignoredRoots`.
|
2016-09-12 22:08:06 +00:00
|
|
|
*/
|
2016-09-15 12:22:07 +00:00
|
|
|
module.exports = function findSymlinksPaths(lookupFolder, ignoredRoots) {
|
2016-08-01 11:37:34 +00:00
|
|
|
const timeStart = Date.now();
|
|
|
|
const folders = fs.readdirSync(lookupFolder);
|
|
|
|
|
2016-09-15 12:22:07 +00:00
|
|
|
const resolvedSymlinks = [];
|
|
|
|
folders.forEach(folder => {
|
|
|
|
const visited = [];
|
|
|
|
|
|
|
|
let symlink = path.resolve(lookupFolder, folder);
|
|
|
|
while (fs.lstatSync(symlink).isSymbolicLink()) {
|
|
|
|
const index = visited.indexOf(symlink);
|
|
|
|
if (index !== -1) {
|
|
|
|
throw Error(
|
2017-10-10 00:37:08 +00:00
|
|
|
'Infinite symlink recursion detected:\n ' +
|
|
|
|
visited.slice(index).join('\n ')
|
2016-09-15 12:22:07 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
visited.push(symlink);
|
|
|
|
symlink = path.resolve(
|
|
|
|
path.dirname(symlink),
|
|
|
|
fs.readlinkSync(symlink)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (visited.length && !rootExists(ignoredRoots, symlink)) {
|
|
|
|
resolvedSymlinks.push(symlink);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const timeEnd = Date.now();
|
2016-08-01 11:37:34 +00:00
|
|
|
console.log(`Scanning ${folders.length} folders for symlinks in ${lookupFolder} (${timeEnd - timeStart}ms)`);
|
|
|
|
|
|
|
|
return resolvedSymlinks;
|
|
|
|
};
|
2016-09-15 12:22:07 +00:00
|
|
|
|
|
|
|
function rootExists(roots, child) {
|
|
|
|
return roots.some(root => isDescendant(root, child));
|
|
|
|
}
|
|
|
|
|
|
|
|
function isDescendant(root, child) {
|
|
|
|
return root === child || child.startsWith(root + path.sep);
|
|
|
|
}
|