1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
From bf33d2b49212f71a7af1aef34e0ffac41140815b Mon Sep 17 00:00:00 2001
From: Eliah Kagan <degeneracypressure@gmail.com>
Date: Fri, 10 Jan 2025 17:41:52 -0500
Subject: [PATCH 3/4] Extract and test +x mode setting logic
---
src/checkout/entry.rs | 81 ++++++++++++++++++++++--
1 file changed, 75 insertions(+), 6 deletions(-)
Index: gix-worktree-state/src/checkout/entry.rs
===================================================================
--- gix-worktree-state.orig/src/checkout/entry.rs
+++ gix-worktree-state/src/checkout/entry.rs
@@ -1,5 +1,5 @@
-use std::borrow::Cow;
use std::{
+ borrow::Cow,
fs::OpenOptions,
io::Write,
path::{Path, PathBuf},
@@ -285,12 +285,8 @@ pub(crate) fn finalize_entry(
// For possibly existing, overwritten files, we must change the file mode explicitly.
#[cfg(unix)]
if let Some(path) = set_executable_after_creation {
- use std::os::unix::fs::PermissionsExt;
let mut perm = std::fs::symlink_metadata(path)?.permissions();
- let mut mode = perm.mode();
- mode &= 0o777; // Clear non-rwx bits (setuid, setgid, sticky).
- mode |= (mode & 0o444) >> 2; // Let readers also execute.
- perm.set_mode(mode);
+ set_mode_executable(&mut perm);
std::fs::set_permissions(path, perm)?;
}
// NOTE: we don't call `file.sync_all()` here knowing that some filesystems don't handle this well.
@@ -299,3 +295,76 @@ pub(crate) fn finalize_entry(
file.close()?;
Ok(())
}
+
+#[cfg(unix)]
+fn set_mode_executable(perm: &mut std::fs::Permissions) {
+ use std::os::unix::fs::PermissionsExt;
+ let mut mode = perm.mode();
+ mode &= 0o777; // Clear non-rwx bits (setuid, setgid, sticky).
+ mode |= (mode & 0o444) >> 2; // Let readers also execute.
+ perm.set_mode(mode);
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ #[cfg(unix)]
+ fn set_mode_executable() {
+ let cases = [
+ // Common cases.
+ (0o100755, 0o755),
+ (0o100644, 0o755),
+ (0o100750, 0o750),
+ (0o100640, 0o750),
+ (0o100700, 0o700),
+ (0o100600, 0o700),
+ (0o100775, 0o775),
+ (0o100664, 0o775),
+ (0o100770, 0o770),
+ (0o100660, 0o770),
+ (0o100764, 0o775),
+ (0o100760, 0o770),
+ // Some less common cases.
+ (0o100674, 0o775),
+ (0o100670, 0o770),
+ (0o100000, 0o000),
+ (0o100400, 0o500),
+ (0o100440, 0o550),
+ (0o100444, 0o555),
+ (0o100462, 0o572),
+ (0o100242, 0o252),
+ (0o100167, 0o177),
+ // Some cases with set-user-ID, set-group-ID, and sticky bits.
+ (0o104755, 0o755),
+ (0o104644, 0o755),
+ (0o102755, 0o755),
+ (0o102644, 0o755),
+ (0o101755, 0o755),
+ (0o101644, 0o755),
+ (0o106755, 0o755),
+ (0o106644, 0o755),
+ (0o104750, 0o750),
+ (0o104640, 0o750),
+ (0o102750, 0o750),
+ (0o102640, 0o750),
+ (0o101750, 0o750),
+ (0o101640, 0o750),
+ (0o106750, 0o750),
+ (0o106640, 0o750),
+ (0o107644, 0o755),
+ (0o107000, 0o000),
+ (0o106400, 0o500),
+ (0o102462, 0o572),
+ ];
+ for (old, expected) in cases {
+ use std::os::unix::fs::PermissionsExt;
+ let mut perm = std::fs::Permissions::from_mode(old);
+ super::set_mode_executable(&mut perm);
+ let actual = perm.mode();
+ assert_eq!(
+ actual, expected,
+ "{old:06o} should become {expected:04o} but became {actual:04o}"
+ );
+ }
+ }
+}
|