Skip to content

Commit 9315dbf

Browse files
committed
fix: Probe executable bits by checking if we can change them
1 parent e343ed9 commit 9315dbf

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

gix-fs/src/capabilities.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,31 @@ impl Capabilities {
5757

5858
#[cfg(unix)]
5959
fn probe_file_mode(root: &Path) -> std::io::Result<bool> {
60-
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
60+
use std::os::unix::fs::{MetadataExt, OpenOptionsExt, PermissionsExt};
6161

62-
// test it exactly as we typically create executable files, not using chmod.
62+
// First check that we can create an executable file, then check that we
63+
// can change the executable bit.
64+
// The equivalent test by git itself is here:
65+
// https://github.com/git/git/blob/f0ef5b6d9bcc258e4cbef93839d1b7465d5212b9/setup.c#L2367-L2379
6366
let rand = fastrand::usize(..);
6467
let test_path = root.join(format!("_test_executable_bit{rand}"));
6568
let res = std::fs::OpenOptions::new()
6669
.create_new(true)
6770
.write(true)
6871
.mode(0o777)
6972
.open(&test_path)
70-
.and_then(|f| f.metadata().map(|m| m.mode() & 0o100 == 0o100));
73+
.and_then(|file| {
74+
let old_mode = file.metadata()?.mode();
75+
let is_executable = old_mode & 0o100 == 0o100;
76+
Ok(is_executable && {
77+
let new_mode = old_mode ^ 0o100;
78+
match file.set_permissions(PermissionsExt::from_mode(new_mode)) {
79+
Ok(()) => new_mode == file.metadata()?.mode(),
80+
Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => false,
81+
Err(err) => return Err(err),
82+
}
83+
})
84+
});
7185
std::fs::remove_file(test_path)?;
7286
res
7387
}

0 commit comments

Comments
 (0)