annotate rust/hg-core/src/checkexec.rs @ 51181:dcaa2df1f688

changelog: never inline changelog The test suite mostly use small repositories, that implies that most changelog in the tests are inlined. As a result, non-inlined changelog are quite poorly tested. Since non-inline changelog are most common case for serious repositories, this lack of testing is a significant problem that results in high profile issue like the one recently fixed by 66417f55ea33 and 849745d7da89. Inlining the changelog does not bring much to the table, the number of total file saved is negligible, and the changelog will be read by most operation anyway. So this changeset is make it so we never inline the changelog, and de-inline the one that are still inlined whenever we touch them. By doing that, we remove the "dual code path" situation for writing new entry to the changelog and move to a "single code path" situation. Having a single code path simplify the code and make sure it is covered by test (if test cover that situation obviously) This impact all tests that care about the number of file and the exchange size, but there is nothing too complicated in them just a lot of churn. The churn is made "worse" by the fact rust will use the persistent nodemap on any changelog now. Which is overall a win as it means testing the persistent nodemap more and having less special cases. In short, having inline changelog is mostly useless and an endless source of pain. We get rid of it.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 11 Dec 2023 22:27:59 +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 }