2015-01-10 21:00:15 +00:00
|
|
|
#![crate_name = "test"]
|
2015-04-30 06:16:53 +00:00
|
|
|
#![feature(convert)]
|
2014-07-12 01:12:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is part of the uutils coreutils package.
|
|
|
|
*
|
|
|
|
* (c) mahkoh (ju.orth [at] gmail [dot] com)
|
|
|
|
*
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern crate libc;
|
|
|
|
|
2014-10-07 19:54:07 +00:00
|
|
|
use std::collections::HashMap;
|
2015-04-30 06:16:53 +00:00
|
|
|
use std::ffi::{CString, OsString};
|
|
|
|
use std::env::{args_os};
|
2014-07-12 01:12:29 +00:00
|
|
|
use std::str::{from_utf8};
|
|
|
|
|
2014-09-28 03:17:34 +00:00
|
|
|
static NAME: &'static str = "test";
|
|
|
|
|
|
|
|
// TODO: decide how to handle non-UTF8 input for all the utils
|
2015-02-06 13:48:07 +00:00
|
|
|
pub fn uumain(_: Vec<String>) -> i32 {
|
2015-04-30 06:16:53 +00:00
|
|
|
let args = args_os().collect::<Vec<OsString>>();
|
|
|
|
let args = args.iter().map(|a| a.to_bytes().unwrap()).collect::<Vec<&[u8]>>();
|
2014-07-12 01:12:29 +00:00
|
|
|
if args.len() == 0 {
|
|
|
|
return 2;
|
|
|
|
}
|
2014-09-28 03:17:34 +00:00
|
|
|
let args =
|
|
|
|
if !args[0].ends_with(NAME.as_bytes()) {
|
2015-01-24 09:44:48 +00:00
|
|
|
&args[1..]
|
2014-09-28 03:17:34 +00:00
|
|
|
} else {
|
2015-04-30 06:16:53 +00:00
|
|
|
&args[..]
|
2014-09-28 03:17:34 +00:00
|
|
|
};
|
2014-07-12 01:12:29 +00:00
|
|
|
let args = match args[0] {
|
2014-09-28 03:17:34 +00:00
|
|
|
b"[" => match args[args.len() - 1] {
|
2015-01-24 09:44:48 +00:00
|
|
|
b"]" => &args[1..args.len() - 1],
|
2014-07-12 01:12:29 +00:00
|
|
|
_ => return 2,
|
|
|
|
},
|
2015-01-24 09:44:48 +00:00
|
|
|
_ => &args[1..args.len()],
|
2014-07-12 01:12:29 +00:00
|
|
|
};
|
2014-10-07 19:54:07 +00:00
|
|
|
let mut error = false;
|
2015-02-06 13:48:07 +00:00
|
|
|
let retval = 1 - parse_expr(args, &mut error) as i32;
|
2014-10-07 19:54:07 +00:00
|
|
|
if error {
|
|
|
|
2
|
|
|
|
} else {
|
|
|
|
retval
|
|
|
|
}
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn one(args: &[&[u8]]) -> bool {
|
|
|
|
args[0].len() > 0
|
|
|
|
}
|
|
|
|
|
2014-10-07 19:54:07 +00:00
|
|
|
fn two(args: &[&[u8]], error: &mut bool) -> bool {
|
2014-07-12 01:12:29 +00:00
|
|
|
match args[0] {
|
2015-01-24 09:44:48 +00:00
|
|
|
b"!" => !one(&args[1..]),
|
2014-11-19 20:50:37 +00:00
|
|
|
b"-b" => path(args[1], PathCondition::BlockSpecial),
|
|
|
|
b"-c" => path(args[1], PathCondition::CharacterSpecial),
|
|
|
|
b"-d" => path(args[1], PathCondition::Directory),
|
|
|
|
b"-e" => path(args[1], PathCondition::Exists),
|
|
|
|
b"-f" => path(args[1], PathCondition::Regular),
|
|
|
|
b"-g" => path(args[1], PathCondition::GroupIDFlag),
|
|
|
|
b"-h" => path(args[1], PathCondition::SymLink),
|
|
|
|
b"-L" => path(args[1], PathCondition::SymLink),
|
2015-01-24 09:44:48 +00:00
|
|
|
b"-n" => one(&args[1..]),
|
2014-11-19 20:50:37 +00:00
|
|
|
b"-p" => path(args[1], PathCondition::FIFO),
|
|
|
|
b"-r" => path(args[1], PathCondition::Readable),
|
|
|
|
b"-S" => path(args[1], PathCondition::Socket),
|
|
|
|
b"-s" => path(args[1], PathCondition::NonEmpty),
|
2014-07-12 01:12:29 +00:00
|
|
|
b"-t" => isatty(args[1]),
|
2014-11-19 20:50:37 +00:00
|
|
|
b"-u" => path(args[1], PathCondition::UserIDFlag),
|
|
|
|
b"-w" => path(args[1], PathCondition::Writable),
|
|
|
|
b"-x" => path(args[1], PathCondition::Executable),
|
2015-01-24 09:44:48 +00:00
|
|
|
b"-z" => !one(&args[1..]),
|
2014-10-07 19:54:07 +00:00
|
|
|
_ => {
|
|
|
|
*error = true;
|
|
|
|
false
|
|
|
|
}
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-07 19:54:07 +00:00
|
|
|
fn three(args: &[&[u8]], error: &mut bool) -> bool {
|
2014-07-12 01:12:29 +00:00
|
|
|
match args[1] {
|
|
|
|
b"=" => args[0] == args[2],
|
2015-04-30 06:16:53 +00:00
|
|
|
b"==" => args[0] == args[2],
|
2014-07-12 01:12:29 +00:00
|
|
|
b"!=" => args[0] != args[2],
|
2014-11-19 20:50:37 +00:00
|
|
|
b"-eq" => integers(args[0], args[2], IntegerCondition::Equal),
|
|
|
|
b"-ne" => integers(args[0], args[2], IntegerCondition::Unequal),
|
|
|
|
b"-gt" => integers(args[0], args[2], IntegerCondition::Greater),
|
|
|
|
b"-ge" => integers(args[0], args[2], IntegerCondition::GreaterEqual),
|
|
|
|
b"-lt" => integers(args[0], args[2], IntegerCondition::Less),
|
|
|
|
b"-le" => integers(args[0], args[2], IntegerCondition::LessEqual),
|
2014-07-12 01:12:29 +00:00
|
|
|
_ => match args[0] {
|
2015-01-24 09:44:48 +00:00
|
|
|
b"!" => !two(&args[1..], error),
|
2014-10-07 19:54:07 +00:00
|
|
|
_ => {
|
|
|
|
*error = true;
|
|
|
|
false
|
|
|
|
}
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-07 19:54:07 +00:00
|
|
|
fn four(args: &[&[u8]], error: &mut bool) -> bool {
|
|
|
|
match args[0] {
|
|
|
|
b"!" => {
|
2015-01-24 09:44:48 +00:00
|
|
|
!three(&args[1..], error)
|
2014-10-07 19:54:07 +00:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
*error = true;
|
|
|
|
false
|
2014-10-07 05:16:07 +00:00
|
|
|
}
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum IntegerCondition {
|
|
|
|
Equal,
|
|
|
|
Unequal,
|
|
|
|
Greater,
|
|
|
|
GreaterEqual,
|
|
|
|
Less,
|
|
|
|
LessEqual,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn integers(a: &[u8], b: &[u8], cond: IntegerCondition) -> bool {
|
|
|
|
let (a, b): (&str, &str) = match (from_utf8(a), from_utf8(b)) {
|
2014-12-24 09:53:27 +00:00
|
|
|
(Ok(a), Ok(b)) => (a, b),
|
2014-07-12 01:12:29 +00:00
|
|
|
_ => return false,
|
|
|
|
};
|
2014-12-25 18:55:32 +00:00
|
|
|
let (a, b): (i64, i64) = match (a.parse(), b.parse()) {
|
2015-02-03 21:19:13 +00:00
|
|
|
(Ok(a), Ok(b)) => (a, b),
|
2014-07-12 01:12:29 +00:00
|
|
|
_ => return false,
|
|
|
|
};
|
|
|
|
match cond {
|
2014-11-19 20:50:37 +00:00
|
|
|
IntegerCondition::Equal => a == b,
|
|
|
|
IntegerCondition::Unequal => a != b,
|
|
|
|
IntegerCondition::Greater => a > b,
|
|
|
|
IntegerCondition::GreaterEqual => a >= b,
|
|
|
|
IntegerCondition::Less => a < b,
|
|
|
|
IntegerCondition::LessEqual => a <= b,
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn isatty(fd: &[u8]) -> bool {
|
|
|
|
use libc::{isatty};
|
2015-02-03 21:19:13 +00:00
|
|
|
from_utf8(fd).ok().and_then(|s| s.parse().ok())
|
2014-07-12 01:12:29 +00:00
|
|
|
.map(|i| unsafe { isatty(i) == 1 }).unwrap_or(false)
|
|
|
|
}
|
|
|
|
|
2014-10-07 19:54:07 +00:00
|
|
|
fn dispatch(args: &mut &[&[u8]], error: &mut bool) -> bool {
|
|
|
|
let (val, idx) = match args.len() {
|
|
|
|
0 => {
|
|
|
|
*error = true;
|
|
|
|
(false, 0)
|
|
|
|
}
|
|
|
|
1 => (one(*args), 1),
|
|
|
|
2 => dispatch_two(args, error),
|
|
|
|
3 => dispatch_three(args, error),
|
|
|
|
_ => dispatch_four(args, error)
|
|
|
|
};
|
2015-01-24 09:44:48 +00:00
|
|
|
*args = &(*args)[idx..];
|
2014-10-07 19:54:07 +00:00
|
|
|
val
|
|
|
|
}
|
|
|
|
|
2015-01-10 18:07:08 +00:00
|
|
|
fn dispatch_two(args: &mut &[&[u8]], error: &mut bool) -> (bool, usize) {
|
2014-10-07 19:54:07 +00:00
|
|
|
let val = two(*args, error);
|
|
|
|
if *error {
|
|
|
|
*error = false;
|
|
|
|
(one(*args), 1)
|
|
|
|
} else {
|
|
|
|
(val, 2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-10 18:07:08 +00:00
|
|
|
fn dispatch_three(args: &mut &[&[u8]], error: &mut bool) -> (bool, usize) {
|
2014-10-07 19:54:07 +00:00
|
|
|
let val = three(*args, error);
|
|
|
|
if *error {
|
|
|
|
*error = false;
|
|
|
|
dispatch_two(args, error)
|
|
|
|
} else {
|
|
|
|
(val, 3)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-10 18:07:08 +00:00
|
|
|
fn dispatch_four(args: &mut &[&[u8]], error: &mut bool) -> (bool, usize) {
|
2014-10-07 19:54:07 +00:00
|
|
|
let val = four(*args, error);
|
|
|
|
if *error {
|
|
|
|
*error = false;
|
|
|
|
dispatch_three(args, error)
|
|
|
|
} else {
|
|
|
|
(val, 4)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 06:16:53 +00:00
|
|
|
#[derive(Clone, Copy)]
|
2014-10-07 19:54:07 +00:00
|
|
|
enum Precedence {
|
|
|
|
Unknown = 0,
|
|
|
|
Paren, // FIXME: this is useless (parentheses have not been implemented)
|
|
|
|
Or,
|
|
|
|
And,
|
|
|
|
BUnOp,
|
|
|
|
BinOp,
|
|
|
|
UnOp
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr(mut args: &[&[u8]], error: &mut bool) -> bool {
|
|
|
|
if args.len() == 0 {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
let hashmap = setup_hashmap();
|
|
|
|
let lhs = dispatch(&mut args, error);
|
|
|
|
|
|
|
|
if args.len() > 0 {
|
2014-11-19 20:50:37 +00:00
|
|
|
parse_expr_helper(&hashmap, &mut args, lhs, Precedence::Unknown, error)
|
2014-10-07 19:54:07 +00:00
|
|
|
} else {
|
|
|
|
lhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr_helper<'a>(hashmap: &HashMap<&'a [u8], Precedence>,
|
|
|
|
args: &mut &[&'a [u8]],
|
|
|
|
mut lhs: bool,
|
|
|
|
min_prec: Precedence,
|
|
|
|
error: &mut bool) -> bool {
|
2014-11-08 06:45:33 +00:00
|
|
|
let mut prec = *hashmap.get(&args[0]).unwrap_or_else(|| {
|
2014-10-07 19:54:07 +00:00
|
|
|
*error = true;
|
|
|
|
&min_prec
|
|
|
|
});
|
2015-01-10 18:07:08 +00:00
|
|
|
while !*error && args.len() > 0 && prec as usize >= min_prec as usize {
|
2014-10-07 19:54:07 +00:00
|
|
|
let op = args[0];
|
2015-01-24 09:44:48 +00:00
|
|
|
*args = &(*args)[1..];
|
2014-10-07 19:54:07 +00:00
|
|
|
let mut rhs = dispatch(args, error);
|
|
|
|
while args.len() > 0 {
|
2014-11-08 06:45:33 +00:00
|
|
|
let subprec = *hashmap.get(&args[0]).unwrap_or_else(|| {
|
2014-10-07 19:54:07 +00:00
|
|
|
*error = true;
|
|
|
|
&min_prec
|
|
|
|
});
|
2015-01-10 18:07:08 +00:00
|
|
|
if subprec as usize <= prec as usize || *error {
|
2014-10-07 19:54:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
rhs = parse_expr_helper(hashmap, args, rhs, subprec, error);
|
|
|
|
}
|
|
|
|
lhs = match prec {
|
2014-11-19 20:50:37 +00:00
|
|
|
Precedence::UnOp | Precedence::BUnOp => {
|
2014-10-07 19:54:07 +00:00
|
|
|
*error = true;
|
|
|
|
false
|
|
|
|
}
|
2014-11-19 20:50:37 +00:00
|
|
|
Precedence::And => lhs && rhs,
|
|
|
|
Precedence::Or => lhs || rhs,
|
|
|
|
Precedence::BinOp => three(&[if lhs { b" " } else { b"" }, op, if rhs { b" " } else { b"" }], error),
|
|
|
|
Precedence::Paren => unimplemented!(), // TODO: implement parentheses
|
2014-10-07 19:54:07 +00:00
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
if args.len() > 0 {
|
2014-11-08 06:45:33 +00:00
|
|
|
prec = *hashmap.get(&args[0]).unwrap_or_else(|| {
|
2014-10-07 19:54:07 +00:00
|
|
|
*error = true;
|
|
|
|
&min_prec
|
|
|
|
});
|
|
|
|
}
|
2014-10-07 05:16:07 +00:00
|
|
|
}
|
2014-10-07 19:54:07 +00:00
|
|
|
lhs
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn setup_hashmap<'a>() -> HashMap<&'a [u8], Precedence> {
|
|
|
|
let mut hashmap = HashMap::<&'a [u8], Precedence>::new();
|
|
|
|
|
2014-11-19 20:50:37 +00:00
|
|
|
hashmap.insert(b"-b", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-c", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-d", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-e", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-f", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-g", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-h", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-L", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-n", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-p", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-r", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-S", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-s", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-t", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-u", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-w", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-x", Precedence::UnOp);
|
|
|
|
hashmap.insert(b"-z", Precedence::UnOp);
|
|
|
|
|
|
|
|
hashmap.insert(b"=", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"!=", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-eq", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-ne", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-gt", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-ge", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-lt", Precedence::BinOp);
|
|
|
|
hashmap.insert(b"-le", Precedence::BinOp);
|
|
|
|
|
|
|
|
hashmap.insert(b"!", Precedence::BUnOp);
|
|
|
|
|
|
|
|
hashmap.insert(b"-a", Precedence::And);
|
|
|
|
hashmap.insert(b"-o", Precedence::Or);
|
|
|
|
|
|
|
|
hashmap.insert(b"(", Precedence::Paren);
|
|
|
|
hashmap.insert(b")", Precedence::Paren);
|
2014-10-07 19:54:07 +00:00
|
|
|
|
|
|
|
hashmap
|
2014-10-07 05:16:07 +00:00
|
|
|
}
|
|
|
|
|
2015-01-08 12:56:41 +00:00
|
|
|
#[derive(Eq, PartialEq)]
|
2014-07-12 01:12:29 +00:00
|
|
|
enum PathCondition {
|
|
|
|
BlockSpecial,
|
|
|
|
CharacterSpecial,
|
|
|
|
Directory,
|
|
|
|
Exists,
|
|
|
|
Regular,
|
|
|
|
GroupIDFlag,
|
|
|
|
SymLink,
|
|
|
|
FIFO,
|
|
|
|
Readable,
|
|
|
|
Socket,
|
|
|
|
NonEmpty,
|
|
|
|
UserIDFlag,
|
|
|
|
Writable,
|
|
|
|
Executable,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
fn path(path: &[u8], cond: PathCondition) -> bool {
|
2014-07-15 22:39:03 +00:00
|
|
|
use libc::{stat, lstat, S_IFMT, S_IFLNK, S_IFBLK, S_IFCHR, S_IFDIR, S_IFREG};
|
2014-07-12 01:12:29 +00:00
|
|
|
use libc::{S_IFIFO, mode_t};
|
|
|
|
static S_ISUID: mode_t = 0o4000;
|
|
|
|
static S_ISGID: mode_t = 0o2000;
|
2014-07-15 22:39:03 +00:00
|
|
|
static S_IFSOCK: mode_t = 0o140000;
|
2014-07-12 01:12:29 +00:00
|
|
|
|
|
|
|
enum Permission {
|
|
|
|
Read = 0o4,
|
|
|
|
Write = 0o2,
|
|
|
|
Execute = 0o1,
|
|
|
|
}
|
2015-03-08 18:06:04 +00:00
|
|
|
let perm = |stat: stat, p: Permission| {
|
2014-07-12 01:12:29 +00:00
|
|
|
use libc::{getgid, getuid};
|
|
|
|
let (uid, gid) = unsafe { (getuid(), getgid()) };
|
|
|
|
if uid == stat.st_uid {
|
2015-01-08 13:04:14 +00:00
|
|
|
stat.st_mode & ((p as mode_t) << 6) != 0
|
2014-07-12 01:12:29 +00:00
|
|
|
} else if gid == stat.st_gid {
|
2015-01-08 13:04:14 +00:00
|
|
|
stat.st_mode & ((p as mode_t) << 3) != 0
|
2014-07-12 01:12:29 +00:00
|
|
|
} else {
|
2015-01-08 13:04:14 +00:00
|
|
|
stat.st_mode & ((p as mode_t) << 0) != 0
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-02-22 12:22:51 +00:00
|
|
|
let path = CString::new(path).unwrap();
|
2014-07-12 01:12:29 +00:00
|
|
|
let mut stat = unsafe { std::mem::zeroed() };
|
2014-11-19 20:50:37 +00:00
|
|
|
if cond == PathCondition::SymLink {
|
2014-07-12 01:12:29 +00:00
|
|
|
if unsafe { lstat(path.as_ptr(), &mut stat) } == 0 {
|
2014-07-15 22:39:03 +00:00
|
|
|
if stat.st_mode & S_IFMT == S_IFLNK {
|
2014-07-12 01:12:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if unsafe { libc::stat(path.as_ptr(), &mut stat) } != 0 {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-15 22:39:03 +00:00
|
|
|
let file_type = stat.st_mode & S_IFMT;
|
2014-07-12 01:12:29 +00:00
|
|
|
match cond {
|
2014-11-19 20:50:37 +00:00
|
|
|
PathCondition::BlockSpecial => file_type == S_IFBLK,
|
|
|
|
PathCondition::CharacterSpecial => file_type == S_IFCHR,
|
|
|
|
PathCondition::Directory => file_type == S_IFDIR,
|
|
|
|
PathCondition::Exists => true,
|
|
|
|
PathCondition::Regular => file_type == S_IFREG,
|
|
|
|
PathCondition::GroupIDFlag => stat.st_mode & S_ISGID != 0,
|
|
|
|
PathCondition::SymLink => true,
|
|
|
|
PathCondition::FIFO => file_type == S_IFIFO,
|
|
|
|
PathCondition::Readable => perm(stat, Permission::Read),
|
|
|
|
PathCondition::Socket => file_type == S_IFSOCK,
|
|
|
|
PathCondition::NonEmpty => stat.st_size > 0,
|
|
|
|
PathCondition::UserIDFlag => stat.st_mode & S_ISUID != 0,
|
|
|
|
PathCondition::Writable => perm(stat, Permission::Write),
|
|
|
|
PathCondition::Executable => perm(stat, Permission::Execute),
|
2014-07-12 01:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn path(path: &[u8], cond: PathCondition) -> bool {
|
2015-01-29 07:29:31 +00:00
|
|
|
use std::old_io::{TypeFile, TypeDirectory, TypeBlockSpecial, TypeNamedPipe};
|
|
|
|
use std::old_io::fs::{stat};
|
2015-02-05 22:09:38 +00:00
|
|
|
use std::old_path::{Path};
|
2014-07-12 01:12:29 +00:00
|
|
|
|
|
|
|
let path = match Path::new_opt(path) {
|
|
|
|
Some(p) => p,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
let stat = match stat(&path) {
|
|
|
|
Ok(s) => s,
|
|
|
|
_ => return false,
|
|
|
|
};
|
|
|
|
match cond {
|
|
|
|
BlockSpecial => stat.kind == TypeBlockSpecial,
|
|
|
|
CharacterSpecial => false,
|
|
|
|
Directory => stat.kind == TypeDirectory,
|
|
|
|
Exists => true,
|
|
|
|
Regular => stat.kind == TypeFile,
|
|
|
|
GroupIDFlag => false,
|
|
|
|
SymLink => false,
|
|
|
|
FIFO => stat.kind == TypeNamedPipe,
|
|
|
|
Readable => false, // TODO
|
|
|
|
Socket => false, // TODO?
|
2014-09-28 03:17:34 +00:00
|
|
|
NonEmpty => stat.size > 0,
|
2014-07-12 01:12:29 +00:00
|
|
|
UserIDFlag => false,
|
|
|
|
Writable => false, // TODO
|
|
|
|
Executable => false, // TODO
|
|
|
|
}
|
|
|
|
}
|