Mercurial > hg
annotate rust/hg-core/src/checkexec.rs @ 51568:2a89d2f6336f stable
match: rename RootFiles to RootFilesIn for more consistency
author | Arseniy Alekseyev <aalekseyev@janestreet.com> |
---|---|
date | Fri, 12 Apr 2024 14:21:14 +0100 |
parents | e2c8b30ab4e7 |
children |
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 } |