equal
deleted
inserted
replaced
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 |
|
6 // This is a rust rewrite of [checkexec] function from [posix.py] |
|
7 |
5 |
8 const EXECFLAGS: u32 = 0o111; |
6 const EXECFLAGS: u32 = 0o111; |
9 |
7 |
10 fn is_executable(path: impl AsRef<Path>) -> Result<bool, io::Error> { |
8 fn is_executable(path: impl AsRef<Path>) -> Result<bool, io::Error> { |
11 let metadata = fs::metadata(path)?; |
9 let metadata = fs::metadata(path)?; |
45 let basedir = path.as_ref().join(".hg"); |
43 let basedir = path.as_ref().join(".hg"); |
46 let cachedir = basedir.join("wcache"); |
44 let cachedir = basedir.join("wcache"); |
47 let storedir = basedir.join("store"); |
45 let storedir = basedir.join("store"); |
48 |
46 |
49 if !cachedir.exists() { |
47 if !cachedir.exists() { |
|
48 // we want to create the 'cache' directory, not the '.hg' one. |
|
49 // Automatically creating '.hg' directory could silently spawn |
|
50 // invalid Mercurial repositories. That seems like a bad idea. |
50 fs::create_dir(&cachedir) |
51 fs::create_dir(&cachedir) |
51 .and_then(|()| { |
52 .and_then(|()| { |
52 if storedir.exists() { |
53 if storedir.exists() { |
53 copy_mode(&storedir, &cachedir) |
54 copy_mode(&storedir, &cachedir) |
54 } else { |
55 } else { |
61 let leave_file: bool; |
62 let leave_file: bool; |
62 let checkdir: &Path; |
63 let checkdir: &Path; |
63 let checkisexec = cachedir.join("checkisexec"); |
64 let checkisexec = cachedir.join("checkisexec"); |
64 let checknoexec = cachedir.join("checknoexec"); |
65 let checknoexec = cachedir.join("checknoexec"); |
65 if cachedir.is_dir() { |
66 if cachedir.is_dir() { |
|
67 // Check if both files already exist in cache and have correct |
|
68 // permissions. if so, we assume that permissions work. |
|
69 // If not, we delete the files and try again. |
66 match is_executable(&checkisexec) { |
70 match is_executable(&checkisexec) { |
67 Err(e) if e.kind() == io::ErrorKind::NotFound => (), |
71 Err(e) if e.kind() == io::ErrorKind::NotFound => (), |
68 Err(e) => return Err(e), |
72 Err(e) => return Err(e), |
69 Ok(is_exec) => { |
73 Ok(is_exec) => { |
70 if is_exec { |
74 if is_exec { |
86 } |
90 } |
87 } |
91 } |
88 checkdir = &cachedir; |
92 checkdir = &cachedir; |
89 leave_file = true; |
93 leave_file = true; |
90 } else { |
94 } else { |
|
95 // no cache directory (probably because .hg doesn't exist): |
|
96 // check directly in `path` and don't leave the temp file behind |
91 checkdir = path.as_ref(); |
97 checkdir = path.as_ref(); |
92 leave_file = false; |
98 leave_file = false; |
93 }; |
99 }; |
94 |
100 |
95 let tmp_file = tempfile::NamedTempFile::new_in(checkdir)?; |
101 let tmp_file = tempfile::NamedTempFile::new_in(checkdir)?; |
104 } |
110 } |
105 |
111 |
106 Ok(false) |
112 Ok(false) |
107 } |
113 } |
108 |
114 |
|
115 /// This function is a rust rewrite of [checkexec] function from [posix.py] |
|
116 /// Returns true if the filesystem supports execute permissions. |
109 pub fn check_exec(path: impl AsRef<Path>) -> bool { |
117 pub fn check_exec(path: impl AsRef<Path>) -> bool { |
110 check_exec_impl(path).unwrap_or(false) |
118 check_exec_impl(path).unwrap_or(false) |
111 } |
119 } |