Skip to content

Commit 786c513

Browse files
SourceControl: add basic support for symlinks
The contents of a symlink is the path to which it points. We can simply read the contents as a new path, and use `getEntry` to get the contents of the symbolic link. This implementation should also fully traverse any path that is a series of symbolic link. This does allow for a DoS attack by creating a recursive symbolic link cycle (e.g. `a` -> `b` -> `a`). Fixes: #7081 Co-authored-by: Max Desiatov <[email protected]>
1 parent 103d275 commit 786c513

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

Sources/SourceControl/GitRepository.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,14 @@ public final class GitRepository: Repository, WorkingCheckout {
914914
}
915915
}
916916
}
917+
918+
/// Read a symbolic link.
919+
func readLink(hash: Hash) throws -> String {
920+
return try callGit(
921+
"cat-file", "-p", String(describing: hash.bytes),
922+
failureMessage: "Couldn't read '\(String(describing: hash.bytes))'"
923+
)
924+
}
917925
}
918926

919927
// MARK: - GitFileSystemView
@@ -1074,13 +1082,18 @@ private class GitFileSystemView: FileSystem {
10741082
guard entry.type != .tree else {
10751083
throw FileSystemError(.isDirectory, path)
10761084
}
1077-
guard entry.type != .symlink else {
1078-
throw InternalError("symlinks not supported")
1079-
}
10801085
guard case .hash(let hash) = entry.location else {
10811086
throw InternalError("only hash locations supported")
10821087
}
1083-
return try self.repository.readBlob(hash: hash)
1088+
switch entry.type {
1089+
case .symlink:
1090+
let path = try repository.readLink(hash: hash)
1091+
return try readFileContents(TSCAbsolutePath(validating: path))
1092+
case .blob:
1093+
return try self.repository.readBlob(hash: hash)
1094+
default:
1095+
fatalError()
1096+
}
10841097
}
10851098

10861099
// MARK: Unsupported methods.

0 commit comments

Comments
 (0)