From 8e49aabcdbc20856c2b5558cf31d990463e8d2fe Mon Sep 17 00:00:00 2001 From: Eliah Kagan Date: Tue, 25 Jun 2024 17:53:48 -0400 Subject: [PATCH] fix: Always fall back to creating file symlinks on Windows 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 (#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 #1420, and also fixes #1421. --- gix-fs/src/symlink.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gix-fs/src/symlink.rs b/gix-fs/src/symlink.rs index ce639c48f65..5022332f264 100644 --- a/gix-fs/src/symlink.rs +++ b/gix-fs/src/symlink.rs @@ -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)