<commit_before>#[no_core];

use core(vers = "0.2");
use std(vers = "0.2");
use rustc(vers = "0.2");

import core::*;

// -*- rust -*-
import result::{ok, err};
import std::getopts;
import io::writer_util;
import getopts::{opt_present};
import rustc::driver::driver::*;
import rustc::syntax::codemap;
import rustc::driver::diagnostic;

fn version(argv0: str) {
    let mut vers = "unknown version";
    let env_vers = #env["CFG_VERSION"];
    if str::len(env_vers) != 0u { vers = env_vers; }
    io::stdout().write_str(#fmt["%s %s\n", argv0, vers]);
    io::stdout().write_str(#fmt["host: %s\n", host_triple()]);
}

fn usage(argv0: str) {
    io::stdout().write_str(#fmt["Usage: %s [options] <input>\n", argv0] +
                               "
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --no-asm-comments  Do not add comments into the assembly source
    --no-trans         Run all passes except translation; no output
    --no-verify        Suppress LLVM verification step (slight speedup)
                       (see http://llvm.org/docs/Passes.html for detail)
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
    --stats            Print compilation statistics
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)
    --debug-rustc      enables different output that helps in debugging rustc,
                       but may be less clear for normal use

    -W <foo>           enable warning <foo>
    -W no-<foo>        disable warning <foo>
    -W err-<foo>       enable warning <foo> as an error

    --time-passes      Time the individual phases of the compiler
    --time-llvm-passes Time the individual phases of the LLVM backend
    --count-llvm-insns Count and categorize generated LLVM instructions

    -v --version       Print version info and exit
");
}

fn run_compiler(args: [str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let mut args = args;
    let binary = vec::shift(args);

    if vec::len(args) == 0u { usage(binary); ret; }

    let match =
        alt getopts::getopts(args, opts()) {
          ok(m) { m }
          err(f) {
            early_error(demitter, getopts::fail_str(f))
          }
        };
    if opt_present(match, "h") || opt_present(match, "help") {
        usage(binary);
        ret;
    }
    if opt_present(match, "v") || opt_present(match, "version") {
        version(binary);
        ret;
    }
    let ifile = alt vec::len(match.free) {
      0u { early_error(demitter, "no input filename given") }
      1u { match.free[0] }
      _ { early_error(demitter, "multiple input filenames provided") }
    };

    let sopts = build_session_options(match, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(match, "out-dir");
    let ofile = getopts::opt_maybe_str(match, "o");
    let cfg = build_configuration(sess, binary, ifile);
    let pretty =
        option::map(getopts::opt_default(match, "pretty",
                                         "normal"),
                    bind parse_pretty(sess, _));
    alt pretty {
      some::<pp_mode>(ppm) { pretty_print_input(sess, cfg, ifile, ppm); ret; }
      none::<pp_mode> {/* continue */ }
    }
    let ls = opt_present(match, "ls");
    if ls {
        list_metadata(sess, ifile, io::stdout());
        ret;
    }

    compile_input(sess, cfg, ifile, odir, ofile);
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(f: fn~(diagnostic::emitter)) {
    enum monitor_msg {
        fatal,
        done,
    };

    let p = comm::port();
    let ch = comm::chan(p);

    alt task::try  {||

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
                           msg: str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        resource finally(ch: comm::chan<monitor_msg>) {
            comm::send(ch, done);
        }

        let _finally = finally(ch);

        f(demitter)
    } {
        result::ok(_) { /* fallthrough */ }
        result::err(_) {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    none,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);
                let note = "The compiler hit an unexpected failure path. \
                            This is a bug. Try running with \
                            RUST_LOG=rustc=0,::rt::backtrace \
                            to get further details and report the results \
                            to github.com/mozilla/rust/issues";
                diagnostic::emit(none, note, diagnostic::note);
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main(args: [str]) {
    monitor {|demitter|
        run_compiler(args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Describe warnings on command line if user says -W help.<commit_after>#[no_core];

use core(vers = "0.2");
use std(vers = "0.2");
use rustc(vers = "0.2");

import core::*;

// -*- rust -*-
import result::{ok, err};
import std::getopts;
import std::map::hashmap;
import getopts::{opt_present};
import rustc::driver::driver::*;
import rustc::syntax::codemap;
import rustc::driver::diagnostic;
import rustc::middle::lint;

fn version(argv0: str) {
    let mut vers = "unknown version";
    let env_vers = #env["CFG_VERSION"];
    if str::len(env_vers) != 0u { vers = env_vers; }
    io::println(#fmt("%s %s", argv0, vers));
    io::println(#fmt("host: %s", host_triple()));
}

fn usage(argv0: str) {
    io::println(#fmt("Usage: %s [options] <input>\n", argv0) +
                 "
Options:

    --bin              Compile an executable crate (default)
    -c                 Compile and assemble, but do not link
    --cfg <cfgspec>    Configure the compilation environment
    --emit-llvm        Produce an LLVM bitcode file
    -g                 Produce debug info
    --gc               Garbage collect shared data (experimental/temporary)
    -h --help          Display this message
    -L <path>          Add a directory to the library search path
    --lib              Compile a library crate
    --ls               List the symbols defined by a compiled library crate
    --no-asm-comments  Do not add comments into the assembly source
    --no-trans         Run all passes except translation; no output
    --no-verify        Suppress LLVM verification step (slight speedup)
                       (see http://llvm.org/docs/Passes.html for detail)
    -O                 Equivalent to --opt-level=2
    -o <filename>      Write output to <filename>
    --opt-level <lvl>  Optimize with possible levels 0-3
    --out-dir <dir>    Write output to compiler-chosen filename in <dir>
    --parse-only       Parse only; do not compile, assemble, or link
    --pretty [type]    Pretty-print the input instead of compiling;
                       valid types are: normal (un-annotated source),
                       expanded (crates expanded), typed (crates expanded,
                       with type annotations), or identified (fully
                       parenthesized, AST nodes and blocks with IDs)
    -S                 Compile only; do not assemble or link
    --save-temps       Write intermediate files (.bc, .opt.bc, .o)
                       in addition to normal output
    --static           Use or produce static libraries or binaries
    --stats            Print compilation statistics
    --sysroot <path>   Override the system root
    --test             Build a test harness
    --target <triple>  Target cpu-manufacturer-kernel[-os] to compile for
                       (default: host triple)
                       (see http://sources.redhat.com/autobook/autobook/
                       autobook_17.html for detail)
    --debug-rustc      enables different output that helps in debugging rustc,
                       but may be less clear for normal use

    -W <foo>           enable warning <foo>
    -W no-<foo>        disable warning <foo>
    -W err-<foo>       enable warning <foo> as an error

    -W help            Print available warnings and default settings

    --time-passes      Time the individual phases of the compiler
    --time-llvm-passes Time the individual phases of the LLVM backend
    --count-llvm-insns Count and categorize generated LLVM instructions

    -v --version       Print version info and exit
");
}

fn describe_warnings() {
    let lint_dict = lint::get_lint_dict();
    let mut max_key = 0u;
    for lint_dict.each_key {|k| max_key = uint::max(k.len(), max_key); }
    fn padded(max: uint, s: str) -> str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    io::println(#fmt("\nAvailable warnings:\n"));
    io::println(#fmt("    %s  %7.7s  %s",
                     padded(max_key, "name"), "default", "meaning"));
    io::println(#fmt("    %s  %7.7s  %s\n",
                     padded(max_key, "----"), "-------", "-------"));
    for lint_dict.each {|k, v|
        let k = str::replace(k, "_", "-");
        io::println(#fmt("    %s  %7.7s  %s",
                         padded(max_key, k),
                         alt v.default { lint::warn { "warn" }
                                        lint::error { "error" }
                                        lint::ignore { "ignore" } },
                         v.desc));
    }
    io::println("");
}

fn run_compiler(args: [str], demitter: diagnostic::emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    logging::console_off();

    let mut args = args;
    let binary = vec::shift(args);

    if vec::len(args) == 0u { usage(binary); ret; }

    let match =
        alt getopts::getopts(args, opts()) {
          ok(m) { m }
          err(f) {
            early_error(demitter, getopts::fail_str(f))
          }
        };

    if opt_present(match, "h") || opt_present(match, "help") {
        usage(binary);
        ret;
    }

    let lint_flags = (getopts::opt_strs(match, "W")
                      + getopts::opt_strs(match, "warn"));
    if lint_flags.contains("help") {
        describe_warnings();
        ret;
    }

    if opt_present(match, "v") || opt_present(match, "version") {
        version(binary);
        ret;
    }
    let ifile = alt vec::len(match.free) {
      0u { early_error(demitter, "no input filename given") }
      1u { match.free[0] }
      _ { early_error(demitter, "multiple input filenames provided") }
    };

    let sopts = build_session_options(match, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(match, "out-dir");
    let ofile = getopts::opt_maybe_str(match, "o");
    let cfg = build_configuration(sess, binary, ifile);
    let pretty =
        option::map(getopts::opt_default(match, "pretty",
                                         "normal"),
                    bind parse_pretty(sess, _));
    alt pretty {
      some::<pp_mode>(ppm) { pretty_print_input(sess, cfg, ifile, ppm); ret; }
      none::<pp_mode> {/* continue */ }
    }
    let ls = opt_present(match, "ls");
    if ls {
        list_metadata(sess, ifile, io::stdout());
        ret;
    }

    compile_input(sess, cfg, ifile, odir, ofile);
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
fn monitor(f: fn~(diagnostic::emitter)) {
    enum monitor_msg {
        fatal,
        done,
    };

    let p = comm::port();
    let ch = comm::chan(p);

    alt task::try  {||

        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
                           msg: str, lvl: diagnostic::level) {
            if lvl == diagnostic::fatal {
                comm::send(ch, fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        resource finally(ch: comm::chan<monitor_msg>) {
            comm::send(ch, done);
        }

        let _finally = finally(ch);

        f(demitter)
    } {
        result::ok(_) { /* fallthrough */ }
        result::err(_) {
            // Task failed without emitting a fatal diagnostic
            if comm::recv(p) == done {
                diagnostic::emit(
                    none,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);
                let note = "The compiler hit an unexpected failure path. \
                            This is a bug. Try running with \
                            RUST_LOG=rustc=0,::rt::backtrace \
                            to get further details and report the results \
                            to github.com/mozilla/rust/issues";
                diagnostic::emit(none, note, diagnostic::note);
            }
            // Fail so the process returns a failure code
            fail;
        }
    }
}

fn main(args: [str]) {
    monitor {|demitter|
        run_compiler(args, demitter);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use std::io::{Read, Result, Error, Seek, SeekFrom};
use std::io::ErrorKind::Other;
use std::path::{Path, PathBuf};
use std::fs;

use byteorder::{LittleEndian, ByteOrder};
use crc::{crc32, Hasher32};
use nix::sys::stat;

const LABEL_SCAN_SECTORS: usize = 4;
const ID_LEN: usize = 32;
const MDA_MAGIC: &'static [u8] = b"\x20\x4c\x56\x4d\x32\x20\x78\x5b\x35\x41\x25\x72\x30\x4e\x2a\x3e";
const INITIAL_CRC: u32 = 0xf597a6cf;
const SECTOR_SIZE: usize = 512;

#[derive(Debug)]
struct LabelHeader {
    id: String,
    sector: u64,
    crc: u32,
    offset: u32,
    label: String,
}

#[derive(Debug)]
struct PvArea {
    offset: u64,
    size: u64,
}

#[derive(Debug)]
struct PvHeader {
    uuid: String,
    size: u64, // in bytes
    ext_version: u32,
    ext_flags: u32,
    data_areas: Vec<PvArea>,
    metadata_areas: Vec<PvArea>,
    bootloader_areas: Vec<PvArea>,
}

fn get_label_header(buf: &[u8]) -> Result<LabelHeader> {

    for x in 0..LABEL_SCAN_SECTORS {
        let sec_buf = &buf[x*SECTOR_SIZE..x*SECTOR_SIZE+SECTOR_SIZE];
        if &sec_buf[..8] == b"LABELONE" {
            let crc = LittleEndian::read_u32(&sec_buf[16..20]);
            crc32_ok(crc, &sec_buf[20..SECTOR_SIZE]);

            let sector = LittleEndian::read_u64(&sec_buf[8..16]);
            if sector != x as u64 {
                return Err(Error::new(Other, "Sector field should equal sector count"));
            }

            return Ok(LabelHeader{
                id: String::from_utf8_lossy(&sec_buf[..8]).into_owned(),
                sector: sector,
                crc: crc,
                offset: LittleEndian::read_u32(&sec_buf[20..24]) + (x*SECTOR_SIZE as usize) as u32,
                label: String::from_utf8_lossy(&sec_buf[24..32]).into_owned(),
            })
        }
    }

    Err(Error::new(Other, "Label not found"))
}

#[derive(Debug)]
struct PvAreaIter<'a> {
    area: &'a[u8],
}

fn iter_pv_area<'a>(buf: &'a[u8]) -> PvAreaIter<'a> {
    PvAreaIter { area: buf }
}

impl<'a> Iterator for PvAreaIter<'a> {
    type Item = PvArea;

    fn next (&mut self) -> Option<PvArea> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[16..];
            Some(PvArea {
                offset: off,
                size: size,
            })
        }
    }
}

//
// PV HEADER LAYOUT:
// - static header (uuid and size)
// - 0+ data areas (actually max 1, usually 1; size 0 == "rest of blkdev")
// - blank entry
// - 0+ metadata areas (max 1, usually 1)
// - blank entry
// - 8 bytes of pvextension header
// - if version > 0
//   - 0+ bootloader areas (usually 0)
//
fn get_pv_header(buf: &[u8]) -> Result<PvHeader> {

    let mut da_buf = &buf[ID_LEN+8..];

    let da_vec: Vec<_> = iter_pv_area(da_buf).collect();

    // move slice past any actual entries plus blank
    // terminating entry
    da_buf = &da_buf[(da_vec.len()+1)*16..];

    let md_vec: Vec<_> = iter_pv_area(da_buf).collect();

    da_buf = &da_buf[(md_vec.len()+1)*16..];

    let ext_version = LittleEndian::read_u32(&da_buf[..4]);
    let mut ext_flags = 0;
    let mut ba_vec = Vec::new();

    if ext_version != 0 {
        ext_flags = LittleEndian::read_u32(&da_buf[4..8]);

        da_buf = &da_buf[8..];

        ba_vec = iter_pv_area(da_buf).collect();
    }

    Ok(PvHeader{
        uuid: String::from_utf8_lossy(&buf[..ID_LEN]).into_owned(),
        size: LittleEndian::read_u64(&buf[ID_LEN..ID_LEN+8]),
        ext_version: ext_version,
        ext_flags: ext_flags,
        data_areas: da_vec,
        metadata_areas: md_vec,
        bootloader_areas: ba_vec,
    })
}

fn crc32_ok(val: u32, buf: &[u8]) -> bool {
    let mut digest = crc32::Digest::new(INITIAL_CRC);
    digest.write(&buf);
    let crc32 = digest.sum32();

    // TODO: all our crcs are failing, how come?
    if val != crc32 {
        println!("CRC32: input {:x} != calculated {:x}", val, crc32);
    }
    val == crc32
}

#[derive(Debug)]
struct RawLocn {
    offset: u64,
    size: u64,
    checksum: u32,
    flags: u32,
}

#[derive(Debug)]
struct RawLocnIter<'a> {
    area: &'a[u8],
}

fn iter_raw_locn<'a>(buf: &'a[u8]) -> RawLocnIter<'a> {
    RawLocnIter { area: buf }
}

impl<'a> Iterator for RawLocnIter<'a> {
    type Item = RawLocn;

    fn next (&mut self) -> Option<RawLocn> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);
        let checksum = LittleEndian::read_u32(&self.area[16..20]);
        let flags = LittleEndian::read_u32(&self.area[20..24]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[24..];
            Some(RawLocn {
                offset: off,
                size: size,
                checksum: checksum,
                flags: flags,
            })
        }
    }
}

fn parse_mda_header(buf: &[u8]) -> Result<()> {

    crc32_ok(LittleEndian::read_u32(&buf[..4]), &buf[4..512]);

    if &buf[4..20] != MDA_MAGIC {
        return Err(Error::new(
            Other, format!("'{}' doesn't match MDA_MAGIC",
                           String::from_utf8_lossy(&buf[4..20]))));
    }

    let ver = LittleEndian::read_u32(&buf[20..24]);
    if ver != 1 {
        return Err(Error::new(Other, format!("Bad version, expected 1")));
    }

    // TODO: validate these somehow
    //println!("mdah start {}", LittleEndian::read_u64(&buf[24..32]));
    //println!("mdah size {}", LittleEndian::read_u64(&buf[32..40]));

    for x in iter_raw_locn(&buf[40..]) {
        println!("rawlocn {:?}", x);
        let start = x.offset as usize;
        let end = start + x.size as usize;
        //lex_and_print(&buf[start..end]);
    }

    Ok(())
}

fn find_label_in_dev(path: &Path) -> Result<LabelHeader> {

    let mut f = try!(fs::File::open(path));

    let mut buf = vec![0; LABEL_SCAN_SECTORS * 512];

    try!(f.read(&mut buf));

    let label_header = try!(get_label_header(&buf));

    let pvheader = try!(get_pv_header(&buf[label_header.offset as usize..]));

    for md in &pvheader.metadata_areas {

        try!(f.seek(SeekFrom::Start(md.offset)));

        let mut buf = vec![0; md.size as usize];

        try!(f.read(&mut buf));

        parse_mda_header(&buf);
    }

    return Ok(label_header);
}

pub fn scan_for_pvs(dirs: &[&Path]) -> Result<Vec<PathBuf>> {

    let mut ret_vec = Vec::new();

    for dir in dirs {
        for direntry in try!(fs::read_dir(dir)) {
            let path = direntry.unwrap().path();
            let s = stat::stat(&path).unwrap();

            if (s.st_mode & 0x6000) == 0x6000 { // S_IFBLK
                if find_label_in_dev(&path).is_ok() {
                    ret_vec.push(path);
                }
            }
        }
    }

    Ok(ret_vec)
}

<commit_msg>redo a bunch of stuff in pvlabel<commit_after>use std::io::{Read, Result, Error, Seek, SeekFrom};
use std::io::ErrorKind::Other;
use std::path::{Path, PathBuf};
use std::fs;
use std::collections::btree_map::BTreeMap;

use byteorder::{LittleEndian, ByteOrder};
use crc::{crc32, Hasher32};
use nix::sys::stat;

use lexer;

const LABEL_SCAN_SECTORS: usize = 4;
const ID_LEN: usize = 32;
const MDA_MAGIC: &'static [u8] = b"\x20\x4c\x56\x4d\x32\x20\x78\x5b\x35\x41\x25\x72\x30\x4e\x2a\x3e";
const INITIAL_CRC: u32 = 0xf597a6cf;
const SECTOR_SIZE: usize = 512;

#[derive(Debug)]
struct LabelHeader {
    id: String,
    sector: u64,
    crc: u32,
    offset: u32,
    label: String,
}

#[derive(Debug)]
struct PvArea {
    offset: u64,
    size: u64,
}

#[derive(Debug)]
struct PvHeader {
    uuid: String,
    size: u64, // in bytes
    ext_version: u32,
    ext_flags: u32,
    data_areas: Vec<PvArea>,
    metadata_areas: Vec<PvArea>,
    bootloader_areas: Vec<PvArea>,
}

fn get_label_header(buf: &[u8]) -> Result<LabelHeader> {

    for x in 0..LABEL_SCAN_SECTORS {
        let sec_buf = &buf[x*SECTOR_SIZE..x*SECTOR_SIZE+SECTOR_SIZE];
        if &sec_buf[..8] == b"LABELONE" {
            let crc = LittleEndian::read_u32(&sec_buf[16..20]);
            crc32_ok(crc, &sec_buf[20..SECTOR_SIZE]);

            let sector = LittleEndian::read_u64(&sec_buf[8..16]);
            if sector != x as u64 {
                return Err(Error::new(Other, "Sector field should equal sector count"));
            }

            return Ok(LabelHeader{
                id: String::from_utf8_lossy(&sec_buf[..8]).into_owned(),
                sector: sector,
                crc: crc,
                offset: LittleEndian::read_u32(&sec_buf[20..24]) + (x*SECTOR_SIZE as usize) as u32,
                label: String::from_utf8_lossy(&sec_buf[24..32]).into_owned(),
            })
        }
    }

    Err(Error::new(Other, "Label not found"))
}

#[derive(Debug)]
struct PvAreaIter<'a> {
    area: &'a[u8],
}

fn iter_pv_area<'a>(buf: &'a[u8]) -> PvAreaIter<'a> {
    PvAreaIter { area: buf }
}

impl<'a> Iterator for PvAreaIter<'a> {
    type Item = PvArea;

    fn next (&mut self) -> Option<PvArea> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[16..];
            Some(PvArea {
                offset: off,
                size: size,
            })
        }
    }
}

//
// PV HEADER LAYOUT:
// - static header (uuid and size)
// - 0+ data areas (actually max 1, usually 1; size 0 == "rest of blkdev")
// - blank entry
// - 0+ metadata areas (max 1, usually 1)
// - blank entry
// - 8 bytes of pvextension header
// - if version > 0
//   - 0+ bootloader areas (usually 0)
//
fn get_pv_header(buf: &[u8]) -> Result<PvHeader> {

    let mut da_buf = &buf[ID_LEN+8..];

    let da_vec: Vec<_> = iter_pv_area(da_buf).collect();

    // move slice past any actual entries plus blank
    // terminating entry
    da_buf = &da_buf[(da_vec.len()+1)*16..];

    let md_vec: Vec<_> = iter_pv_area(da_buf).collect();

    da_buf = &da_buf[(md_vec.len()+1)*16..];

    let ext_version = LittleEndian::read_u32(&da_buf[..4]);
    let mut ext_flags = 0;
    let mut ba_vec = Vec::new();

    if ext_version != 0 {
        ext_flags = LittleEndian::read_u32(&da_buf[4..8]);

        da_buf = &da_buf[8..];

        ba_vec = iter_pv_area(da_buf).collect();
    }

    Ok(PvHeader{
        uuid: String::from_utf8_lossy(&buf[..ID_LEN]).into_owned(),
        size: LittleEndian::read_u64(&buf[ID_LEN..ID_LEN+8]),
        ext_version: ext_version,
        ext_flags: ext_flags,
        data_areas: da_vec,
        metadata_areas: md_vec,
        bootloader_areas: ba_vec,
    })
}

fn crc32_ok(val: u32, buf: &[u8]) -> bool {
    let mut digest = crc32::Digest::new(INITIAL_CRC);
    digest.write(&buf);
    let crc32 = digest.sum32();

    // TODO: all our crcs are failing, how come?
    if val != crc32 {
        println!("CRC32: input {:x} != calculated {:x}", val, crc32);
    }
    val == crc32
}

#[derive(Debug)]
struct RawLocn {
    offset: u64,
    size: u64,
    checksum: u32,
    flags: u32,
}

#[derive(Debug)]
struct RawLocnIter<'a> {
    area: &'a[u8],
}

fn iter_raw_locn<'a>(buf: &'a[u8]) -> RawLocnIter<'a> {
    RawLocnIter { area: buf }
}

impl<'a> Iterator for RawLocnIter<'a> {
    type Item = RawLocn;

    fn next (&mut self) -> Option<RawLocn> {
        let off = LittleEndian::read_u64(&self.area[..8]);
        let size = LittleEndian::read_u64(&self.area[8..16]);
        let checksum = LittleEndian::read_u32(&self.area[16..20]);
        let flags = LittleEndian::read_u32(&self.area[20..24]);

        if off == 0 {
            None
        }
        else {
            self.area = &self.area[24..];
            Some(RawLocn {
                offset: off,
                size: size,
                checksum: checksum,
                flags: flags,
            })
        }
    }
}

fn find_pv_in_dev(path: &Path) -> Result<PvHeader> {

    let mut f = try!(fs::File::open(path));

    let mut buf = vec![0; LABEL_SCAN_SECTORS * 512];

    try!(f.read(&mut buf));

    let label_header = try!(get_label_header(&buf));
    let pvheader = try!(get_pv_header(&buf[label_header.offset as usize..]));

    return Ok(pvheader);
}

pub fn metadata_from_dev(path: &Path) -> Result<BTreeMap<String, lexer::Entry>> {

    let pvheader = try!(find_pv_in_dev(&path));

    let mut f = try!(fs::File::open(path));

    let mda_areas = pvheader.metadata_areas.len();
    if mda_areas != 1 {
        return Err(Error::new(Other, format!("Expecting 1 mda, found {}", mda_areas)));
    }

    let md = &pvheader.metadata_areas[0];
    try!(f.seek(SeekFrom::Start(md.offset)));
    let mut buf = vec![0; md.size as usize];
    try!(f.read(&mut buf));

    crc32_ok(LittleEndian::read_u32(&buf[..4]), &buf[4..512]);

    if &buf[4..20] != MDA_MAGIC {
        return Err(Error::new(
            Other, format!("'{}' doesn't match MDA_MAGIC",
                           String::from_utf8_lossy(&buf[4..20]))));
    }

    let ver = LittleEndian::read_u32(&buf[20..24]);
    if ver != 1 {
        return Err(Error::new(Other, "Bad version, expected 1"));
    }

    // TODO: validate these somehow
    //println!("mdah start {}", LittleEndian::read_u64(&buf[24..32]));
    //println!("mdah size {}", LittleEndian::read_u64(&buf[32..40]));

    let raw_locns: Vec<_> = iter_raw_locn(&buf[40..]).collect();
    let rlocn_len = raw_locns.len();
    if rlocn_len != 1 {
        return Err(Error::new(Other, format!("Expecting 1 rlocn, found {}", rlocn_len)));
    }

    let rl = &raw_locns[0];
    let rl_start = rl.offset as usize;
    let rl_end = rl_start + rl.size as usize;
    lexer::lex_and_structize(&buf[rl_start..rl_end])
}

pub fn scan_for_pvs(dirs: &[&Path]) -> Result<Vec<PathBuf>> {

    let mut ret_vec = Vec::new();

    for dir in dirs {
        for direntry in try!(fs::read_dir(dir)) {
            let path = direntry.unwrap().path();
            let s = stat::stat(&path).unwrap();

            if (s.st_mode & 0x6000) == 0x6000 { // S_IFBLK
                if find_pv_in_dev(&path).is_ok() {
                    ret_vec.push(path);
                }
            }
        }
    }

    Ok(ret_vec)
}

<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the PWM peripheral.
//!
//! RPPAL configures the Raspberry Pi's PWM peripheral through the `/sys/class/pwm`
//! sysfs interface.
//!
//! ## PWM channels
//!
//! The BCM283x SoC supports two hardware PWM channels. By default, both channels
//! are disabled. To enable only PWM0 on its default pin (BCM GPIO 18, physical pin 12),
//! add `dtoverlay=pwm` to `/boot/config.txt`. If you need both PWM channels, replace
//! `pwm` with `pwm-2chan`, which enables PWM0 on BCM GPIO 18 (physical pin 12), and PWM1
//! on BCM GPIO 19 (physical pin 35). More details on enabling and configuring PWM on
//! other GPIO pins than the default ones can be found in `/boot/overlays/README`.
//!
//! The Raspberry Pi's analog audio output needs both PWM channels. Using both audio out
//! and PWM at the same time may cause issues.
//!
//! Some of the GPIO pins capable of supporting hardware PWM can also be configured for
//! use with other peripherals. Be careful not to enable two peripherals on the same pin
//! at the same time.
//!
//! ## Using PWM without superuser privileges (`sudo`)
//!
//! As of kernel version 4.14.34, released on April 16 2018, it's possible to
//! configure your Raspberry Pi to allow non-root access to PWM. 4.14.34 includes
//! a [patch] that allows udev to change file permissions when a
//! PWM channel is exported. This will let any user that's a member of the `gpio`
//! group configure PWM without having to use `sudo`.
//!
//! The udev rules needed to make this work haven't been patched in yet as of
//! June 2018, but you can easily add them yourself. Make sure you're running
//! 4.14.34 or later, and append the following snippet to
//! `/etc/udev/rules.d/99-com.rules`. Reboot the Raspberry Pi afterwards.
//!
//! ```text
//! SUBSYSTEM=="pwm*", PROGRAM="/bin/sh -c '\
//!     chown -R root:gpio /sys/class/pwm && chmod -R 770 /sys/class/pwm;\
//!     chown -R root:gpio /sys/devices/platform/soc/*.pwm/pwm/pwmchip* &&\
//!     chmod -R 770 /sys/devices/platform/soc/*.pwm/pwm/pwmchip*\
//! '"
//! ```
//!
//! ## Troubleshooting
//!
//! ### Permission denied
//!
//! If [`new`] returns an `io::ErrorKind::PermissionDenied`
//! error, make sure `/sys/class/pwm` and all of its subdirectories
//! are owned by `root:gpio`, the current user is a member of the `gpio` group
//! and udev is properly configured as mentioned above. Alternatively, you can
//! launch your application using `sudo`.
//!
//! [patch]: https://github.com/raspberrypi/linux/issues/1983

use std::io;
use std::result;
use std::time::Duration;

mod sysfs;

quick_error! {
/// Errors that can occur when accessing the PWM peripheral.
    #[derive(Debug)]
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `pwm::Error`s.
pub type Result<T> = result::Result<T, Error>;

/// Channel
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Channel {
    Pwm0 = 0,
    Pwm1 = 1,
}

/// Polarity
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Polarity {
    Normal,
    Inverse,
}

/// Provides access to the Raspberry Pi's PWM peripheral.
///
/// Before using `Pwm`, make sure your Raspberry Pi has the necessary PWM
/// channels enabled. More information can be found [here].
///
/// [here]: index.html
pub struct Pwm {
    channel: Channel,
}

impl Pwm {
    /// Constructs a new `Pwm`.
    pub fn new(channel: Channel) -> Result<Pwm> {
        sysfs::export(channel as u8)?;

        let pwm = Pwm { channel };

        // Always reset "enable" to 0. The sysfs interface has a bug where a previous
        // export may have left "enable" as 1 after unexporting. On the next export,
        // "enable" is still set to 1, even though the channel isn't enabled.
        let _ = pwm.disable();

        // Default settings
        let _ = pwm.set_duty_cycle(Duration::from_secs(0));
        let _ = pwm.set_period(Duration::from_secs(0));
        let _ = pwm.set_polarity(Polarity::Normal);

        Ok(pwm)
    }

    /// Constructs a new `Pwm` using the specified settings.
    pub fn with_settings(
        channel: Channel,
        period: Duration,
        duty_cycle: Duration,
        polarity: Polarity,
        enabled: bool,
    ) -> Result<Pwm> {
        sysfs::export(channel as u8)?;

        let pwm = Pwm { channel };

        // Always reset "enable" to 0. The sysfs pwm interface has a bug where a previous
        // export may have left "enable" as 1 after unexporting. On the next export,
        // "enable" is still set to 1, even though the channel isn't enabled.
        let _ = pwm.disable();

        // Set duty cycle to 0 first in case the new period is shorter than the current duty cycle
        let _ = pwm.set_duty_cycle(Duration::from_secs(0));

        pwm.set_period(period)?;
        pwm.set_duty_cycle(duty_cycle)?;
        pwm.set_polarity(polarity)?;
        if enabled {
            pwm.enable()?;
        }

        Ok(pwm)
    }

    // Gets the period.
    pub fn period(&self) -> Result<Duration> {
        Ok(Duration::from_nanos(sysfs::period(self.channel as u8)?))
    }

    /// Sets the period.
    ///
    /// `period` must be longer than or equal to the selected duty cycle.
    pub fn set_period(&self, period: Duration) -> Result<()> {
        sysfs::set_period(
            self.channel as u8,
            u64::from(period.subsec_nanos())
                .saturating_add(period.as_secs().saturating_mul(1_000_000_000)),
        )?;

        Ok(())
    }

    /// Gets the duty cycle.
    pub fn duty_cycle(&self) -> Result<Duration> {
        Ok(Duration::from_nanos(sysfs::duty_cycle(self.channel as u8)?))
    }

    /// Sets the duty cycle.
    ///
    /// `duty_cycle` must be shorter than or equal to the selected period.
    pub fn set_duty_cycle(&self, duty_cycle: Duration) -> Result<()> {
        sysfs::set_duty_cycle(
            self.channel as u8,
            u64::from(duty_cycle.subsec_nanos())
                .saturating_add(duty_cycle.as_secs().saturating_mul(1_000_000_000)),
        )?;

        Ok(())
    }

    /// Gets the polarity.
    pub fn polarity(&self) -> Result<Polarity> {
        Ok(sysfs::polarity(self.channel as u8)?)
    }

    /// Sets the polarity.
    ///
    /// Changing the polarity from [`Normal`] to [`Inverse`] inverts
    /// the selected duty cycle.
    ///
    /// By default, `polarity` is set to [`Normal`].
    ///
    /// [`Normal`]: enum.Polarity.html
    pub fn set_polarity(&self, polarity: Polarity) -> Result<()> {
        sysfs::set_polarity(self.channel as u8, polarity)?;

        Ok(())
    }

    /// Gets the enabled status.
    pub fn enabled(&self) -> Result<bool> {
        Ok(sysfs::enabled(self.channel as u8)?)
    }

    /// Enables the PWM channel.
    pub fn enable(&self) -> Result<()> {
        sysfs::set_enabled(self.channel as u8, true)?;

        Ok(())
    }

    /// Disables the PWM channel.
    pub fn disable(&self) -> Result<()> {
        sysfs::set_enabled(self.channel as u8, false)?;

        Ok(())
    }
}

impl Drop for Pwm {
    fn drop(&mut self) {
        let _ = sysfs::set_enabled(self.channel as u8, false);
        let _ = sysfs::unexport(self.channel as u8);
    }
}
<commit_msg>Add frequency convenience methods<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the PWM peripheral.
//!
//! RPPAL configures the Raspberry Pi's PWM peripheral through the `/sys/class/pwm`
//! sysfs interface.
//!
//! ## PWM channels
//!
//! The BCM283x SoC supports two hardware PWM channels. By default, both channels
//! are disabled. To enable only PWM0 on its default pin (BCM GPIO 18, physical pin 12),
//! add `dtoverlay=pwm` to `/boot/config.txt`. If you need both PWM channels, replace
//! `pwm` with `pwm-2chan`, which enables PWM0 on BCM GPIO 18 (physical pin 12), and PWM1
//! on BCM GPIO 19 (physical pin 35). More details on enabling and configuring PWM on
//! other GPIO pins than the default ones can be found in `/boot/overlays/README`.
//!
//! The Raspberry Pi's analog audio output needs both PWM channels. Using both audio out
//! and PWM at the same time may cause issues.
//!
//! Some of the GPIO pins capable of supporting hardware PWM can also be configured for
//! use with other peripherals. Be careful not to enable two peripherals on the same pin
//! at the same time.
//!
//! ## Using PWM without superuser privileges (`sudo`)
//!
//! As of kernel version 4.14.34, released on April 16 2018, it's possible to
//! configure your Raspberry Pi to allow non-root access to PWM. 4.14.34 includes
//! a [patch] that allows udev to change file permissions when a
//! PWM channel is exported. This will let any user that's a member of the `gpio`
//! group configure PWM without having to use `sudo`.
//!
//! The udev rules needed to make this work haven't been patched in yet as of
//! June 2018, but you can easily add them yourself. Make sure you're running
//! 4.14.34 or later, and append the following snippet to
//! `/etc/udev/rules.d/99-com.rules`. Reboot the Raspberry Pi afterwards.
//!
//! ```text
//! SUBSYSTEM=="pwm*", PROGRAM="/bin/sh -c '\
//!     chown -R root:gpio /sys/class/pwm && chmod -R 770 /sys/class/pwm;\
//!     chown -R root:gpio /sys/devices/platform/soc/*.pwm/pwm/pwmchip* &&\
//!     chmod -R 770 /sys/devices/platform/soc/*.pwm/pwm/pwmchip*\
//! '"
//! ```
//!
//! ## Troubleshooting
//!
//! ### Permission denied
//!
//! If [`new`] returns an `io::ErrorKind::PermissionDenied`
//! error, make sure `/sys/class/pwm` and all of its subdirectories
//! are owned by `root:gpio`, the current user is a member of the `gpio` group
//! and udev is properly configured as mentioned above. Alternatively, you can
//! launch your application using `sudo`.
//!
//! [patch]: https://github.com/raspberrypi/linux/issues/1983

use std::io;
use std::result;
use std::time::Duration;

mod sysfs;

quick_error! {
/// Errors that can occur when accessing the PWM peripheral.
    #[derive(Debug)]
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `pwm::Error`s.
pub type Result<T> = result::Result<T, Error>;

/// PWM channels.
///
/// More information on enabling and configuring the PWM channels can be
/// found [here].
///
/// [here]: index.html
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Channel {
    Pwm0 = 0,
    Pwm1 = 1,
}

/// Output polarities.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Polarity {
    Normal,
    Inverse,
}

/// Provides access to the Raspberry Pi's PWM peripheral.
///
/// Before using `Pwm`, make sure the selected PWM channel has been configured
/// and activated. More information can be found [here].
///
/// [here]: index.html
pub struct Pwm {
    channel: Channel,
}

impl Pwm {
    /// Constructs a new `Pwm`.
    pub fn new(channel: Channel) -> Result<Pwm> {
        sysfs::export(channel as u8)?;

        let pwm = Pwm { channel };

        // Always reset "enable" to 0. The sysfs interface has a bug where a previous
        // export may have left "enable" as 1 after unexporting. On the next export,
        // "enable" is still set to 1, even though the channel isn't enabled.
        let _ = pwm.disable();

        // Default settings
        let _ = pwm.set_duty_cycle(Duration::from_secs(0));
        let _ = pwm.set_period(Duration::from_secs(0));
        let _ = pwm.set_polarity(Polarity::Normal);

        Ok(pwm)
    }

    /// Constructs a new `Pwm` using the specified settings.
    ///
    /// `period` represents the time it takes for the PWM channel to complete one cycle.
    ///
    /// `duty_cycle` represents the amount of time the PWM channel's logic level is set
    /// high (or low if the polarity is set to [`Inverse`]) during a single period.
    ///
    /// `polarity` configures the active logic level as either high ([`Normal`]) or low ([`Inverse`]).
    ///
    /// `enabled` immediately enables PWM on the selected channel.
    ///
    /// This method will fail if `period` is shorter than `duty_cycle`.
    ///
    /// [`Normal`]: enum.Polarity.html
    /// [`Inverse`]: enum.Polarity.html
    pub fn with_period(
        channel: Channel,
        period: Duration,
        duty_cycle: Duration,
        polarity: Polarity,
        enabled: bool,
    ) -> Result<Pwm> {
        sysfs::export(channel as u8)?;

        let pwm = Pwm { channel };

        // Always reset "enable" to 0. The sysfs pwm interface has a bug where a previous
        // export may have left "enable" as 1 after unexporting. On the next export,
        // "enable" is still set to 1, even though the channel isn't enabled.
        let _ = pwm.disable();

        // Set duty cycle to 0 first in case the new period is shorter than the current duty cycle
        let _ = sysfs::set_duty_cycle(channel as u8, 0);

        pwm.set_period(period)?;
        pwm.set_duty_cycle(duty_cycle)?;
        pwm.set_polarity(polarity)?;
        if enabled {
            pwm.enable()?;
        }

        Ok(pwm)
    }

    /// Constructs a new `Pwm` using the specified settings.
    ///
    /// `with_frequency` is a convenience method that converts `frequency` to a period,
    /// and calculates the duty cycle as a percentage of the frequency.
    ///
    /// `frequency` is specified in herz (Hz).
    ///
    /// `duty_cycle` is specified as a floating point percentage, where `1.0` represents 100%.
    ///
    /// `polarity` configures the active logic level as either high ([`Normal`]) or low ([`Inverse`]).
    ///
    /// `enabled` immediately enables PWM on the selected channel.
    ///
    /// [`Normal`]: enum.Polarity.html
    /// [`Inverse`]: enum.Polarity.html
    pub fn with_frequency(
        channel: Channel,
        frequency: f64,
        duty_cycle: f64,
        polarity: Polarity,
        enabled: bool,
    ) -> Result<Pwm> {
        sysfs::export(channel as u8)?;

        let pwm = Pwm { channel };

        // Always reset "enable" to 0. The sysfs pwm interface has a bug where a previous
        // export may have left "enable" as 1 after unexporting. On the next export,
        // "enable" is still set to 1, even though the channel isn't enabled.
        let _ = pwm.disable();

        // Set duty cycle to 0 first in case the new period is shorter than the current duty cycle
        let _ = sysfs::set_duty_cycle(channel as u8, 0);

        // Convert to nanoseconds
        let period = (1.0f64 / frequency) * 1_000_000_000f64;
        let duty_cycle = period * duty_cycle.min(1.0);

        sysfs::set_period(channel as u8, period as u64)?;
        sysfs::set_duty_cycle(channel as u8, duty_cycle as u64)?;

        pwm.set_polarity(polarity)?;
        if enabled {
            pwm.enable()?;
        }

        Ok(pwm)
    }

    /// Gets the configured period.
    pub fn period(&self) -> Result<Duration> {
        Ok(Duration::from_nanos(sysfs::period(self.channel as u8)?))
    }

    /// Sets the period.
    ///
    /// `period` represents the time it takes for the PWM channel to complete one cycle.
    /// The selected period must be longer than or equal to the duty cycle.
    pub fn set_period(&self, period: Duration) -> Result<()> {
        sysfs::set_period(
            self.channel as u8,
            u64::from(period.subsec_nanos())
                .saturating_add(period.as_secs().saturating_mul(1_000_000_000)),
        )?;

        Ok(())
    }

    /// Gets the configured duty cycle.
    pub fn duty_cycle(&self) -> Result<Duration> {
        Ok(Duration::from_nanos(sysfs::duty_cycle(self.channel as u8)?))
    }

    /// Sets the duty cycle.
    ///
    /// `duty_cycle` represents the amount of time the PWM channel's logic level is set
    /// high (or low if the polarity is set to [`Inverse`]) during a single period. The
    /// duty cycle must be shorter than or equal to the period.
    ///
    /// [`Inverse`]: enum.Polarity.html
    pub fn set_duty_cycle(&self, duty_cycle: Duration) -> Result<()> {
        sysfs::set_duty_cycle(
            self.channel as u8,
            u64::from(duty_cycle.subsec_nanos())
                .saturating_add(duty_cycle.as_secs().saturating_mul(1_000_000_000)),
        )?;

        Ok(())
    }

    /// Sets the frequency and duty cycle.
    ///
    /// `set_frequency` is a convenience method that converts `frequency` to a period,
    /// and calculates the duty cycle as a percentage of the frequency.
    ///
    /// `frequency` is specified in herz (Hz).
    ///
    /// `duty_cycle` is specified as a floating point percentage, where `1.0` represents 100%.
    pub fn set_frequency(&self, frequency: f64, duty_cycle: f64) -> Result<()> {
        // Set duty cycle to 0 first in case the new period is shorter than the current duty cycle
        let _ = sysfs::set_duty_cycle(self.channel as u8, 0);

        // Convert to nanoseconds
        let period = (1.0f64 / frequency) * 1_000_000_000f64;
        let duty_cycle = period * duty_cycle.min(1.0);

        sysfs::set_period(self.channel as u8, period as u64)?;
        sysfs::set_duty_cycle(self.channel as u8, duty_cycle as u64)?;

        Ok(())
    }

    /// Gets the configured polarity.
    pub fn polarity(&self) -> Result<Polarity> {
        Ok(sysfs::polarity(self.channel as u8)?)
    }

    /// Sets the polarity.
    ///
    /// `polarity` configures the active logic level as either high ([`Normal`]) or low ([`Inverse`]).
    ///
    /// By default, `polarity` is set to [`Normal`].
    ///
    /// [`Normal`]: enum.Polarity.html
    pub fn set_polarity(&self, polarity: Polarity) -> Result<()> {
        sysfs::set_polarity(self.channel as u8, polarity)?;

        Ok(())
    }

    /// Checks whether PWM is currently enabled on the selected channel.
    pub fn enabled(&self) -> Result<bool> {
        Ok(sysfs::enabled(self.channel as u8)?)
    }

    /// Enables PWM on the selected channel.
    pub fn enable(&self) -> Result<()> {
        sysfs::set_enabled(self.channel as u8, true)?;

        Ok(())
    }

    /// Disables PWM on the selected channel.
    pub fn disable(&self) -> Result<()> {
        sysfs::set_enabled(self.channel as u8, false)?;

        Ok(())
    }
}

impl Drop for Pwm {
    fn drop(&mut self) {
        let _ = sysfs::set_enabled(self.channel as u8, false);
        let _ = sysfs::unexport(self.channel as u8);
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc::{self, channel, TryRecvError};
use std::io::{Read, ErrorKind};
use std::collections::HashMap;
use std::time::Duration;
use std::usize;

use mio::*;
use mio::tcp::TcpListener;

use ladspa::{PluginDescriptor, Plugin, PortConnection};
use ladspa::{Port, PortDescriptor};
use ladspa::{PROP_NONE, HINT_INTEGER, DefaultValue};

use super::BASE_PORT;
use super::packet::{BUFFER_SIZE, BYTE_BUFFER_SIZE, Packet};

type ClientPacket = (u64, Packet);

const SERVER: Token = Token(0);

pub struct Receiver {
    channel: u16,
    packet_rx: Option<mpsc::Receiver<ClientPacket>>,
    active_packets: Vec<ClientPacket>,
    notify_tx: Option<Sender<<PacketReceiver as Handler>::Message>>,
    client_time_map: HashMap<u64, u64>,
}

impl Receiver {
    pub fn new(_: &PluginDescriptor, _: u64) -> Box<Plugin + Send> {
        println!("receiver::new");
        Box::new(Receiver {
            channel: 0,
            packet_rx: None,
            active_packets: Vec::new(),
            notify_tx: None,
            client_time_map: HashMap::new(),
        })
    }

    pub fn get_descriptor() -> PluginDescriptor {
        PluginDescriptor {
            unique_id: 5878,
            label: "feedback_rx",
            properties: PROP_NONE,
            name: "Feedback Receiver",
            maker: "Noah Weninger",
            copyright: "None",
            ports: vec![Port {
                name: "Left Audio In",
                desc: PortDescriptor::AudioInput,
                ..Default::default()
            },
            Port {
                name: "Right Audio In",
                desc: PortDescriptor::AudioInput,
                ..Default::default()
            },
            Port {
                name: "Left Audio Out",
                desc: PortDescriptor::AudioOutput,
                ..Default::default()
            },
            Port {
                name: "Right Audio Out",
                desc: PortDescriptor::AudioOutput,
                ..Default::default()
            },
            Port {
                name: "Channel",
                desc: PortDescriptor::ControlInput,
                hint: Some(HINT_INTEGER),
                default: Some(DefaultValue::Value0),
                lower_bound: Some(0_f32),
                upper_bound: Some(255_f32),
            },
            Port {
                name: "Dry",
                desc: PortDescriptor::ControlInput,
                hint: None,
                default: Some(DefaultValue::Value1),
                lower_bound: Some(0_f32),
                upper_bound: Some(1_f32),
            },
            Port {
                name: "Recv",
                desc: PortDescriptor::ControlInput,
                hint: None,
                default: Some(DefaultValue::Value1),
                lower_bound: Some(0_f32),
                upper_bound: Some(1_f32),
            }],
            new: Receiver::new,
        }
    }

    fn init_server(&mut self) {
        let (data_tx, data_rx) = channel();
        self.packet_rx = Some(data_rx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let server;
            loop {
                match TcpListener::bind(&addr) {
                    Ok(s) => {
                        server = s;
                        break;
                    }
                    Err(_) => {}
                }
            }
            event_loop.register(&server, SERVER).unwrap();
            event_loop.run(&mut PacketReceiver {
                          server: server,
                          data_tx: data_tx,
                          client_id: 0,
                      })
                      .unwrap();
        });
    }

    fn kill_server(&mut self) {
        self.notify_tx.as_ref().unwrap().send(()).unwrap();
    }

    fn restart_server(&mut self) {
        self.kill_server();
        self.init_server();
    }

    fn recv_packets(&mut self) {
        loop {
            let packet = match self.packet_rx.as_ref().unwrap().try_recv() {
                Ok(packet) => packet,
                Err(TryRecvError::Disconnected) => {
                    println!("ladspa packet receive failed, dead channel!");
                    self.kill_server();
                    self.init_server();
                    break;
                }
                Err(TryRecvError::Empty) => {
                    break;
                }
            };
            self.active_packets.push(packet);
        }
    }

    fn set_channel(&mut self, channel: u16) {
        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.restart_server();
            return;
        }
    }

    fn get_client_time(&self, client_id: u64) -> u64 {
        self.client_time_map.get(&client_id).map(|x| *x).unwrap_or(0)
    }

    fn prune_packets(&mut self) {
        let mut i = self.active_packets.len();
        while i > 0 {
            i -= 1;
            let complete = {
                let (client_id, ref packet) = self.active_packets[i];
                let client_time = self.get_client_time(client_id);
                packet.complete(client_time)
            };
            if complete {
                self.active_packets.remove(i);
            }
        }
    }
}

impl Plugin for Receiver {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;
        let dry = ports[5].unwrap_control();
        let wet = ports[6].unwrap_control();

        self.set_channel(channel);
        self.recv_packets();

        for i in 0..sample_count {
            outputl[i] = inputl[i]*(*dry);
            outputr[i] = inputr[i]*(*dry);
        }

        let mut client_availibility = HashMap::new();
        for &(client_id, _) in &self.active_packets {
            let availibility = client_availibility.get(&client_id).map(|x| *x).unwrap_or(0);
            client_availibility.insert(client_id, availibility + 1);
        }

        if client_availibility.len() > 0 {
            let mut min_availibility = usize::max_value();
            for (_, &availibility) in &client_availibility {
                if availibility < min_availibility {
                    min_availibility = availibility;
                }
            }

            if min_availibility * BUFFER_SIZE < sample_count {
                return;
            }
        }

        let mut read_clients = Vec::new();
        for &(client_id, ref packet) in &self.active_packets {
            let client_time = self.get_client_time(client_id);
            for i in 0..sample_count {
                let (l, r) = packet.read(client_time + i as u64);
                outputl[i] += l*(*wet);
                outputr[i] += r*(*wet);
            }
            read_clients.push(client_id);
        }
        for client_id in read_clients {
            let client_time = self.get_client_time(client_id);
            self.client_time_map.insert(client_id, client_time + sample_count as u64);
        }
        self.prune_packets();
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.client_time_map.clear();
        self.init_server();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_server();
    }
}

struct PacketReceiver {
    server: TcpListener,
    data_tx: mpsc::Sender<ClientPacket>,
    client_id: u64,
}

impl Handler for PacketReceiver {
    type Timeout = ();
        type Message = ();

    fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                // Only receive readable events
                assert!(events.is_readable());

                println!("server wait");
                match self.server.accept() {
                    Ok(Some(mut socket)) => {
                        let client_id = self.client_id;
                        self.client_id += 1;
                        let tx = self.data_tx.clone();
                        thread::spawn(move || {
                            socket.set_nodelay(true).unwrap();
                            let mut buf = [0; BYTE_BUFFER_SIZE];
                            let mut buf_pos = 0;
                            println!("server accept client {}", client_id);
                            loop {
                                let res = socket.read(&mut buf[buf_pos..]);
                                match res {
                                    Ok(num_read) => {
                                        //println!("server read {}", num_read);
                                        // if we got a length zero read, the connection is done.
                                        if num_read == 0 {
                                            println!("read zero bytes");
                                            return;
                                        }

                                        // check if we've filled the buffer
                                        buf_pos += num_read;
                                        if buf_pos != BYTE_BUFFER_SIZE {
                                            continue;
                                        }
                                        buf_pos = 0;
                                    }
                                    Err(e) => {
                                        if e.kind() == ErrorKind::WouldBlock {
                                            //TODO this is a quick hack to reduce CPU usage
                                            thread::sleep(Duration::from_millis(10));
                                            continue;
                                        }
                                        panic!(e);
                                    }
                                }
                                let packet = Packet::parse(&buf[..]);
                                if let Err(_) = tx.send((client_id, packet)) {
                                    println!("send packet to ladspa error! channel is dead.");
                                    return;
                                }
                            }
                        });
                    }
                    Ok(None) => {
                        println!("the server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept() errored: {}", e);
                        // event_loop.shutdown();
                    }
                }
            }
            _ => panic!("Received unknown token"),
        }
    }
    fn notify(&mut self, event_loop: &mut EventLoop<Self>, _: Self::Message) {
        event_loop.shutdown();
    }
}
<commit_msg>factor<commit_after>use std::thread;
use std::sync::mpsc::{self, channel, TryRecvError};
use std::io::{Read, ErrorKind};
use std::collections::HashMap;
use std::time::Duration;
use std::usize;

use mio::*;
use mio::tcp::TcpListener;

use ladspa::{PluginDescriptor, Plugin, PortConnection};
use ladspa::{Port, PortDescriptor};
use ladspa::{PROP_NONE, HINT_INTEGER, DefaultValue};

use super::BASE_PORT;
use super::packet::{BUFFER_SIZE, BYTE_BUFFER_SIZE, Packet};

type ClientPacket = (u64, Packet);

const SERVER: Token = Token(0);

pub struct Receiver {
    channel: u16,
    packet_rx: Option<mpsc::Receiver<ClientPacket>>,
    active_packets: Vec<ClientPacket>,
    notify_tx: Option<Sender<<PacketReceiver as Handler>::Message>>,
    client_time_map: HashMap<u64, u64>,
}

impl Receiver {
    pub fn new(_: &PluginDescriptor, _: u64) -> Box<Plugin + Send> {
        println!("receiver::new");
        Box::new(Receiver {
            channel: 0,
            packet_rx: None,
            active_packets: Vec::new(),
            notify_tx: None,
            client_time_map: HashMap::new(),
        })
    }

    pub fn get_descriptor() -> PluginDescriptor {
        PluginDescriptor {
            unique_id: 5878,
            label: "feedback_rx",
            properties: PROP_NONE,
            name: "Feedback Receiver",
            maker: "Noah Weninger",
            copyright: "None",
            ports: vec![Port {
                name: "Left Audio In",
                desc: PortDescriptor::AudioInput,
                ..Default::default()
            },
            Port {
                name: "Right Audio In",
                desc: PortDescriptor::AudioInput,
                ..Default::default()
            },
            Port {
                name: "Left Audio Out",
                desc: PortDescriptor::AudioOutput,
                ..Default::default()
            },
            Port {
                name: "Right Audio Out",
                desc: PortDescriptor::AudioOutput,
                ..Default::default()
            },
            Port {
                name: "Channel",
                desc: PortDescriptor::ControlInput,
                hint: Some(HINT_INTEGER),
                default: Some(DefaultValue::Value0),
                lower_bound: Some(0_f32),
                upper_bound: Some(255_f32),
            },
            Port {
                name: "Dry",
                desc: PortDescriptor::ControlInput,
                hint: None,
                default: Some(DefaultValue::Value1),
                lower_bound: Some(0_f32),
                upper_bound: Some(1_f32),
            },
            Port {
                name: "Recv",
                desc: PortDescriptor::ControlInput,
                hint: None,
                default: Some(DefaultValue::Value1),
                lower_bound: Some(0_f32),
                upper_bound: Some(1_f32),
            }],
            new: Receiver::new,
        }
    }

    fn init_server(&mut self) {
        let (data_tx, data_rx) = channel();
        self.packet_rx = Some(data_rx);

        let channel = self.channel;
        let mut event_loop = EventLoop::new().unwrap();
        self.notify_tx = Some(event_loop.channel());
        thread::spawn(move || {
            let addr = format!("127.0.0.1:{}", BASE_PORT + channel).parse().unwrap();
            let server;
            loop {
                match TcpListener::bind(&addr) {
                    Ok(s) => {
                        server = s;
                        break;
                    }
                    Err(_) => {}
                }
            }
            event_loop.register(&server, SERVER).unwrap();
            event_loop.run(&mut PacketReceiver {
                          server: server,
                          data_tx: data_tx,
                          client_id: 0,
                      })
                      .unwrap();
        });
    }

    fn kill_server(&mut self) {
        self.notify_tx.as_ref().unwrap().send(()).unwrap();
    }

    fn restart_server(&mut self) {
        self.kill_server();
        self.init_server();
    }

    fn recv_packets(&mut self) {
        loop {
            let packet = match self.packet_rx.as_ref().unwrap().try_recv() {
                Ok(packet) => packet,
                Err(TryRecvError::Disconnected) => {
                    println!("ladspa packet receive failed, dead channel!");
                    self.kill_server();
                    self.init_server();
                    break;
                }
                Err(TryRecvError::Empty) => {
                    break;
                }
            };
            self.active_packets.push(packet);
        }
    }

    fn set_channel(&mut self, channel: u16) {
        if channel != self.channel {
            self.channel = channel;
            println!("set channel {}", self.channel);
            self.restart_server();
            return;
        }
    }

    fn get_client_time(&self, client_id: u64) -> u64 {
        self.client_time_map.get(&client_id).map(|x| *x).unwrap_or(0)
    }

    fn set_client_time(&mut self, client_id: u64, time: u64) {
        self.client_time_map.insert(client_id, time);
    }

    fn prune_packets(&mut self) {
        let mut i = self.active_packets.len();
        while i > 0 {
            i -= 1;
            let complete = {
                let (client_id, ref packet) = self.active_packets[i];
                let client_time = self.get_client_time(client_id);
                packet.complete(client_time)
            };
            if complete {
                self.active_packets.remove(i);
            }
        }
    }

    fn have_enough_data(&self, sample_count: usize) -> bool {
        let mut client_availibility = HashMap::new();
        for &(client_id, _) in &self.active_packets {
            let availibility = client_availibility.get(&client_id).map(|x| *x).unwrap_or(0);
            client_availibility.insert(client_id, availibility + 1);
        }

        if client_availibility.len() > 0 {
            let mut min_availibility = usize::max_value();
            for (_, &availibility) in &client_availibility {
                if availibility < min_availibility {
                    min_availibility = availibility;
                }
            }

            return min_availibility * BUFFER_SIZE >= sample_count;
        }

        // no packets, don't waste time
        return false;
    }
}

impl Plugin for Receiver {
    fn run<'a>(&mut self, sample_count: usize, ports: &[&'a PortConnection<'a>]) {
        let inputl = ports[0].unwrap_audio();
        let inputr = ports[1].unwrap_audio();
        let mut outputl = ports[2].unwrap_audio_mut();
        let mut outputr = ports[3].unwrap_audio_mut();

        let channel = *ports[4].unwrap_control() as u16;
        let dry = ports[5].unwrap_control();
        let wet = ports[6].unwrap_control();

        self.set_channel(channel);
        self.recv_packets();

        for i in 0..sample_count {
            outputl[i] = inputl[i]*(*dry);
            outputr[i] = inputr[i]*(*dry);
        }

        if !self.have_enough_data(sample_count) {
            return;
        }

        let mut read_clients = Vec::new();
        for &(client_id, ref packet) in &self.active_packets {
            let client_time = self.get_client_time(client_id);
            for i in 0..sample_count {
                let (l, r) = packet.read(client_time + i as u64);
                outputl[i] += l*(*wet);
                outputr[i] += r*(*wet);
            }
            read_clients.push(client_id);
        }
        for client_id in read_clients {
            let client_time = self.get_client_time(client_id);
            self.set_client_time(client_id, client_time + sample_count as u64);
        }
        self.prune_packets();
    }

    fn activate(&mut self) {
        println!("activate {}", self.channel);
        self.client_time_map.clear();
        self.init_server();
    }

    fn deactivate(&mut self) {
        println!("deactivate {}", self.channel);
        self.kill_server();
    }
}

struct PacketReceiver {
    server: TcpListener,
    data_tx: mpsc::Sender<ClientPacket>,
    client_id: u64,
}

impl Handler for PacketReceiver {
    type Timeout = ();
        type Message = ();

    fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                // Only receive readable events
                assert!(events.is_readable());

                println!("server wait");
                match self.server.accept() {
                    Ok(Some(mut socket)) => {
                        let client_id = self.client_id;
                        self.client_id += 1;
                        let tx = self.data_tx.clone();
                        thread::spawn(move || {
                            socket.set_nodelay(true).unwrap();
                            let mut buf = [0; BYTE_BUFFER_SIZE];
                            let mut buf_pos = 0;
                            println!("server accept client {}", client_id);
                            loop {
                                let res = socket.read(&mut buf[buf_pos..]);
                                match res {
                                    Ok(num_read) => {
                                        //println!("server read {}", num_read);
                                        // if we got a length zero read, the connection is done.
                                        if num_read == 0 {
                                            println!("read zero bytes");
                                            return;
                                        }

                                        // check if we've filled the buffer
                                        buf_pos += num_read;
                                        if buf_pos != BYTE_BUFFER_SIZE {
                                            continue;
                                        }
                                        buf_pos = 0;
                                    }
                                    Err(e) => {
                                        if e.kind() == ErrorKind::WouldBlock {
                                            //TODO this is a quick hack to reduce CPU usage
                                            thread::sleep(Duration::from_millis(10));
                                            continue;
                                        }
                                        panic!(e);
                                    }
                                }
                                let packet = Packet::parse(&buf[..]);
                                if let Err(_) = tx.send((client_id, packet)) {
                                    println!("send packet to ladspa error! channel is dead.");
                                    return;
                                }
                            }
                        });
                    }
                    Ok(None) => {
                        println!("the server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept() errored: {}", e);
                        // event_loop.shutdown();
                    }
                }
            }
            _ => panic!("Received unknown token"),
        }
    }
    fn notify(&mut self, event_loop: &mut EventLoop<Self>, _: Self::Message) {
        event_loop.shutdown();
    }
}
<|endoftext|>


<commit_before>use core_collections::borrow::ToOwned;
use io::{self, BufRead, BufReader, Read, Error, Result, Write, Seek, SeekFrom};
use os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use mem;
use path::{PathBuf, Path};
use string::String;
use sys_common::AsInner;
use vec::Vec;

use system::syscall::{sys_open, sys_dup, sys_close, sys_fpath, sys_ftruncate, sys_read,
              sys_write, sys_lseek, sys_fsync, sys_mkdir, sys_rmdir, sys_stat, sys_unlink};
use system::syscall::{O_RDWR, O_RDONLY, O_WRONLY, O_APPEND, O_CREAT, O_TRUNC, MODE_DIR, MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END, Stat};

/// A Unix-style file
#[derive(Debug)]
pub struct File {
    /// The id for the file
    fd: usize,
}

impl File {
    /// Open a new file using a path
    pub fn open<P: AsRef<Path>>(path: P) -> Result<File> {
        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), O_RDONLY, 0).map(|fd| File::from_raw_fd(fd) )
        }.map_err(|x| Error::from_sys(x))
    }

    /// Create a new file using a path
    pub fn create<P: AsRef<Path>>(path: P) -> Result<File> {
        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), O_CREAT | O_RDWR | O_TRUNC, 0).map(|fd| File::from_raw_fd(fd) )
        }.map_err(|x| Error::from_sys(x))
    }

    /// Duplicate the file
    pub fn dup(&self) -> Result<File> {
        sys_dup(self.fd).map(|fd| unsafe { File::from_raw_fd(fd) }).map_err(|x| Error::from_sys(x))
    }

    /// Get the canonical path of the file
    pub fn path(&self) -> Result<PathBuf> {
        let mut buf: [u8; 4096] = [0; 4096];
        match sys_fpath(self.fd, &mut buf) {
            Ok(count) => Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[0..count])) })),
            Err(err) => Err(Error::from_sys(err)),
        }
    }

    /// Flush the file data and metadata
    pub fn sync_all(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }

    /// Flush the file data
    pub fn sync_data(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }

    /// Truncates the file
    pub fn set_len(&mut self, size: u64) -> Result<()> {
        sys_ftruncate(self.fd, size as usize).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

impl AsRawFd for File {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl FromRawFd for File {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        File {
            fd: fd
        }
    }
}

impl IntoRawFd for File {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);
        fd
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        sys_read(self.fd, buf).map_err(|x| Error::from_sys(x))
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        sys_write(self.fd, buf).map_err(|x| Error::from_sys(x))
    }

    fn flush(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

impl Seek for File {
    /// Seek a given position
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        let (whence, offset) = match pos {
            SeekFrom::Start(offset) => (SEEK_SET, offset as isize),
            SeekFrom::Current(offset) => (SEEK_CUR, offset as isize),
            SeekFrom::End(offset) => (SEEK_END, offset as isize),
        };

        sys_lseek(self.fd, offset, whence).map(|position| position as u64).map_err(|x| Error::from_sys(x))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        let _ = sys_close(self.fd);
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct FileType {
    dir: bool,
    file: bool,
}

impl FileType {
    pub fn is_dir(&self) -> bool {
        self.dir
    }

    pub fn is_file(&self) -> bool {
        self.file
    }

    pub fn is_symlink(&self) -> bool {
        false
    }
}

pub struct OpenOptions {
    read: bool,
    write: bool,
    append: bool,
    create: bool,
    truncate: bool,
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            read: false,
            write: false,
            append: false,
            create: false,
            truncate: false,
        }
    }

    pub fn read(&mut self, read: bool) -> &mut OpenOptions {
        self.read = read;
        self
    }

    pub fn write(&mut self, write: bool) -> &mut OpenOptions {
        self.write = write;
        self
    }

    pub fn append(&mut self, append: bool) -> &mut OpenOptions {
        self.append = append;
        self
    }

    pub fn create(&mut self, create: bool) -> &mut OpenOptions {
        self.create = create;
        self
    }

    pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
        self.truncate = truncate;
        self
    }

    pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<File> {
        let mut flags = 0;

        if self.read && self.write {
            flags |= O_RDWR;
        } else if self.read {
            flags |= O_RDONLY;
        } else if self.write {
            flags |= O_WRONLY;
        }

        if self.append {
            flags |= O_APPEND;
        }

        if self.create {
            flags |= O_CREAT;
        }

        if self.truncate {
            flags |= O_TRUNC;
        }

        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), flags, 0).map(|fd| File::from_raw_fd(fd))
        }.map_err(|x| Error::from_sys(x))
    }
}

pub struct Metadata {
    stat: Stat
}

impl Metadata {
    pub fn file_type(&self) -> FileType {
        FileType {
            dir: self.stat.st_mode & MODE_DIR == MODE_DIR,
            file: self.stat.st_mode & MODE_FILE == MODE_FILE
        }
    }

    pub fn is_dir(&self) -> bool {
        self.stat.st_mode & MODE_DIR == MODE_DIR
    }

    pub fn is_file(&self) -> bool {
        self.stat.st_mode & MODE_FILE == MODE_FILE
    }

    pub fn len(&self) -> u64 {
        self.stat.st_size as u64
    }
}

pub struct DirEntry {
    path: PathBuf,
    dir: bool,
    file: bool,
}

impl DirEntry {
    pub fn file_name(&self) -> &Path {
        unsafe { mem::transmute(self.path.file_name().unwrap().to_str().unwrap()) }
    }

    pub fn file_type(&self) -> Result<FileType> {
        Ok(FileType {
            dir: self.dir,
            file: self.file,
        })
    }

    pub fn metadata(&self) -> Result<Metadata> {
        metadata(&self.path)
    }

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

pub struct ReadDir {
    path: PathBuf,
    file: BufReader<File>,
}

impl Iterator for ReadDir {
    type Item = Result<DirEntry>;
    fn next(&mut self) -> Option<Result<DirEntry>> {
        let mut name = String::new();
        match self.file.read_line(&mut name) {
            Ok(0) => None,
            Ok(_) => {
                if name.ends_with('\n') {
                    name.pop();
                }
                let dir = name.ends_with('/');
                if dir {
                    name.pop();
                }

                let mut path = self.path.clone();
                path.push(name);
                Some(Ok(DirEntry {
                    path: path,
                    dir: dir,
                    file: !dir,
                }))
            },
            Err(err) => Some(Err(err))
        }
    }
}

/// Find the canonical path of a file
pub fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
    match File::open(path) {
        Ok(file) => {
            match file.path() {
                Ok(realpath) => Ok(realpath),
                Err(err) => Err(err)
            }
        },
        Err(err) => Err(err)
    }
}

/// Get information about a file
pub fn metadata<P: AsRef<Path>>(path: P) -> Result<Metadata> {
    let mut stat = Stat::default();
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        try!(sys_stat(path_c.as_ptr(), &mut stat).map_err(|x| Error::from_sys(x)));
    }
    Ok(Metadata {
        stat: stat
    })
}

/// Get information about a file without following symlinks
/// Warning: Redox does not currently support symlinks
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> Result<Metadata> {
    metadata(path)
}

/// Create a new directory, using a path
/// The default mode of the directory is 744
pub fn create_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_mkdir(path_c.as_ptr(), 755).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

/// Copy the contents of one file to another
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
    let mut infile = try!(File::open(from));
    let mut outfile = try!(File::create(to));
    io::copy(&mut infile, &mut outfile)
}

/// Rename a file or directory to a new name
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    try!(copy(Path::new(from.as_ref()), to));
    remove_file(from)
}

/// Return an iterator over the entries within a directory
pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir> {
    let path_buf = path.as_ref().to_owned();
    File::open(&path_buf).map(|file| ReadDir { path: path_buf, file: BufReader::new(file) })
}

/// Removes an existing, empty directory
pub fn remove_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_rmdir(path_c.as_ptr()).and(Ok(()))
    }.map_err(|x| Error::from_sys(x))
}

/// Removes a directory at this path, after removing all its contents. Use carefully!
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
    for child in try!(read_dir(&path)) {
        let child = try!(child);
        if try!(child.file_type()).is_dir() {
            try!(remove_dir_all(&child.path()));
        } else {
            try!(remove_file(&child.path()));
        }
    }
    remove_dir(path)
}

/// Removes a file from the filesystem
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_unlink(path_c.as_ptr()).and(Ok(()))
    }.map_err(|x| Error::from_sys(x))
}
<commit_msg>Fix signature of File::set_len<commit_after>use core_collections::borrow::ToOwned;
use io::{self, BufRead, BufReader, Read, Error, Result, Write, Seek, SeekFrom};
use os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use mem;
use path::{PathBuf, Path};
use string::String;
use sys_common::AsInner;
use vec::Vec;

use system::syscall::{sys_open, sys_dup, sys_close, sys_fpath, sys_ftruncate, sys_read,
              sys_write, sys_lseek, sys_fsync, sys_mkdir, sys_rmdir, sys_stat, sys_unlink};
use system::syscall::{O_RDWR, O_RDONLY, O_WRONLY, O_APPEND, O_CREAT, O_TRUNC, MODE_DIR, MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END, Stat};

/// A Unix-style file
#[derive(Debug)]
pub struct File {
    /// The id for the file
    fd: usize,
}

impl File {
    /// Open a new file using a path
    pub fn open<P: AsRef<Path>>(path: P) -> Result<File> {
        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), O_RDONLY, 0).map(|fd| File::from_raw_fd(fd) )
        }.map_err(|x| Error::from_sys(x))
    }

    /// Create a new file using a path
    pub fn create<P: AsRef<Path>>(path: P) -> Result<File> {
        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), O_CREAT | O_RDWR | O_TRUNC, 0).map(|fd| File::from_raw_fd(fd) )
        }.map_err(|x| Error::from_sys(x))
    }

    /// Duplicate the file
    pub fn dup(&self) -> Result<File> {
        sys_dup(self.fd).map(|fd| unsafe { File::from_raw_fd(fd) }).map_err(|x| Error::from_sys(x))
    }

    /// Get the canonical path of the file
    pub fn path(&self) -> Result<PathBuf> {
        let mut buf: [u8; 4096] = [0; 4096];
        match sys_fpath(self.fd, &mut buf) {
            Ok(count) => Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[0..count])) })),
            Err(err) => Err(Error::from_sys(err)),
        }
    }

    /// Flush the file data and metadata
    pub fn sync_all(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }

    /// Flush the file data
    pub fn sync_data(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }

    /// Truncates the file
    pub fn set_len(&self, size: u64) -> Result<()> {
        sys_ftruncate(self.fd, size as usize).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

impl AsRawFd for File {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl FromRawFd for File {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        File {
            fd: fd
        }
    }
}

impl IntoRawFd for File {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);
        fd
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        sys_read(self.fd, buf).map_err(|x| Error::from_sys(x))
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        sys_write(self.fd, buf).map_err(|x| Error::from_sys(x))
    }

    fn flush(&mut self) -> Result<()> {
        sys_fsync(self.fd).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

impl Seek for File {
    /// Seek a given position
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        let (whence, offset) = match pos {
            SeekFrom::Start(offset) => (SEEK_SET, offset as isize),
            SeekFrom::Current(offset) => (SEEK_CUR, offset as isize),
            SeekFrom::End(offset) => (SEEK_END, offset as isize),
        };

        sys_lseek(self.fd, offset, whence).map(|position| position as u64).map_err(|x| Error::from_sys(x))
    }
}

impl Drop for File {
    fn drop(&mut self) {
        let _ = sys_close(self.fd);
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct FileType {
    dir: bool,
    file: bool,
}

impl FileType {
    pub fn is_dir(&self) -> bool {
        self.dir
    }

    pub fn is_file(&self) -> bool {
        self.file
    }

    pub fn is_symlink(&self) -> bool {
        false
    }
}

pub struct OpenOptions {
    read: bool,
    write: bool,
    append: bool,
    create: bool,
    truncate: bool,
}

impl OpenOptions {
    pub fn new() -> OpenOptions {
        OpenOptions {
            read: false,
            write: false,
            append: false,
            create: false,
            truncate: false,
        }
    }

    pub fn read(&mut self, read: bool) -> &mut OpenOptions {
        self.read = read;
        self
    }

    pub fn write(&mut self, write: bool) -> &mut OpenOptions {
        self.write = write;
        self
    }

    pub fn append(&mut self, append: bool) -> &mut OpenOptions {
        self.append = append;
        self
    }

    pub fn create(&mut self, create: bool) -> &mut OpenOptions {
        self.create = create;
        self
    }

    pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
        self.truncate = truncate;
        self
    }

    pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<File> {
        let mut flags = 0;

        if self.read && self.write {
            flags |= O_RDWR;
        } else if self.read {
            flags |= O_RDONLY;
        } else if self.write {
            flags |= O_WRONLY;
        }

        if self.append {
            flags |= O_APPEND;
        }

        if self.create {
            flags |= O_CREAT;
        }

        if self.truncate {
            flags |= O_TRUNC;
        }

        let path_str = path.as_ref().as_os_str().as_inner();
        let mut path_c = path_str.to_owned();
        path_c.push_str("\0");
        unsafe {
            sys_open(path_c.as_ptr(), flags, 0).map(|fd| File::from_raw_fd(fd))
        }.map_err(|x| Error::from_sys(x))
    }
}

pub struct Metadata {
    stat: Stat
}

impl Metadata {
    pub fn file_type(&self) -> FileType {
        FileType {
            dir: self.stat.st_mode & MODE_DIR == MODE_DIR,
            file: self.stat.st_mode & MODE_FILE == MODE_FILE
        }
    }

    pub fn is_dir(&self) -> bool {
        self.stat.st_mode & MODE_DIR == MODE_DIR
    }

    pub fn is_file(&self) -> bool {
        self.stat.st_mode & MODE_FILE == MODE_FILE
    }

    pub fn len(&self) -> u64 {
        self.stat.st_size as u64
    }
}

pub struct DirEntry {
    path: PathBuf,
    dir: bool,
    file: bool,
}

impl DirEntry {
    pub fn file_name(&self) -> &Path {
        unsafe { mem::transmute(self.path.file_name().unwrap().to_str().unwrap()) }
    }

    pub fn file_type(&self) -> Result<FileType> {
        Ok(FileType {
            dir: self.dir,
            file: self.file,
        })
    }

    pub fn metadata(&self) -> Result<Metadata> {
        metadata(&self.path)
    }

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

pub struct ReadDir {
    path: PathBuf,
    file: BufReader<File>,
}

impl Iterator for ReadDir {
    type Item = Result<DirEntry>;
    fn next(&mut self) -> Option<Result<DirEntry>> {
        let mut name = String::new();
        match self.file.read_line(&mut name) {
            Ok(0) => None,
            Ok(_) => {
                if name.ends_with('\n') {
                    name.pop();
                }
                let dir = name.ends_with('/');
                if dir {
                    name.pop();
                }

                let mut path = self.path.clone();
                path.push(name);
                Some(Ok(DirEntry {
                    path: path,
                    dir: dir,
                    file: !dir,
                }))
            },
            Err(err) => Some(Err(err))
        }
    }
}

/// Find the canonical path of a file
pub fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
    match File::open(path) {
        Ok(file) => {
            match file.path() {
                Ok(realpath) => Ok(realpath),
                Err(err) => Err(err)
            }
        },
        Err(err) => Err(err)
    }
}

/// Get information about a file
pub fn metadata<P: AsRef<Path>>(path: P) -> Result<Metadata> {
    let mut stat = Stat::default();
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        try!(sys_stat(path_c.as_ptr(), &mut stat).map_err(|x| Error::from_sys(x)));
    }
    Ok(Metadata {
        stat: stat
    })
}

/// Get information about a file without following symlinks
/// Warning: Redox does not currently support symlinks
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> Result<Metadata> {
    metadata(path)
}

/// Create a new directory, using a path
/// The default mode of the directory is 744
pub fn create_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_mkdir(path_c.as_ptr(), 755).and(Ok(())).map_err(|x| Error::from_sys(x))
    }
}

/// Copy the contents of one file to another
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
    let mut infile = try!(File::open(from));
    let mut outfile = try!(File::create(to));
    io::copy(&mut infile, &mut outfile)
}

/// Rename a file or directory to a new name
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    try!(copy(Path::new(from.as_ref()), to));
    remove_file(from)
}

/// Return an iterator over the entries within a directory
pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir> {
    let path_buf = path.as_ref().to_owned();
    File::open(&path_buf).map(|file| ReadDir { path: path_buf, file: BufReader::new(file) })
}

/// Removes an existing, empty directory
pub fn remove_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_rmdir(path_c.as_ptr()).and(Ok(()))
    }.map_err(|x| Error::from_sys(x))
}

/// Removes a directory at this path, after removing all its contents. Use carefully!
pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
    for child in try!(read_dir(&path)) {
        let child = try!(child);
        if try!(child.file_type()).is_dir() {
            try!(remove_dir_all(&child.path()));
        } else {
            try!(remove_file(&child.path()));
        }
    }
    remove_dir(path)
}

/// Removes a file from the filesystem
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
    let path_str = path.as_ref().as_os_str().as_inner();
    let mut path_c = path_str.to_owned();
    path_c.push_str("\0");
    unsafe {
        sys_unlink(path_c.as_ptr()).and(Ok(()))
    }.map_err(|x| Error::from_sys(x))
}
<|endoftext|>