##// END OF EJS Templates
rustdoc: wording for checkexec...
Georges Racinet -
r51273:e2c8b30a default
parent child Browse files
Show More
@@ -1,119 +1,121 b''
1 1 use std::fs;
2 2 use std::io;
3 3 use std::os::unix::fs::{MetadataExt, PermissionsExt};
4 4 use std::path::Path;
5 5
6 6 const EXECFLAGS: u32 = 0o111;
7 7
8 8 fn is_executable(path: impl AsRef<Path>) -> Result<bool, io::Error> {
9 9 let metadata = fs::metadata(path)?;
10 10 let mode = metadata.mode();
11 11 Ok(mode & EXECFLAGS != 0)
12 12 }
13 13
14 14 fn make_executable(path: impl AsRef<Path>) -> Result<(), io::Error> {
15 15 let mode = fs::metadata(path.as_ref())?.mode();
16 16 fs::set_permissions(
17 17 path,
18 18 fs::Permissions::from_mode((mode & 0o777) | EXECFLAGS),
19 19 )?;
20 20 Ok(())
21 21 }
22 22
23 23 fn copy_mode(
24 24 src: impl AsRef<Path>,
25 25 dst: impl AsRef<Path>,
26 26 ) -> Result<(), io::Error> {
27 27 let mode = match fs::symlink_metadata(src) {
28 28 Ok(metadata) => metadata.mode(),
29 29 Err(e) if e.kind() == io::ErrorKind::NotFound =>
30 30 // copymode in python has a more complicated handling of FileNotFound
31 31 // error, which we don't need because all it does is applying
32 32 // umask, which the OS already does when we mkdir.
33 33 {
34 34 return Ok(())
35 35 }
36 36 Err(e) => return Err(e),
37 37 };
38 38 fs::set_permissions(dst, fs::Permissions::from_mode(mode))?;
39 39 Ok(())
40 40 }
41 41
42 42 fn check_exec_impl(path: impl AsRef<Path>) -> Result<bool, io::Error> {
43 43 let basedir = path.as_ref().join(".hg");
44 44 let cachedir = basedir.join("wcache");
45 45 let storedir = basedir.join("store");
46 46
47 47 if !cachedir.exists() {
48 48 // we want to create the 'cache' directory, not the '.hg' one.
49 49 // Automatically creating '.hg' directory could silently spawn
50 50 // invalid Mercurial repositories. That seems like a bad idea.
51 51 fs::create_dir(&cachedir)
52 52 .and_then(|()| {
53 53 if storedir.exists() {
54 54 copy_mode(&storedir, &cachedir)
55 55 } else {
56 56 copy_mode(&basedir, &cachedir)
57 57 }
58 58 })
59 59 .ok();
60 60 }
61 61
62 62 let leave_file: bool;
63 63 let checkdir: &Path;
64 64 let checkisexec = cachedir.join("checkisexec");
65 65 let checknoexec = cachedir.join("checknoexec");
66 66 if cachedir.is_dir() {
67 67 // Check if both files already exist in cache and have correct
68 68 // permissions. if so, we assume that permissions work.
69 69 // If not, we delete the files and try again.
70 70 match is_executable(&checkisexec) {
71 71 Err(e) if e.kind() == io::ErrorKind::NotFound => (),
72 72 Err(e) => return Err(e),
73 73 Ok(is_exec) => {
74 74 if is_exec {
75 75 let noexec_is_exec = match is_executable(&checknoexec) {
76 76 Err(e) if e.kind() == io::ErrorKind::NotFound => {
77 77 fs::write(&checknoexec, "")?;
78 78 is_executable(&checknoexec)?
79 79 }
80 80 Err(e) => return Err(e),
81 81 Ok(exec) => exec,
82 82 };
83 83 if !noexec_is_exec {
84 84 // check-exec is exec and check-no-exec is not exec
85 85 return Ok(true);
86 86 }
87 87 fs::remove_file(&checknoexec)?;
88 88 }
89 89 fs::remove_file(&checkisexec)?;
90 90 }
91 91 }
92 92 checkdir = &cachedir;
93 93 leave_file = true;
94 94 } else {
95 95 // no cache directory (probably because .hg doesn't exist):
96 96 // check directly in `path` and don't leave the temp file behind
97 97 checkdir = path.as_ref();
98 98 leave_file = false;
99 99 };
100 100
101 101 let tmp_file = tempfile::NamedTempFile::new_in(checkdir)?;
102 102 if !is_executable(tmp_file.path())? {
103 103 make_executable(tmp_file.path())?;
104 104 if is_executable(tmp_file.path())? {
105 105 if leave_file {
106 106 tmp_file.persist(checkisexec).ok();
107 107 }
108 108 return Ok(true);
109 109 }
110 110 }
111 111
112 112 Ok(false)
113 113 }
114 114
115 /// This function is a rust rewrite of `checkexec` function from `posix.py`
116 /// Returns true if the filesystem supports execute permissions.
115 /// This function is a Rust rewrite of the `checkexec` function from
116 /// `posix.py`.
117 ///
118 /// Returns `true` if the filesystem supports execute permissions.
117 119 pub fn check_exec(path: impl AsRef<Path>) -> bool {
118 120 check_exec_impl(path).unwrap_or(false)
119 121 }
General Comments 0
You need to be logged in to leave comments. Login now