<commit_before>#![feature(env, old_io, libc, old_path, plugin)]
#![plugin(json_macros)]

extern crate fuse;
extern crate time;
extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use std::old_io::{FileType, USER_FILE, USER_DIR};
use std::env;
use std::old_path::PosixPath;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use rustc_serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.pretty().to_string().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.pretty().to_string().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (days 15 & 16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let args = env::args().collect::<Vec<_>>();
    let mountpoint = match &args[..] {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", args[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>env is a stable feature.<commit_after>#![feature(old_io, libc, old_path, plugin)]
#![plugin(json_macros)]

extern crate fuse;
extern crate time;
extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use std::old_io::{FileType, USER_FILE, USER_DIR};
use std::env;
use std::old_path::PosixPath;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use rustc_serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.pretty().to_string().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.pretty().to_string().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (days 15 & 16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let args = env::args().collect::<Vec<_>>();
    let mountpoint = match &args[..] {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", args[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = ::EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<commit_msg>Errno: Add compatibility for PowerPC<commit_after>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = ::EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    #[cfg(not(target_arch = "powerpc"))]
    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    #[cfg(target_arch = "powerpc")]
    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = 58;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::error;
use std::io;
use std::fmt;
use std::num;
use std::result;
use std::string;

use gpgme;
use libarchive;
use regex;

use package;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    ArchiveError(libarchive::error::ArchiveError),
    FileNotFound(String),
    GPG(gpgme::Error),
    InvalidKeyParameter(String),
    InvalidPackageIdent(String),
    IO(io::Error),
    MetaFileNotFound(package::MetaFile),
    MetaFileMalformed(package::MetaFile),
    ParseIntError(num::ParseIntError),
    PermissionFailed,
    RegexParse(regex::Error),
    StringFromUtf8Error(string::FromUtf8Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Error::ArchiveError(ref err) => format!("{}", err),
            Error::FileNotFound(ref e) => format!("File not found at: {}", e),
            Error::GPG(ref e) => format!("{}", e),
            Error::InvalidKeyParameter(ref e) => {
                format!("Invalid parameter for key generation: {:?}", e)
            }
            Error::InvalidPackageIdent(ref e) => {
                format!("Invalid package identifier: {:?}. A valid identifier is in the form \
                         origin/name (example: chef/redis)",
                        e)
            }
            Error::IO(ref err) => format!("{}", err),
            Error::MetaFileNotFound(ref e) => format!("Couldn't read MetaFile: {}, not found", e),
            Error::MetaFileMalformed(ref e) => {
                format!("MetaFile: {:?}, didn't contain a valid UTF-8 string", e)
            }
            Error::ParseIntError(ref e) => format!("{}", e),
            Error::PermissionFailed => format!("Failed to set permissions"),
            Error::RegexParse(ref e) => format!("{}", e),
            Error::StringFromUtf8Error(ref e) => format!("{}", e),
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ArchiveError(ref err) => err.description(),
            Error::FileNotFound(_) => "File not found",
            Error::GPG(_) => "gpgme error",
            Error::InvalidKeyParameter(_) => "Key parameter error",
            Error::InvalidPackageIdent(_) => "Package identifiers must be in origin/name format (example: chef/redis)",
            Error::IO(ref err) => err.description(),
            Error::MetaFileNotFound(_) => "Failed to read an archive's metafile",
            Error::MetaFileMalformed(_) => "MetaFile didn't contain a valid UTF-8 string",
            Error::ParseIntError(_) => "Failed to parse an integer from a string!",
            Error::PermissionFailed => "Failed to set permissions",
            Error::RegexParse(_) => "Failed to parse a regular expression",
            Error::StringFromUtf8Error(_) => "Failed to convert a string from a Vec<u8> as UTF-8",
        }
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(err: string::FromUtf8Error) -> Error {
        Error::StringFromUtf8Error(err)
    }
}

impl From<gpgme::Error> for Error {
    fn from(err: gpgme::Error) -> Error {
        Error::GPG(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<libarchive::error::ArchiveError> for Error {
    fn from(err: libarchive::error::ArchiveError) -> Error {
        Error::ArchiveError(err)
    }
}

impl From<num::ParseIntError> for Error {
    fn from(err: num::ParseIntError) -> Error {
        Error::ParseIntError(err)
    }
}

impl From<regex::Error> for Error {
    fn from(err: regex::Error) -> Error {
        Error::RegexParse(err)
    }
}
<commit_msg>Audit all Error types in `bldr` crate.<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

use std::error;
use std::io;
use std::fmt;
use std::num;
use std::result;
use std::string;

use gpgme;
use libarchive;
use regex;

use package;

pub type Result<T> = result::Result<T, Error>;

/// Core error types
#[derive(Debug)]
pub enum Error {
    /// Occurs when a `bldr_core::package::PackageArchive` is being read.
    ArchiveError(libarchive::error::ArchiveError),
    /// Occurs when a file that should exist does not or could not be read.
    FileNotFound(String),
    /// When an error occurs in GpgME library calls.
    GPG(gpgme::Error),
    /// Occurs when a required GPG key is not found.
    InvalidKeyParameter(String),
    /// Occurs when a package identifier string cannot be successfully parsed.
    InvalidPackageIdent(String),
    /// Occurs when making lower level IO calls.
    IO(io::Error),
    /// Occurs when a package metadata file cannot be opened, read, or parsed.
    MetaFileMalformed(package::MetaFile),
    /// Occurs when a particular package metadata file is not found.
    MetaFileNotFound(package::MetaFile),
    /// When an error occurs parsing an integer.
    ParseIntError(num::ParseIntError),
    /// Occurs when setting ownership or permissions on a file or directory fails.
    PermissionFailed,
    /// When an error occurs parsing or compiling a regular expression.
    RegexParse(regex::Error),
    /// When an error occurs converting a `String` from a UTF-8 byte vector.
    StringFromUtf8Error(string::FromUtf8Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Error::ArchiveError(ref err) => format!("{}", err),
            Error::FileNotFound(ref e) => format!("File not found at: {}", e),
            Error::GPG(ref e) => format!("{}", e),
            Error::InvalidKeyParameter(ref e) => {
                format!("Invalid parameter for key generation: {:?}", e)
            }
            Error::InvalidPackageIdent(ref e) => {
                format!("Invalid package identifier: {:?}. A valid identifier is in the form \
                         origin/name (example: chef/redis)",
                        e)
            }
            Error::IO(ref err) => format!("{}", err),
            Error::MetaFileNotFound(ref e) => format!("Couldn't read MetaFile: {}, not found", e),
            Error::MetaFileMalformed(ref e) => {
                format!("MetaFile: {:?}, didn't contain a valid UTF-8 string", e)
            }
            Error::ParseIntError(ref e) => format!("{}", e),
            Error::PermissionFailed => format!("Failed to set permissions"),
            Error::RegexParse(ref e) => format!("{}", e),
            Error::StringFromUtf8Error(ref e) => format!("{}", e),
        };
        write!(f, "{}", msg)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ArchiveError(ref err) => err.description(),
            Error::FileNotFound(_) => "File not found",
            Error::GPG(_) => "gpgme error",
            Error::InvalidKeyParameter(_) => "Key parameter error",
            Error::InvalidPackageIdent(_) => "Package identifiers must be in origin/name format (example: chef/redis)",
            Error::IO(ref err) => err.description(),
            Error::MetaFileNotFound(_) => "Failed to read an archive's metafile",
            Error::MetaFileMalformed(_) => "MetaFile didn't contain a valid UTF-8 string",
            Error::ParseIntError(_) => "Failed to parse an integer from a string!",
            Error::PermissionFailed => "Failed to set permissions",
            Error::RegexParse(_) => "Failed to parse a regular expression",
            Error::StringFromUtf8Error(_) => "Failed to convert a string from a Vec<u8> as UTF-8",
        }
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(err: string::FromUtf8Error) -> Error {
        Error::StringFromUtf8Error(err)
    }
}

impl From<gpgme::Error> for Error {
    fn from(err: gpgme::Error) -> Error {
        Error::GPG(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<libarchive::error::ArchiveError> for Error {
    fn from(err: libarchive::error::ArchiveError) -> Error {
        Error::ArchiveError(err)
    }
}

impl From<num::ParseIntError> for Error {
    fn from(err: num::ParseIntError) -> Error {
        Error::ParseIntError(err)
    }
}

impl From<regex::Error> for Error {
    fn from(err: regex::Error) -> Error {
        Error::RegexParse(err)
    }
}
<|endoftext|>


<commit_before>//! Copy paste of Cargo's src/util/flock.rs with modifications to not depend on
//! other Cargo stuff

use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::{Display, Path, PathBuf};
use std::{fs, io};

use fs2::FileExt;
use fs2;

#[derive(PartialEq)]
enum State {
    Exclusive,
    Shared,
}

pub struct FileLock {
    file: File,
    path: PathBuf,
}

impl FileLock {
    pub fn parent(&self) -> &Path {
        self.path.parent().unwrap()
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn remove_siblings(&self) -> io::Result<()> {
        let path = self.path();
        for entry in path.parent().unwrap().read_dir()? {
            let entry = entry?;
            if Some(&entry.file_name()[..]) == path.file_name() {
                continue;
            }
            let kind = entry.file_type()?;
            if kind.is_dir() {
                fs::remove_dir_all(entry.path())?;
            } else {
                fs::remove_file(entry.path())?;
            }
        }
        Ok(())
    }
}

pub struct Filesystem {
    path: PathBuf,
}

impl Filesystem {
    pub fn new(path: PathBuf) -> Filesystem {
        Filesystem { path: path }
    }

    pub fn join<T>(&self, other: T) -> Filesystem
    where
        T: AsRef<Path>,
    {
        Filesystem::new(self.path.join(other))
    }

    pub fn open_ro<P>(&self, path: P, msg: &str) -> io::Result<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true),
            State::Shared,
            msg,
        )
    }

    pub fn open_rw<P>(&self, path: P, msg: &str) -> io::Result<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true).write(true).create(true),
            State::Exclusive,
            msg,
        )
    }

    fn open(
        &self,
        path: &Path,
        opts: &OpenOptions,
        state: State,
        msg: &str,
    ) -> io::Result<FileLock> {
        let path = self.path.join(path);

        let f = opts.open(&path).or_else(|e| {
            if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
                create_dir_all(path.parent().unwrap())?;
                opts.open(&path)
            } else {
                Err(e)
            }
        })?;

        match state {
            State::Exclusive => {
                acquire(
                    msg,
                    &path,
                    &|| f.try_lock_exclusive(),
                    &|| f.lock_exclusive(),
                )?;
            }
            State::Shared => {
                acquire(msg, &path, &|| f.try_lock_shared(), &|| f.lock_shared())?;
            }
        }

        Ok(FileLock {
            file: f,
            path: path,
        })
    }

    pub fn display(&self) -> Display {
        self.path.display()
    }
}

impl Drop for FileLock {
    fn drop(&mut self) {
        self.file.unlock().ok();
    }
}

fn acquire(
    msg: &str,
    path: &Path,
    try: &Fn() -> io::Result<()>,
    block: &Fn() -> io::Result<()>,
) -> io::Result<()> {
    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    fn is_on_nfs_mount(path: &Path) -> bool {
        use std::ffi::CString;
        use std::mem;
        use std::os::unix::prelude::*;

        let path = match CString::new(path.as_os_str().as_bytes()) {
            Ok(path) => path,
            Err(_) => return false,
        };

        unsafe {
            let mut buf: ::libc::statfs = mem::zeroed();
            let r = ::libc::statfs(path.as_ptr(), &mut buf);

            r == 0 && buf.f_type as u32 == ::libc::NFS_SUPER_MAGIC as u32
        }
    }

    #[cfg(any(not(target_os = "linux"), target_env = "musl"))]
    fn is_on_nfs_mount(_path: &Path) -> bool {
        false
    }

    if is_on_nfs_mount(path) {
        return Ok(());
    }

    match try() {
        Ok(_) => return Ok(()),
        #[cfg(target_os = "macos")]
        Err(ref e) if e.raw_os_error() == Some(::libc::ENOTSUP) =>
        {
            return Ok(())
        }
        Err(e) => if e.raw_os_error() != fs2::lock_contended_error().raw_os_error() {
            return Err(e);
        },
    }

    writeln!(
        io::stderr(),
        "{:>12} waiting for file lock on {}",
        "Blocking",
        msg
    ).ok();

    block()
}

fn create_dir_all(path: &Path) -> io::Result<()> {
    match create_dir(path) {
        Ok(()) => Ok(()),
        Err(e) => {
            if e.kind() == io::ErrorKind::NotFound {
                if let Some(p) = path.parent() {
                    return create_dir_all(p).and_then(|()| create_dir(path));
                }
            }
            Err(e)
        }
    }
}

fn create_dir(path: &Path) -> io::Result<()> {
    match fs::create_dir(path) {
        Ok(()) => Ok(()),
        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
        Err(e) => Err(e),
    }
}
<commit_msg>fix compilation with latest nightly<commit_after>//! Copy paste of Cargo's src/util/flock.rs with modifications to not depend on
//! other Cargo stuff

use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::{Display, Path, PathBuf};
use std::{fs, io};

use fs2::FileExt;
use fs2;

#[derive(PartialEq)]
enum State {
    Exclusive,
    Shared,
}

pub struct FileLock {
    file: File,
    path: PathBuf,
}

impl FileLock {
    pub fn parent(&self) -> &Path {
        self.path.parent().unwrap()
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn remove_siblings(&self) -> io::Result<()> {
        let path = self.path();
        for entry in path.parent().unwrap().read_dir()? {
            let entry = entry?;
            if Some(&entry.file_name()[..]) == path.file_name() {
                continue;
            }
            let kind = entry.file_type()?;
            if kind.is_dir() {
                fs::remove_dir_all(entry.path())?;
            } else {
                fs::remove_file(entry.path())?;
            }
        }
        Ok(())
    }
}

pub struct Filesystem {
    path: PathBuf,
}

impl Filesystem {
    pub fn new(path: PathBuf) -> Filesystem {
        Filesystem { path: path }
    }

    pub fn join<T>(&self, other: T) -> Filesystem
    where
        T: AsRef<Path>,
    {
        Filesystem::new(self.path.join(other))
    }

    pub fn open_ro<P>(&self, path: P, msg: &str) -> io::Result<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true),
            State::Shared,
            msg,
        )
    }

    pub fn open_rw<P>(&self, path: P, msg: &str) -> io::Result<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true).write(true).create(true),
            State::Exclusive,
            msg,
        )
    }

    fn open(
        &self,
        path: &Path,
        opts: &OpenOptions,
        state: State,
        msg: &str,
    ) -> io::Result<FileLock> {
        let path = self.path.join(path);

        let f = opts.open(&path).or_else(|e| {
            if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
                create_dir_all(path.parent().unwrap())?;
                opts.open(&path)
            } else {
                Err(e)
            }
        })?;

        match state {
            State::Exclusive => {
                acquire(
                    msg,
                    &path,
                    &|| f.try_lock_exclusive(),
                    &|| f.lock_exclusive(),
                )?;
            }
            State::Shared => {
                acquire(msg, &path, &|| f.try_lock_shared(), &|| f.lock_shared())?;
            }
        }

        Ok(FileLock {
            file: f,
            path: path,
        })
    }

    pub fn display(&self) -> Display {
        self.path.display()
    }
}

impl Drop for FileLock {
    fn drop(&mut self) {
        self.file.unlock().ok();
    }
}

fn acquire(
    msg: &str,
    path: &Path,
    try: &dyn Fn() -> io::Result<()>,
    block: &dyn Fn() -> io::Result<()>,
) -> io::Result<()> {
    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    fn is_on_nfs_mount(path: &Path) -> bool {
        use std::ffi::CString;
        use std::mem;
        use std::os::unix::prelude::*;

        let path = match CString::new(path.as_os_str().as_bytes()) {
            Ok(path) => path,
            Err(_) => return false,
        };

        unsafe {
            let mut buf: ::libc::statfs = mem::zeroed();
            let r = ::libc::statfs(path.as_ptr(), &mut buf);

            r == 0 && buf.f_type as u32 == ::libc::NFS_SUPER_MAGIC as u32
        }
    }

    #[cfg(any(not(target_os = "linux"), target_env = "musl"))]
    fn is_on_nfs_mount(_path: &Path) -> bool {
        false
    }

    if is_on_nfs_mount(path) {
        return Ok(());
    }

    match try() {
        Ok(_) => return Ok(()),
        #[cfg(target_os = "macos")]
        Err(ref e) if e.raw_os_error() == Some(::libc::ENOTSUP) =>
        {
            return Ok(())
        }
        Err(e) => if e.raw_os_error() != fs2::lock_contended_error().raw_os_error() {
            return Err(e);
        },
    }

    writeln!(
        io::stderr(),
        "{:>12} waiting for file lock on {}",
        "Blocking",
        msg
    ).ok();

    block()
}

fn create_dir_all(path: &Path) -> io::Result<()> {
    match create_dir(path) {
        Ok(()) => Ok(()),
        Err(e) => {
            if e.kind() == io::ErrorKind::NotFound {
                if let Some(p) = path.parent() {
                    return create_dir_all(p).and_then(|()| create_dir(path));
                }
            }
            Err(e)
        }
    }
}

fn create_dir(path: &Path) -> io::Result<()> {
    match fs::create_dir(path) {
        Ok(()) => Ok(()),
        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
        Err(e) => Err(e),
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::eve::eve::EveJson;
use crate::logger::log;
use maxminddb::{geoip2, Reader};
use std::sync::Mutex;
use std::time::{Duration, UNIX_EPOCH};

const DAYS_28: i64 = 86400 * 28;
const UPDATE_CHECK_TIMEOUT: u64 = 60;

struct Inner {
    reader: Reader<Vec<u8>>,
    last_modified: u64,
    last_update_check: std::time::Instant,
}

pub struct GeoIP {
    filename: String,
    inner: Mutex<Inner>,
}

impl GeoIP {
    pub fn open(filename: Option<String>) -> Result<GeoIP, Box<dyn std::error::Error>> {
        let (filename, reader) = if let Some(filename) = &filename {
            let reader = Reader::open_readfile(filename)?;
            (filename.clone(), reader)
        } else if let Some(filename) = find_database() {
            let reader = Reader::open_readfile(&filename)?;
            (filename, reader)
        } else {
            return Err("No database file found".into());
        };

        // Warn if database older than 4 weeks.
        let now = chrono::offset::Utc::now();
        let dt = chrono::NaiveDateTime::from_timestamp(reader.metadata.build_epoch as i64, 0);
        if (reader.metadata.build_epoch as i64) < now.timestamp() - DAYS_28 {
            log::warn!("GeoIP database older than 4 weeks: {}", dt);
        } else {
            log::info!("Loaded GeoIP database: {}: {}", filename, dt);
        }

        let last_modified = match Self::get_last_modified(&filename) {
            Ok(last_modified) => last_modified,
            Err(err) => {
                log::error!(
                    "Failed to get last modified time for {}, file watch will not be enabled: {}",
                    filename,
                    err
                );
                0
            }
        };

        let inner = Inner {
            reader: reader,
            last_modified: last_modified,
            last_update_check: std::time::Instant::now(),
        };

        let geoip = GeoIP {
            filename: filename,
            inner: Mutex::new(inner),
        };
        return Ok(geoip);
    }

    pub fn get_last_modified(filename: &str) -> Result<u64, Box<dyn std::error::Error>> {
        let last_modified = std::fs::metadata(filename)?
            .modified()?
            .duration_since(UNIX_EPOCH)?
            .as_secs();
        Ok(last_modified)
    }

    fn check_for_update(&self, inner: &mut Inner) -> bool {
        if inner.last_update_check.elapsed() < Duration::from_secs(UPDATE_CHECK_TIMEOUT) {
            return false;
        }
        let last_modified = match Self::get_last_modified(&self.filename) {
            Ok(last_modified) => last_modified,
            Err(err) => {
                log::warn!(
                    "Failed to get modification time for GeoIP database file {}: {}: ",
                    self.filename,
                    err
                );
                return false;
            }
        };
        let mut updated = false;
        if last_modified <= inner.last_modified {
            log::debug!("GeoIP database file has not been updated");
        } else {
            log::debug!("GeoIP database file on disk has been updated");
            match Reader::open_readfile(&self.filename) {
                Err(err) => {
                    log::error!("Failed to open new GeoIP database file: {}", err);
                }
                Ok(new_reader) => {
                    inner.reader = new_reader;
                    inner.last_modified = last_modified;
                    updated = true;
                }
            }
        }
        inner.last_update_check = std::time::Instant::now();
        updated
    }

    pub fn lookup_city_from_str(
        &self,
        addr: &str,
    ) -> Result<geoip2::City, Box<dyn std::error::Error>> {
        let mut inner = self.inner.lock().unwrap();
        if self.check_for_update(&mut inner) {
            let build_time =
                chrono::NaiveDateTime::from_timestamp(inner.reader.metadata.build_epoch as i64, 0);
            log::info!("GeoIP database has been updated to {}", build_time);
        }
        let ip: std::net::IpAddr = std::str::FromStr::from_str(addr)?;
        let city = inner.reader.lookup(ip)?;
        Ok(city)
    }

    pub fn add_geoip_to_eve(&self, eve: &mut EveJson) {
        if let EveJson::String(addr) = &eve["dest_ip"] {
            if let Ok(city) = self.lookup_city_from_str(addr) {
                eve["geoip_destination"] = self.as_json(city);
            }
        }
        if let EveJson::String(addr) = &eve["src_ip"] {
            if let Ok(city) = self.lookup_city_from_str(addr) {
                eve["geoip_source"] = self.as_json(city);
            }
        }
    }

    fn as_json(&self, city: geoip2::City) -> serde_json::Value {
        let mut obj = serde_json::json!({});
        if let Some(city) = city.city {
            if let Some(names) = city.names {
                if let Some(name) = names.get("en") {
                    obj["city_name"] = name.to_string().into();
                }
            }
        }
        if let Some(country) = city.country {
            if let Some(names) = country.names {
                if let Some(name) = names.get("en") {
                    obj["country_name"] = name.to_string().into();
                }
            }
            if let Some(iso_code) = country.iso_code {
                obj["country_iso_code"] = iso_code.into();
            }
        }
        if let Some(subdivisions) = city.subdivisions {
            if let Some(subdivision) = &subdivisions.first() {
                if let Some(names) = &subdivision.names {
                    if let Some(name) = names.get("en") {
                        obj["region_name"] = name.to_string().into();
                    }
                }
                if let Some(iso_code) = &subdivision.iso_code {
                    obj["region_iso_code"] = iso_code.to_string().into();
                }
            }
        }
        if let Some(location) = city.location {
            let mut locobj = serde_json::json!({});
            let mut include = false;
            if let Some(lat) = location.latitude {
                locobj["lat"] = lat.into();
                include = true;
            }
            if let Some(lon) = location.longitude {
                locobj["lon"] = lon.into();
                include = true;
            }
            if include {
                obj["location"] = locobj;
            }
        }
        if let Some(continent) = city.continent {
            if let Some(names) = continent.names {
                if let Some(name) = names.get("en") {
                    obj["continent_name"] = name.to_string().into();
                }
            }
        }
        return obj;
    }
}

lazy_static! {
    static ref PATHS: Vec<&'static str> = {
        let mut v = Vec::new();
        v.push("/etc/evebox/GeoLite2-City.mmdb");
        v.push("/usr/local/share/GeoIP/GeoLite2-City.mmdb");
        v.push("/usr/share/GeoIP/GeoLite2-City.mmdb");
        v
    };
}

fn find_database() -> Option<String> {
    for filename in PATHS.iter() {
        if maxminddb::Reader::open_readfile(filename).is_ok() {
            log::debug!("Found geoip database file {}", filename);
            return Some(filename.to_string());
        }
    }
    None
}

#[cfg(test)]
mod test {

    #[test]
    fn lookup_example() {
        let db = super::GeoIP::open(None).unwrap();
        let _city = db.lookup_city_from_str("128.101.101.101").unwrap();
    }
}
<commit_msg>geoip: logging fixup<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::eve::eve::EveJson;
use crate::logger::log;
use maxminddb::{geoip2, Reader};
use std::sync::Mutex;
use std::time::{Duration, UNIX_EPOCH};

const DAYS_28: i64 = 86400 * 28;
const UPDATE_CHECK_TIMEOUT: u64 = 60;

struct Inner {
    reader: Reader<Vec<u8>>,
    last_modified: u64,
    last_update_check: std::time::Instant,
}

pub struct GeoIP {
    filename: String,
    inner: Mutex<Inner>,
}

impl GeoIP {
    pub fn open(filename: Option<String>) -> Result<GeoIP, Box<dyn std::error::Error>> {
        let (filename, reader) = if let Some(filename) = &filename {
            let reader = Reader::open_readfile(filename)?;
            (filename.clone(), reader)
        } else if let Some(filename) = find_database() {
            let reader = Reader::open_readfile(&filename)?;
            (filename, reader)
        } else {
            return Err("No database file found".into());
        };

        // Warn if database older than 4 weeks.
        let now = chrono::offset::Utc::now();
        let dt = chrono::NaiveDateTime::from_timestamp(reader.metadata.build_epoch as i64, 0);
        if (reader.metadata.build_epoch as i64) < now.timestamp() - DAYS_28 {
            log::warn!("GeoIP database older than 4 weeks: {}", dt);
        }
        log::info!("Loaded GeoIP database: {}: {}", filename, dt);

        let last_modified = match Self::get_last_modified(&filename) {
            Ok(last_modified) => last_modified,
            Err(err) => {
                log::error!(
                    "Failed to get last modified time for {}, file watch will not be enabled: {}",
                    filename,
                    err
                );
                0
            }
        };

        let inner = Inner {
            reader: reader,
            last_modified: last_modified,
            last_update_check: std::time::Instant::now(),
        };

        let geoip = GeoIP {
            filename: filename,
            inner: Mutex::new(inner),
        };
        return Ok(geoip);
    }

    pub fn get_last_modified(filename: &str) -> Result<u64, Box<dyn std::error::Error>> {
        let last_modified = std::fs::metadata(filename)?
            .modified()?
            .duration_since(UNIX_EPOCH)?
            .as_secs();
        Ok(last_modified)
    }

    fn check_for_update(&self, inner: &mut Inner) -> bool {
        if inner.last_update_check.elapsed() < Duration::from_secs(UPDATE_CHECK_TIMEOUT) {
            return false;
        }
        let last_modified = match Self::get_last_modified(&self.filename) {
            Ok(last_modified) => last_modified,
            Err(err) => {
                log::warn!(
                    "Failed to get modification time for GeoIP database file {}: {}: ",
                    self.filename,
                    err
                );
                return false;
            }
        };
        let mut updated = false;
        if last_modified <= inner.last_modified {
            log::debug!("GeoIP database file has not been updated");
        } else {
            log::debug!("GeoIP database file on disk has been updated");
            match Reader::open_readfile(&self.filename) {
                Err(err) => {
                    log::error!("Failed to open new GeoIP database file: {}", err);
                }
                Ok(new_reader) => {
                    inner.reader = new_reader;
                    inner.last_modified = last_modified;
                    updated = true;
                }
            }
        }
        inner.last_update_check = std::time::Instant::now();
        updated
    }

    pub fn lookup_city_from_str(
        &self,
        addr: &str,
    ) -> Result<geoip2::City, Box<dyn std::error::Error>> {
        let mut inner = self.inner.lock().unwrap();
        if self.check_for_update(&mut inner) {
            let build_time =
                chrono::NaiveDateTime::from_timestamp(inner.reader.metadata.build_epoch as i64, 0);
            log::info!("GeoIP database has been updated to {}", build_time);
        }
        let ip: std::net::IpAddr = std::str::FromStr::from_str(addr)?;
        let city = inner.reader.lookup(ip)?;
        Ok(city)
    }

    pub fn add_geoip_to_eve(&self, eve: &mut EveJson) {
        if let EveJson::String(addr) = &eve["dest_ip"] {
            if let Ok(city) = self.lookup_city_from_str(addr) {
                eve["geoip_destination"] = self.as_json(city);
            }
        }
        if let EveJson::String(addr) = &eve["src_ip"] {
            if let Ok(city) = self.lookup_city_from_str(addr) {
                eve["geoip_source"] = self.as_json(city);
            }
        }
    }

    fn as_json(&self, city: geoip2::City) -> serde_json::Value {
        let mut obj = serde_json::json!({});
        if let Some(city) = city.city {
            if let Some(names) = city.names {
                if let Some(name) = names.get("en") {
                    obj["city_name"] = name.to_string().into();
                }
            }
        }
        if let Some(country) = city.country {
            if let Some(names) = country.names {
                if let Some(name) = names.get("en") {
                    obj["country_name"] = name.to_string().into();
                }
            }
            if let Some(iso_code) = country.iso_code {
                obj["country_iso_code"] = iso_code.into();
            }
        }
        if let Some(subdivisions) = city.subdivisions {
            if let Some(subdivision) = &subdivisions.first() {
                if let Some(names) = &subdivision.names {
                    if let Some(name) = names.get("en") {
                        obj["region_name"] = name.to_string().into();
                    }
                }
                if let Some(iso_code) = &subdivision.iso_code {
                    obj["region_iso_code"] = iso_code.to_string().into();
                }
            }
        }
        if let Some(location) = city.location {
            let mut locobj = serde_json::json!({});
            let mut include = false;
            if let Some(lat) = location.latitude {
                locobj["lat"] = lat.into();
                include = true;
            }
            if let Some(lon) = location.longitude {
                locobj["lon"] = lon.into();
                include = true;
            }
            if include {
                obj["location"] = locobj;
            }
        }
        if let Some(continent) = city.continent {
            if let Some(names) = continent.names {
                if let Some(name) = names.get("en") {
                    obj["continent_name"] = name.to_string().into();
                }
            }
        }
        return obj;
    }
}

lazy_static! {
    static ref PATHS: Vec<&'static str> = {
        let mut v = Vec::new();
        v.push("/etc/evebox/GeoLite2-City.mmdb");
        v.push("/usr/local/share/GeoIP/GeoLite2-City.mmdb");
        v.push("/usr/share/GeoIP/GeoLite2-City.mmdb");
        v
    };
}

fn find_database() -> Option<String> {
    for filename in PATHS.iter() {
        if maxminddb::Reader::open_readfile(filename).is_ok() {
            log::debug!("Found geoip database file {}", filename);
            return Some(filename.to_string());
        }
    }
    None
}

#[cfg(test)]
mod test {

    #[test]
    fn lookup_example() {
        let db = super::GeoIP::open(None).unwrap();
        let _city = db.lookup_city_from_str("128.101.101.101").unwrap();
    }
}
<|endoftext|>


<commit_before>
extern crate ndarray;

use ndarray::Array;
//use ndarray::{Si, S};

fn main()
{
    let mat = Array::range(0.0f32, 16.0).reshape((2, 4, 2));
    println!("{a:?}\n times \n{b:?}\nis equal to:\n{c:?}",
             a=mat.subview(2,1),
             b=mat.subview(0,1),
             c=mat.subview(2,1).mat_mul(&mat.subview(0,1)));

}
<commit_msg>Remove examples<commit_after><|endoftext|>


<commit_before>use raw::{
    jit_label_t,
    jit_function_reserve_label
};
use function::UncompiledFunction;
use std::kinds::marker::ContravariantLifetime;
use util::NativeRef;
#[deriving(PartialEq)]
/// A label in the code that can be branched to in instructions
pub struct Label<'a> {
    _label: jit_label_t,
    marker: ContravariantLifetime<'a>
}
impl<'a> Label<'a> {
    #[inline(always)]
    /// Create a new label
    pub fn new(func:&UncompiledFunction<'a>) -> Label<'a> {
        unsafe {
            Label {
                _label: jit_function_reserve_label(func.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
    /// Get the value of this label
    #[inline(always)]
    pub fn get_value(&self) -> uint {
        self._label as uint
    }
}<commit_msg>Implement show for Label<commit_after>use raw::{
    jit_label_t,
    jit_function_reserve_label
};
use function::UncompiledFunction;
use std::kinds::marker::ContravariantLifetime;
use std::fmt::{Show, Result, Formatter};
use util::NativeRef;
#[deriving(PartialEq)]
/// A label in the code that can be branched to in instructions
pub struct Label<'a> {
    _label: jit_label_t,
    marker: ContravariantLifetime<'a>
}
impl<'a> Show for Label<'a> {
    fn fmt(&self, fmt:&mut Formatter) -> Result {
        self._label.fmt(fmt)
    }
}
impl<'a> Label<'a> {
    #[inline(always)]
    /// Create a new label
    pub fn new(func:&UncompiledFunction<'a>) -> Label<'a> {
        unsafe {
            Label {
                _label: jit_function_reserve_label(func.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
    /// Get the value of this label
    #[inline(always)]
    pub fn get_value(&self) -> uint {
        self._label as uint
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// TODO: Possible optimization could avoid pushing characters on a buffer.
mod command;
mod input;
mod job;
mod token;

use std::borrow::Cow;
use std::path::Path;
use std::process::Command;
use std::sync::{Arc, Mutex};

use regex::Regex;

use self::command::execute_command;
use self::input::{basename, dirname, remove_extension};
pub use self::job::job;
use self::token::Token;

/// Represents a template that is utilized to generate command strings.
///
/// The template is meant to be coupled with an input in order to generate a command. The
/// `generate_and_execute()` method will be used to generate a command and execute it.
#[derive(Debug, Clone, PartialEq)]
pub struct CommandTemplate {
    args: Vec<ArgumentTemplate>,
}

impl CommandTemplate {
    pub fn new<I, S>(input: I) -> CommandTemplate
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        lazy_static! {
            static ref PLACEHOLDER_PATTERN: Regex = Regex::new(r"\{(/?\.?|//)\}").unwrap();
        }

        let mut args = Vec::new();
        let mut has_placeholder = false;

        for arg in input {
            let arg = arg.as_ref();

            let mut tokens = Vec::new();
            let mut start = 0;

            for placeholder in PLACEHOLDER_PATTERN.find_iter(arg) {
                // Leading text before the placeholder.
                if placeholder.start() > start {
                    tokens.push(Token::Text(arg[start..placeholder.start()].to_owned()));
                }

                start = placeholder.end();

                match placeholder.as_str() {
                    "{}" => tokens.push(Token::Placeholder),
                    "{.}" => tokens.push(Token::NoExt),
                    "{/}" => tokens.push(Token::Basename),
                    "{//}" => tokens.push(Token::Parent),
                    "{/.}" => tokens.push(Token::BasenameNoExt),
                    _ => panic!("Unhandled placeholder"),
                }

                has_placeholder = true;
            }

            // Without a placeholder, the argument is just fixed text.
            if tokens.is_empty() {
                args.push(ArgumentTemplate::Text(arg.to_owned()));
                continue;
            }

            if start < arg.len() {
                // Trailing text after last placeholder.
                tokens.push(Token::Text(arg[start..].to_owned()));
            }

            args.push(ArgumentTemplate::Tokens(tokens));
        }

        // If a placeholder token was not supplied, append one at the end of the command.
        if !has_placeholder {
            args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
        }

        CommandTemplate { args: args }
    }

    /// Generates and executes a command.
    ///
    /// Using the internal `args` field, and a supplied `input` variable, a `Command` will be
    /// build. Once all arguments have been processed, the command is executed.
    pub fn generate_and_execute(&self, input: &Path, out_perm: Arc<Mutex<()>>) {
        let input = input
            .strip_prefix(".")
            .unwrap_or(input)
            .to_string_lossy()
            .into_owned();

        let mut cmd = Command::new(self.args[0].generate(&input).as_ref());
        for arg in &self.args[1..] {
            cmd.arg(arg.generate(&input).as_ref());
        }

        execute_command(cmd, out_perm)
    }
}

/// Represents a template for a single command argument.
///
/// The argument is either a collection of `Token`s including at least one placeholder variant, or
/// a fixed text.
#[derive(Clone, Debug, PartialEq)]
enum ArgumentTemplate {
    Tokens(Vec<Token>),
    Text(String),
}

impl ArgumentTemplate {
    pub fn generate<'a>(&'a self, path: &str) -> Cow<'a, str> {
        use self::Token::*;

        match *self {
            ArgumentTemplate::Tokens(ref tokens) => {
                let mut s = String::new();
                for token in tokens {
                    match *token {
                        Basename => s += basename(path),
                        BasenameNoExt => s += remove_extension(basename(path)),
                        NoExt => s += remove_extension(path),
                        Parent => s += dirname(path),
                        Placeholder => s += path,
                        Text(ref string) => s += string,
                    }
                }
                Cow::Owned(s)
            }
            ArgumentTemplate::Text(ref text) => Cow::Borrowed(text),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn tokens_with_placeholder() {
        assert_eq!(
            CommandTemplate::new(&[&"echo", &"${SHELL}:"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Text("${SHELL}:".into()),
                    ArgumentTemplate::Tokens(vec![Token::Placeholder]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_no_extension() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{.}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::NoExt]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_basename() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{/}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::Basename]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_parent() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{//}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::Parent]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_basename_no_extension() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{/.}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::BasenameNoExt]),
                ],
            }
        );
    }
}
<commit_msg>refactor: use shorthand fields<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// TODO: Possible optimization could avoid pushing characters on a buffer.
mod command;
mod input;
mod job;
mod token;

use std::borrow::Cow;
use std::path::Path;
use std::process::Command;
use std::sync::{Arc, Mutex};

use regex::Regex;

use self::command::execute_command;
use self::input::{basename, dirname, remove_extension};
pub use self::job::job;
use self::token::Token;

/// Represents a template that is utilized to generate command strings.
///
/// The template is meant to be coupled with an input in order to generate a command. The
/// `generate_and_execute()` method will be used to generate a command and execute it.
#[derive(Debug, Clone, PartialEq)]
pub struct CommandTemplate {
    args: Vec<ArgumentTemplate>,
}

impl CommandTemplate {
    pub fn new<I, S>(input: I) -> CommandTemplate
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        lazy_static! {
            static ref PLACEHOLDER_PATTERN: Regex = Regex::new(r"\{(/?\.?|//)\}").unwrap();
        }

        let mut args = Vec::new();
        let mut has_placeholder = false;

        for arg in input {
            let arg = arg.as_ref();

            let mut tokens = Vec::new();
            let mut start = 0;

            for placeholder in PLACEHOLDER_PATTERN.find_iter(arg) {
                // Leading text before the placeholder.
                if placeholder.start() > start {
                    tokens.push(Token::Text(arg[start..placeholder.start()].to_owned()));
                }

                start = placeholder.end();

                match placeholder.as_str() {
                    "{}" => tokens.push(Token::Placeholder),
                    "{.}" => tokens.push(Token::NoExt),
                    "{/}" => tokens.push(Token::Basename),
                    "{//}" => tokens.push(Token::Parent),
                    "{/.}" => tokens.push(Token::BasenameNoExt),
                    _ => panic!("Unhandled placeholder"),
                }

                has_placeholder = true;
            }

            // Without a placeholder, the argument is just fixed text.
            if tokens.is_empty() {
                args.push(ArgumentTemplate::Text(arg.to_owned()));
                continue;
            }

            if start < arg.len() {
                // Trailing text after last placeholder.
                tokens.push(Token::Text(arg[start..].to_owned()));
            }

            args.push(ArgumentTemplate::Tokens(tokens));
        }

        // If a placeholder token was not supplied, append one at the end of the command.
        if !has_placeholder {
            args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
        }

        CommandTemplate { args }
    }

    /// Generates and executes a command.
    ///
    /// Using the internal `args` field, and a supplied `input` variable, a `Command` will be
    /// build. Once all arguments have been processed, the command is executed.
    pub fn generate_and_execute(&self, input: &Path, out_perm: Arc<Mutex<()>>) {
        let input = input
            .strip_prefix(".")
            .unwrap_or(input)
            .to_string_lossy()
            .into_owned();

        let mut cmd = Command::new(self.args[0].generate(&input).as_ref());
        for arg in &self.args[1..] {
            cmd.arg(arg.generate(&input).as_ref());
        }

        execute_command(cmd, out_perm)
    }
}

/// Represents a template for a single command argument.
///
/// The argument is either a collection of `Token`s including at least one placeholder variant, or
/// a fixed text.
#[derive(Clone, Debug, PartialEq)]
enum ArgumentTemplate {
    Tokens(Vec<Token>),
    Text(String),
}

impl ArgumentTemplate {
    pub fn generate<'a>(&'a self, path: &str) -> Cow<'a, str> {
        use self::Token::*;

        match *self {
            ArgumentTemplate::Tokens(ref tokens) => {
                let mut s = String::new();
                for token in tokens {
                    match *token {
                        Basename => s += basename(path),
                        BasenameNoExt => s += remove_extension(basename(path)),
                        NoExt => s += remove_extension(path),
                        Parent => s += dirname(path),
                        Placeholder => s += path,
                        Text(ref string) => s += string,
                    }
                }
                Cow::Owned(s)
            }
            ArgumentTemplate::Text(ref text) => Cow::Borrowed(text),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn tokens_with_placeholder() {
        assert_eq!(
            CommandTemplate::new(&[&"echo", &"${SHELL}:"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Text("${SHELL}:".into()),
                    ArgumentTemplate::Tokens(vec![Token::Placeholder]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_no_extension() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{.}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::NoExt]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_basename() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{/}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::Basename]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_parent() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{//}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::Parent]),
                ],
            }
        );
    }

    #[test]
    fn tokens_with_basename_no_extension() {
        assert_eq!(
            CommandTemplate::new(&["echo", "{/.}"]),
            CommandTemplate {
                args: vec![
                    ArgumentTemplate::Text("echo".into()),
                    ArgumentTemplate::Tokens(vec![Token::BasenameNoExt]),
                ],
            }
        );
    }
}
<|endoftext|>


<commit_before>extern crate find_folder;

use screen::{self, Screen, MainMenu};
use context::{Context, GameState};

use piston_window::{self, PistonWindow, WindowSettings};

type Screens = Vec<Box<Screen>>;

pub struct Game {
    window: PistonWindow,
    context: Context,
    screens: Screens,
}

impl Game {
    pub fn new() -> Self {
        let window: PistonWindow = WindowSettings::new("rrthozopsi", [600, 600])
                                       .build()
                                       .unwrap();
        let mut context = Context {
            assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(),
            game_state: GameState::NotStarted,
        };
        let screens: Screens = vec![Box::new(MainMenu::new(&window, &mut context))];
        Game {
            window: window,
            screens: screens,
            context: context,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    if handle_input(screens, &input, &window, &mut self.context) {
                        // Exit game.
                        return;
                    }
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> bool {
    use screen::InputResult;

    for action in last(screens).on_input(&input, &window, context) {
        match action {
            InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            InputResult::PopScreen => {
                screens.pop();
            }
            InputResult::Exit => { return true }
        }
    }

    false
}
<commit_msg>Unused import fix<commit_after>extern crate find_folder;

use screen::{Screen, MainMenu};
use context::{Context, GameState};

use piston_window::{self, PistonWindow, WindowSettings};

type Screens = Vec<Box<Screen>>;

pub struct Game {
    window: PistonWindow,
    context: Context,
    screens: Screens,
}

impl Game {
    pub fn new() -> Self {
        let window: PistonWindow = WindowSettings::new("rrthozopsi", [600, 600])
                                       .build()
                                       .unwrap();
        let mut context = Context {
            assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(),
            game_state: GameState::NotStarted,
        };
        let screens: Screens = vec![Box::new(MainMenu::new(&window, &mut context))];
        Game {
            window: window,
            screens: screens,
            context: context,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    if handle_input(screens, &input, &window, &mut self.context) {
                        // Exit game.
                        return;
                    }
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> bool {
    use screen::InputResult;

    for action in last(screens).on_input(&input, &window, context) {
        match action {
            InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            InputResult::PopScreen => {
                screens.pop();
            }
            InputResult::Exit => { return true }
        }
    }

    false
}
<|endoftext|>