"Fossies" - the Fresh Open Source Software Archive

Member "fd-8.1.1/src/filter/owner.rs" (25 May 2020, 3691 Bytes) of package /linux/privat/fd-8.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Rust source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 use anyhow::{anyhow, Result};
    2 use std::fs;
    3 
    4 #[derive(Clone, Copy, Debug, PartialEq)]
    5 pub struct OwnerFilter {
    6     uid: Check<u32>,
    7     gid: Check<u32>,
    8 }
    9 
   10 #[derive(Clone, Copy, Debug, PartialEq)]
   11 enum Check<T> {
   12     Equal(T),
   13     NotEq(T),
   14     Ignore,
   15 }
   16 
   17 impl OwnerFilter {
   18     /// Parses an owner constraint
   19     /// Returns an error if the string is invalid
   20     /// Returns Ok(None) when string is acceptable but a noop (such as "" or ":")
   21     pub fn from_string(input: &str) -> Result<Option<Self>> {
   22         let mut it = input.split(':');
   23         let (fst, snd) = (it.next(), it.next());
   24 
   25         if it.next().is_some() {
   26             return Err(anyhow!(
   27                 "more than one ':' present in owner string '{}'. See 'fd --help'.",
   28                 input
   29             ));
   30         }
   31 
   32         let uid = Check::parse(fst, |s| {
   33             s.parse()
   34                 .ok()
   35                 .or_else(|| users::get_user_by_name(s).map(|user| user.uid()))
   36                 .ok_or_else(|| anyhow!("'{}' is not a recognized user name", s))
   37         })?;
   38         let gid = Check::parse(snd, |s| {
   39             s.parse()
   40                 .ok()
   41                 .or_else(|| users::get_group_by_name(s).map(|group| group.gid()))
   42                 .ok_or_else(|| anyhow!("'{}' is not a recognized group name", s))
   43         })?;
   44 
   45         if let (Check::Ignore, Check::Ignore) = (uid, gid) {
   46             Ok(None)
   47         } else {
   48             Ok(Some(OwnerFilter { uid, gid }))
   49         }
   50     }
   51 
   52     pub fn matches(&self, md: &fs::Metadata) -> bool {
   53         use std::os::unix::fs::MetadataExt;
   54 
   55         self.uid.check(md.uid()) && self.gid.check(md.gid())
   56     }
   57 }
   58 
   59 impl<T: PartialEq> Check<T> {
   60     fn check(&self, v: T) -> bool {
   61         match self {
   62             Check::Equal(x) => v == *x,
   63             Check::NotEq(x) => v != *x,
   64             Check::Ignore => true,
   65         }
   66     }
   67 
   68     fn parse<F>(s: Option<&str>, f: F) -> Result<Self>
   69     where
   70         F: Fn(&str) -> Result<T>,
   71     {
   72         let (s, equality) = match s {
   73             Some("") | None => return Ok(Check::Ignore),
   74             Some(s) if s.starts_with('!') => (&s[1..], false),
   75             Some(s) => (s, true),
   76         };
   77 
   78         f(s).map(|x| {
   79             if equality {
   80                 Check::Equal(x)
   81             } else {
   82                 Check::NotEq(x)
   83             }
   84         })
   85     }
   86 }
   87 
   88 #[cfg(test)]
   89 mod owner_parsing {
   90     use super::OwnerFilter;
   91 
   92     macro_rules! owner_tests {
   93         ($($name:ident: $value:expr => $result:pat,)*) => {
   94             $(
   95                 #[test]
   96                 fn $name() {
   97                     let o = OwnerFilter::from_string($value);
   98                     match o {
   99                         $result => {},
  100                         _ => panic!("{:?} does not match {}", o, stringify!($result)),
  101                     }
  102                 }
  103             )*
  104         };
  105     }
  106 
  107     use super::Check::*;
  108     owner_tests! {
  109         empty:      ""      => Ok(None),
  110         uid_only:   "5"     => Ok(Some(OwnerFilter { uid: Equal(5), gid: Ignore     })),
  111         uid_gid:    "9:3"   => Ok(Some(OwnerFilter { uid: Equal(9), gid: Equal(3)   })),
  112         gid_only:   ":8"    => Ok(Some(OwnerFilter { uid: Ignore,   gid: Equal(8)   })),
  113         colon_only: ":"     => Ok(None),
  114         trailing:   "5:"    => Ok(Some(OwnerFilter { uid: Equal(5), gid: Ignore     })),
  115 
  116         uid_negate: "!5"    => Ok(Some(OwnerFilter { uid: NotEq(5), gid: Ignore     })),
  117         both_negate:"!4:!3" => Ok(Some(OwnerFilter { uid: NotEq(4), gid: NotEq(3)   })),
  118         uid_not_gid:"6:!8"  => Ok(Some(OwnerFilter { uid: Equal(6), gid: NotEq(8)   })),
  119 
  120         more_colons:"3:5:"  => Err(_),
  121         only_colons:"::"    => Err(_),
  122     }
  123 }