annotate rust/hg-core/src/checkexec.rs @ 51471:5633de951d34 stable

rust-matchers: raw regular expression builder Extracting this `re_builder()` from `re_matcher()` makes it reusable in more general cases than matching `HgPath` instances and would help reducing code duplication in RHGitaly.
author Georges Racinet <georges.racinet@octobus.net>
date Mon, 11 Mar 2024 13:36:25 +0100
parents e2c8b30ab4e7
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
49894
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
1 use std::fs;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
2 use std::io;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
3 use std::os::unix::fs::{MetadataExt, PermissionsExt};
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
4 use std::path::Path;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
5
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
6 const EXECFLAGS: u32 = 0o111;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
7
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
8 fn is_executable(path: impl AsRef<Path>) -> Result<bool, io::Error> {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
9 let metadata = fs::metadata(path)?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
10 let mode = metadata.mode();
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
11 Ok(mode & EXECFLAGS != 0)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
12 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
13
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
14 fn make_executable(path: impl AsRef<Path>) -> Result<(), io::Error> {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
15 let mode = fs::metadata(path.as_ref())?.mode();
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
16 fs::set_permissions(
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
17 path,
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
18 fs::Permissions::from_mode((mode & 0o777) | EXECFLAGS),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
19 )?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
20 Ok(())
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
21 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
22
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
23 fn copy_mode(
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
24 src: impl AsRef<Path>,
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
25 dst: impl AsRef<Path>,
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
26 ) -> Result<(), io::Error> {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
27 let mode = match fs::symlink_metadata(src) {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
28 Ok(metadata) => metadata.mode(),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
29 Err(e) if e.kind() == io::ErrorKind::NotFound =>
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
30 // copymode in python has a more complicated handling of FileNotFound
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
31 // error, which we don't need because all it does is applying
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
32 // umask, which the OS already does when we mkdir.
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
33 {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
34 return Ok(())
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
35 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
36 Err(e) => return Err(e),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
37 };
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
38 fs::set_permissions(dst, fs::Permissions::from_mode(mode))?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
39 Ok(())
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
40 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
41
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
42 fn check_exec_impl(path: impl AsRef<Path>) -> Result<bool, io::Error> {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
43 let basedir = path.as_ref().join(".hg");
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
44 let cachedir = basedir.join("wcache");
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
45 let storedir = basedir.join("store");
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
46
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
47 if !cachedir.exists() {
49895
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
48 // we want to create the 'cache' directory, not the '.hg' one.
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
49 // Automatically creating '.hg' directory could silently spawn
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
50 // invalid Mercurial repositories. That seems like a bad idea.
49894
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
51 fs::create_dir(&cachedir)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
52 .and_then(|()| {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
53 if storedir.exists() {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
54 copy_mode(&storedir, &cachedir)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
55 } else {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
56 copy_mode(&basedir, &cachedir)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
57 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
58 })
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
59 .ok();
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
60 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
61
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
62 let leave_file: bool;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
63 let checkdir: &Path;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
64 let checkisexec = cachedir.join("checkisexec");
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
65 let checknoexec = cachedir.join("checknoexec");
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
66 if cachedir.is_dir() {
49895
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
67 // Check if both files already exist in cache and have correct
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
68 // permissions. if so, we assume that permissions work.
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
69 // If not, we delete the files and try again.
49894
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
70 match is_executable(&checkisexec) {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
71 Err(e) if e.kind() == io::ErrorKind::NotFound => (),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
72 Err(e) => return Err(e),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
73 Ok(is_exec) => {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
74 if is_exec {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
75 let noexec_is_exec = match is_executable(&checknoexec) {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
76 Err(e) if e.kind() == io::ErrorKind::NotFound => {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
77 fs::write(&checknoexec, "")?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
78 is_executable(&checknoexec)?
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
79 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
80 Err(e) => return Err(e),
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
81 Ok(exec) => exec,
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
82 };
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
83 if !noexec_is_exec {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
84 // check-exec is exec and check-no-exec is not exec
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
85 return Ok(true);
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
86 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
87 fs::remove_file(&checknoexec)?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
88 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
89 fs::remove_file(&checkisexec)?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
90 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
91 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
92 checkdir = &cachedir;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
93 leave_file = true;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
94 } else {
49895
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
95 // no cache directory (probably because .hg doesn't exist):
07792fd1837f doc: add a few comments
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49894
diff changeset
96 // check directly in `path` and don't leave the temp file behind
49894
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
97 checkdir = path.as_ref();
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
98 leave_file = false;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
99 };
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
100
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
101 let tmp_file = tempfile::NamedTempFile::new_in(checkdir)?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
102 if !is_executable(tmp_file.path())? {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
103 make_executable(tmp_file.path())?;
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
104 if is_executable(tmp_file.path())? {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
105 if leave_file {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
106 tmp_file.persist(checkisexec).ok();
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
107 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
108 return Ok(true);
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
109 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
110 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
111
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
112 Ok(false)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
113 }
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
114
50416
e2c8b30ab4e7 rustdoc: wording for checkexec
Georges Racinet <georges.racinet@octobus.net>
parents: 50415
diff changeset
115 /// This function is a Rust rewrite of the `checkexec` function from
e2c8b30ab4e7 rustdoc: wording for checkexec
Georges Racinet <georges.racinet@octobus.net>
parents: 50415
diff changeset
116 /// `posix.py`.
e2c8b30ab4e7 rustdoc: wording for checkexec
Georges Racinet <georges.racinet@octobus.net>
parents: 50415
diff changeset
117 ///
e2c8b30ab4e7 rustdoc: wording for checkexec
Georges Racinet <georges.racinet@octobus.net>
parents: 50415
diff changeset
118 /// Returns `true` if the filesystem supports execute permissions.
49894
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
119 pub fn check_exec(path: impl AsRef<Path>) -> bool {
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
120 check_exec_impl(path).unwrap_or(false)
678588b01af1 rhg: implement checkexec to support weird filesystems
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents:
diff changeset
121 }