Skip to content

Commit bf33d2b

Browse files
committed
Extract and test +x mode setting logic
1 parent 879d29d commit bf33d2b

File tree

1 file changed

+75
-6
lines changed

1 file changed

+75
-6
lines changed

gix-worktree-state/src/checkout/entry.rs

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::borrow::Cow;
21
use std::{
2+
borrow::Cow,
33
fs::OpenOptions,
44
io::Write,
55
path::{Path, PathBuf},
@@ -286,12 +286,8 @@ pub(crate) fn finalize_entry(
286286
// For possibly existing, overwritten files, we must change the file mode explicitly.
287287
#[cfg(unix)]
288288
if let Some(path) = set_executable_after_creation {
289-
use std::os::unix::fs::PermissionsExt;
290289
let mut perm = std::fs::symlink_metadata(path)?.permissions();
291-
let mut mode = perm.mode();
292-
mode &= 0o777; // Clear non-rwx bits (setuid, setgid, sticky).
293-
mode |= (mode & 0o444) >> 2; // Let readers also execute.
294-
perm.set_mode(mode);
290+
set_mode_executable(&mut perm);
295291
std::fs::set_permissions(path, perm)?;
296292
}
297293
// NOTE: we don't call `file.sync_all()` here knowing that some filesystems don't handle this well.
@@ -300,3 +296,76 @@ pub(crate) fn finalize_entry(
300296
file.close()?;
301297
Ok(())
302298
}
299+
300+
#[cfg(unix)]
301+
fn set_mode_executable(perm: &mut std::fs::Permissions) {
302+
use std::os::unix::fs::PermissionsExt;
303+
let mut mode = perm.mode();
304+
mode &= 0o777; // Clear non-rwx bits (setuid, setgid, sticky).
305+
mode |= (mode & 0o444) >> 2; // Let readers also execute.
306+
perm.set_mode(mode);
307+
}
308+
309+
#[cfg(test)]
310+
mod tests {
311+
#[test]
312+
#[cfg(unix)]
313+
fn set_mode_executable() {
314+
let cases = [
315+
// Common cases.
316+
(0o100755, 0o755),
317+
(0o100644, 0o755),
318+
(0o100750, 0o750),
319+
(0o100640, 0o750),
320+
(0o100700, 0o700),
321+
(0o100600, 0o700),
322+
(0o100775, 0o775),
323+
(0o100664, 0o775),
324+
(0o100770, 0o770),
325+
(0o100660, 0o770),
326+
(0o100764, 0o775),
327+
(0o100760, 0o770),
328+
// Some less common cases.
329+
(0o100674, 0o775),
330+
(0o100670, 0o770),
331+
(0o100000, 0o000),
332+
(0o100400, 0o500),
333+
(0o100440, 0o550),
334+
(0o100444, 0o555),
335+
(0o100462, 0o572),
336+
(0o100242, 0o252),
337+
(0o100167, 0o177),
338+
// Some cases with set-user-ID, set-group-ID, and sticky bits.
339+
(0o104755, 0o755),
340+
(0o104644, 0o755),
341+
(0o102755, 0o755),
342+
(0o102644, 0o755),
343+
(0o101755, 0o755),
344+
(0o101644, 0o755),
345+
(0o106755, 0o755),
346+
(0o106644, 0o755),
347+
(0o104750, 0o750),
348+
(0o104640, 0o750),
349+
(0o102750, 0o750),
350+
(0o102640, 0o750),
351+
(0o101750, 0o750),
352+
(0o101640, 0o750),
353+
(0o106750, 0o750),
354+
(0o106640, 0o750),
355+
(0o107644, 0o755),
356+
(0o107000, 0o000),
357+
(0o106400, 0o500),
358+
(0o102462, 0o572),
359+
];
360+
for (old, expected) in cases {
361+
use std::os::unix::fs::PermissionsExt;
362+
let mut perm = std::fs::Permissions::from_mode(old);
363+
super::set_mode_executable(&mut perm);
364+
let actual = perm.mode();
365+
assert_eq!(
366+
actual, expected,
367+
"{old:06o} should become {expected:04o} but became {actual:04o}"
368+
);
369+
}
370+
}
371+
}

0 commit comments

Comments
 (0)