rust/hg-core/src/checkexec.rs
changeset 49895 07792fd1837f
parent 49894 678588b01af1
child 50412 331a3cbe1c9e
equal deleted inserted replaced
49894:678588b01af1 49895:07792fd1837f
     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 }