UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

54 lines 2.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolvePhysicalTarget = resolvePhysicalTarget; const fs = require("fs"); const path = require("path"); const config_1 = require("../config"); const errors_1 = require("../errors"); // ANCHOR - Exported Functions /** * Resolves a symlink target to the physical path the kernel would read: it starts * from the link's real directory and walks the target segment by segment, following * each symlink component and taking the real parent on '..'. A missing tail resolves * lexically from the deepest real point (a dangling link stays where it points). * path.resolve and realpathSync both collapse '..' lexically, which disagrees with the * kernel across a symlinked component, so neither can guard the boundary. * * @param {string} linkDirAbs - The link's own directory (absolute). * @param {string} rawTarget - The raw link target as stored on disk. * @param {string} linkRel - The link's POSIX-relative path for error messages. * @param {number} depth - The current symlink-following depth. * @returns {string} The physical target path. */ function resolvePhysicalTarget(linkDirAbs, rawTarget, linkRel, depth = 0) { if (depth > config_1.MAX_LINK_DEPTH) { throw new errors_1.RemoteBuildError('context', `${linkRel} resolves through too many symlinks`, 'Remove the link cycle, then re-run the build.'); } const absolute = path.isAbsolute(rawTarget); const startDir = fs.realpathSync(linkDirAbs); const root = absolute ? path.parse(rawTarget).root : ''; let current = absolute ? root : startDir; // The root is stripped before splitting so a drive-letter prefix never re-joins as a segment. const remainder = absolute ? rawTarget.slice(root.length) : rawTarget; for (const segment of remainder.split(/[\\/]+/)) { if (segment === '' || segment === '.') { continue; } if (segment === '..') { current = path.dirname(current); continue; } const next = path.join(current, segment); let stat; try { stat = fs.lstatSync(next); } catch (_a) { current = next; // missing from here on — resolve the remainder lexically continue; } current = stat.isSymbolicLink() ? resolvePhysicalTarget(path.dirname(next), fs.readlinkSync(next), linkRel, depth + 1) : next; } return current; } //# sourceMappingURL=symlink.js.map