<commit_before>use std::io;
use std::io::FilePermission;
use std::os::getenv;
use std::path::BytesContainer;
use std::io::fs::{PathExtensions, mkdir_recursive};
use std::str::from_utf8_lossy;
use std::os::env as get_environ;
use std::io::fs::{mkdir, rename, symlink, unlink, readlink};
use std::io::process::{ExitStatus, Command, Ignored, InheritFd};
use std::io::stdio::{stdout, stderr};

use super::sha256::Sha256;
use super::sha256::Digest;

use argparse::{ArgumentParser, Store, StoreTrue};

use super::env::{Environ, Container};
use super::options::env_options;
use super::clean::run_rmdirs;
use super::linux::ensure_dir;

fn makedirs(path: &Path) -> Result<(),String> {
    if path.exists() {
        return Ok(());
    }
    try!(makedirs(&path.dir_path()));
    return match mkdir(path, io::USER_RWX) {
        Ok(()) => Ok(()),
        Err(e) => Err(format!("Can't mkdir: {}", e)),
    };
}

pub fn build_command(environ: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut force = false;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut force)
            .add_option(["--force"], box StoreTrue,
                "Force rebuild of container event if it already exists");
        env_options(environ, &mut ap);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(environ.get_container(&cname));
    try!(build_container(environ, &mut container, force));
    try!(link_container(environ, &container));

    return Ok(0);
}

pub fn link_container(environ: &Environ, container: &Container)
    -> Result<(), String>
{
    let container_root = container.container_root.as_ref().unwrap();
    let cdir = container_root.filename().unwrap();
    let tmptarget = environ.local_vagga.join(
        (".lnk.".container_into_owned_bytes() + cdir).as_slice());
    if tmptarget.exists() {
        match unlink(&tmptarget) {
            Ok(()) => {}
            Err(x) => return Err(format!("Error removing file: {}", x)),
        }
    }
    let target = environ.local_vagga.join(container.name.as_slice());
    debug!("Linking {} -> {}", container_root.display(), target.display())
    let relative_root = Path::new(".roots").join(cdir);
    match symlink(&relative_root, &tmptarget)
          .and(rename(&tmptarget, &target)) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't symlink new root: {}", x)),
    }
    if !container.name.eq(&container.fullname) {
        let target = environ.local_vagga.join(container.fullname.as_slice());
        debug!("Linking {} -> {}", container_root.display(), target.display())
        match symlink(&relative_root, &tmptarget)
              .and(rename(&tmptarget, &target)) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't symlink new root: {}", x)),
        }
    }
    return Ok(());
}

pub fn build_container(environ: &Environ, container: &mut Container,
                       force: bool)
    -> Result <bool, String>
{
    info!("Checking {}", container.name);

    let builder = &container.builder;
    let bldpath = match environ.find_builder(builder) {
        Some(b) => b,
        None => return Err(format!("Can't find builder {}, \
            check your VAGGA_PATH", builder)),
    };
    info!("Builder full path is {}", bldpath.display());
    let cache_dir = environ.local_vagga.join_many(
        [".cache", builder.as_slice()]);

    // TODO(tailhook) which path should be here?
    let path = getenv("PATH").unwrap_or(
        "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"
        .to_string());

    let mut env: Vec<(&[u8], &[u8])> = Vec::new();
    let mut caller_env: Vec<(String, String)> = Vec::new();
    let mut parameters: Vec<(String, String)> = Vec::new();
    env.push(("HOME".as_bytes(), "/homeless-shelter".as_bytes()));
    env.push(("PATH".as_bytes(), path.as_bytes()));
    env.push(("container_name".as_bytes(), container.name.as_bytes()));
    env.push(("container_fullname".as_bytes(), container.fullname.as_bytes()));
    env.push(("cache_dir".as_bytes(), cache_dir.as_vec()));
    env.push(("project_root".as_bytes(), environ.project_root.as_vec()));
    for (k, v) in get_environ().into_iter() {
        let pk = "CALLER_".to_string() + k;
        let pv = v;
        caller_env.push((pk, pv));
    }
    for (k, v) in container.parameters.iter() {
        parameters.push((builder + "_" + *k, v.clone()));
    }
    let mut caller_env_iter = caller_env.iter();
    for &(ref k, ref v) in caller_env_iter {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }
    let mut parameters_iter = parameters.iter();
    for &(ref k, ref v) in parameters_iter {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }

    let version_sh = bldpath.join("version.sh");
    let mut digest = Sha256::new();
    if version_sh.exists() {
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        match Command::new(&version_sh).env_set_all(env.as_slice())
            .cwd(&environ.project_root)
            .stdin(Ignored).stderr(InheritFd(2)).output() {
            Ok(out) => match out.status {
                ExitStatus(0) => {
                    debug!("Version data ```{}```",
                           from_utf8_lossy(out.output.as_slice()));
                    digest.input(out.output.as_slice());
                }
                e => {
                    return Err(format!("Error running {}: {}",
                        version_sh.display(), e));
                }
            },
            Err(e) => {
                return Err(format!("Error running {}: {}",
                    version_sh.display(), e));
            }
        }
    } else {
        warn!("This backend has no versioning. Using primitive one.");
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        for (k, v) in container.parameters.iter() {
            digest.input_str(k.as_slice());
            digest.input_str("=");
            digest.input_str(v.as_slice());
            digest.input_str(";");
        }
    }
    if container.uids.len() > 0 {
        digest.input_str("uids:");
        for rng in container.uids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.gids.len() > 0 {
        digest.input_str("gids:");
        for rng in container.gids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.ensure_dirs.len() > 0 {
        digest.input_str("ensure_dir:");
        for (path, val) in container.ensure_dirs.iter() {
            digest.input(path.as_vec());
            digest.input_uint(val.mode as u64);
        }
    }
    match container.provision {
        Some(ref x) => digest.input_str(x.as_slice()),
        None => {}
    }

    let fullhash = digest.result_str();
    let hash = fullhash.as_slice().slice_to(7);

    let build_sh = bldpath.join("build.sh");
    if !build_sh.exists() {
        return Err(format!("Builder {} does not exist", builder));
    }

    let cdir = format!("{}.{}", container.fullname, hash);
    let container_root = environ.local_vagga.join_many(
        [".roots", cdir.as_slice()]);

    if container_root.exists() && !force {
        info!("Container {} already built as {}",
            container.name, container_root.display());
        container.container_root = Some(container_root);
        return Ok(false);
    }

    let artifacts_dir = environ.local_vagga.join_many(
        [".artifacts", cdir.as_slice()]);
    let container_tmp = environ.local_vagga.join_many(
        [".roots", (cdir + ".tmp").as_slice()]);

    info!("Building {} by {}", container_root.display(), build_sh.display());

    if container_tmp.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(container_tmp.clone())));
    }
    if artifacts_dir.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(artifacts_dir.clone())));
    }
    try!(makedirs(&container_tmp));

    env.push(("vagga_exe".as_bytes(), environ.vagga_exe.container_as_bytes()));
    env.push(("vagga_inventory".as_bytes(),
        environ.vagga_inventory.container_as_bytes()));
    env.push(("artifacts_dir".as_bytes(), artifacts_dir.as_vec()));
    env.push(("container_hash".as_bytes(), hash.as_bytes()));
    env.push(("container_root".as_bytes(), container_tmp.as_vec()));
    env.push(("VAGGA_IN_BUILD".as_bytes(), "1".as_bytes()));
    let rustlog = getenv("RUST_LOG");
    match rustlog {
        Some(ref x) => env.push(("RUST_LOG".as_bytes(), x.as_bytes())),
        None => {}
    }

    let mut cmd = Command::new(environ.vagga_exe.as_vec());
    cmd.arg("_userns");
    if container.uids.len() > 0 {
        cmd.arg("--uid-ranges");
        let lst: Vec<String> = container.uids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    if container.gids.len() > 0 {
        cmd.arg("--gid-ranges");
        let lst: Vec<String> = container.gids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    cmd.arg(build_sh);
    cmd.env_set_all(env.as_slice());
    cmd.cwd(&environ.project_root);
    cmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
    match cmd.status() {
        Ok(ExitStatus(0)) => {}
        Ok(x) => return Err(format!("Builder exited with status {}", x)),
        Err(x) => return Err(format!("Can't spawn: {}", x)),
    }

    if container.provision.is_some() {
        let mut pcmd = Command::new(environ.vagga_exe.as_vec());
        pcmd.env_set_all(env.as_slice());
        pcmd.arg("_chroot");
        pcmd.arg("--writeable");
        pcmd.arg("--inventory");
        pcmd.arg("--force-user-namespace");
        if container.uids.len() > 0 {
            let lst: Vec<String> = container.uids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            pcmd.arg("--uid-ranges");
            pcmd.arg(lst.connect(","));
        }
        if container.gids.len() > 0 {
            let lst: Vec<String> = container.gids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            pcmd.arg("--gid-ranges");
            pcmd.arg(lst.connect(","));
        }
        pcmd.arg(container_tmp.as_vec());
        pcmd.args(container.shell.as_slice());
        pcmd.arg(container.provision.as_ref().unwrap().as_slice());
        pcmd.cwd(&environ.project_root);
        pcmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
        debug!("Provision command {}", pcmd);

        match pcmd.status() {
            Ok(ExitStatus(0)) => {}
            Ok(x) => return Err(format!("Provision exited with status {}", x)),
            Err(x) => return Err(format!("Can't spawn provisor: {}", x)),
        }
    }

    for dir in ["proc", "sys", "dev", "work", "tmp", "etc", "mnt"].iter() {
        try!(ensure_dir(&container_tmp.join(*dir)));
    }

    let root = Path::new("/");
    for (path, props) in container.ensure_dirs.iter() {
        assert!(path.is_absolute());
        try!(mkdir_recursive(
            &container_tmp.join(path.path_relative_from(&root).unwrap()),
            FilePermission::from_bits(props.mode).unwrap())
            .map_err(|e| format!("Can't create dir {}: {}",
                                 path.display(), e)));
    }

    let container_old = environ.local_vagga.join_many(
        [".roots", (cdir + ".old").as_slice()]);
    if container_root.exists() {
        if container_old.exists() {
            try!(run_rmdirs(&environ.vagga_exe, vec!(container_old.clone())));
        }
        match rename(&container_root, &container_old) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't rename old root: {}", x)),
        }
    }

    match rename(&container_tmp, &container_root) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't rename root: {}", x)),
    }

    if container_old.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(container_old.clone())));
    }
    info!("Done building {} as {}",
        container.name, container_root.display());

    container.container_root = Some(container_root);

    return Ok(true);
}

pub fn ensure_container(env: &Environ, container: &mut Container)
    -> Result<(), String>
{
    if env.settings.version_check {
        try!(build_container(env, container, false));
        try!(link_container(env, container));
    } else {
        let lnk = env.local_vagga.join(container.fullname.as_slice());
        container.container_root = match readlink(&lnk) {
            Ok(path) => Some(lnk.dir_path().join(path)),
            Err(e) => return Err(format!("Container {} not found: {}",
                                         container.fullname, e)),
        };
    };
    return Ok(());
}
<commit_msg>Fix permissions for directories<commit_after>use std::io;
use std::io::FilePermission;
use std::os::getenv;
use std::path::BytesContainer;
use std::io::fs::{PathExtensions, mkdir_recursive};
use std::str::from_utf8_lossy;
use std::os::env as get_environ;
use std::io::fs::{mkdir, rename, symlink, unlink, readlink};
use std::io::process::{ExitStatus, Command, Ignored, InheritFd};
use std::io::stdio::{stdout, stderr};

use super::sha256::Sha256;
use super::sha256::Digest;

use argparse::{ArgumentParser, Store, StoreTrue};

use super::env::{Environ, Container};
use super::options::env_options;
use super::clean::run_rmdirs;
use super::linux::ensure_dir;

fn makedirs(path: &Path) -> Result<(),String> {
    if path.exists() {
        return Ok(());
    }
    try!(makedirs(&path.dir_path()));
    return match mkdir(path, io::ALL_PERMISSIONS) {
        Ok(()) => Ok(()),
        Err(e) => Err(format!("Can't mkdir: {}", e)),
    };
}

pub fn build_command(environ: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut force = false;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut force)
            .add_option(["--force"], box StoreTrue,
                "Force rebuild of container event if it already exists");
        env_options(environ, &mut ap);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(environ.get_container(&cname));
    try!(build_container(environ, &mut container, force));
    try!(link_container(environ, &container));

    return Ok(0);
}

pub fn link_container(environ: &Environ, container: &Container)
    -> Result<(), String>
{
    let container_root = container.container_root.as_ref().unwrap();
    let cdir = container_root.filename().unwrap();
    let tmptarget = environ.local_vagga.join(
        (".lnk.".container_into_owned_bytes() + cdir).as_slice());
    if tmptarget.exists() {
        match unlink(&tmptarget) {
            Ok(()) => {}
            Err(x) => return Err(format!("Error removing file: {}", x)),
        }
    }
    let target = environ.local_vagga.join(container.name.as_slice());
    debug!("Linking {} -> {}", container_root.display(), target.display())
    let relative_root = Path::new(".roots").join(cdir);
    match symlink(&relative_root, &tmptarget)
          .and(rename(&tmptarget, &target)) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't symlink new root: {}", x)),
    }
    if !container.name.eq(&container.fullname) {
        let target = environ.local_vagga.join(container.fullname.as_slice());
        debug!("Linking {} -> {}", container_root.display(), target.display())
        match symlink(&relative_root, &tmptarget)
              .and(rename(&tmptarget, &target)) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't symlink new root: {}", x)),
        }
    }
    return Ok(());
}

pub fn build_container(environ: &Environ, container: &mut Container,
                       force: bool)
    -> Result <bool, String>
{
    info!("Checking {}", container.name);

    let builder = &container.builder;
    let bldpath = match environ.find_builder(builder) {
        Some(b) => b,
        None => return Err(format!("Can't find builder {}, \
            check your VAGGA_PATH", builder)),
    };
    info!("Builder full path is {}", bldpath.display());
    let cache_dir = environ.local_vagga.join_many(
        [".cache", builder.as_slice()]);

    // TODO(tailhook) which path should be here?
    let path = getenv("PATH").unwrap_or(
        "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"
        .to_string());

    let mut env: Vec<(&[u8], &[u8])> = Vec::new();
    let mut caller_env: Vec<(String, String)> = Vec::new();
    let mut parameters: Vec<(String, String)> = Vec::new();
    env.push(("HOME".as_bytes(), "/homeless-shelter".as_bytes()));
    env.push(("PATH".as_bytes(), path.as_bytes()));
    env.push(("container_name".as_bytes(), container.name.as_bytes()));
    env.push(("container_fullname".as_bytes(), container.fullname.as_bytes()));
    env.push(("cache_dir".as_bytes(), cache_dir.as_vec()));
    env.push(("project_root".as_bytes(), environ.project_root.as_vec()));
    for (k, v) in get_environ().into_iter() {
        let pk = "CALLER_".to_string() + k;
        let pv = v;
        caller_env.push((pk, pv));
    }
    for (k, v) in container.parameters.iter() {
        parameters.push((builder + "_" + *k, v.clone()));
    }
    let mut caller_env_iter = caller_env.iter();
    for &(ref k, ref v) in caller_env_iter {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }
    let mut parameters_iter = parameters.iter();
    for &(ref k, ref v) in parameters_iter {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }

    let version_sh = bldpath.join("version.sh");
    let mut digest = Sha256::new();
    if version_sh.exists() {
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        match Command::new(&version_sh).env_set_all(env.as_slice())
            .cwd(&environ.project_root)
            .stdin(Ignored).stderr(InheritFd(2)).output() {
            Ok(out) => match out.status {
                ExitStatus(0) => {
                    debug!("Version data ```{}```",
                           from_utf8_lossy(out.output.as_slice()));
                    digest.input(out.output.as_slice());
                }
                e => {
                    return Err(format!("Error running {}: {}",
                        version_sh.display(), e));
                }
            },
            Err(e) => {
                return Err(format!("Error running {}: {}",
                    version_sh.display(), e));
            }
        }
    } else {
        warn!("This backend has no versioning. Using primitive one.");
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        for (k, v) in container.parameters.iter() {
            digest.input_str(k.as_slice());
            digest.input_str("=");
            digest.input_str(v.as_slice());
            digest.input_str(";");
        }
    }
    if container.uids.len() > 0 {
        digest.input_str("uids:");
        for rng in container.uids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.gids.len() > 0 {
        digest.input_str("gids:");
        for rng in container.gids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.ensure_dirs.len() > 0 {
        digest.input_str("ensure_dir:");
        for (path, val) in container.ensure_dirs.iter() {
            digest.input(path.as_vec());
            digest.input_uint(val.mode as u64);
        }
    }
    match container.provision {
        Some(ref x) => digest.input_str(x.as_slice()),
        None => {}
    }

    let fullhash = digest.result_str();
    let hash = fullhash.as_slice().slice_to(7);

    let build_sh = bldpath.join("build.sh");
    if !build_sh.exists() {
        return Err(format!("Builder {} does not exist", builder));
    }

    let cdir = format!("{}.{}", container.fullname, hash);
    let container_root = environ.local_vagga.join_many(
        [".roots", cdir.as_slice()]);

    if container_root.exists() && !force {
        info!("Container {} already built as {}",
            container.name, container_root.display());
        container.container_root = Some(container_root);
        return Ok(false);
    }

    let artifacts_dir = environ.local_vagga.join_many(
        [".artifacts", cdir.as_slice()]);
    let container_tmp = environ.local_vagga.join_many(
        [".roots", (cdir + ".tmp").as_slice()]);

    info!("Building {} by {}", container_root.display(), build_sh.display());

    if container_tmp.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(container_tmp.clone())));
    }
    if artifacts_dir.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(artifacts_dir.clone())));
    }
    try!(makedirs(&container_tmp));

    env.push(("vagga_exe".as_bytes(), environ.vagga_exe.container_as_bytes()));
    env.push(("vagga_inventory".as_bytes(),
        environ.vagga_inventory.container_as_bytes()));
    env.push(("artifacts_dir".as_bytes(), artifacts_dir.as_vec()));
    env.push(("container_hash".as_bytes(), hash.as_bytes()));
    env.push(("container_root".as_bytes(), container_tmp.as_vec()));
    env.push(("VAGGA_IN_BUILD".as_bytes(), "1".as_bytes()));
    let rustlog = getenv("RUST_LOG");
    match rustlog {
        Some(ref x) => env.push(("RUST_LOG".as_bytes(), x.as_bytes())),
        None => {}
    }

    let mut cmd = Command::new(environ.vagga_exe.as_vec());
    cmd.arg("_userns");
    if container.uids.len() > 0 {
        cmd.arg("--uid-ranges");
        let lst: Vec<String> = container.uids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    if container.gids.len() > 0 {
        cmd.arg("--gid-ranges");
        let lst: Vec<String> = container.gids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    cmd.arg(build_sh);
    cmd.env_set_all(env.as_slice());
    cmd.cwd(&environ.project_root);
    cmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
    match cmd.status() {
        Ok(ExitStatus(0)) => {}
        Ok(x) => return Err(format!("Builder exited with status {}", x)),
        Err(x) => return Err(format!("Can't spawn: {}", x)),
    }

    if container.provision.is_some() {
        let mut pcmd = Command::new(environ.vagga_exe.as_vec());
        pcmd.env_set_all(env.as_slice());
        pcmd.arg("_chroot");
        pcmd.arg("--writeable");
        pcmd.arg("--inventory");
        pcmd.arg("--force-user-namespace");
        if container.uids.len() > 0 {
            let lst: Vec<String> = container.uids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            pcmd.arg("--uid-ranges");
            pcmd.arg(lst.connect(","));
        }
        if container.gids.len() > 0 {
            let lst: Vec<String> = container.gids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            pcmd.arg("--gid-ranges");
            pcmd.arg(lst.connect(","));
        }
        pcmd.arg(container_tmp.as_vec());
        pcmd.args(container.shell.as_slice());
        pcmd.arg(container.provision.as_ref().unwrap().as_slice());
        pcmd.cwd(&environ.project_root);
        pcmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
        debug!("Provision command {}", pcmd);

        match pcmd.status() {
            Ok(ExitStatus(0)) => {}
            Ok(x) => return Err(format!("Provision exited with status {}", x)),
            Err(x) => return Err(format!("Can't spawn provisor: {}", x)),
        }
    }

    for dir in ["proc", "sys", "dev", "work", "tmp", "etc", "mnt"].iter() {
        try!(ensure_dir(&container_tmp.join(*dir)));
    }

    let root = Path::new("/");
    for (path, props) in container.ensure_dirs.iter() {
        assert!(path.is_absolute());
        try!(mkdir_recursive(
            &container_tmp.join(path.path_relative_from(&root).unwrap()),
            FilePermission::from_bits(props.mode).unwrap())
            .map_err(|e| format!("Can't create dir {}: {}",
                                 path.display(), e)));
    }

    let container_old = environ.local_vagga.join_many(
        [".roots", (cdir + ".old").as_slice()]);
    if container_root.exists() {
        if container_old.exists() {
            try!(run_rmdirs(&environ.vagga_exe, vec!(container_old.clone())));
        }
        match rename(&container_root, &container_old) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't rename old root: {}", x)),
        }
    }

    match rename(&container_tmp, &container_root) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't rename root: {}", x)),
    }

    if container_old.exists() {
        try!(run_rmdirs(&environ.vagga_exe, vec!(container_old.clone())));
    }
    info!("Done building {} as {}",
        container.name, container_root.display());

    container.container_root = Some(container_root);

    return Ok(true);
}

pub fn ensure_container(env: &Environ, container: &mut Container)
    -> Result<(), String>
{
    if env.settings.version_check {
        try!(build_container(env, container, false));
        try!(link_container(env, container));
    } else {
        let lnk = env.local_vagga.join(container.fullname.as_slice());
        container.container_root = match readlink(&lnk) {
            Ok(path) => Some(lnk.dir_path().join(path)),
            Err(e) => return Err(format!("Container {} not found: {}",
                                         container.fullname, e)),
        };
    };
    return Ok(());
}
<|endoftext|>


<commit_before>extern crate builtins;

pub fn read(command_line: &str) {
	/*match control_machine(command_line) {
		Ok(mut tree) => tree.execute_command(),
		Err(err) => println!("{}", err),
	}*/
	let token_list = tokenize(command_line);
	let mut token_iter = token_list.iter();
	let tree = generate_tree(&mut token_iter);
}

#[derive(Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum TokenMachineState {
	Start,
	StrCmd(usize),
	SeparateWs,
	StrArg(usize),
}

#[derive(PartialEq, Debug)] // used for tests
enum Token<'a, 'b> {
	LeftParen,
	RightParen,
	Cmd(&'a str),
	Arg(&'b str),
}

fn tokenize(command_line: &str) -> Vec<Token> {
	use self::TokenMachineState::*;
	use self::Token::*;

	let mut state = Start;
	let mut token_list = Vec::new();

	let mut char_it = command_line.char_indices();

	loop {
		if let Some((i, curr_char)) = char_it.next() {
			match (state, curr_char) {
				(Start, ' ') | (Start, '\t') => {},
				(Start, '(') => token_list.push(LeftParen),
				(Start, ')') => token_list.push(RightParen), // this is invalid but it's the parser's job to find it out
				(Start, _) => state = StrCmd(i),

				(StrCmd(slice_start), ')') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = Start;
				},
				(StrCmd(slice_start), ' ') | (StrCmd(slice_start), '\t') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrCmd(_), _) => {},

				(SeparateWs, ' ') | (SeparateWs, '\t') => {},
				(SeparateWs, ')') => {
					token_list.push(RightParen);
					state = Start;
				},
				(SeparateWs, '(') => {
					token_list.push(LeftParen);
					state = Start;
				},
				(SeparateWs, _) => state = StrArg(i),

				(StrArg(slice_start), ' ') | (StrArg(slice_start), '\t') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrArg(slice_start), ')') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = Start;
				}
				(StrArg(_), _) => {},
			}
		} else {
			break;
		}
	}

	token_list
}

#[derive(PartialEq, Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum ParseMachineState {
	Start,
	//CollectCmd,
	CollectArg,
	SubcommandEnd,
}

use std::slice::Iter;

fn generate_tree<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> Result<Command<'a>, &'static str> {
	use self::ParseMachineState::*;

	let (res, state) = parse(token_iter);

	if state != CollectArg { // accepting state when not doing recursion
		Err("Parse error")
	} else {
		res
	}
}

fn parse<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> (Result<Command<'a>, &'static str>, ParseMachineState) {
	use self::ParseMachineState::*;
	use self::Token::*;

	let mut state = Start;
	let mut cmd = Command::new();

	loop {
		if let Some(token) = token_iter.next() {
			match (state, token) {
				(Start, &Cmd(cmd_name)) => {
					cmd.cmd = Some(Box::new(Param::Arg(cmd_name)));
					state = CollectArg;
				},
				(Start, &LeftParen) => {
					// do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => return(res, state),
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								panic!("ERROR");
							} else {
								cmd.cmd = Some(Box::new(Param::Cmd(subcmd)));
							}
						},
					}
				},
				(Start, &RightParen) => return (Err("Unexpected ')'"), state),
				(Start, &Arg(_)) => unreachable!(), // if that happens the tokenizer is buggy

				(CollectArg, &Arg(arg_str)) => {
					cmd.params.push(Param::Arg(arg_str));
				}
				(CollectArg, &Cmd(_)) => unreachable!(), // if that happens the tokenizer is buggy
				(CollectArg, &RightParen) => return (Ok(cmd), SubcommandEnd),
				(CollectArg, &LeftParen) => {
					//do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => return(res, state),
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								panic!("ERROR");
							} else {
								cmd.params.push(Param::Cmd(subcmd));
							}
						},
					}
				}

				(SubcommandEnd, _) => unreachable!(),
			}
		} else {
			break;
		}
	}

	(Err("Empy commands are not allowed"), state)
}

struct Command<'a> {
	cmd: Option<Box<Param<'a>>>,
	params: Vec<Param<'a>>,
}
impl<'a> Command<'a> {
	fn new() -> Command<'a> {
		Command {
			cmd: None,
			params: Vec::new(),
		}
	}
	fn get_final_arglist(&mut self) -> Vec<&str> {
		let mut final_arglist: Vec<&str> = Vec::with_capacity(self.params.len());

		/*for arg in self.params.iter_mut() { // substitue subcommands recursively
			let stdout = if let Param::Cmd(ref mut subcommand) = *arg {
				Some(subcommand.execute_subcommand())
			} else {
				None
			};

			if let Some(stdout) = stdout {
				*arg = Param::Arg(stdout); // the datastructure holds the `String`
			}

			if let Param::Arg(ref arg_str) = *arg { // at this point this always happen because `Cmd` became `Arg`s
				final_arglist.push(arg_str);
			}
		}*/

		final_arglist
	}
	fn execute_command(&mut self) {//returns stdout - possibly return a array of strings?
		/*match &self.cmd[..] {
			"" => {},
			/*"cd" => builtins::cd(&self.params),
			"exit" => builtins::exit(&self.params),*/
			_ => invoke_command(self),
		};*/
	}
	fn execute_subcommand(&mut self) -> String {
		/*match &self.cmd[..] {
			/*"" => {},
			"cd" => builtins::cd(&self.params),
			"exit" => builtins::exit(&self.params),*/
			_ => invoke_subcommand(self),
		}*/ "fuck you".to_string()
	}
}
enum Param<'a> {
	Arg(&'a str),
	Cmd(Command<'a>),

}
fn invoke_command(command: &mut Command) {
	use std::process::Command;
	/*match Command::new(&command.cmd)
		.args(&command.get_final_arglist())
		.spawn() {
			Ok(mut subproc) => {
				subproc.wait();
			},
			Err(err) => println!("{}", err),
	}*/
}
fn invoke_subcommand(command: &mut Command) -> String {
	/*{
		for arg in command.get_final_arglist() {
			println!("shitty debugging: {}", arg);
		}
	}
	use std::process::Command;
	let output = Command::new(&command.cmd)
		.args(&command.get_final_arglist())
		.output()
		.expect("Failed to start command");

	String::from_utf8(output.stdout).unwrap()*/ "fuck you".to_string()
}

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

		assert_eq!(
			[Cmd("echo"), Arg("lol"), LeftParen, Cmd("srnaeinei"), RightParen],
			tokenize("echo lol (srnaeinei)").as_slice()
		);

		assert_eq!(
			[LeftParen, RightParen],
			tokenize("()").as_slice()
		);
	}
}
<commit_msg>Let the `cmd` field of the `Command` being created uninitialized at first<commit_after>extern crate builtins;

pub fn read(command_line: &str) {
	let token_list = tokenize(command_line);
	let mut token_iter = token_list.iter();
	match generate_tree(&mut token_iter) {
		Ok(mut tree) => tree.execute_command(),
		Err(err) => println!("{}", err),
	}
}

#[derive(Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum TokenMachineState {
	Start,
	StrCmd(usize),
	SeparateWs,
	StrArg(usize),
}

#[derive(PartialEq, Debug)] // used for tests
enum Token<'a, 'b> {
	LeftParen,
	RightParen,
	Cmd(&'a str),
	Arg(&'b str),
}

fn tokenize(command_line: &str) -> Vec<Token> {
	use self::TokenMachineState::*;
	use self::Token::*;

	let mut state = Start;
	let mut token_list = Vec::new();

	let mut char_it = command_line.char_indices();

	loop {
		if let Some((i, curr_char)) = char_it.next() {
			match (state, curr_char) {
				(Start, ' ') | (Start, '\t') => {},
				(Start, '(') => token_list.push(LeftParen),
				(Start, ')') => token_list.push(RightParen), // this is invalid but it's the parser's job to find it out
				(Start, _) => state = StrCmd(i),

				(StrCmd(slice_start), ')') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = Start;
				},
				(StrCmd(slice_start), ' ') | (StrCmd(slice_start), '\t') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrCmd(_), _) => {},

				(SeparateWs, ' ') | (SeparateWs, '\t') => {},
				(SeparateWs, ')') => {
					token_list.push(RightParen);
					state = Start;
				},
				(SeparateWs, '(') => {
					token_list.push(LeftParen);
					state = Start;
				},
				(SeparateWs, _) => state = StrArg(i),

				(StrArg(slice_start), ' ') | (StrArg(slice_start), '\t') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrArg(slice_start), ')') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = Start;
				}
				(StrArg(_), _) => {},
			}
		} else {
			// there might be a last token undergoing the token creation process
			// it has to be appended to the token list
			match state {
				StrCmd(slice_start) => token_list.push(Cmd(&command_line[slice_start..])),
				StrArg(slice_start) => token_list.push(Arg(&command_line[slice_start..])),
				_ => {},
			}
			break;
		}
	}

	token_list
}

#[derive(PartialEq, Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum ParseMachineState {
	Start,
	CollectArg,
	SubcommandEnd,
}

use std::slice::Iter;

fn generate_tree<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> Result<Command<'a>, &'static str> {
	use self::ParseMachineState::*;

	let (res, state) = parse(token_iter);

	if state != CollectArg && res.is_ok() { // accepting state when not doing recursion
		Err("Parse error")
	} else {
		res
	}
}

fn parse<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> (Result<Command<'a>, &'static str>, ParseMachineState) {
	use self::ParseMachineState::*;
	use self::Token::*;
	use std::ptr;
	use std::mem;

	let mut state = Start;
	let mut cmd = Command::new();

	loop {
		if let Some(token) = token_iter.next() {
			match (state, token) {
				(Start, &Cmd(cmd_name)) => {
					unsafe {
						ptr::write(&mut cmd.cmd, Box::new(Param::Arg(cmd_name)));
					}
					state = CollectArg;
				},
				(Start, &LeftParen) => {
					// do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => {
							mem::forget(cmd.cmd);
							return (res, state)
						},
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								mem::forget(cmd.cmd);
								return (Err("Error"), state);
							} else {
								unsafe {
									ptr::write(&mut cmd.cmd, Box::new(Param::Cmd(subcmd)));
								}
							}
						},
					}
				},
				(Start, &RightParen) => {
					mem::forget(cmd.cmd);
					return (Err("Unexpected ')'"), state)
				},
				(Start, &Arg(_)) => unreachable!(), // if that happens the tokenizer is buggy

				(CollectArg, &Arg(arg_str)) => {
					cmd.params.push(Param::Arg(arg_str));
				}
				(CollectArg, &Cmd(_)) => unreachable!(), // if that happens the tokenizer is buggy
				(CollectArg, &RightParen) => {
					return (Ok(cmd), SubcommandEnd);
				},
				(CollectArg, &LeftParen) => {
					//do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => return (res, state),
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								panic!("ERROR");
							} else {
								cmd.params.push(Param::Cmd(subcmd));
							}
						},
					}
				}

				(SubcommandEnd, _) => unreachable!(),
			}
		} else {
			break;
		}
	}

	if state == Start {
		mem::forget(cmd.cmd);
		(Err("Empty commands are not allowed"), state)
	} else {
		(Ok(cmd), state)
	}
}

struct Command<'a> {
	cmd: Box<Param<'a>>,
	params: Vec<Param<'a>>,
}
impl<'a> Command<'a> {
	fn new() -> Command<'a> {
		use std::mem;

		unsafe {
			Command {
				cmd: mem::uninitialized(),
				params: Vec::new(),
			}
		}
	}
	fn get_final_arglist(&mut self) -> Vec<&str> {
		let mut final_arglist: Vec<&str> = Vec::with_capacity(self.params.len());

		/*for arg in self.params.iter_mut() { // substitue subcommands recursively
			let stdout = if let Param::Cmd(ref mut subcommand) = *arg {
				Some(subcommand.execute_subcommand())
			} else {
				None
			};

			if let Some(stdout) = stdout {
				*arg = Param::Arg(stdout); // the datastructure holds the `String`
			}

			if let Param::Arg(ref arg_str) = *arg { // at this point this always happen because `Cmd` became `Arg`s
				final_arglist.push(arg_str);
			}
		}*/

		final_arglist
	}
	fn execute_command(&mut self) {//returns stdout - possibly return a array of strings?
		/*match &self.cmd[..] {
			"" => {},
			/*"cd" => builtins::cd(&self.params),
			"exit" => builtins::exit(&self.params),*/
			_ => invoke_command(self),
		};*/
	}
	fn execute_subcommand(&mut self) -> String {
		/*match &self.cmd[..] {
			/*"" => {},
			"cd" => builtins::cd(&self.params),
			"exit" => builtins::exit(&self.params),*/
			_ => invoke_subcommand(self),
		}*/ "fuck you".to_string()
	}
}
enum Param<'a> {
	Arg(&'a str),
	Cmd(Command<'a>),

}
fn invoke_command(command: &mut Command) {
	use std::process::Command;
	/*match Command::new(&command.cmd)
		.args(&command.get_final_arglist())
		.spawn() {
			Ok(mut subproc) => {
				subproc.wait();
			},
			Err(err) => println!("{}", err),
	}*/
}
fn invoke_subcommand(command: &mut Command) -> String {
	/*{
		for arg in command.get_final_arglist() {
			println!("shitty debugging: {}", arg);
		}
	}
	use std::process::Command;
	let output = Command::new(&command.cmd)
		.args(&command.get_final_arglist())
		.output()
		.expect("Failed to start command");

	String::from_utf8(output.stdout).unwrap()*/ "fuck you".to_string()
}

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

		assert_eq!(
			[Cmd("echo"), Arg("lol"), LeftParen, Cmd("srnaeinei"), RightParen],
			tokenize("echo lol (srnaeinei)").as_slice()
		);

		assert_eq!(
			[LeftParen, RightParen],
			tokenize("()").as_slice()
		);

		assert_eq!(
			[Cmd("echo")],
			tokenize("echo").as_slice()
		);

		assert_eq!(
			[Cmd("echo"), Arg("lol")],
			tokenize("echo lol").as_slice()
		);
	}
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = usize;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type in_addr_t = u32;
pub type in_port_t = u16;

pub type socklen_t = u32;
pub type sa_family_t = u16;

s! {
    pub struct in_addr {
        pub s_addr: in_addr_t,
    }

    pub struct in6_addr {
        pub s6_addr: [u8; 16],
        __align: [u32; 0],
    }

    pub struct sockaddr {
        pub sa_family: sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: sa_family_t,
        pub sin6_port: in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }
}
<commit_msg>Auto merge of #478 - jackpot51:patch-1, r=alexcrichton<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = usize;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type in_addr_t = u32;
pub type in_port_t = u16;

pub type socklen_t = u32;
pub type sa_family_t = u16;

s! {
    pub struct in_addr {
        pub s_addr: in_addr_t,
    }

    pub struct in6_addr {
        pub s6_addr: [u8; 16],
        __align: [u32; 0],
    }

    pub struct sockaddr {
        pub sa_family: sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: sa_family_t,
        pub sin6_port: in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }
}

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
}
<|endoftext|>


<commit_before>use std::fmt;

use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};

pub enum Item {
  Torch,
}

impl fmt::Display for Item {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Item::Torch => "a torch",
    })
  }
}

pub enum InventoryCommand {
  Buy(Item, i32),
  Quit,
}

static INVENTORY_COMMAND_HELP: HelpInfo = &[
  ('1', "buy a flaming torch ($15)"),
  ('0', "continue adventure"),
];

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> HelpInfo { INVENTORY_COMMAND_HELP }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(InventoryCommand::Buy(Item::Torch, 15)),
      _ => Some(InventoryCommand::Quit),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        InventoryCommand::Buy(item, price) => {
          if price > self.wealth {
            println!("You don't have enough money to buy that.");
          } else {
            self.wealth -= price;
            println!("You bought {}.", item);
            self.print_wealth();
            match item {
              Item::Torch => self.light = true,
            }
          }
          println!("");
        },
        InventoryCommand::Quit => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<commit_msg>Add Item::price().<commit_after>use std::fmt;

use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};

pub enum Item {
  Torch,
}

impl Item {
  pub fn price(&self) -> i32 {
    match *self {
      Item::Torch => 15
    }
  }
}

impl fmt::Display for Item {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Item::Torch => "a torch",
    })
  }
}

pub enum InventoryCommand {
  Buy(Item),
  Quit,
}

static INVENTORY_COMMAND_HELP: HelpInfo = &[
  ('1', "buy a flaming torch ($15)"),
  ('0', "continue adventure"),
];

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> HelpInfo { INVENTORY_COMMAND_HELP }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(InventoryCommand::Buy(Item::Torch)),
      _ => Some(InventoryCommand::Quit),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        InventoryCommand::Buy(item) => {
          let price = item.price();
          if price > self.wealth {
            println!("You don't have enough money to buy that.");
          } else {
            self.wealth -= price;
            println!("You bought {}.", item);
            self.print_wealth();
            match item {
              Item::Torch => self.light = true,
            }
          }
          println!("");
        },
        InventoryCommand::Quit => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<|endoftext|>


<commit_before>use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};
use items::Item;
use items::Item::*;

use self::InventoryCommand::*;

pub enum InventoryCommand {
  Buy(Item),
  Leave,
}

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> Vec<HelpInfo> {
    let buy = |item: Item| format!("buy {} (${})", item, item.price());

    HelpInfo::list(vec![
      ('1', buy(Torch)),
      ('2', buy(Axe)),
      ('3', buy(Sword)),
      ('4', buy(Food)),
      ('5', buy(Amulet)),
      ('6', buy(Armor)),
      ('0', String::from("continue adventure")),
    ])
  }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(Buy(Torch)),
      '2' => Some(Buy(Axe)),
      '3' => Some(Buy(Sword)),
      '4' => Some(Buy(Food)),
      '5' => Some(Buy(Amulet)),
      '6' => Some(Buy(Armor)),
      _ => Some(Leave),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        Buy(item) => {
          let price = item.price();
          if price > self.wealth {
            println!("You don't have enough money to buy that.");
          } else {
            if match item {
              Torch => self.light,
              Axe => self.axe,
              Sword => self.sword,
              Food => false,
              Amulet => self.amulet,
              Armor => self.suit,
            } {
              println!("You already own {}.", item);
            } else {
              self.wealth -= price;
              println!("You bought {}.", item);
              self.print_wealth();
              match item {
                Torch => self.light = true,
                Axe => self.axe = true,
                Sword => self.sword = true,
                Food => self.food += 1,
                Amulet => self.amulet = true,
                Armor => self.suit = true,
              }
            }
          }
          println!("");
        },
        Leave => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<commit_msg>YOU HAVE TRIED TO CHEAT ME<commit_after>use game_state::{GameState, GameMode};
use command::{CommandProcessor, HelpInfo};
use items::Item;
use items::Item::*;

use self::InventoryCommand::*;

pub enum InventoryCommand {
  Buy(Item),
  Leave,
}

impl CommandProcessor<InventoryCommand> for InventoryCommand {
  fn prompt() -> &'static str { "What do you want to buy? " }

  fn get_help() -> Vec<HelpInfo> {
    let buy = |item: Item| format!("buy {} (${})", item, item.price());

    HelpInfo::list(vec![
      ('1', buy(Torch)),
      ('2', buy(Axe)),
      ('3', buy(Sword)),
      ('4', buy(Food)),
      ('5', buy(Amulet)),
      ('6', buy(Armor)),
      ('0', String::from("continue adventure")),
    ])
  }

  fn from_char(c: char) -> Option<InventoryCommand> {
    match c {
      '1' => Some(Buy(Torch)),
      '2' => Some(Buy(Axe)),
      '3' => Some(Buy(Sword)),
      '4' => Some(Buy(Food)),
      '5' => Some(Buy(Amulet)),
      '6' => Some(Buy(Armor)),
      _ => Some(Leave),
    }
  }
}

impl<'a> GameState<'a> {
  pub fn tick_inventory_mode(&mut self) {
    if self.show_desc {
      println!("Provisions & inventory\n");
      self.print_wealth();
      println!("");
      InventoryCommand::show_help();
      println!("");
      self.show_desc = false;
    }

    if let Some(cmd) = InventoryCommand::get() {
      match cmd {
        Buy(item) => {
          let price = item.price();
          if match item {
            Torch => self.light,
            Axe => self.axe,
            Sword => self.sword,
            Food => false,
            Amulet => self.amulet,
            Armor => self.suit,
          } {
            println!("You already own {}.", item);
          } else if self.wealth < price {
            println!("YOU HAVE TRIED TO CHEAT ME!");
            self.wealth = 0;
            self.light = false;
            self.axe = false;
            self.sword = false;
            self.food = self.food / 4;
            self.amulet = false;
            self.suit = false;
          } else {
            self.wealth -= price;
            println!("You bought {}.", item);
            self.print_wealth();
            match item {
              Torch => self.light = true,
              Axe => self.axe = true,
              Sword => self.sword = true,
              Food => self.food += 1,
              Amulet => self.amulet = true,
              Armor => self.suit = true,
            }
          }
          println!("");
        },
        Leave => { self.set_mode(GameMode::Primary) },
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;
use graphics::vecmath::Matrix2d;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id.clone()).unwrap();
                let (status, _) = a.event(e, &mut |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in self.children.iter() {
            child.draw(t, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id.clone(), animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<commit_msg>Made most Uuid functions take by reference<commit_after>use std::collections::HashMap;
use uuid::Uuid;

use graphics::*;
use graphics::vecmath::Matrix2d;

use event::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(&id).unwrap();
                let (status, _) = a.event(e, &mut |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in self.children.iter() {
            child.draw(t, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: &Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for i in 0..animations.len() {
                let (ref b, _, _) = animations[i];
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: &Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: &Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(&sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: &Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: &Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&self.children[*index])
        } else {
            for child in self.children.iter() {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: &Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(id) {
            Some(&mut self.children[*index])
        } else {
            for child in self.children.iter_mut() {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use libc::{c_int, c_uint, c_void, c_ulong, pid_t};
use errno::Errno;
use {Result, Error};

pub type CloneFlags = c_uint;

pub static CLONE_VM:             CloneFlags = 0x00000100;
pub static CLONE_FS:             CloneFlags = 0x00000200;
pub static CLONE_FILES:          CloneFlags = 0x00000400;
pub static CLONE_SIGHAND:        CloneFlags = 0x00000800;
pub static CLONE_PTRACE:         CloneFlags = 0x00002000;
pub static CLONE_VFORK:          CloneFlags = 0x00004000;
pub static CLONE_PARENT:         CloneFlags = 0x00008000;
pub static CLONE_THREAD:         CloneFlags = 0x00010000;
pub static CLONE_NEWNS:          CloneFlags = 0x00020000;
pub static CLONE_SYSVSEM:        CloneFlags = 0x00040000;
pub static CLONE_SETTLS:         CloneFlags = 0x00080000;
pub static CLONE_PARENT_SETTID:  CloneFlags = 0x00100000;
pub static CLONE_CHILD_CLEARTID: CloneFlags = 0x00200000;
pub static CLONE_DETACHED:       CloneFlags = 0x00400000;
pub static CLONE_UNTRACED:       CloneFlags = 0x00800000;
pub static CLONE_CHILD_SETTID:   CloneFlags = 0x01000000;
pub static CLONE_NEWUTS:         CloneFlags = 0x04000000;
pub static CLONE_NEWIPC:         CloneFlags = 0x08000000;
pub static CLONE_NEWUSER:        CloneFlags = 0x10000000;
pub static CLONE_NEWPID:         CloneFlags = 0x20000000;
pub static CLONE_NEWNET:         CloneFlags = 0x40000000;
pub static CLONE_IO:             CloneFlags = 0x80000000;

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: super::CloneFlags,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: super::CloneFlags) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    if res != 0 {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(())
    }
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags, &mut cb)
    };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags) };

    if res != 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<commit_msg>Fix build on Linux & Rust nightly<commit_after>use std::mem;
use libc::{c_int, c_uint, c_void, c_ulong, pid_t};
use errno::Errno;
use {Result, Error};

pub type CloneFlags = c_uint;

pub static CLONE_VM:             CloneFlags = 0x00000100;
pub static CLONE_FS:             CloneFlags = 0x00000200;
pub static CLONE_FILES:          CloneFlags = 0x00000400;
pub static CLONE_SIGHAND:        CloneFlags = 0x00000800;
pub static CLONE_PTRACE:         CloneFlags = 0x00002000;
pub static CLONE_VFORK:          CloneFlags = 0x00004000;
pub static CLONE_PARENT:         CloneFlags = 0x00008000;
pub static CLONE_THREAD:         CloneFlags = 0x00010000;
pub static CLONE_NEWNS:          CloneFlags = 0x00020000;
pub static CLONE_SYSVSEM:        CloneFlags = 0x00040000;
pub static CLONE_SETTLS:         CloneFlags = 0x00080000;
pub static CLONE_PARENT_SETTID:  CloneFlags = 0x00100000;
pub static CLONE_CHILD_CLEARTID: CloneFlags = 0x00200000;
pub static CLONE_DETACHED:       CloneFlags = 0x00400000;
pub static CLONE_UNTRACED:       CloneFlags = 0x00800000;
pub static CLONE_CHILD_SETTID:   CloneFlags = 0x01000000;
pub static CLONE_NEWUTS:         CloneFlags = 0x04000000;
pub static CLONE_NEWIPC:         CloneFlags = 0x08000000;
pub static CLONE_NEWUSER:        CloneFlags = 0x10000000;
pub static CLONE_NEWPID:         CloneFlags = 0x20000000;
pub static CLONE_NEWNET:         CloneFlags = 0x40000000;
pub static CLONE_IO:             CloneFlags = 0x80000000;

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: super::CloneFlags,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: super::CloneFlags) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    if res != 0 {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(())
    }
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags, &mut cb)
    };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags) };

    if res != 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "coinaddress"]

//! Functions for validating the base58 hash checksums, including specifically
//! the bitcoin and litecoin addresses.

#![feature(test)]
#![feature(rustc_private)]

extern crate num;
extern crate rustc;
extern crate test;

use num::bigint::{ToBigUint,BigUint};
use num::traits::ToPrimitive;
use num::Zero;
use rustc::util::sha2::{Sha256, Digest};

#[derive(PartialEq, Debug)]
pub enum ValidationError {
    /// Given address is too short to be valid
    TooShort,
    /// Encoding is not a valid base58
    InvalidEncoding,
    /// Computed hash does not match the embedded one
    HashMismatch,

    // currency specific
    /// This address is not a bitcoin address (testnet or real).
    /// May happen when attempting to validate btc address
    NotBitcoin,
    /// This address is not a litecoin address.
    /// May happen when attempting to validate ltc address
    NotLitecoin,
}

static BASE58_CHARS: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

fn decode_base58(bc: &str) -> Option<BigUint> {
    let mut res: BigUint = Zero::zero();
    let b58: BigUint = 58.to_biguint().unwrap();

    for c in bc.chars() {
        match BASE58_CHARS.find(c) {
            None => {
                return None
            },
            Some(x) => {
                res = res * &b58 + x.to_biguint().unwrap();
            }
        }
    }
    Some(res)
}

fn bigint_to_bytes(n: BigUint) -> Vec<u8> {
    let mut res: Vec<u8> = Vec::new();
    let mut tmp = n;
    let b256: BigUint = 256.to_biguint().unwrap();

    while !tmp.is_zero() {
        res.insert(0, (&tmp % &b256).to_u8().unwrap());
        tmp = tmp / &b256;
    }

    if res.len() == 0 {
        return vec!(0);
    }

    res
}

fn pad_to(v: Vec<u8>, len: usize) -> Vec<u8> {
    let mut tmp: Vec<u8> = v;
    while tmp.len() < len {
        tmp.insert(0, 0)
    }
    tmp
}

fn double_sha256(chunk: &[u8]) -> Vec<u8> {
    let mut hash = Sha256::new();
    hash.input(chunk);
    let mut hash2 = Sha256::new();
    hash2.input(&hash.result_bytes()[..]);
    hash2.result_bytes()
}

/// Validate provided generic base58 hash.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_base58_hash(addr: &str) -> Result<usize, ValidationError> {
    if addr.len() == 0 {
        return Err(ValidationError::TooShort);
    }

    let big = match decode_base58(addr) {
        None => return Err(ValidationError::InvalidEncoding),
        Some(x) => x
    };
    let bytes = bigint_to_bytes(big);
    let padded = pad_to(bytes, 25);

    let hash = double_sha256(&padded[0 .. padded.len() - 4]);
    let short_hash = &hash[0..4];
    let known = &padded[padded.len()-4 .. padded.len()];
    if &short_hash[..] == known {
        Ok(padded[0] as usize)
    } else {
        Err(ValidationError::HashMismatch)
    }
}

/// Validate bitcoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_btc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(0) => Ok(0),      // real address
        Ok(5) => Ok(5),      // script hash
        Ok(111) => Ok(111),  // testnet address
        Ok(_) => Err(ValidationError::NotBitcoin),
        Err(x) => Err(x)
    }
}

/// Validate litecoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_ltc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(48) => Ok(48),      // real address
        Ok(111) => Ok(111),    // testnet address
        Ok(_) => Err(ValidationError::NotLitecoin),
        Err(x) => Err(x)
    }
}

#[test]
fn test_decoding() {
    use num::traits::Num;

    assert_eq!(decode_base58("1"), 0.to_biguint());
    assert_eq!(decode_base58("1AaZz"), 0x1C8485.to_biguint());
    assert_eq!(decode_base58("AO"), None);
    assert_eq!(decode_base58("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), BigUint::from_str_radix("65A16059864A2FDBC7C99A4723A8395BC6F188EBC046B2FF", 16).ok());
}

#[test]
fn test_to_bytes() {
    assert_eq!(bigint_to_bytes(Zero::zero()), vec!(0));
    assert_eq!(bigint_to_bytes(1.to_biguint().unwrap()), vec!(1));
    assert_eq!(bigint_to_bytes(256.to_biguint().unwrap()), vec!(1, 0));
}

#[test]
fn test_validate_hash() {
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_base58_hash("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYheX"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYh  "), Err(ValidationError::InvalidEncoding));
    assert_eq!(validate_base58_hash("1"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash(""), Err(ValidationError::TooShort));
}

#[test]
fn test_validate_btc_address() {
    assert_eq!(validate_btc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_btc_address("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX"), Ok(5));
    assert_eq!(validate_btc_address("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_btc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Err(ValidationError::NotBitcoin));
}

#[test]
fn test_validate_ltc_address() {
    assert_eq!(validate_ltc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Ok(48));
    assert_eq!(validate_ltc_address("muen9zszN6rVwXaFw48xh6YkdUSjJcfzek"), Ok(111));
    assert_eq!(validate_ltc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Err(ValidationError::NotLitecoin));
}

#[bench]
fn bench_validate_hash(b: &mut test::Bencher) {
    b.iter(|| {
        validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem")
    })
}
<commit_msg>Use correct function name (biguint)<commit_after>#![crate_type = "lib"]
#![crate_name = "coinaddress"]

//! Functions for validating the base58 hash checksums, including specifically
//! the bitcoin and litecoin addresses.

#![feature(test)]
#![feature(rustc_private)]

extern crate num;
extern crate rustc;
extern crate test;

use num::bigint::{ToBigUint,BigUint};
use num::traits::ToPrimitive;
use num::Zero;
use rustc::util::sha2::{Sha256, Digest};

#[derive(PartialEq, Debug)]
pub enum ValidationError {
    /// Given address is too short to be valid
    TooShort,
    /// Encoding is not a valid base58
    InvalidEncoding,
    /// Computed hash does not match the embedded one
    HashMismatch,

    // currency specific
    /// This address is not a bitcoin address (testnet or real).
    /// May happen when attempting to validate btc address
    NotBitcoin,
    /// This address is not a litecoin address.
    /// May happen when attempting to validate ltc address
    NotLitecoin,
}

static BASE58_CHARS: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

fn decode_base58(bc: &str) -> Option<BigUint> {
    let mut res: BigUint = Zero::zero();
    let b58: BigUint = 58.to_biguint().unwrap();

    for c in bc.chars() {
        match BASE58_CHARS.find(c) {
            None => {
                return None
            },
            Some(x) => {
                res = res * &b58 + x.to_biguint().unwrap();
            }
        }
    }
    Some(res)
}

fn biguint_to_bytes(n: BigUint) -> Vec<u8> {
    let mut res: Vec<u8> = Vec::new();
    let mut tmp = n;
    let b256: BigUint = 256.to_biguint().unwrap();

    while !tmp.is_zero() {
        res.insert(0, (&tmp % &b256).to_u8().unwrap());
        tmp = tmp / &b256;
    }

    if res.len() == 0 {
        return vec!(0);
    }

    res
}

fn pad_to(v: Vec<u8>, len: usize) -> Vec<u8> {
    let mut tmp: Vec<u8> = v;
    while tmp.len() < len {
        tmp.insert(0, 0)
    }
    tmp
}

fn double_sha256(chunk: &[u8]) -> Vec<u8> {
    let mut hash = Sha256::new();
    hash.input(chunk);
    let mut hash2 = Sha256::new();
    hash2.input(&hash.result_bytes()[..]);
    hash2.result_bytes()
}

/// Validate provided generic base58 hash.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_base58_hash(addr: &str) -> Result<usize, ValidationError> {
    if addr.len() == 0 {
        return Err(ValidationError::TooShort);
    }

    let big = match decode_base58(addr) {
        None => return Err(ValidationError::InvalidEncoding),
        Some(x) => x
    };
    let bytes = biguint_to_bytes(big);
    let padded = pad_to(bytes, 25);

    let hash = double_sha256(&padded[0 .. padded.len() - 4]);
    let short_hash = &hash[0..4];
    let known = &padded[padded.len()-4 .. padded.len()];
    if &short_hash[..] == known {
        Ok(padded[0] as usize)
    } else {
        Err(ValidationError::HashMismatch)
    }
}

/// Validate bitcoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_btc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(0) => Ok(0),      // real address
        Ok(5) => Ok(5),      // script hash
        Ok(111) => Ok(111),  // testnet address
        Ok(_) => Err(ValidationError::NotBitcoin),
        Err(x) => Err(x)
    }
}

/// Validate litecoin address checksum.
/// Returns the hash version/type if correct and an error otherwise.
pub fn validate_ltc_address(addr: &str) -> Result<usize, ValidationError> {
    match validate_base58_hash(addr) {
        Ok(48) => Ok(48),      // real address
        Ok(111) => Ok(111),    // testnet address
        Ok(_) => Err(ValidationError::NotLitecoin),
        Err(x) => Err(x)
    }
}

#[test]
fn test_decoding() {
    use num::traits::Num;

    assert_eq!(decode_base58("1"), 0.to_biguint());
    assert_eq!(decode_base58("1AaZz"), 0x1C8485.to_biguint());
    assert_eq!(decode_base58("AO"), None);
    assert_eq!(decode_base58("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), BigUint::from_str_radix("65A16059864A2FDBC7C99A4723A8395BC6F188EBC046B2FF", 16).ok());
}

#[test]
fn test_to_bytes() {
    assert_eq!(biguint_to_bytes(Zero::zero()), vec!(0));
    assert_eq!(biguint_to_bytes(1.to_biguint().unwrap()), vec!(1));
    assert_eq!(biguint_to_bytes(256.to_biguint().unwrap()), vec!(1, 0));
}

#[test]
fn test_validate_hash() {
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_base58_hash("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYheX"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYh  "), Err(ValidationError::InvalidEncoding));
    assert_eq!(validate_base58_hash("1"), Err(ValidationError::HashMismatch));
    assert_eq!(validate_base58_hash(""), Err(ValidationError::TooShort));
}

#[test]
fn test_validate_btc_address() {
    assert_eq!(validate_btc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Ok(0));
    assert_eq!(validate_btc_address("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX"), Ok(5));
    assert_eq!(validate_btc_address("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"), Ok(111));
    assert_eq!(validate_btc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Err(ValidationError::NotBitcoin));
}

#[test]
fn test_validate_ltc_address() {
    assert_eq!(validate_ltc_address("LRELGDJyeCPRDXz4Dh1kWorMN9hTBB7CEz"), Ok(48));
    assert_eq!(validate_ltc_address("muen9zszN6rVwXaFw48xh6YkdUSjJcfzek"), Ok(111));
    assert_eq!(validate_ltc_address("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"), Err(ValidationError::NotLitecoin));
}

#[bench]
fn bench_validate_hash(b: &mut test::Bencher) {
    b.iter(|| {
        validate_base58_hash("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem")
    })
}
<|endoftext|>