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