Skip to content

Commit

Permalink
fix: Always fall back to creating file symlinks on Windows
Browse files Browse the repository at this point in the history
When the metadata of a symlink's target cannot be obtained, even if
the error is something other than `NotFound`, this falls back to
creating file symbolic links. This only affects scenarios where
either the checkout would fail entirely or where the symlink would
have been treated as a collision and skipped (even though it was
not really a collision, since only its target had an error). Other
cases are not affected, and all exisitng scenarios where directory
symlink would be created will still create directory symlinks.

This builds on 31d02a8 (GitoxideLabs#1363) by supporting dangling symlinks even
when the target filenames are unusual, such as when the name is
invalid or reserved. Windows permits such symlinks to be created,
and going ahead and creating the matches the Git behavior.

This should also support other errors beisdes `NotFound`. For
example, some permissions-related errors, in some cases where
traversal or acccess (even to access metadata) are not allowed,
would fail to create a symlink. This should address that as well.

This works by using `Path::is_dir()` in the standard library, which
automatically converts all errors (not just `NotFound`) into
`false`. The logic here is thus quite similar to what was already
present, just more tolerant, even though the code itself is shorter
and simpler.

This fixes GitoxideLabs#1420, and also fixes GitoxideLabs#1421.
  • Loading branch information
EliahKagan authored and LuaKT committed Aug 20, 2024
1 parent 69f3c5b commit 8e49aab
Showing 1 changed file with 1 addition and 6 deletions.
7 changes: 1 addition & 6 deletions gix-fs/src/symlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,7 @@ pub fn create(original: &Path, link: &Path) -> io::Result<()> {
use std::os::windows::fs::{symlink_dir, symlink_file};
// TODO: figure out if links to links count as files or whatever they point at
let orig_abs = link.parent().expect("dir for link").join(original);
let is_dir = match std::fs::metadata(orig_abs) {
Ok(m) => m.is_dir(),
Err(err) if err.kind() == io::ErrorKind::NotFound => false,
Err(err) => return Err(err),
};
if is_dir {
if orig_abs.is_dir() {
symlink_dir(original, link)
} else {
symlink_file(original, link)
Expand Down

0 comments on commit 8e49aab

Please sign in to comment.