<commit_before>//! FIXME: write short doc here

pub mod codegen;

use std::{
    error::Error,
    fs,
    io::{Error as IoError, ErrorKind},
    path::{Path, PathBuf},
    process::{Command, Output, Stdio},
};

use crate::codegen::Mode;

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

const TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(&env!("CARGO_MANIFEST_DIR")).ancestors().nth(1).unwrap().to_path_buf()
}

pub struct Cmd<'a> {
    pub unix: &'a str,
    pub windows: &'a str,
    pub work_dir: &'a str,
}

impl Cmd<'_> {
    pub fn run(self) -> Result<()> {
        if cfg!(windows) {
            run(self.windows, self.work_dir)
        } else {
            run(self.unix, self.work_dir)
        }
    }
    pub fn run_with_output(self) -> Result<Output> {
        if cfg!(windows) {
            run_with_output(self.windows, self.work_dir)
        } else {
            run_with_output(self.unix, self.work_dir)
        }
    }
}

pub fn run(cmdline: &str, dir: &str) -> Result<()> {
    do_run(cmdline, dir, |c| {
        c.stdout(Stdio::inherit());
    })
    .map(|_| ())
}

pub fn run_with_output(cmdline: &str, dir: &str) -> Result<Output> {
    do_run(cmdline, dir, |_| {})
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_rustfmt()?,
    };

    if mode == Mode::Verify {
        run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
    } else {
        run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
    }
    Ok(())
}

pub fn install_rustfmt() -> Result<()> {
    run(&format!("rustup install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
}

pub fn install_format_hook() -> Result<()> {
    let result_path = Path::new(if cfg!(windows) {
        "./.git/hooks/pre-commit.exe"
    } else {
        "./.git/hooks/pre-commit"
    });
    if !result_path.exists() {
        run("cargo build --package xtask --bin pre-commit", ".")?;
        if cfg!(windows) {
            fs::copy("./target/debug/pre-commit.exe", result_path)?;
        } else {
            fs::copy("./target/debug/pre-commit", result_path)?;
        }
    } else {
        Err(IoError::new(ErrorKind::AlreadyExists, "Git hook already created"))?;
    }
    Ok(())
}

pub fn run_clippy() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_clippy()?,
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::map_clone", // FIXME: remove when Iterator::copied stabilizes (1.36.0)
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run(
        &format!(
            "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
            TOOLCHAIN,
            allowed_lints.join(" -A ")
        ),
        ".",
    )?;
    Ok(())
}

pub fn install_clippy() -> Result<()> {
    run(&format!("rustup install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_fuzzer() -> Result<()> {
    match Command::new("cargo")
        .args(&["fuzz", "--help"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => run("cargo install cargo-fuzz", ".")?,
    };

    run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
}

fn do_run<F>(cmdline: &str, dir: &str, mut f: F) -> Result<Output>
where
    F: FnMut(&mut Command),
{
    eprintln!("\nwill run: {}", cmdline);
    let proj_dir = project_root().join(dir);
    let mut args = cmdline.split_whitespace();
    let exec = args.next().unwrap();
    let mut cmd = Command::new(exec);
    f(cmd.args(args).current_dir(proj_dir).stderr(Stdio::inherit()));
    let output = cmd.output()?;
    if !output.status.success() {
        Err(format!("`{}` exited with {}", cmdline, output.status))?;
    }
    Ok(output)
}
<commit_msg>Use run-time project path in xtask<commit_after>//! FIXME: write short doc here

pub mod codegen;

use std::{
    env,
    error::Error,
    fs,
    io::{Error as IoError, ErrorKind},
    path::{Path, PathBuf},
    process::{Command, Output, Stdio},
};

use crate::codegen::Mode;

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

const TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(1)
    .unwrap()
    .to_path_buf()
}

pub struct Cmd<'a> {
    pub unix: &'a str,
    pub windows: &'a str,
    pub work_dir: &'a str,
}

impl Cmd<'_> {
    pub fn run(self) -> Result<()> {
        if cfg!(windows) {
            run(self.windows, self.work_dir)
        } else {
            run(self.unix, self.work_dir)
        }
    }
    pub fn run_with_output(self) -> Result<Output> {
        if cfg!(windows) {
            run_with_output(self.windows, self.work_dir)
        } else {
            run_with_output(self.unix, self.work_dir)
        }
    }
}

pub fn run(cmdline: &str, dir: &str) -> Result<()> {
    do_run(cmdline, dir, |c| {
        c.stdout(Stdio::inherit());
    })
    .map(|_| ())
}

pub fn run_with_output(cmdline: &str, dir: &str) -> Result<Output> {
    do_run(cmdline, dir, |_| {})
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_rustfmt()?,
    };

    if mode == Mode::Verify {
        run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
    } else {
        run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
    }
    Ok(())
}

pub fn install_rustfmt() -> Result<()> {
    run(&format!("rustup install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
}

pub fn install_format_hook() -> Result<()> {
    let result_path = Path::new(if cfg!(windows) {
        "./.git/hooks/pre-commit.exe"
    } else {
        "./.git/hooks/pre-commit"
    });
    if !result_path.exists() {
        run("cargo build --package xtask --bin pre-commit", ".")?;
        if cfg!(windows) {
            fs::copy("./target/debug/pre-commit.exe", result_path)?;
        } else {
            fs::copy("./target/debug/pre-commit", result_path)?;
        }
    } else {
        Err(IoError::new(ErrorKind::AlreadyExists, "Git hook already created"))?;
    }
    Ok(())
}

pub fn run_clippy() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_clippy()?,
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::map_clone", // FIXME: remove when Iterator::copied stabilizes (1.36.0)
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run(
        &format!(
            "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
            TOOLCHAIN,
            allowed_lints.join(" -A ")
        ),
        ".",
    )?;
    Ok(())
}

pub fn install_clippy() -> Result<()> {
    run(&format!("rustup install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_fuzzer() -> Result<()> {
    match Command::new("cargo")
        .args(&["fuzz", "--help"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => run("cargo install cargo-fuzz", ".")?,
    };

    run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
}

fn do_run<F>(cmdline: &str, dir: &str, mut f: F) -> Result<Output>
where
    F: FnMut(&mut Command),
{
    eprintln!("\nwill run: {}", cmdline);
    let proj_dir = project_root().join(dir);
    let mut args = cmdline.split_whitespace();
    let exec = args.next().unwrap();
    let mut cmd = Command::new(exec);
    f(cmd.args(args).current_dir(proj_dir).stderr(Stdio::inherit()));
    let output = cmd.output()?;
    if !output.status.success() {
        Err(format!("`{}` exited with {}", cmdline, output.status))?;
    }
    Ok(output)
}
<|endoftext|>


<commit_before>use std::c_str::CString;
use std::c_vec::CVec;
use std::kinds::marker::NoCopy;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_int, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

#[repr(C)]
pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	nocopy: NoCopy,
}

pub struct Method {
	nocopy: NoCopy,
}

pub struct Class {
	nocopy: NoCopy,
}

pub struct Object {
	nocopy: NoCopy,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int;
	pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class;
	pub fn objc_getClass(name: *const c_char) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_copyReturnType(method: *const Method) -> *mut c_char;
	pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	pub fn return_type(&self) -> CString {
		unsafe {
			let encoding = method_copyReturnType(self);
			CString::new(encoding as *const _, true)
		}
	}

	pub fn argument_type(&self, index: uint) -> Option<CString> {
		unsafe {
			let encoding = method_copyArgumentType(self, index as c_uint);
			if encoding.is_null() {
				None
			} else {
				Some(CString::new(encoding as *const _, true))
			}
		}
	}

	pub fn arguments_count(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	pub fn get(name: &str) -> Option<&'static Class> {
		name.with_c_str(|name| unsafe {
			objc_getClass(name).as_ref()
		})
	}

	pub fn classes() -> CVec<&'static Class> {
		unsafe {
			let mut count: c_uint = 0;
			let classes = objc_copyClassList(&mut count);
			CVec::new_with_dtor(classes as *mut _, count as uint, proc() {
				libc::free(classes as *mut c_void);
			})
		}
	}

	pub fn classes_count() -> uint {
		unsafe {
			objc_getClassList(RawPtr::null(), 0) as uint
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		unsafe {
			class_getInstanceMethod(self, sel).as_ref()
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name).as_ref()
		})
	}

	pub fn instance_methods(&self) -> CVec<&Method> {
		unsafe {
			let mut count: c_uint = 0;
			let methods = class_copyMethodList(self, &mut count);
			CVec::new_with_dtor(methods as *mut _, count as uint, proc() {
				libc::free(methods as *mut c_void);
			})
		}

	}

	pub fn instance_variables(&self) -> CVec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			CVec::new_with_dtor(ivars as *mut _, count as uint, proc() {
				libc::free(ivars as *mut c_void);
			})
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

#[cfg(test)]
mod tests {
	use std::mem;
	use super::{Class, Sel};

	#[test]
	fn test_ivar() {
		let cls = Class::get("NSObject").unwrap();
		let ivar = cls.instance_variable("isa").unwrap();
		assert!(ivar.name() == "isa");
		assert!(ivar.type_encoding() == "#");
		assert!(ivar.offset() == 0);

		let ivars = cls.instance_variables();
		assert!(ivars.len() > 0);
	}

	#[test]
	fn test_method() {
		let cls = Class::get("NSObject").unwrap();
		let sel = Sel::register("description");
		let method = cls.instance_method(sel).unwrap();
		assert!(method.name().name() == "description");
		assert!(method.type_encoding() != "");
		assert!(method.arguments_count() == 2);
		assert!(method.return_type().as_bytes_no_nul() == "@".as_bytes());
		assert!(method.argument_type(1).unwrap().as_bytes_no_nul() ==
			":".as_bytes());

		let methods = cls.instance_methods();
		assert!(methods.len() > 0);
	}

	#[test]
	fn test_class() {
		let cls = Class::get("NSObject").unwrap();
		assert!(cls.name() == "NSObject");
		assert!(cls.instance_size() == mem::size_of::<*const Class>());
	}

	#[test]
	fn test_classes() {
		let classes_count = Class::classes_count();
		assert!(classes_count > 0);

		let classes = Class::classes();
		assert!(classes.len() == classes_count);
	}

	#[test]
	fn test_object() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			&*obj
		};
		assert!(obj.class() == cls);
		unsafe {
			msg_send![obj release];
		}
	}
}
<commit_msg>Added runtime documentation for Sel, Ivar, and Method.<commit_after>//! A Rust interface for the functionality of the Objective-C runtime.
//!
//! For more information on foreign functions, see Apple's documentation:
//! https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html

use std::c_str::CString;
use std::c_vec::CVec;
use std::kinds::marker::NoCopy;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_int, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

/// A type that represents a method selector.
#[repr(C)]
pub struct Sel {
	ptr: *const c_void,
}

/// A type that represents an instance variable.
pub struct Ivar {
	nocopy: NoCopy,
}

/// A type that represents a method in a class definition.
pub struct Method {
	nocopy: NoCopy,
}

/// A type that represents an Objective-C class.
pub struct Class {
	nocopy: NoCopy,
}

/// A type that represents an instance of a class.
pub struct Object {
	nocopy: NoCopy,
}

/// A pointer to the start of a method implementation.
pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int;
	pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class;
	pub fn objc_getClass(name: *const c_char) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_copyReturnType(method: *const Method) -> *mut c_char;
	pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	/// Registers a method with the Objective-C runtime system,
	/// maps the method name to a selector, and returns the selector value.
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	/// Returns the name of the method specified by self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	/// Returns the name of self.
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	/// Returns the offset of self.
	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	/// Returns the type string of self.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	/// Returns the name of self.
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	/// Returns a string describing self's parameter and return types.
	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	/// Returns a string describing self's return type.
	pub fn return_type(&self) -> CString {
		unsafe {
			let encoding = method_copyReturnType(self);
			CString::new(encoding as *const _, true)
		}
	}

	/// Returns a string describing a single parameter type of self, or
	/// None if self has no parameter at the given index.
	pub fn argument_type(&self, index: uint) -> Option<CString> {
		unsafe {
			let encoding = method_copyArgumentType(self, index as c_uint);
			if encoding.is_null() {
				None
			} else {
				Some(CString::new(encoding as *const _, true))
			}
		}
	}

	/// Returns the number of arguments accepted by self.
	pub fn arguments_count(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	/// Returns the implementation of self.
	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	/// Sets the implementation of self.
	/// Unsafe because the caller must ensure the implementation has the
	/// correct self, return, and argument types for the method.
	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	/// Exchanges the implementations of self with another `Method`.
	/// Unsafe because the caller must ensure the two methods have the same
	/// self, return, and argument types.
	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	pub fn get(name: &str) -> Option<&'static Class> {
		name.with_c_str(|name| unsafe {
			objc_getClass(name).as_ref()
		})
	}

	pub fn classes() -> CVec<&'static Class> {
		unsafe {
			let mut count: c_uint = 0;
			let classes = objc_copyClassList(&mut count);
			CVec::new_with_dtor(classes as *mut _, count as uint, proc() {
				libc::free(classes as *mut c_void);
			})
		}
	}

	pub fn classes_count() -> uint {
		unsafe {
			objc_getClassList(RawPtr::null(), 0) as uint
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		unsafe {
			class_getInstanceMethod(self, sel).as_ref()
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name).as_ref()
		})
	}

	pub fn instance_methods(&self) -> CVec<&Method> {
		unsafe {
			let mut count: c_uint = 0;
			let methods = class_copyMethodList(self, &mut count);
			CVec::new_with_dtor(methods as *mut _, count as uint, proc() {
				libc::free(methods as *mut c_void);
			})
		}

	}

	pub fn instance_variables(&self) -> CVec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			CVec::new_with_dtor(ivars as *mut _, count as uint, proc() {
				libc::free(ivars as *mut c_void);
			})
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => panic!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

#[cfg(test)]
mod tests {
	use std::mem;
	use super::{Class, Sel};

	#[test]
	fn test_ivar() {
		let cls = Class::get("NSObject").unwrap();
		let ivar = cls.instance_variable("isa").unwrap();
		assert!(ivar.name() == "isa");
		assert!(ivar.type_encoding() == "#");
		assert!(ivar.offset() == 0);

		let ivars = cls.instance_variables();
		assert!(ivars.len() > 0);
	}

	#[test]
	fn test_method() {
		let cls = Class::get("NSObject").unwrap();
		let sel = Sel::register("description");
		let method = cls.instance_method(sel).unwrap();
		assert!(method.name().name() == "description");
		assert!(method.type_encoding() != "");
		assert!(method.arguments_count() == 2);
		assert!(method.return_type().as_bytes_no_nul() == "@".as_bytes());
		assert!(method.argument_type(1).unwrap().as_bytes_no_nul() ==
			":".as_bytes());

		let methods = cls.instance_methods();
		assert!(methods.len() > 0);
	}

	#[test]
	fn test_class() {
		let cls = Class::get("NSObject").unwrap();
		assert!(cls.name() == "NSObject");
		assert!(cls.instance_size() == mem::size_of::<*const Class>());
	}

	#[test]
	fn test_classes() {
		let classes_count = Class::classes_count();
		assert!(classes_count > 0);

		let classes = Class::classes();
		assert!(classes.len() == classes_count);
	}

	#[test]
	fn test_object() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			&*obj
		};
		assert!(obj.class() == cls);
		unsafe {
			msg_send![obj release];
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{json_rpc::JsonRpcClientWrapper, TransactionContext};
use libra_crypto::{ed25519::Ed25519PublicKey, x25519};
use libra_global_constants::{
    CONSENSUS_KEY, FULLNODE_NETWORK_KEY, OPERATOR_ACCOUNT, OWNER_ACCOUNT, VALIDATOR_NETWORK_KEY,
};
use libra_management::{error::Error, storage::to_x25519};
use libra_network_address::{
    encrypted::{EncNetworkAddress, Key, RawEncNetworkAddress, TEST_SHARED_VAL_NETADDR_KEY},
    NetworkAddress, Protocol, RawNetworkAddress,
};
use libra_types::account_address::AccountAddress;
use serde::Serialize;
use std::convert::TryFrom;
use structopt::StructOpt;

// TODO: Load all chain IDs from the host
#[derive(Debug, StructOpt)]
pub struct SetValidatorConfig {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
    #[structopt(flatten)]
    validator_config: libra_management::validator_config::ValidatorConfig,
    #[structopt(
        long,
        required_unless = "fullnode-address",
        help = "Validator Network Address"
    )]
    validator_address: Option<NetworkAddress>,
    #[structopt(
        long,
        required_unless = "validator-address",
        help = "Full Node Network Address"
    )]
    fullnode_address: Option<NetworkAddress>,
}

impl SetValidatorConfig {
    pub fn execute(self) -> Result<TransactionContext, Error> {
        let config = self
            .validator_config
            .config
            .load()?
            .override_chain_id(self.validator_config.chain_id)
            .override_json_server(&self.json_server)
            .override_validator_backend(
                &self.validator_config.validator_backend.validator_backend,
            )?;
        let storage = config.validator_backend();

        let operator_account = storage.account_address(OPERATOR_ACCOUNT)?;
        let owner_account = storage.account_address(OWNER_ACCOUNT)?;
        let client = JsonRpcClientWrapper::new(config.json_server);
        let sequence_number = client.sequence_number(operator_account)?;

        // Retrieve the current validator / fullnode addresses and update accordingly
        let validator_config = client.validator_config(owner_account)?;
        let validator_address = if let Some(validator_address) = self.validator_address {
            validator_address
        } else {
            decode_validator_address(
                &validator_config.validator_network_address,
                &owner_account,
                &TEST_SHARED_VAL_NETADDR_KEY,
                0, // addr_idx
            )?
        };

        let fullnode_address = if let Some(fullnode_address) = self.fullnode_address {
            fullnode_address
        } else {
            decode_address(&validator_config.full_node_network_address)?
        };

        let txn = self.validator_config.build_transaction(
            sequence_number,
            fullnode_address,
            validator_address,
            true,
        )?;
        client.submit_transaction(txn.as_signed_user_txn().unwrap().clone())
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateKey {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
    #[structopt(flatten)]
    validator_config: libra_management::validator_config::ValidatorConfig,
}

impl RotateKey {
    pub fn execute(
        self,
        key_name: &'static str,
    ) -> Result<(TransactionContext, Ed25519PublicKey), Error> {
        // Load the config, storage backend and create a json rpc client.
        let config = self
            .validator_config
            .config()?
            .override_json_server(&self.json_server);
        let mut storage = config.validator_backend();
        let client = JsonRpcClientWrapper::new(config.json_server);

        // Fetch the current on-chain validator config for the node
        let owner_account = storage.account_address(OWNER_ACCOUNT)?;
        let validator_config = client.validator_config(owner_account)?;

        // Check that the key held in storage matches the key registered on-chain in the validator
        // config. If so, rotate the key in storage. If not, don't rotate the key in storage and
        // rather allow the next step to resubmit the set_validator_config transaction with the
        // current key (to resynchronize the validator config on the blockchain).
        let mut storage_key = storage.ed25519_public_from_private(key_name)?;
        let keys_match = match key_name {
            CONSENSUS_KEY => storage_key == validator_config.consensus_public_key,
            VALIDATOR_NETWORK_KEY => {
                to_x25519(storage_key.clone())?
                    == validator_config.validator_network_identity_public_key
            }
            FULLNODE_NETWORK_KEY => {
                to_x25519(storage_key.clone())?
                    == validator_config.full_node_network_identity_public_key
            }
            _ => {
                return Err(Error::UnexpectedError(
                    "Rotate key was called with an unknown key name!".into(),
                ));
            }
        };
        if keys_match {
            storage_key = storage.rotate_key(key_name)?;
        }

        // Create and set the validator config state on the blockchain.
        let set_validator_config = SetValidatorConfig {
            json_server: self.json_server,
            validator_config: self.validator_config,
            validator_address: None,
            fullnode_address: None,
        };
        set_validator_config
            .execute()
            .map(|txn_ctx| (txn_ctx, storage_key))
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateConsensusKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateConsensusKey {
    pub fn execute(self) -> Result<(TransactionContext, Ed25519PublicKey), Error> {
        self.rotate_key.execute(CONSENSUS_KEY)
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateValidatorNetworkKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateValidatorNetworkKey {
    pub fn execute(self) -> Result<(TransactionContext, x25519::PublicKey), Error> {
        let (txn_ctx, key) = self.rotate_key.execute(VALIDATOR_NETWORK_KEY)?;
        Ok((txn_ctx, to_x25519(key)?))
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateFullNodeNetworkKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateFullNodeNetworkKey {
    pub fn execute(self) -> Result<(TransactionContext, x25519::PublicKey), Error> {
        let (txn_ctx, key) = self.rotate_key.execute(FULLNODE_NETWORK_KEY)?;
        Ok((txn_ctx, to_x25519(key)?))
    }
}

pub fn decode_validator_address(
    address: &RawEncNetworkAddress,
    account: &AccountAddress,
    key: &Key,
    addr_idx: u32,
) -> Result<NetworkAddress, Error> {
    let enc_addr = EncNetworkAddress::try_from(address).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decode network address {}",
            e.to_string()
        ))
    })?;
    let raw_addr = enc_addr.decrypt(key, account, addr_idx).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decrypt network address {}",
            e.to_string()
        ))
    })?;
    decode_address(&raw_addr)
}

pub fn decode_address(raw_address: &RawNetworkAddress) -> Result<NetworkAddress, Error> {
    let network_address = NetworkAddress::try_from(raw_address).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decode network address {}",
            e.to_string()
        ))
    })?;
    let protocols = network_address
        .as_slice()
        .iter()
        .filter(|protocol| match protocol {
            Protocol::Dns(_)
            | Protocol::Dns4(_)
            | Protocol::Dns6(_)
            | Protocol::Ip4(_)
            | Protocol::Ip6(_)
            | Protocol::Memory(_)
            | Protocol::Tcp(_) => true,
            _ => false,
        })
        .cloned()
        .collect::<Vec<_>>();
    Ok(NetworkAddress::try_from(protocols).unwrap())
}

#[derive(Debug, StructOpt)]
pub struct ValidatorConfig {
    #[structopt(long, help = "Validator account address to display the config")]
    account_address: AccountAddress,
    #[structopt(flatten)]
    config: libra_management::config::ConfigPath,
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
}

impl ValidatorConfig {
    pub fn execute(self) -> Result<DecryptedValidatorConfig, Error> {
        let config = self.config.load()?.override_json_server(&self.json_server);
        let client = JsonRpcClientWrapper::new(config.json_server);
        client.validator_config(self.account_address).map(|config| {
            DecryptedValidatorConfig::from_validator_config(
                self.account_address,
                &TEST_SHARED_VAL_NETADDR_KEY,
                0,
                &config,
            )
            .unwrap()
        })
    }
}

#[derive(Serialize)]
pub struct DecryptedValidatorConfig {
    pub consensus_public_key: Ed25519PublicKey,
    pub validator_network_key: x25519::PublicKey,
    pub validator_network_address: NetworkAddress,
    pub full_node_network_key: x25519::PublicKey,
    pub full_node_network_address: NetworkAddress,
}

impl DecryptedValidatorConfig {
    pub fn from_validator_config(
        account: AccountAddress,
        address_encryption_key: &libra_network_address::encrypted::Key,
        addr_idx: u32,
        validator_config: &libra_types::validator_config::ValidatorConfig,
    ) -> Result<DecryptedValidatorConfig, Error> {
        let full_node_network_address =
            crate::validator_config::decode_address(&validator_config.full_node_network_address)?;

        let validator_network_address = crate::validator_config::decode_validator_address(
            &validator_config.validator_network_address,
            &account,
            address_encryption_key,
            addr_idx,
        )?;

        Ok(DecryptedValidatorConfig {
            consensus_public_key: validator_config.consensus_public_key.clone(),
            validator_network_key: validator_config.validator_network_identity_public_key,
            validator_network_address,
            full_node_network_key: validator_config.full_node_network_identity_public_key,
            full_node_network_address,
        })
    }
}
<commit_msg>[management] Validate network address before setting config<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{json_rpc::JsonRpcClientWrapper, TransactionContext};
use libra_crypto::{ed25519::Ed25519PublicKey, x25519};
use libra_global_constants::{
    CONSENSUS_KEY, FULLNODE_NETWORK_KEY, OPERATOR_ACCOUNT, OWNER_ACCOUNT, VALIDATOR_NETWORK_KEY,
};
use libra_management::{error::Error, storage::to_x25519};
use libra_network_address::{
    encrypted::{EncNetworkAddress, Key, RawEncNetworkAddress, TEST_SHARED_VAL_NETADDR_KEY},
    NetworkAddress, Protocol, RawNetworkAddress,
};
use libra_types::account_address::AccountAddress;
use serde::Serialize;
use std::{convert::TryFrom, net::ToSocketAddrs};
use structopt::StructOpt;

// TODO: Load all chain IDs from the host
#[derive(Debug, StructOpt)]
pub struct SetValidatorConfig {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
    #[structopt(flatten)]
    validator_config: libra_management::validator_config::ValidatorConfig,
    #[structopt(
        long,
        required_unless = "fullnode-address",
        help = "Validator Network Address"
    )]
    validator_address: Option<NetworkAddress>,
    #[structopt(
        long,
        required_unless = "validator-address",
        help = "Full Node Network Address"
    )]
    fullnode_address: Option<NetworkAddress>,
}

impl SetValidatorConfig {
    fn address_valid(network_address: &NetworkAddress) -> Result<(), Error> {
        // Only allow DNS and IP addresses
        for protocol in network_address.as_slice().iter() {
            match protocol {
                Protocol::Ip4(_)
                | Protocol::Ip6(_)
                | Protocol::Dns(_)
                | Protocol::Dns4(_)
                | Protocol::Dns6(_)
                | Protocol::Tcp(_) => {}
                _ => {
                    return Err(Error::CommandArgumentError(format!(
                        "Invalid protocol '{}'",
                        protocol
                    )))
                }
            }
        }

        // Ensure that the address resolves to IP addresses
        let addrs = network_address.to_socket_addrs().map_err(|err| {
            Error::CommandArgumentError(format!(
                "Failed to resolve address '{}': {}",
                network_address, err
            ))
        })?;

        if addrs.len() < 1 {
            return Err(Error::CommandArgumentError(format!(
                "Resolved to no IP addresses '{}' did you forget to add the port? '/tcp/<port>'",
                network_address
            )));
        }

        Ok(())
    }

    pub fn execute(self) -> Result<TransactionContext, Error> {
        let config = self
            .validator_config
            .config
            .load()?
            .override_chain_id(self.validator_config.chain_id)
            .override_json_server(&self.json_server)
            .override_validator_backend(
                &self.validator_config.validator_backend.validator_backend,
            )?;
        let storage = config.validator_backend();

        let operator_account = storage.account_address(OPERATOR_ACCOUNT)?;
        let owner_account = storage.account_address(OWNER_ACCOUNT)?;
        let client = JsonRpcClientWrapper::new(config.json_server);
        let sequence_number = client.sequence_number(operator_account)?;

        // Retrieve the current validator / fullnode addresses and update accordingly
        let validator_config = client.validator_config(owner_account)?;
        let validator_address = if let Some(validator_address) = self.validator_address {
            Self::address_valid(&validator_address)?;
            validator_address
        } else {
            decode_validator_address(
                &validator_config.validator_network_address,
                &owner_account,
                &TEST_SHARED_VAL_NETADDR_KEY,
                0, // addr_idx
            )?
        };

        let fullnode_address = if let Some(fullnode_address) = self.fullnode_address {
            Self::address_valid(&fullnode_address)?;
            fullnode_address
        } else {
            decode_address(&validator_config.full_node_network_address)?
        };

        let txn = self.validator_config.build_transaction(
            sequence_number,
            fullnode_address,
            validator_address,
            true,
        )?;
        client.submit_transaction(txn.as_signed_user_txn().unwrap().clone())
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateKey {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
    #[structopt(flatten)]
    validator_config: libra_management::validator_config::ValidatorConfig,
}

impl RotateKey {
    pub fn execute(
        self,
        key_name: &'static str,
    ) -> Result<(TransactionContext, Ed25519PublicKey), Error> {
        // Load the config, storage backend and create a json rpc client.
        let config = self
            .validator_config
            .config()?
            .override_json_server(&self.json_server);
        let mut storage = config.validator_backend();
        let client = JsonRpcClientWrapper::new(config.json_server);

        // Fetch the current on-chain validator config for the node
        let owner_account = storage.account_address(OWNER_ACCOUNT)?;
        let validator_config = client.validator_config(owner_account)?;

        // Check that the key held in storage matches the key registered on-chain in the validator
        // config. If so, rotate the key in storage. If not, don't rotate the key in storage and
        // rather allow the next step to resubmit the set_validator_config transaction with the
        // current key (to resynchronize the validator config on the blockchain).
        let mut storage_key = storage.ed25519_public_from_private(key_name)?;
        let keys_match = match key_name {
            CONSENSUS_KEY => storage_key == validator_config.consensus_public_key,
            VALIDATOR_NETWORK_KEY => {
                to_x25519(storage_key.clone())?
                    == validator_config.validator_network_identity_public_key
            }
            FULLNODE_NETWORK_KEY => {
                to_x25519(storage_key.clone())?
                    == validator_config.full_node_network_identity_public_key
            }
            _ => {
                return Err(Error::UnexpectedError(
                    "Rotate key was called with an unknown key name!".into(),
                ));
            }
        };
        if keys_match {
            storage_key = storage.rotate_key(key_name)?;
        }

        // Create and set the validator config state on the blockchain.
        let set_validator_config = SetValidatorConfig {
            json_server: self.json_server,
            validator_config: self.validator_config,
            validator_address: None,
            fullnode_address: None,
        };
        set_validator_config
            .execute()
            .map(|txn_ctx| (txn_ctx, storage_key))
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateConsensusKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateConsensusKey {
    pub fn execute(self) -> Result<(TransactionContext, Ed25519PublicKey), Error> {
        self.rotate_key.execute(CONSENSUS_KEY)
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateValidatorNetworkKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateValidatorNetworkKey {
    pub fn execute(self) -> Result<(TransactionContext, x25519::PublicKey), Error> {
        let (txn_ctx, key) = self.rotate_key.execute(VALIDATOR_NETWORK_KEY)?;
        Ok((txn_ctx, to_x25519(key)?))
    }
}

#[derive(Debug, StructOpt)]
pub struct RotateFullNodeNetworkKey {
    #[structopt(flatten)]
    rotate_key: RotateKey,
}

impl RotateFullNodeNetworkKey {
    pub fn execute(self) -> Result<(TransactionContext, x25519::PublicKey), Error> {
        let (txn_ctx, key) = self.rotate_key.execute(FULLNODE_NETWORK_KEY)?;
        Ok((txn_ctx, to_x25519(key)?))
    }
}

pub fn decode_validator_address(
    address: &RawEncNetworkAddress,
    account: &AccountAddress,
    key: &Key,
    addr_idx: u32,
) -> Result<NetworkAddress, Error> {
    let enc_addr = EncNetworkAddress::try_from(address).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decode network address {}",
            e.to_string()
        ))
    })?;
    let raw_addr = enc_addr.decrypt(key, account, addr_idx).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decrypt network address {}",
            e.to_string()
        ))
    })?;
    decode_address(&raw_addr)
}

pub fn decode_address(raw_address: &RawNetworkAddress) -> Result<NetworkAddress, Error> {
    let network_address = NetworkAddress::try_from(raw_address).map_err(|e| {
        Error::UnexpectedError(format!(
            "Failed to decode network address {}",
            e.to_string()
        ))
    })?;
    let protocols = network_address
        .as_slice()
        .iter()
        .filter(|protocol| match protocol {
            Protocol::Dns(_)
            | Protocol::Dns4(_)
            | Protocol::Dns6(_)
            | Protocol::Ip4(_)
            | Protocol::Ip6(_)
            | Protocol::Memory(_)
            | Protocol::Tcp(_) => true,
            _ => false,
        })
        .cloned()
        .collect::<Vec<_>>();
    Ok(NetworkAddress::try_from(protocols).unwrap())
}

#[derive(Debug, StructOpt)]
pub struct ValidatorConfig {
    #[structopt(long, help = "Validator account address to display the config")]
    account_address: AccountAddress,
    #[structopt(flatten)]
    config: libra_management::config::ConfigPath,
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: Option<String>,
}

impl ValidatorConfig {
    pub fn execute(self) -> Result<DecryptedValidatorConfig, Error> {
        let config = self.config.load()?.override_json_server(&self.json_server);
        let client = JsonRpcClientWrapper::new(config.json_server);
        client.validator_config(self.account_address).map(|config| {
            DecryptedValidatorConfig::from_validator_config(
                self.account_address,
                &TEST_SHARED_VAL_NETADDR_KEY,
                0,
                &config,
            )
            .unwrap()
        })
    }
}

#[derive(Serialize)]
pub struct DecryptedValidatorConfig {
    pub consensus_public_key: Ed25519PublicKey,
    pub validator_network_key: x25519::PublicKey,
    pub validator_network_address: NetworkAddress,
    pub full_node_network_key: x25519::PublicKey,
    pub full_node_network_address: NetworkAddress,
}

impl DecryptedValidatorConfig {
    pub fn from_validator_config(
        account: AccountAddress,
        address_encryption_key: &libra_network_address::encrypted::Key,
        addr_idx: u32,
        validator_config: &libra_types::validator_config::ValidatorConfig,
    ) -> Result<DecryptedValidatorConfig, Error> {
        let full_node_network_address =
            crate::validator_config::decode_address(&validator_config.full_node_network_address)?;

        let validator_network_address = crate::validator_config::decode_validator_address(
            &validator_config.validator_network_address,
            &account,
            address_encryption_key,
            addr_idx,
        )?;

        Ok(DecryptedValidatorConfig {
            consensus_public_key: validator_config.consensus_public_key.clone(),
            validator_network_key: validator_config.validator_network_identity_public_key,
            validator_network_address,
            full_node_network_key: validator_config.full_node_network_identity_public_key,
            full_node_network_address,
        })
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::enums::ProtobufEnumOrUnknown;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::ProtobufValue;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone)]
pub struct EnumValueDescriptor {
    proto: &'static EnumValueDescriptorProto,
    protobuf_value: &'static dyn ProtobufValue,
    enum_descriptor_static: fn() -> &'static EnumDescriptor,
    get_descriptor: &'static dyn GetEnumDescriptor,
}

impl PartialEq for EnumValueDescriptor {
    fn eq(&self, other: &EnumValueDescriptor) -> bool {
        self.enum_descriptor() == other.enum_descriptor() && self.value() == other.value()
    }
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            .field("proto", self.proto)
            .field("value", &"...")
            .finish()
    }
}

impl Copy for EnumValueDescriptor {}

impl EnumValueDescriptor {
    /// Name of enum variant as specified in proto file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.proto.get_number()
    }

    /// Convert to generic `ProtobufValue`
    pub fn protobuf_value(&self) -> &'static dyn ProtobufValue {
        self.protobuf_value
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        (self.enum_descriptor_static)()
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: &EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        self.enum_descriptor()
            .cast_to_protobuf_enum::<E>(self.value())
    }
}

trait GetEnumDescriptor: Send + Sync + 'static {
    unsafe fn copy_to(&self, value: i32, dest: *mut ());
}

struct GetDescriptorImpl<E: ProtobufEnum>(marker::PhantomData<E>);

impl<E: ProtobufEnum> GetEnumDescriptor for GetDescriptorImpl<E> {
    unsafe fn copy_to(&self, value: i32, dest: *mut ()) {
        let e = E::from_i32(value).expect("unknown value");
        (&e as *const E).copy_to(dest as *mut E, 1);
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
pub struct EnumDescriptor {
    full_name: String,
    proto: &'static EnumDescriptorProto,
    values: Vec<EnumValueDescriptor>,
    /// Type id of `<E>`
    type_id: TypeId,
    /// Type id of `<ProtobufEnumOrUnknown<E>>`
    enum_or_unknown_type_id: TypeId,

    #[cfg(not(rustc_nightly))]
    get_descriptor: &'static dyn GetEnumDescriptor,

    index_by_name: HashMap<String, usize>,
    index_by_number: HashMap<i32, usize>,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            .field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for EnumDescriptor {
    fn eq(&self, other: &EnumDescriptor) -> bool {
        self as *const EnumDescriptor == other as *const EnumDescriptor
    }
}

impl EnumDescriptor {
    /// Enum name as given in `.proto` file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor {
        E::enum_descriptor_static()
    }

    fn compute_full_name(
        package: &str,
        path_to_package: &str,
        proto: &EnumDescriptorProto,
    ) -> String {
        let mut full_name = package.to_owned();
        if path_to_package.len() != 0 {
            if full_name.len() != 0 {
                full_name.push('.');
            }
            full_name.push_str(path_to_package);
        }
        if full_name.len() != 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.get_name());
        full_name
    }

    /// Separate function to reduce generated code size bloat.
    fn make_indices(proto: &EnumDescriptorProto) -> (HashMap<String, usize>, HashMap<i32, usize>) {
        let mut index_by_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, v) in proto.value.iter().enumerate() {
            index_by_number.insert(v.get_number(), i);
            index_by_name.insert(v.get_name().to_string(), i);
        }

        (index_by_name, index_by_number)
    }

    /// Construct `EnumDescriptor` given enum name and `FileDescriptorProto`.
    ///
    /// This function is called from generated code, and should rarely be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new<E>(name_in_file: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor
    where
        E: ProtobufEnum,
    {
        let (path_to_package, proto) = match find_message_or_enum(file, name_in_file) {
            (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e),
            (_, MessageOrEnum::Message(_)) => panic!("not an enum"),
        };

        let (index_by_name, index_by_number) = EnumDescriptor::make_indices(proto);

        let proto_values = &proto.value;
        let code_values = E::values();
        assert_eq!(proto_values.len(), code_values.len());

        let get_descriptor = &GetDescriptorImpl(marker::PhantomData::<E>);

        let values = proto_values
            .iter()
            .zip(code_values)
            .map(|(p, c)| EnumValueDescriptor {
                proto: p,
                protobuf_value: c,
                enum_descriptor_static: E::enum_descriptor_static,
                get_descriptor,
            })
            .collect();

        EnumDescriptor {
            full_name: EnumDescriptor::compute_full_name(
                file.get_package(),
                &path_to_package,
                &proto,
            ),
            proto,
            values,
            type_id: TypeId::of::<E>(),
            enum_or_unknown_type_id: TypeId::of::<ProtobufEnumOrUnknown<E>>(),
            #[cfg(not(rustc_nightly))]
            get_descriptor,
            index_by_name,
            index_by_number,
        }
    }

    /// This enum values
    pub fn values(&self) -> &[EnumValueDescriptor] {
        &self.values
    }

    /// Find enum variant by name
    pub fn value_by_name<'a>(&'a self, name: &str) -> Option<&'a EnumValueDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number
    pub fn value_by_number(&self, number: i32) -> Option<&EnumValueDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.values[index])
    }

    pub(crate) fn value_by_number_or_default(&self, number: i32) -> &EnumValueDescriptor {
        match self.value_by_number(number) {
            Some(v) => v,
            None => &self.values()[0],
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: &EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        TypeId::of::<E>() == self.type_id
    }

    /// Create enum object from given value.
    ///
    /// Type parameter `E` can be either [`ProtobufEnum`](crate::ProtobufEnum)
    /// or [`ProtobufEnumOrUnknown`](crate::ProtobufEnumOrUnknown).
    ///
    /// # Panics
    ///
    /// This operation panics of `E` is `ProtobufEnum` and `value` is unknown.
    pub(crate) fn cast<E: 'static>(&self, value: i32) -> Option<E> {
        if let Some(e) = self.cast_to_protobuf_enum(value) {
            return Some(e);
        }
        if let Some(e) = self.cast_to_protobuf_enum_or_unknown(value) {
            return Some(e);
        }
        None
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnum>::cast(value))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        use std::mem;
        unsafe {
            let mut r = mem::uninitialized();
            self.get_descriptor
                .copy_to(value, &mut r as *mut E as *mut ());
            Some(r)
        }
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum_or_unknown<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnumOrUnknown>::cast(
            value,
        ))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum_or_unknown<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        use std::mem;
        use std::ptr;
        debug_assert_eq!(mem::size_of::<E>(), mem::size_of::<i32>());
        unsafe {
            // This works because `ProtobufEnumOrUnknown<E>` is `#[repr(transparent)]`
            let mut r = mem::uninitialized();
            ptr::copy(&value, &mut r as *mut E as *mut i32, 1);
            Some(r)
        }
    }
}

#[cfg(rustc_nightly)]
mod cast_impl {
    use super::*;

    pub(crate) trait CastValueToProtobufEnumOrUnknown: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnumOrUnknown for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnumOrUnknown for ProtobufEnumOrUnknown<E> {
        fn cast(value: i32) -> ProtobufEnumOrUnknown<E> {
            ProtobufEnumOrUnknown::from_i32(value)
        }
    }

    pub(crate) trait CastValueToProtobufEnum: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnum for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnum for E {
        fn cast(value: i32) -> E {
            E::from_i32(value).expect(&format!("unknown enum value: {}", value))
        }
    }
}
<commit_msg>Remove unused GetEnumDescriptor field from EnumValueDescriptor<commit_after>use std::any::TypeId;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::enums::ProtobufEnumOrUnknown;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::ProtobufValue;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone)]
pub struct EnumValueDescriptor {
    proto: &'static EnumValueDescriptorProto,
    protobuf_value: &'static dyn ProtobufValue,
    enum_descriptor_static: fn() -> &'static EnumDescriptor,
}

impl PartialEq for EnumValueDescriptor {
    fn eq(&self, other: &EnumValueDescriptor) -> bool {
        self.enum_descriptor() == other.enum_descriptor() && self.value() == other.value()
    }
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            .field("proto", self.proto)
            .field("value", &"...")
            .finish()
    }
}

impl Copy for EnumValueDescriptor {}

impl EnumValueDescriptor {
    /// Name of enum variant as specified in proto file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.proto.get_number()
    }

    /// Convert to generic `ProtobufValue`
    pub fn protobuf_value(&self) -> &'static dyn ProtobufValue {
        self.protobuf_value
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        (self.enum_descriptor_static)()
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: &EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        self.enum_descriptor()
            .cast_to_protobuf_enum::<E>(self.value())
    }
}

trait GetEnumDescriptor: Send + Sync + 'static {
    unsafe fn copy_to(&self, value: i32, dest: *mut ());
}

struct GetDescriptorImpl<E: ProtobufEnum>(marker::PhantomData<E>);

impl<E: ProtobufEnum> GetEnumDescriptor for GetDescriptorImpl<E> {
    unsafe fn copy_to(&self, value: i32, dest: *mut ()) {
        let e = E::from_i32(value).expect("unknown value");
        (&e as *const E).copy_to(dest as *mut E, 1);
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
pub struct EnumDescriptor {
    full_name: String,
    proto: &'static EnumDescriptorProto,
    values: Vec<EnumValueDescriptor>,
    /// Type id of `<E>`
    type_id: TypeId,
    /// Type id of `<ProtobufEnumOrUnknown<E>>`
    enum_or_unknown_type_id: TypeId,

    #[cfg(not(rustc_nightly))]
    get_descriptor: &'static dyn GetEnumDescriptor,

    index_by_name: HashMap<String, usize>,
    index_by_number: HashMap<i32, usize>,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            .field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

/// Identity comparison: message descriptor are equal if their addresses are equal
impl PartialEq for EnumDescriptor {
    fn eq(&self, other: &EnumDescriptor) -> bool {
        self as *const EnumDescriptor == other as *const EnumDescriptor
    }
}

impl EnumDescriptor {
    /// Enum name as given in `.proto` file
    pub fn name(&self) -> &'static str {
        self.proto.get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        &self.full_name[..]
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor {
        E::enum_descriptor_static()
    }

    fn compute_full_name(
        package: &str,
        path_to_package: &str,
        proto: &EnumDescriptorProto,
    ) -> String {
        let mut full_name = package.to_owned();
        if path_to_package.len() != 0 {
            if full_name.len() != 0 {
                full_name.push('.');
            }
            full_name.push_str(path_to_package);
        }
        if full_name.len() != 0 {
            full_name.push('.');
        }
        full_name.push_str(proto.get_name());
        full_name
    }

    /// Separate function to reduce generated code size bloat.
    fn make_indices(proto: &EnumDescriptorProto) -> (HashMap<String, usize>, HashMap<i32, usize>) {
        let mut index_by_name = HashMap::new();
        let mut index_by_number = HashMap::new();
        for (i, v) in proto.value.iter().enumerate() {
            index_by_number.insert(v.get_number(), i);
            index_by_name.insert(v.get_name().to_string(), i);
        }

        (index_by_name, index_by_number)
    }

    /// Construct `EnumDescriptor` given enum name and `FileDescriptorProto`.
    ///
    /// This function is called from generated code, and should rarely be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new<E>(name_in_file: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor
    where
        E: ProtobufEnum,
    {
        let (path_to_package, proto) = match find_message_or_enum(file, name_in_file) {
            (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e),
            (_, MessageOrEnum::Message(_)) => panic!("not an enum"),
        };

        let (index_by_name, index_by_number) = EnumDescriptor::make_indices(proto);

        let proto_values = &proto.value;
        let code_values = E::values();
        assert_eq!(proto_values.len(), code_values.len());

        let values = proto_values
            .iter()
            .zip(code_values)
            .map(|(p, c)| EnumValueDescriptor {
                proto: p,
                protobuf_value: c,
                enum_descriptor_static: E::enum_descriptor_static,
            })
            .collect();

        EnumDescriptor {
            full_name: EnumDescriptor::compute_full_name(
                file.get_package(),
                &path_to_package,
                &proto,
            ),
            proto,
            values,
            type_id: TypeId::of::<E>(),
            enum_or_unknown_type_id: TypeId::of::<ProtobufEnumOrUnknown<E>>(),
            #[cfg(not(rustc_nightly))]
            get_descriptor: &GetDescriptorImpl(marker::PhantomData::<E>),
            index_by_name,
            index_by_number,
        }
    }

    /// This enum values
    pub fn values(&self) -> &[EnumValueDescriptor] {
        &self.values
    }

    /// Find enum variant by name
    pub fn value_by_name<'a>(&'a self, name: &str) -> Option<&'a EnumValueDescriptor> {
        let &index = self.index_by_name.get(name)?;
        Some(&self.values[index])
    }

    /// Find enum variant by number
    pub fn value_by_number(&self, number: i32) -> Option<&EnumValueDescriptor> {
        let &index = self.index_by_number.get(&number)?;
        Some(&self.values[index])
    }

    pub(crate) fn value_by_number_or_default(&self, number: i32) -> &EnumValueDescriptor {
        match self.value_by_number(number) {
            Some(v) => v,
            None => &self.values()[0],
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: &EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        TypeId::of::<E>() == self.type_id
    }

    /// Create enum object from given value.
    ///
    /// Type parameter `E` can be either [`ProtobufEnum`](crate::ProtobufEnum)
    /// or [`ProtobufEnumOrUnknown`](crate::ProtobufEnumOrUnknown).
    ///
    /// # Panics
    ///
    /// This operation panics of `E` is `ProtobufEnum` and `value` is unknown.
    pub(crate) fn cast<E: 'static>(&self, value: i32) -> Option<E> {
        if let Some(e) = self.cast_to_protobuf_enum(value) {
            return Some(e);
        }
        if let Some(e) = self.cast_to_protobuf_enum_or_unknown(value) {
            return Some(e);
        }
        None
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnum>::cast(value))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.type_id {
            return None;
        }

        use std::mem;
        unsafe {
            let mut r = mem::uninitialized();
            self.get_descriptor
                .copy_to(value, &mut r as *mut E as *mut ());
            Some(r)
        }
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum_or_unknown<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnumOrUnknown>::cast(
            value,
        ))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum_or_unknown<E: 'static>(&self, value: i32) -> Option<E> {
        if TypeId::of::<E>() != self.enum_or_unknown_type_id {
            return None;
        }

        use std::mem;
        use std::ptr;
        debug_assert_eq!(mem::size_of::<E>(), mem::size_of::<i32>());
        unsafe {
            // This works because `ProtobufEnumOrUnknown<E>` is `#[repr(transparent)]`
            let mut r = mem::uninitialized();
            ptr::copy(&value, &mut r as *mut E as *mut i32, 1);
            Some(r)
        }
    }
}

#[cfg(rustc_nightly)]
mod cast_impl {
    use super::*;

    pub(crate) trait CastValueToProtobufEnumOrUnknown: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnumOrUnknown for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnumOrUnknown for ProtobufEnumOrUnknown<E> {
        fn cast(value: i32) -> ProtobufEnumOrUnknown<E> {
            ProtobufEnumOrUnknown::from_i32(value)
        }
    }

    pub(crate) trait CastValueToProtobufEnum: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnum for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnum for E {
        fn cast(value: i32) -> E {
            E::from_i32(value).expect(&format!("unknown enum value: {}", value))
        }
    }
}
<|endoftext|>


<commit_before>mod prelude {
    pub use super::log_request::add_custom_metadata;
    pub use conduit::{box_error, header, Body, Handler, RequestExt, Response, StatusCode};
    pub use conduit_middleware::{AfterResult, AroundMiddleware, BeforeResult, Middleware};
}

use self::app::AppMiddleware;
use self::debug::*;
use self::ember_html::EmberHtml;
use self::head::Head;
use self::known_error_to_json::KnownErrorToJson;
use self::log_connection_pool_status::LogConnectionPoolStatus;
use self::static_or_continue::StaticOrContinue;
use self::update_metrics::UpdateMetrics;

pub mod app;
mod balance_capacity;
mod block_traffic;
mod debug;
mod ember_html;
mod head;
mod known_error_to_json;
mod log_connection_pool_status;
pub mod log_request;
mod normalize_path;
mod require_user_agent;
mod static_or_continue;
mod update_metrics;

use conduit_conditional_get::ConditionalGet;
use conduit_cookie::{Middleware as Cookie, SessionMiddleware};
use conduit_middleware::MiddlewareBuilder;
use conduit_router::RouteBuilder;
use sentry_conduit::SentryMiddleware;

use std::env;
use std::sync::Arc;

use crate::{App, Env};

pub fn build_middleware(app: Arc<App>, endpoints: RouteBuilder) -> MiddlewareBuilder {
    let mut m = MiddlewareBuilder::new(endpoints);
    let env = app.config.env();
    let blocked_traffic = app.config.blocked_traffic.clone();

    if env != Env::Test {
        m.add(log_request::LogRequests::default());
        m.around(SentryMiddleware::default());
    }

    if env == Env::Development {
        // Optionally print debug information for each request
        // To enable, set the environment variable: `RUST_LOG=cargo_registry::middleware=debug`
        m.add(Debug);
    }

    if env::var_os("LOG_CONNECTION_POOL_STATUS").is_some() {
        m.add(LogConnectionPoolStatus::new(&app));
    }

    m.add(normalize_path::NormalizePath);
    m.add(ConditionalGet);

    m.add(Cookie::new());
    m.add(SessionMiddleware::new(
        "cargo_session",
        cookie::Key::derive_from(app.session_key().as_bytes()),
        env == Env::Production,
    ));

    m.add(AppMiddleware::new(app));
    m.add(KnownErrorToJson);

    // This is added *after* AppMiddleware to make sure the app is available.
    m.add(UpdateMetrics);

    // Note: The following `m.around()` middleware is run from bottom to top

    // This is currently the final middleware to run. If a middleware layer requires a database
    // connection, it should be run after this middleware so that the potential pool usage can be
    // tracked here.
    //
    // In production we currently have 2 equally sized pools (primary and a read-only replica).
    // Because such a large portion of production traffic is for download requests (which update
    // download counts), we consider only the primary pool here.
    if let Ok(capacity) = env::var("DB_PRIMARY_POOL_SIZE") {
        if let Ok(capacity) = capacity.parse() {
            if capacity >= 10 {
                println!(
                    "Enabling BalanceCapacity middleware with {} pool capacity",
                    capacity
                );
                m.around(balance_capacity::BalanceCapacity::new(capacity))
            } else {
                println!(
                    "BalanceCapacity middleware not enabled. DB_PRIMARY_POOL_SIZE is too low."
                );
            }
        }
    }

    // Serve the static files in the *dist* directory, which are the frontend assets.
    // Not needed for the backend tests.
    if env != Env::Test {
        m.around(EmberHtml::new("dist"));
        m.around(StaticOrContinue::new("dist"));
    }

    if env == Env::Development {
        // Locally serve crates and readmes
        m.around(StaticOrContinue::new("local_uploads"));
    }

    m.around(Head::default());

    for (header, blocked_values) in blocked_traffic {
        m.around(block_traffic::BlockTraffic::new(header, blocked_values));
    }

    m.around(require_user_agent::RequireUserAgent::default());

    m
}
<commit_msg>middleware: Adjust `SentryMiddleware` invocation<commit_after>mod prelude {
    pub use super::log_request::add_custom_metadata;
    pub use conduit::{box_error, header, Body, Handler, RequestExt, Response, StatusCode};
    pub use conduit_middleware::{AfterResult, AroundMiddleware, BeforeResult, Middleware};
}

use self::app::AppMiddleware;
use self::debug::*;
use self::ember_html::EmberHtml;
use self::head::Head;
use self::known_error_to_json::KnownErrorToJson;
use self::log_connection_pool_status::LogConnectionPoolStatus;
use self::static_or_continue::StaticOrContinue;
use self::update_metrics::UpdateMetrics;

pub mod app;
mod balance_capacity;
mod block_traffic;
mod debug;
mod ember_html;
mod head;
mod known_error_to_json;
mod log_connection_pool_status;
pub mod log_request;
mod normalize_path;
mod require_user_agent;
mod static_or_continue;
mod update_metrics;

use conduit_conditional_get::ConditionalGet;
use conduit_cookie::{Middleware as Cookie, SessionMiddleware};
use conduit_middleware::MiddlewareBuilder;
use conduit_router::RouteBuilder;
use sentry_conduit::SentryMiddleware;

use std::env;
use std::sync::Arc;

use crate::{App, Env};

pub fn build_middleware(app: Arc<App>, endpoints: RouteBuilder) -> MiddlewareBuilder {
    let mut m = MiddlewareBuilder::new(endpoints);
    let env = app.config.env();
    let blocked_traffic = app.config.blocked_traffic.clone();

    if env != Env::Test {
        m.add(SentryMiddleware::default());
        m.add(log_request::LogRequests::default());
    }

    if env == Env::Development {
        // Optionally print debug information for each request
        // To enable, set the environment variable: `RUST_LOG=cargo_registry::middleware=debug`
        m.add(Debug);
    }

    if env::var_os("LOG_CONNECTION_POOL_STATUS").is_some() {
        m.add(LogConnectionPoolStatus::new(&app));
    }

    m.add(normalize_path::NormalizePath);
    m.add(ConditionalGet);

    m.add(Cookie::new());
    m.add(SessionMiddleware::new(
        "cargo_session",
        cookie::Key::derive_from(app.session_key().as_bytes()),
        env == Env::Production,
    ));

    m.add(AppMiddleware::new(app));
    m.add(KnownErrorToJson);

    // This is added *after* AppMiddleware to make sure the app is available.
    m.add(UpdateMetrics);

    // Note: The following `m.around()` middleware is run from bottom to top

    // This is currently the final middleware to run. If a middleware layer requires a database
    // connection, it should be run after this middleware so that the potential pool usage can be
    // tracked here.
    //
    // In production we currently have 2 equally sized pools (primary and a read-only replica).
    // Because such a large portion of production traffic is for download requests (which update
    // download counts), we consider only the primary pool here.
    if let Ok(capacity) = env::var("DB_PRIMARY_POOL_SIZE") {
        if let Ok(capacity) = capacity.parse() {
            if capacity >= 10 {
                println!(
                    "Enabling BalanceCapacity middleware with {} pool capacity",
                    capacity
                );
                m.around(balance_capacity::BalanceCapacity::new(capacity))
            } else {
                println!(
                    "BalanceCapacity middleware not enabled. DB_PRIMARY_POOL_SIZE is too low."
                );
            }
        }
    }

    // Serve the static files in the *dist* directory, which are the frontend assets.
    // Not needed for the backend tests.
    if env != Env::Test {
        m.around(EmberHtml::new("dist"));
        m.around(StaticOrContinue::new("dist"));
    }

    if env == Env::Development {
        // Locally serve crates and readmes
        m.around(StaticOrContinue::new("local_uploads"));
    }

    m.around(Head::default());

    for (header, blocked_values) in blocked_traffic {
        m.around(block_traffic::BlockTraffic::new(header, blocked_values));
    }

    m.around(require_user_agent::RequireUserAgent::default());

    m
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Clone trait for types that cannot be "implicitly copied"

In Rust, some simple types are "implicitly copyable" and when you
assign them or pass them as arguments, the receiver will get a copy,
leaving the original value in place. These types do not require
allocation to copy and do not have finalizers (i.e. they do not
contain owned boxes or implement `Drop`), so the compiler considers
them cheap and safe to copy and automatically implements the `Copy`
trait for them. For other types copies must be made explicitly,
by convention implementing the `Clone` trait and calling the
`clone` method.

*/

use core::kinds::Const;

/// A common trait for cloning an object.
pub trait Clone {
    /// Returns a copy of the value. The contents of owned pointers
    /// are copied to maintain uniqueness, while the contents of
    /// managed pointers are not copied.
    fn clone(&self) -> Self;
}

impl<T: Clone> Clone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn clone(&self) -> ~T { ~(**self).clone() }
}

impl<T> Clone for @T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @T { *self }
}

impl<T> Clone for @mut T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @mut T { *self }
}

impl<'self, T> Clone for &'self T {
    /// Return a shallow copy of the borrowed pointer.
    #[inline(always)]
    fn clone(&self) -> &'self T { *self }
}

macro_rules! clone_impl(
    ($t:ty) => {
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn clone(&self) -> $t { *self }
        }
    }
)

clone_impl!(int)
clone_impl!(i8)
clone_impl!(i16)
clone_impl!(i32)
clone_impl!(i64)

clone_impl!(uint)
clone_impl!(u8)
clone_impl!(u16)
clone_impl!(u32)
clone_impl!(u64)

clone_impl!(float)
clone_impl!(f32)
clone_impl!(f64)

clone_impl!(())
clone_impl!(bool)
clone_impl!(char)

/// A trait distinct from `Clone` which represents "deep copies" of things like
/// managed boxes which would otherwise not be copied.
pub trait DeepClone {
    /// Return a deep copy of the value. Unlike `Clone`, the contents of shared pointer types
    /// *are* copied. Note that this is currently unimplemented for managed boxes, as
    /// it would need to handle cycles, but it is implemented for other smart-pointer types.
    fn deep_clone(&self) -> Self;
}

impl<T: DeepClone> DeepClone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @T { @(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @mut T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() }
}

macro_rules! deep_clone_impl(
    ($t:ty) => {
        impl DeepClone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn deep_clone(&self) -> $t { *self }
        }
    }
)

deep_clone_impl!(int)
deep_clone_impl!(i8)
deep_clone_impl!(i16)
deep_clone_impl!(i32)
deep_clone_impl!(i64)

deep_clone_impl!(uint)
deep_clone_impl!(u8)
deep_clone_impl!(u16)
deep_clone_impl!(u32)
deep_clone_impl!(u64)

deep_clone_impl!(float)
deep_clone_impl!(f32)
deep_clone_impl!(f64)

deep_clone_impl!(())
deep_clone_impl!(bool)
deep_clone_impl!(char)

#[test]
fn test_owned_clone() {
    let a = ~5i;
    let b: ~int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_clone() {
    let a = @5i;
    let b: @int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_mut_deep_clone() {
    let x = @mut 5i;
    let y: @mut int = x.deep_clone();
    *x = 20;
    assert_eq!(*y, 5);
}

#[test]
fn test_managed_mut_clone() {
    let a = @mut 5i;
    let b: @mut int = a.clone();
    assert_eq!(a, b);
    *b = 10;
    assert_eq!(a, b);
}

#[test]
fn test_borrowed_clone() {
    let x = 5i;
    let y: &int = &x;
    let z: &int = (&y).clone();
    assert_eq!(*z, 5);
}
<commit_msg>clone: fix docstring<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Clone trait for types that cannot be "implicitly copied"

In Rust, some simple types are "implicitly copyable" and when you
assign them or pass them as arguments, the receiver will get a copy,
leaving the original value in place. These types do not require
allocation to copy and do not have finalizers (i.e. they do not
contain owned boxes or implement `Drop`), so the compiler considers
them cheap and safe to copy and automatically implements the `Copy`
trait for them. For other types copies must be made explicitly,
by convention implementing the `Clone` trait and calling the
`clone` method.

*/

use core::kinds::Const;

/// A common trait for cloning an object.
pub trait Clone {
    /// Returns a copy of the value. The contents of owned pointers
    /// are copied to maintain uniqueness, while the contents of
    /// managed pointers are not copied.
    fn clone(&self) -> Self;
}

impl<T: Clone> Clone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn clone(&self) -> ~T { ~(**self).clone() }
}

impl<T> Clone for @T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @T { *self }
}

impl<T> Clone for @mut T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @mut T { *self }
}

impl<'self, T> Clone for &'self T {
    /// Return a shallow copy of the borrowed pointer.
    #[inline(always)]
    fn clone(&self) -> &'self T { *self }
}

macro_rules! clone_impl(
    ($t:ty) => {
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn clone(&self) -> $t { *self }
        }
    }
)

clone_impl!(int)
clone_impl!(i8)
clone_impl!(i16)
clone_impl!(i32)
clone_impl!(i64)

clone_impl!(uint)
clone_impl!(u8)
clone_impl!(u16)
clone_impl!(u32)
clone_impl!(u64)

clone_impl!(float)
clone_impl!(f32)
clone_impl!(f64)

clone_impl!(())
clone_impl!(bool)
clone_impl!(char)

/// A trait distinct from `Clone` which represents "deep copies" of things like
/// managed boxes which would otherwise not be copied.
pub trait DeepClone {
    /// Return a deep copy of the value. Unlike `Clone`, the contents of shared pointer types
    /// *are* copied.
    fn deep_clone(&self) -> Self;
}

impl<T: DeepClone> DeepClone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @T { @(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @mut T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() }
}

macro_rules! deep_clone_impl(
    ($t:ty) => {
        impl DeepClone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn deep_clone(&self) -> $t { *self }
        }
    }
)

deep_clone_impl!(int)
deep_clone_impl!(i8)
deep_clone_impl!(i16)
deep_clone_impl!(i32)
deep_clone_impl!(i64)

deep_clone_impl!(uint)
deep_clone_impl!(u8)
deep_clone_impl!(u16)
deep_clone_impl!(u32)
deep_clone_impl!(u64)

deep_clone_impl!(float)
deep_clone_impl!(f32)
deep_clone_impl!(f64)

deep_clone_impl!(())
deep_clone_impl!(bool)
deep_clone_impl!(char)

#[test]
fn test_owned_clone() {
    let a = ~5i;
    let b: ~int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_clone() {
    let a = @5i;
    let b: @int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_mut_deep_clone() {
    let x = @mut 5i;
    let y: @mut int = x.deep_clone();
    *x = 20;
    assert_eq!(*y, 5);
}

#[test]
fn test_managed_mut_clone() {
    let a = @mut 5i;
    let b: @mut int = a.clone();
    assert_eq!(a, b);
    *b = 10;
    assert_eq!(a, b);
}

#[test]
fn test_borrowed_clone() {
    let x = 5i;
    let y: &int = &x;
    let z: &int = (&y).clone();
    assert_eq!(*z, 5);
}
<|endoftext|>


<commit_before>#![crate_name = "uu_unlink"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Colin Warren <me@zv.ms>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: unlink (GNU coreutils) 8.21 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use getopts::Options;
use libc::{S_IFLNK, S_IFMT, S_IFREG};
use libc::{c_char, lstat, stat, unlink};
use std::io::{Error, ErrorKind};
use std::mem::uninitialized;
use std::ffi::CString;

static NAME: &'static str = "unlink";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [FILE]... [OPTION]...", NAME);
        println!("");
        println!("{}", opts.usage("Unlink the file at [FILE]."));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        crash!(
            1,
            "missing operand\nTry '{0} --help' for more information.",
            NAME
        );
    } else if matches.free.len() > 1 {
        crash!(
            1,
            "extra operand: '{1}'\nTry '{0} --help' for more information.",
            NAME,
            matches.free[1]
        );
    }

    let st_mode = {
        let mut buf: stat = unsafe { uninitialized() };
        let c_string = CString::new(matches.free[0].clone()).unwrap(); // unwrap() cannot fail, the string comes from argv so it cannot contain a \0.
        let result = unsafe {
            lstat(
                c_string.as_ptr(),
                &mut buf as *mut stat,
            )
        };

        if result < 0 {
            crash!(
                1,
                "Cannot stat '{}': {}",
                matches.free[0],
                Error::last_os_error()
            );
        }

        buf.st_mode & S_IFMT
    };

    let result = if st_mode != S_IFREG && st_mode != S_IFLNK {
        Err(Error::new(
            ErrorKind::Other,
            "Not a regular file or symlink",
        ))
    } else {
        let result = unsafe { unlink(matches.free[0].as_ptr() as *const c_char) };

        if result < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(())
        }
    };

    match result {
        Ok(_) => (),
        Err(e) => {
            crash!(1, "cannot unlink '{0}': {1}", matches.free[0], e);
        }
    }

    0
}
<commit_msg>unlink: Use a NUL-terminated string when calling unlink().<commit_after>#![crate_name = "uu_unlink"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Colin Warren <me@zv.ms>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: unlink (GNU coreutils) 8.21 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use getopts::Options;
use libc::{S_IFLNK, S_IFMT, S_IFREG};
use libc::{lstat, stat, unlink};
use std::io::{Error, ErrorKind};
use std::mem::uninitialized;
use std::ffi::CString;

static NAME: &'static str = "unlink";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [FILE]... [OPTION]...", NAME);
        println!("");
        println!("{}", opts.usage("Unlink the file at [FILE]."));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        crash!(
            1,
            "missing operand\nTry '{0} --help' for more information.",
            NAME
        );
    } else if matches.free.len() > 1 {
        crash!(
            1,
            "extra operand: '{1}'\nTry '{0} --help' for more information.",
            NAME,
            matches.free[1]
        );
    }

    let c_string = CString::new(matches.free[0].clone()).unwrap(); // unwrap() cannot fail, the string comes from argv so it cannot contain a \0.

    let st_mode = {
        let mut buf: stat = unsafe { uninitialized() };
        let result = unsafe {
            lstat(
                c_string.as_ptr(),
                &mut buf as *mut stat,
            )
        };

        if result < 0 {
            crash!(
                1,
                "Cannot stat '{}': {}",
                matches.free[0],
                Error::last_os_error()
            );
        }

        buf.st_mode & S_IFMT
    };

    let result = if st_mode != S_IFREG && st_mode != S_IFLNK {
        Err(Error::new(
            ErrorKind::Other,
            "Not a regular file or symlink",
        ))
    } else {
        let result = unsafe { unlink(c_string.as_ptr()) };

        if result < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(())
        }
    };

    match result {
        Ok(_) => (),
        Err(e) => {
            crash!(1, "cannot unlink '{0}': {1}", matches.free[0], e);
        }
    }

    0
}
<|endoftext|>