safeResolvePath function

SafeResolvePathResult safeResolvePath(
  1. FsOperations fs,
  2. String filePath
)

Safely resolves a file path, handling symlinks and errors gracefully.

Error handling strategy:

  • If the file doesn't exist, returns the original path (allows for file creation)
  • If symlink resolution fails (broken symlink, permission denied, circular links), returns the original path and marks it as not a symlink
  • This ensures operations can continue with the original path rather than failing

Implementation

SafeResolvePathResult safeResolvePath(FsOperations fs, String filePath) {
  // Block UNC paths before any filesystem access to prevent network
  // requests (DNS/SMB) during validation on Windows
  if (filePath.startsWith('//') || filePath.startsWith('\\\\')) {
    return SafeResolvePathResult(
      resolvedPath: filePath,
      isSymlink: false,
      isCanonical: false,
    );
  }

  try {
    // Check for special file types (FIFOs, sockets, devices) before calling realpathSync.
    // realpathSync can block on FIFOs waiting for a writer, causing hangs.
    // If the file doesn't exist, lstatSync throws which the catch
    // below handles by returning the original path (allows file creation).
    final stats = fs.lstatSync(filePath);
    if (stats.isFIFO() ||
        stats.isSocket() ||
        stats.isCharacterDevice() ||
        stats.isBlockDevice()) {
      return SafeResolvePathResult(
        resolvedPath: filePath,
        isSymlink: false,
        isCanonical: false,
      );
    }

    final resolvedPath = fs.realpathSync(filePath);
    return SafeResolvePathResult(
      resolvedPath: resolvedPath,
      isSymlink: resolvedPath != filePath,
      // realpathSync returned: resolvedPath is canonical (all symlinks in
      // all path components resolved). Callers can skip further symlink
      // resolution on this path.
      isCanonical: true,
    );
  } catch (_) {
    // If lstat/realpath fails for any reason (ENOENT, broken symlink,
    // EACCES, ELOOP, etc.), return the original path to allow operations
    // to proceed
    return SafeResolvePathResult(
      resolvedPath: filePath,
      isSymlink: false,
      isCanonical: false,
    );
  }
}