<commit_before>extern crate libc;
extern crate time;

use api::ErrorCode;
use utils::cstring::CStringUtils;
use utils::json::JsonDecodable;
use utils::sequence::SequenceUtils;

use self::libc::c_char;
use self::time::Timespec;

use std::collections::HashMap;
use std::ffi::CString;
use std::sync::Mutex;
use std::ops::Sub;

#[derive(Deserialize)]
struct InmemWalletRuntimeConfig {
    freshness_time: i64
}

impl<'a> JsonDecodable<'a> for InmemWalletRuntimeConfig {}

impl Default for InmemWalletRuntimeConfig {
    fn default() -> Self {
        InmemWalletRuntimeConfig { freshness_time: 1000 }
    }
}

#[derive(Debug)]
struct InmemWalletContext {
    name: String,
    freshness_time: i64
}

#[derive(Debug)]
struct InmemWalletRecord {
    key: String,
    value: String,
    time_created: Timespec
}

lazy_static! {
    static ref INMEM_WALLETS: Mutex<HashMap<String, HashMap<String, InmemWalletRecord>>> = Default::default();
}

lazy_static! {
    static ref INMEM_WALLET_HANDLES: Mutex<HashMap<i32, InmemWalletContext>> = Default::default();
}

pub struct InmemWallet {}

impl InmemWallet {
    pub extern "C" fn create(name: *const c_char,
                             config: *const c_char,
                             credentials: *const c_char) -> ErrorCode {
        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(credentials, ErrorCode::CommonInvalidStructure);

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if wallets.contains_key(&name) {
            // Invalid state as "already exists" case must be checked on service layer
            return ErrorCode::CommonInvalidState;
        }
        wallets.insert(name.clone(), HashMap::new());
        ErrorCode::Success
    }

    pub extern "C" fn open(name: *const c_char,
                           config: *const c_char,
                           runtime_config: *const c_char,
                           credentials: *const c_char,
                           handle: *mut i32) -> ErrorCode {

        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(runtime_config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(credentials, ErrorCode::CommonInvalidStructure);

        let runtime_config = match runtime_config {
            Some(config) => InmemWalletRuntimeConfig::from_json(config.as_str()).unwrap(), // FIXME: parse error!!!
            None => InmemWalletRuntimeConfig::default()
        };

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&name) {
            return ErrorCode::CommonInvalidState;
        }

        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();
        let xhandle = SequenceUtils::get_next_id();
        handles.insert(xhandle, InmemWalletContext {
            name,
            freshness_time: runtime_config.freshness_time
        });

        unsafe { *handle = xhandle };
        ErrorCode::Success
    }

    pub extern "C" fn set(xhandle: i32,
                          key: *const c_char,
                          value: *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);
        check_useful_c_str!(value, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get_mut(&wallet_context.name).unwrap();

        wallet.insert(key.clone(), InmemWalletRecord {
            key,
            value,
            time_created: time::get_time()
        });
        ErrorCode::Success
    }

    pub extern "C" fn get(xhandle: i32,
                          key: *const c_char,
                          value_ptr: *mut *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get(&wallet_context.name).unwrap();

        if !wallet.contains_key(&key) {
            return ErrorCode::WalletNotFoundError;
        }

        let ref value = wallet.get(&key).unwrap().value;
        unsafe { *value_ptr = CString::new(value.as_str()).unwrap().into_raw(); }
        ErrorCode::Success
    }

    pub extern "C" fn get_not_expied(xhandle: i32,
                                     key: *const c_char,
                                     value_ptr: *mut *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get(&wallet_context.name).unwrap();

        if !wallet.contains_key(&key) {
            return ErrorCode::WalletNotFoundError;
        }

        let ref record = wallet.get(&key).unwrap();

        if time::get_time().sub(record.time_created).num_seconds() > wallet_context.freshness_time {
            return ErrorCode::WalletNotFoundError;
        }

        unsafe { *value_ptr = CString::new(record.value.as_str()).unwrap().into_raw(); }
        ErrorCode::Success
    }

    pub extern "C" fn list(xhandle: i32,
                           key_prefix: *const c_char,
                           values_json_ptr: *mut *const c_char) -> ErrorCode {
        unimplemented!()
    }

    pub extern "C" fn close(xhandle: i32) -> ErrorCode {
        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        handles.remove(&xhandle);
        ErrorCode::Success
    }

    pub extern "C" fn delete(name: *const c_char,
                             config: *const c_char,
                             credentials: *const c_char) -> ErrorCode {
        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&name) {
            return ErrorCode::CommonInvalidState;
        }

        wallets.remove(&name);
        ErrorCode::Success
    }

    pub extern "C" fn free(xhandle: i32,
                           value: *const c_char) -> ErrorCode {
        unsafe { CString::from_raw(value as *mut c_char); }
        ErrorCode::Success
    }

    pub fn cleanup() {
        let mut wallets = INMEM_WALLETS.lock().unwrap();
        wallets.clear();

        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();
        handles.clear();
    }
}<commit_msg>* Added implementation of list handler for inmem wallet<commit_after>extern crate libc;
extern crate time;

use api::ErrorCode;
use utils::cstring::CStringUtils;
use utils::json::{JsonDecodable, JsonEncodable};
use utils::sequence::SequenceUtils;

use self::libc::c_char;
use self::time::Timespec;

use std::collections::HashMap;
use std::ffi::CString;
use std::sync::Mutex;
use std::ops::Sub;

#[derive(Deserialize)]
struct InmemWalletRuntimeConfig {
    freshness_time: i64
}

impl<'a> JsonDecodable<'a> for InmemWalletRuntimeConfig {}

impl Default for InmemWalletRuntimeConfig {
    fn default() -> Self {
        InmemWalletRuntimeConfig { freshness_time: 1000 }
    }
}

#[derive(Debug)]
struct InmemWalletContext {
    name: String,
    freshness_time: i64
}

#[derive(Debug)]
struct InmemWalletRecord {
    key: String,
    value: String,
    time_created: Timespec
}

#[derive(Debug, Serialize)]
pub struct InmemWalletJSONValue {
    pub key: String,
    pub value: String
}

#[derive(Debug, Serialize)]
pub struct InmemWalletJSONValues {
    pub values: Vec<InmemWalletJSONValue>
}

impl JsonEncodable for InmemWalletJSONValues {}

lazy_static! {
    static ref INMEM_WALLETS: Mutex<HashMap<String, HashMap<String, InmemWalletRecord>>> = Default::default();
}

lazy_static! {
    static ref INMEM_WALLET_HANDLES: Mutex<HashMap<i32, InmemWalletContext>> = Default::default();
}

pub struct InmemWallet {}

impl InmemWallet {
    pub extern "C" fn create(name: *const c_char,
                             config: *const c_char,
                             credentials: *const c_char) -> ErrorCode {
        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(credentials, ErrorCode::CommonInvalidStructure);

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if wallets.contains_key(&name) {
            // Invalid state as "already exists" case must be checked on service layer
            return ErrorCode::CommonInvalidState;
        }
        wallets.insert(name.clone(), HashMap::new());
        ErrorCode::Success
    }

    pub extern "C" fn open(name: *const c_char,
                           config: *const c_char,
                           runtime_config: *const c_char,
                           credentials: *const c_char,
                           handle: *mut i32) -> ErrorCode {
        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(runtime_config, ErrorCode::CommonInvalidStructure);
        check_useful_opt_c_str!(credentials, ErrorCode::CommonInvalidStructure);

        let runtime_config = match runtime_config {
            Some(config) => InmemWalletRuntimeConfig::from_json(config.as_str()).unwrap(), // FIXME: parse error!!!
            None => InmemWalletRuntimeConfig::default()
        };

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&name) {
            return ErrorCode::CommonInvalidState;
        }

        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();
        let xhandle = SequenceUtils::get_next_id();
        handles.insert(xhandle, InmemWalletContext {
            name,
            freshness_time: runtime_config.freshness_time
        });

        unsafe { *handle = xhandle };
        ErrorCode::Success
    }

    pub extern "C" fn set(xhandle: i32,
                          key: *const c_char,
                          value: *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);
        check_useful_c_str!(value, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get_mut(&wallet_context.name).unwrap();

        wallet.insert(key.clone(), InmemWalletRecord {
            key,
            value,
            time_created: time::get_time()
        });
        ErrorCode::Success
    }

    pub extern "C" fn get(xhandle: i32,
                          key: *const c_char,
                          value_ptr: *mut *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get(&wallet_context.name).unwrap();

        if !wallet.contains_key(&key) {
            return ErrorCode::WalletNotFoundError;
        }

        let ref value = wallet.get(&key).unwrap().value;
        unsafe { *value_ptr = CString::new(value.as_str()).unwrap().into_raw(); }
        ErrorCode::Success
    }

    pub extern "C" fn get_not_expied(xhandle: i32,
                                     key: *const c_char,
                                     value_ptr: *mut *const c_char) -> ErrorCode {
        check_useful_c_str!(key, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get(&wallet_context.name).unwrap();

        if !wallet.contains_key(&key) {
            return ErrorCode::WalletNotFoundError;
        }

        let ref record = wallet.get(&key).unwrap();

        if time::get_time().sub(record.time_created).num_seconds() > wallet_context.freshness_time {
            return ErrorCode::WalletNotFoundError;
        }

        unsafe { *value_ptr = CString::new(record.value.as_str()).unwrap().into_raw(); }
        ErrorCode::Success
    }

    pub extern "C" fn list(xhandle: i32,
                           key_prefix: *const c_char,
                           values_json_ptr: *mut *const c_char) -> ErrorCode {
        check_useful_c_str!(key_prefix, ErrorCode::CommonInvalidStructure);

        let handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet_context = handles.get(&xhandle).unwrap();

        let wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&wallet_context.name) {
            return ErrorCode::CommonInvalidState;
        }

        let wallet = wallets.get(&wallet_context.name).unwrap();

        let values = InmemWalletJSONValues {
            values: wallet
                .keys()
                .filter(|&ref key| key.starts_with(&key_prefix))
                .map(|&ref key| InmemWalletJSONValue {
                    key: key.clone(),
                    value: wallet.get(key).unwrap().value.clone()
                })
                .collect()
        }
            .to_json()
            .unwrap();

        unsafe { *values_json_ptr = CString::new(values.as_str()).unwrap().into_raw(); }
        ErrorCode::Success
    }

    pub extern "C" fn close(xhandle: i32) -> ErrorCode {
        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();

        if !handles.contains_key(&xhandle) {
            return ErrorCode::CommonInvalidState;
        }

        handles.remove(&xhandle);
        ErrorCode::Success
    }

    pub extern "C" fn delete(name: *const c_char,
                             config: *const c_char,
                             credentials: *const c_char) -> ErrorCode {
        check_useful_c_str!(name, ErrorCode::CommonInvalidStructure);

        let mut wallets = INMEM_WALLETS.lock().unwrap();

        if !wallets.contains_key(&name) {
            return ErrorCode::CommonInvalidState;
        }

        wallets.remove(&name);
        ErrorCode::Success
    }

    pub extern "C" fn free(xhandle: i32,
                           value: *const c_char) -> ErrorCode {
        unsafe { CString::from_raw(value as *mut c_char); }
        ErrorCode::Success
    }

    pub fn cleanup() {
        let mut wallets = INMEM_WALLETS.lock().unwrap();
        wallets.clear();

        let mut handles = INMEM_WALLET_HANDLES.lock().unwrap();
        handles.clear();
    }
}<|endoftext|>


<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::DiskType;

use crate::sys::disk::{new_disk, Disk};
use crate::sys::processor::{self, Processor, Query};

use std::ffi::OsStr;
use std::mem::{size_of, zeroed};

use winapi::shared::ntdef::ULARGE_INTEGER;
use winapi::{ctypes::c_void, um::winbase::DRIVE_REMOVABLE};

use winapi::shared::minwindef::{DWORD, MAX_PATH, TRUE};
use winapi::um::fileapi::{
    CreateFileW, GetDiskFreeSpaceExW, GetDriveTypeW, GetLogicalDrives, GetVolumeInformationW,
    OPEN_EXISTING,
};
use winapi::um::handleapi::CloseHandle;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::sysinfoapi::{GetSystemInfo, SYSTEM_INFO};
use winapi::um::winbase::DRIVE_FIXED;
use winapi::um::winioctl::{
    DEVICE_TRIM_DESCRIPTOR, IOCTL_DISK_GET_PARTITION_INFO_EX, IOCTL_STORAGE_QUERY_PROPERTY,
    PARTITION_INFORMATION_EX, STORAGE_PROPERTY_QUERY,
};
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, HANDLE};

pub(crate) struct KeyHandler {
    pub unique_id: String,
}

impl KeyHandler {
    pub fn new(unique_id: String) -> KeyHandler {
        KeyHandler { unique_id }
    }
}

pub(crate) fn init_processors() -> (Vec<Processor>, String, String) {
    unsafe {
        let mut sys_info: SYSTEM_INFO = zeroed();
        GetSystemInfo(&mut sys_info);
        let (vendor_id, brand) = processor::get_vendor_id_and_brand(&sys_info);
        let frequencies = processor::get_frequencies(sys_info.dwNumberOfProcessors as usize);
        let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1);
        for nb in 0..sys_info.dwNumberOfProcessors {
            ret.push(Processor::new_with_values(
                &format!("CPU {}", nb + 1),
                vendor_id.clone(),
                brand.clone(),
                frequencies[nb as usize],
            ));
        }
        (ret, vendor_id, brand)
    }
}

pub unsafe fn open_drive(drive_name: &[u16], open_rights: DWORD) -> HANDLE {
    CreateFileW(
        drive_name.as_ptr(),
        open_rights,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        std::ptr::null_mut(),
        OPEN_EXISTING,
        0,
        std::ptr::null_mut(),
    )
}

pub unsafe fn get_drive_size(handle: HANDLE, mount_point: &[u16]) -> u64 {
    let mut pdg: PARTITION_INFORMATION_EX = std::mem::zeroed();
    let mut junk = 0;
    let result = DeviceIoControl(
        handle,
        IOCTL_DISK_GET_PARTITION_INFO_EX,
        std::ptr::null_mut(),
        0,
        &mut pdg as *mut PARTITION_INFORMATION_EX as *mut c_void,
        size_of::<PARTITION_INFORMATION_EX>() as DWORD,
        &mut junk,
        std::ptr::null_mut(),
    );
    if result == TRUE {
        *pdg.PartitionLength.QuadPart() as u64
    } else {
        // Sometimes DeviceIoControl can fail, so try using GetDiskFreeSpaceEx as a backup
        let mut tmp: ULARGE_INTEGER = std::mem::zeroed();
        if GetDiskFreeSpaceExW(
            mount_point.as_ptr(),
            std::ptr::null_mut(),
            &mut tmp,
            std::ptr::null_mut(),
        ) != 0
        {
            *tmp.QuadPart() as u64
        } else {
            0
        }
    }
}

pub unsafe fn get_disks() -> Vec<Disk> {
    let drives = GetLogicalDrives();
    if drives == 0 {
        return Vec::new();
    }

    #[cfg(feature = "multithread")]
    use rayon::iter::ParallelIterator;

    crate::utils::into_iter(0..DWORD::BITS)
        .filter_map(|x| {
            if (drives >> x) & 1 == 0 {
                return None;
            }
            let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0];

            let drive_type = GetDriveTypeW(mount_point.as_ptr());

            let is_removable = drive_type == DRIVE_REMOVABLE;

            if drive_type != DRIVE_FIXED && drive_type != DRIVE_REMOVABLE {
                return None;
            }
            let mut name = [0u16; MAX_PATH + 1];
            let mut file_system = [0u16; 32];
            if GetVolumeInformationW(
                mount_point.as_ptr(),
                name.as_mut_ptr(),
                name.len() as DWORD,
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                file_system.as_mut_ptr(),
                file_system.len() as DWORD,
            ) == 0
            {
                return None;
            }
            let mut pos = 0;
            for x in name.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let name = String::from_utf16_lossy(&name[..pos]);
            let name = OsStr::new(&name);

            pos = 0;
            for x in file_system.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let file_system: Vec<u8> = file_system[..pos].iter().map(|x| *x as u8).collect();

            let drive_name = [
                b'\\' as u16,
                b'\\' as u16,
                b'.' as u16,
                b'\\' as u16,
                b'A' as u16 + x as u16,
                b':' as u16,
                0,
            ];
            let handle = open_drive(&drive_name, 0);
            if handle == INVALID_HANDLE_VALUE {
                CloseHandle(handle);
                return new_disk(
                    name,
                    &mount_point,
                    &file_system,
                    DiskType::Unknown(-1),
                    0,
                    is_removable,
                );
            }
            let disk_size = get_drive_size(handle, &mount_point);
            /*let mut spq_trim: STORAGE_PROPERTY_QUERY = std::mem::zeroed();
            spq_trim.PropertyId = StorageDeviceTrimProperty;
            spq_trim.QueryType = PropertyStandardQuery;
            let mut dtd: DEVICE_TRIM_DESCRIPTOR = std::mem::zeroed();*/
            let mut spq_trim = STORAGE_PROPERTY_QUERY {
                PropertyId: 8,
                QueryType: 0,
                AdditionalParameters: [0],
            };
            let mut dtd: DEVICE_TRIM_DESCRIPTOR = std::mem::zeroed();

            let mut dw_size = 0;
            if DeviceIoControl(
                handle,
                IOCTL_STORAGE_QUERY_PROPERTY,
                &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void,
                size_of::<STORAGE_PROPERTY_QUERY>() as DWORD,
                &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void,
                size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD,
                &mut dw_size,
                std::ptr::null_mut(),
            ) == 0
                || dw_size != size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD
            {
                CloseHandle(handle);
                return new_disk(
                    name,
                    &mount_point,
                    &file_system,
                    DiskType::Unknown(-1),
                    disk_size,
                    is_removable,
                );
            }
            let is_ssd = dtd.TrimEnabled != 0;
            CloseHandle(handle);
            new_disk(
                name,
                &mount_point,
                &file_system,
                if is_ssd { DiskType::SSD } else { DiskType::HDD },
                disk_size,
                is_removable,
            )
        })
        .collect::<Vec<_>>()
}

pub(crate) fn add_english_counter(
    s: String,
    query: &mut Query,
    keys: &mut Option<KeyHandler>,
    counter_name: String,
) {
    let mut full = s.encode_utf16().collect::<Vec<_>>();
    full.push(0);
    if query.add_english_counter(&counter_name, full) {
        *keys = Some(KeyHandler::new(counter_name));
    }
}
<commit_msg>Replace DeviceIoControl with GetDiskFreeSpaceExW<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::DiskType;

use crate::sys::disk::{new_disk, Disk};
use crate::sys::processor::{self, Processor, Query};

use std::ffi::OsStr;
use std::mem::{size_of, zeroed};

use winapi::shared::ntdef::ULARGE_INTEGER;
use winapi::{ctypes::c_void, um::winbase::DRIVE_REMOVABLE};

use winapi::shared::minwindef::{DWORD, MAX_PATH};
use winapi::um::fileapi::{
    CreateFileW, GetDiskFreeSpaceExW, GetDriveTypeW, GetLogicalDrives, GetVolumeInformationW,
    OPEN_EXISTING,
};
use winapi::um::handleapi::CloseHandle;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::sysinfoapi::{GetSystemInfo, SYSTEM_INFO};
use winapi::um::winbase::DRIVE_FIXED;
use winapi::um::winioctl::{
    DEVICE_TRIM_DESCRIPTOR, IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_QUERY,
};
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, HANDLE};

pub(crate) struct KeyHandler {
    pub unique_id: String,
}

impl KeyHandler {
    pub fn new(unique_id: String) -> KeyHandler {
        KeyHandler { unique_id }
    }
}

pub(crate) fn init_processors() -> (Vec<Processor>, String, String) {
    unsafe {
        let mut sys_info: SYSTEM_INFO = zeroed();
        GetSystemInfo(&mut sys_info);
        let (vendor_id, brand) = processor::get_vendor_id_and_brand(&sys_info);
        let frequencies = processor::get_frequencies(sys_info.dwNumberOfProcessors as usize);
        let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1);
        for nb in 0..sys_info.dwNumberOfProcessors {
            ret.push(Processor::new_with_values(
                &format!("CPU {}", nb + 1),
                vendor_id.clone(),
                brand.clone(),
                frequencies[nb as usize],
            ));
        }
        (ret, vendor_id, brand)
    }
}

pub unsafe fn open_drive(drive_name: &[u16], open_rights: DWORD) -> HANDLE {
    CreateFileW(
        drive_name.as_ptr(),
        open_rights,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        std::ptr::null_mut(),
        OPEN_EXISTING,
        0,
        std::ptr::null_mut(),
    )
}

pub unsafe fn get_drive_size(mount_point: &[u16]) -> u64 {
    let mut tmp: ULARGE_INTEGER = std::mem::zeroed();
    if GetDiskFreeSpaceExW(
        mount_point.as_ptr(),
        std::ptr::null_mut(),
        &mut tmp,
        std::ptr::null_mut(),
    ) != 0
    {
        *tmp.QuadPart() as u64
    } else {
        0
    }
}

pub unsafe fn get_disks() -> Vec<Disk> {
    let drives = GetLogicalDrives();
    if drives == 0 {
        return Vec::new();
    }

    #[cfg(feature = "multithread")]
    use rayon::iter::ParallelIterator;

    crate::utils::into_iter(0..DWORD::BITS)
        .filter_map(|x| {
            if (drives >> x) & 1 == 0 {
                return None;
            }
            let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0];

            let drive_type = GetDriveTypeW(mount_point.as_ptr());

            let is_removable = drive_type == DRIVE_REMOVABLE;

            if drive_type != DRIVE_FIXED && drive_type != DRIVE_REMOVABLE {
                return None;
            }
            let mut name = [0u16; MAX_PATH + 1];
            let mut file_system = [0u16; 32];
            if GetVolumeInformationW(
                mount_point.as_ptr(),
                name.as_mut_ptr(),
                name.len() as DWORD,
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                file_system.as_mut_ptr(),
                file_system.len() as DWORD,
            ) == 0
            {
                return None;
            }
            let mut pos = 0;
            for x in name.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let name = String::from_utf16_lossy(&name[..pos]);
            let name = OsStr::new(&name);

            pos = 0;
            for x in file_system.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let file_system: Vec<u8> = file_system[..pos].iter().map(|x| *x as u8).collect();

            let drive_name = [
                b'\\' as u16,
                b'\\' as u16,
                b'.' as u16,
                b'\\' as u16,
                b'A' as u16 + x as u16,
                b':' as u16,
                0,
            ];
            let handle = open_drive(&drive_name, 0);
            if handle == INVALID_HANDLE_VALUE {
                CloseHandle(handle);
                return new_disk(
                    name,
                    &mount_point,
                    &file_system,
                    DiskType::Unknown(-1),
                    0,
                    is_removable,
                );
            }
            let disk_size = get_drive_size(&mount_point);
            /*let mut spq_trim: STORAGE_PROPERTY_QUERY = std::mem::zeroed();
            spq_trim.PropertyId = StorageDeviceTrimProperty;
            spq_trim.QueryType = PropertyStandardQuery;
            let mut dtd: DEVICE_TRIM_DESCRIPTOR = std::mem::zeroed();*/
            let mut spq_trim = STORAGE_PROPERTY_QUERY {
                PropertyId: 8,
                QueryType: 0,
                AdditionalParameters: [0],
            };
            let mut dtd: DEVICE_TRIM_DESCRIPTOR = std::mem::zeroed();

            let mut dw_size = 0;
            if DeviceIoControl(
                handle,
                IOCTL_STORAGE_QUERY_PROPERTY,
                &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void,
                size_of::<STORAGE_PROPERTY_QUERY>() as DWORD,
                &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void,
                size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD,
                &mut dw_size,
                std::ptr::null_mut(),
            ) == 0
                || dw_size != size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD
            {
                CloseHandle(handle);
                return new_disk(
                    name,
                    &mount_point,
                    &file_system,
                    DiskType::Unknown(-1),
                    disk_size,
                    is_removable,
                );
            }
            let is_ssd = dtd.TrimEnabled != 0;
            CloseHandle(handle);
            new_disk(
                name,
                &mount_point,
                &file_system,
                if is_ssd { DiskType::SSD } else { DiskType::HDD },
                disk_size,
                is_removable,
            )
        })
        .collect::<Vec<_>>()
}

pub(crate) fn add_english_counter(
    s: String,
    query: &mut Query,
    keys: &mut Option<KeyHandler>,
    counter_name: String,
) {
    let mut full = s.encode_utf16().collect::<Vec<_>>();
    full.push(0);
    if query.add_english_counter(&counter_name, full) {
        *keys = Some(KeyHandler::new(counter_name));
    }
}
<|endoftext|>


<commit_before>//! Basic symbolic computation system.

pub use utils::symbolic::univariate_fn::UnivariateFn;
pub use utils::symbolic::bivariate_fn::BivariateFn;
pub use utils::symbolic::deriv::{Deriv, deriv, DerivU, deriv_u, DerivV, deriv_v};
pub use utils::symbolic::comp::{SymComp, comp};
pub use utils::symbolic::mult::{SymMult, mult};
pub use utils::symbolic::add::{SymAdd, add};
pub use utils::symbolic::sub::{SymSub, sub};
pub use utils::symbolic::neg::{SymNeg, neg};
pub use utils::symbolic::t::{T, t};
pub use utils::symbolic::u::{U, u};
pub use utils::symbolic::v::{V, v};
pub use utils::symbolic::sin::{Sin, sin};
pub use utils::symbolic::cos::{Cos, cos};
pub use utils::symbolic::exp::{Exp, exp};
pub use utils::symbolic::poly::{Poly1, t1,
                                Poly2, t2,
                                Poly3, t3,
                                Poly4, t4,
                                Poly5, t5,
                                Poly6, t6};

mod ops;
mod univariate_fn;
mod bivariate_fn;
mod t;
mod u;
mod v;
mod deriv;
mod comp;
mod mult;
mod add;
mod sub;
mod neg;
mod consts;
mod sin;
mod cos;
mod exp;
mod poly;

#[cfg(test)]
mod test;
<commit_msg>tests build under new rustc<commit_after>//! Basic symbolic computation system.

pub use utils::symbolic::univariate_fn::UnivariateFn;
pub use utils::symbolic::bivariate_fn::BivariateFn;
pub use utils::symbolic::deriv::{Deriv, deriv, DerivU, deriv_u, DerivV, deriv_v};
pub use utils::symbolic::comp::{SymComp, comp};
pub use utils::symbolic::mult::{SymMult, mult};
pub use utils::symbolic::add::{SymAdd, add};
pub use utils::symbolic::sub::{SymSub, sub};
pub use utils::symbolic::neg::{SymNeg, neg};
pub use utils::symbolic::t::{T, t};
pub use utils::symbolic::u::{U, u};
pub use utils::symbolic::v::{V, v};
pub use utils::symbolic::sin::{Sin, sin};
pub use utils::symbolic::cos::{Cos, cos};
pub use utils::symbolic::exp::{Exp, exp};
pub use utils::symbolic::poly::{Poly1, t1,
                                Poly2, t2,
                                Poly3, t3,
                                Poly4, t4,
                                Poly5, t5,
                                Poly6, t6};

mod ops;
mod univariate_fn;
#[allow(missing_doc)]
pub mod bivariate_fn;
mod t;
mod u;
mod v;
mod deriv;
mod comp;
mod mult;
mod add;
mod sub;
mod neg;
mod consts;
mod sin;
mod cos;
mod exp;
mod poly;

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Passwd RFILE RFILE's derefer dgid duid groupname

use uucore::display::Quotable;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::format_usage;
use uucore::perms::{chown_base, options, IfFrom};

use uucore::error::{FromIo, UResult, USimpleError};

use clap::{crate_version, Arg, ArgMatches, Command};

use std::fs;
use std::os::unix::fs::MetadataExt;

static ABOUT: &str = "change file owner and group";

const USAGE: &str = "\
    {} [OPTION]... [OWNER][:[GROUP]] FILE...
    {} [OPTION]... --reference=RFILE FILE...";

fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
    let filter = if let Some(spec) = matches.value_of(options::FROM) {
        match parse_spec(spec, ':')? {
            (Some(uid), None) => IfFrom::User(uid),
            (None, Some(gid)) => IfFrom::Group(gid),
            (Some(uid), Some(gid)) => IfFrom::UserGroup(uid, gid),
            (None, None) => IfFrom::All,
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(options::REFERENCE) {
        let meta = fs::metadata(&file)
            .map_err_context(|| format!("failed to get attributes of {}", file.quote()))?;
        dest_gid = Some(meta.gid());
        dest_uid = Some(meta.uid());
    } else {
        let (u, g) = parse_spec(matches.value_of(options::ARG_OWNER).unwrap(), ':')?;
        dest_uid = u;
        dest_gid = g;
    }
    Ok((dest_gid, dest_uid, filter))
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    chown_base(
        uu_app(),
        args,
        options::ARG_OWNER,
        parse_gid_uid_and_filter,
        false,
    )
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::HELP)
                .long(options::HELP)
                .help("Print help information."),
        )
        .arg(
            Arg::new(options::verbosity::CHANGES)
                .short('c')
                .long(options::verbosity::CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(
            Arg::new(options::dereference::DEREFERENCE)
                .long(options::dereference::DEREFERENCE)
                .help(
                    "affect the referent of each symbolic link (this is the default), \
                    rather than the symbolic link itself",
                ),
        )
        .arg(
            Arg::new(options::dereference::NO_DEREFERENCE)
                .short('h')
                .long(options::dereference::NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file \
                    (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::new(options::FROM)
                .long(options::FROM)
                .help(
                    "change the owner and/or group of each file only if its \
                    current owner and/or group match those specified here. \
                    Either may be omitted, in which case a match is not required \
                    for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::new(options::preserve_root::PRESERVE)
                .long(options::preserve_root::PRESERVE)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::new(options::preserve_root::NO_PRESERVE)
                .long(options::preserve_root::NO_PRESERVE)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::new(options::verbosity::QUIET)
                .long(options::verbosity::QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(options::RECURSIVE)
                .short('R')
                .long(options::RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::new(options::REFERENCE)
                .long(options::REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(
            Arg::new(options::verbosity::SILENT)
                .short('f')
                .long(options::verbosity::SILENT),
        )
        .arg(
            Arg::new(options::traverse::TRAVERSE)
                .short(options::traverse::TRAVERSE.chars().next().unwrap())
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::new(options::traverse::EVERY)
                .short(options::traverse::EVERY.chars().next().unwrap())
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::new(options::traverse::NO_TRAVERSE)
                .short(options::traverse::NO_TRAVERSE.chars().next().unwrap())
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
        )
        .arg(
            Arg::new(options::verbosity::VERBOSE)
                .long(options::verbosity::VERBOSE)
                .short('v')
                .help("output a diagnostic for every file processed"),
        )
}

/// Parse the owner/group specifier string into a user ID and a group ID.
///
/// The `spec` can be of the form:
///
/// * `"owner:group"`,
/// * `"owner"`,
/// * `":group"`,
///
/// and the owner or group can be specified either as an ID or a
/// name. The `sep` argument specifies which character to use as a
/// separator between the owner and group; calling code should set
/// this to `':'`.
fn parse_spec(spec: &str, sep: char) -> UResult<(Option<u32>, Option<u32>)> {
    assert!(['.', ':'].contains(&sep));
    let mut args = spec.splitn(2, sep);
    let user = args.next().unwrap_or("");
    let group = args.next().unwrap_or("");

    let uid = if !user.is_empty() {
        Some(match Passwd::locate(user) {
            Ok(u) => u.uid, // We have been able to get the uid
            Err(_) =>
            // we have NOT been able to find the uid
            // but we could be in the case where we have user.group
            {
                if spec.contains('.') && !spec.contains(':') && sep == ':' {
                    // but the input contains a '.' but not a ':'
                    // we might have something like username.groupname
                    // So, try to parse it this way
                    return parse_spec(spec, '.');
                } else {
                    // It's possible that the `user` string contains a
                    // numeric user ID, in which case, we respect that.
                    match user.parse() {
                        Ok(uid) => uid,
                        Err(_) => {
                            return Err(USimpleError::new(
                                1,
                                format!("invalid user: {}", spec.quote()),
                            ))
                        }
                    }
                }
            }
        })
    } else {
        None
    };
    let gid = if !group.is_empty() {
        Some(match Group::locate(group) {
            Ok(g) => g.gid,
            Err(_) => match group.parse() {
                Ok(gid) => gid,
                Err(e) => {
                    eprintln!("error {}, user {}, group {}, uid {:?}", e, user, group, uid);
                    return Err(USimpleError::new(
                        1,
                        format!("invalid group: {}", spec.quote()),
                    ));
                }
            },
        })
    } else {
        None
    };
    Ok((uid, gid))
}

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

    #[test]
    fn test_parse_spec() {
        assert!(matches!(parse_spec(":", ':'), Ok((None, None))));
        assert!(matches!(parse_spec(".", ':'), Ok((None, None))));
        assert!(matches!(parse_spec(".", '.'), Ok((None, None))));
        assert!(format!("{}", parse_spec("::", ':').err().unwrap()).starts_with("invalid group: "));
        assert!(format!("{}", parse_spec("..", ':').err().unwrap()).starts_with("invalid group: "));
    }

    /// Test for parsing IDs that don't correspond to a named user or group.
    #[test]
    fn test_parse_spec_nameless_ids() {
        // This assumes that there is no named user with ID 12345.
        assert!(matches!(parse_spec("12345", ':'), Ok((Some(12345), None))));
        // This assumes that there is no named group with ID 54321.
        assert!(matches!(parse_spec(":54321", ':'), Ok((None, Some(54321)))));
        assert!(matches!(
            parse_spec("12345:54321", ':'),
            Ok((Some(12345), Some(54321)))
        ));
    }
}
<commit_msg>Revert "WIP Trying to diagnose 'invalid group: 1001:121' error in CI environment"<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Passwd RFILE RFILE's derefer dgid duid groupname

use uucore::display::Quotable;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::format_usage;
use uucore::perms::{chown_base, options, IfFrom};

use uucore::error::{FromIo, UResult, USimpleError};

use clap::{crate_version, Arg, ArgMatches, Command};

use std::fs;
use std::os::unix::fs::MetadataExt;

static ABOUT: &str = "change file owner and group";

const USAGE: &str = "\
    {} [OPTION]... [OWNER][:[GROUP]] FILE...
    {} [OPTION]... --reference=RFILE FILE...";

fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
    let filter = if let Some(spec) = matches.value_of(options::FROM) {
        match parse_spec(spec, ':')? {
            (Some(uid), None) => IfFrom::User(uid),
            (None, Some(gid)) => IfFrom::Group(gid),
            (Some(uid), Some(gid)) => IfFrom::UserGroup(uid, gid),
            (None, None) => IfFrom::All,
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(options::REFERENCE) {
        let meta = fs::metadata(&file)
            .map_err_context(|| format!("failed to get attributes of {}", file.quote()))?;
        dest_gid = Some(meta.gid());
        dest_uid = Some(meta.uid());
    } else {
        let (u, g) = parse_spec(matches.value_of(options::ARG_OWNER).unwrap(), ':')?;
        dest_uid = u;
        dest_gid = g;
    }
    Ok((dest_gid, dest_uid, filter))
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    chown_base(
        uu_app(),
        args,
        options::ARG_OWNER,
        parse_gid_uid_and_filter,
        false,
    )
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::HELP)
                .long(options::HELP)
                .help("Print help information."),
        )
        .arg(
            Arg::new(options::verbosity::CHANGES)
                .short('c')
                .long(options::verbosity::CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(
            Arg::new(options::dereference::DEREFERENCE)
                .long(options::dereference::DEREFERENCE)
                .help(
                    "affect the referent of each symbolic link (this is the default), \
                    rather than the symbolic link itself",
                ),
        )
        .arg(
            Arg::new(options::dereference::NO_DEREFERENCE)
                .short('h')
                .long(options::dereference::NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file \
                    (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::new(options::FROM)
                .long(options::FROM)
                .help(
                    "change the owner and/or group of each file only if its \
                    current owner and/or group match those specified here. \
                    Either may be omitted, in which case a match is not required \
                    for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::new(options::preserve_root::PRESERVE)
                .long(options::preserve_root::PRESERVE)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::new(options::preserve_root::NO_PRESERVE)
                .long(options::preserve_root::NO_PRESERVE)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::new(options::verbosity::QUIET)
                .long(options::verbosity::QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(options::RECURSIVE)
                .short('R')
                .long(options::RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::new(options::REFERENCE)
                .long(options::REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(
            Arg::new(options::verbosity::SILENT)
                .short('f')
                .long(options::verbosity::SILENT),
        )
        .arg(
            Arg::new(options::traverse::TRAVERSE)
                .short(options::traverse::TRAVERSE.chars().next().unwrap())
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::new(options::traverse::EVERY)
                .short(options::traverse::EVERY.chars().next().unwrap())
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::new(options::traverse::NO_TRAVERSE)
                .short(options::traverse::NO_TRAVERSE.chars().next().unwrap())
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
        )
        .arg(
            Arg::new(options::verbosity::VERBOSE)
                .long(options::verbosity::VERBOSE)
                .short('v')
                .help("output a diagnostic for every file processed"),
        )
}

/// Parse the owner/group specifier string into a user ID and a group ID.
///
/// The `spec` can be of the form:
///
/// * `"owner:group"`,
/// * `"owner"`,
/// * `":group"`,
///
/// and the owner or group can be specified either as an ID or a
/// name. The `sep` argument specifies which character to use as a
/// separator between the owner and group; calling code should set
/// this to `':'`.
fn parse_spec(spec: &str, sep: char) -> UResult<(Option<u32>, Option<u32>)> {
    assert!(['.', ':'].contains(&sep));
    let mut args = spec.splitn(2, sep);
    let user = args.next().unwrap_or("");
    let group = args.next().unwrap_or("");

    let uid = if !user.is_empty() {
        Some(match Passwd::locate(user) {
            Ok(u) => u.uid, // We have been able to get the uid
            Err(_) =>
            // we have NOT been able to find the uid
            // but we could be in the case where we have user.group
            {
                if spec.contains('.') && !spec.contains(':') && sep == ':' {
                    // but the input contains a '.' but not a ':'
                    // we might have something like username.groupname
                    // So, try to parse it this way
                    return parse_spec(spec, '.');
                } else {
                    // It's possible that the `user` string contains a
                    // numeric user ID, in which case, we respect that.
                    match user.parse() {
                        Ok(uid) => uid,
                        Err(_) => {
                            return Err(USimpleError::new(
                                1,
                                format!("invalid user: {}", spec.quote()),
                            ))
                        }
                    }
                }
            }
        })
    } else {
        None
    };
    let gid = if !group.is_empty() {
        Some(match Group::locate(group) {
            Ok(g) => g.gid,
            Err(_) => match group.parse() {
                Ok(gid) => gid,
                Err(_) => {
                    return Err(USimpleError::new(
                        1,
                        format!("invalid group: {}", spec.quote()),
                    ));
                }
            },
        })
    } else {
        None
    };
    Ok((uid, gid))
}

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

    #[test]
    fn test_parse_spec() {
        assert!(matches!(parse_spec(":", ':'), Ok((None, None))));
        assert!(matches!(parse_spec(".", ':'), Ok((None, None))));
        assert!(matches!(parse_spec(".", '.'), Ok((None, None))));
        assert!(format!("{}", parse_spec("::", ':').err().unwrap()).starts_with("invalid group: "));
        assert!(format!("{}", parse_spec("..", ':').err().unwrap()).starts_with("invalid group: "));
    }

    /// Test for parsing IDs that don't correspond to a named user or group.
    #[test]
    fn test_parse_spec_nameless_ids() {
        // This assumes that there is no named user with ID 12345.
        assert!(matches!(parse_spec("12345", ':'), Ok((Some(12345), None))));
        // This assumes that there is no named group with ID 54321.
        assert!(matches!(parse_spec(":54321", ':'), Ok((None, Some(54321)))));
        assert!(matches!(
            parse_spec("12345:54321", ':'),
            Ok((Some(12345), Some(54321)))
        ));
    }
}
<|endoftext|>


<commit_before>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use serde_json;
use serde::de::DeserializeOwned;

use reqwest::Client;
use reqwest::header::UserAgent;

use pipeliner::Pipeline;

use std::io::Read;
use std::collections::HashMap;

use esr_errors::Result;

// QUIZ: Explain `'static` in this context.
pub trait EsrFromMulti: EsrFrom + Send + 'static {
    type Inner: Clone;
    type Inner2: Clone;

    fn from_url_multi(url: &str, multi_page: bool) -> Result<Self> {
        let url = url.to_string();

        let mut initial_self = Self::from_url(&url)?;
        let total = initial_self.total_from_meta()?;

        // per_page=100 is the maximum number allowed.
        // If total > 100, GET all pages and append all results to initial_self inner vec
        if multi_page && total > 100 {
            let num_pages = (total as f64 / 100.0).ceil() as usize;

            // with_threads() is provided by the pipeliner::Pipeline trait
            let more_pages = (2..=num_pages)
                .map(move |page| url.clone() + &format!("&page={}", page))
                .with_threads(8)
                .map(|page_url| Self::from_url(&page_url));

            for page_res in more_pages {
                let page = page_res?;
                initial_self.get_inner_mut().extend_from_slice(&*page.get_inner());

                // If inner2 exists
                match (initial_self.get_inner2_mut_opt(), page.get_inner2_opt()) {
                    (Some(initial_inner2_mut), Some(page_inner2)) => initial_inner2_mut.extend_from_slice(&*page_inner2),
                    (Some(_), None) | (None, Some(_)) => Err("Wrong trait implementation!")?,
                    (None, None) => (),
                }
            }

        }

        if multi_page && initial_self.get_inner().len() != total {
            Err("Total no. of results does not match total reported")?;
        }

        if let Some(inner2) = initial_self.get_inner2_opt() {
            if inner2.len() != initial_self.get_inner().len() {
                Err("Inner/Inner2 length mismatch")?;
            }
        }

        Ok(initial_self)
    }

    fn total_from_meta(&self) -> Result<usize> {
        let num = self.get_meta().get("total").ok_or("total num of dependants missing")?;
        Ok(*num)
    }

    fn get_meta(&self) -> &HashMap<String, usize>;
    fn get_inner(&self) -> &Vec<Self::Inner>;
    fn get_inner_mut(&mut self) -> &mut Vec<Self::Inner>;

    fn get_inner2_opt(&self) -> Option<&Vec<Self::Inner2>> {
        None
    }

    fn get_inner2_mut_opt(&mut self) -> Option<&mut Vec<Self::Inner2>> {
        None
    }
}

pub trait EsrFrom: Sized + DeserializeOwned {
    // url=id by default
    fn url_from_id(id: &str) -> String {
        String::from(id)
    }

    fn url_from_id_and_token(id: &str, token: &str) -> String {
        let url = Self::url_from_id(id);
        if url.find('?').is_some() {
            url + "&access_token=" + token
        } else {
            url + "?access_token=" + token
        }
    }

    fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
        let client = Client::builder().build()?;

        // Creating an outgoing request.
        let mut resp = client.get(url)
            .header(UserAgent::new("cargo-esr/0.1"))
            .send()?;

        // Read the Response.
        let mut buf = Vec::with_capacity(256 * 1024);
        resp.read_to_end(&mut buf)?;
        Ok(buf)
    }

    fn bytes_from_id(id: &str) -> Result<Vec<u8>> {
        Self::bytes_from_url(&Self::url_from_id(id))
    }

    fn bytes_from_id_with_token(id: &str, token: &str) -> Result<Vec<u8>> {
        Self::bytes_from_url(&Self::url_from_id_and_token(id, token))
    }

    fn from_bytes(bytes: &[u8]) -> Result<Self> {
        // Deserialize
        let info = serde_json::from_slice(bytes)?;
        Ok(info)
    }

    fn from_url(url: &str) -> Result<Self> {
        let bytes = Self::bytes_from_url(url)?;
        Self::from_bytes(&*bytes)
    }

    fn from_id(id: &str) -> Result<Self> {
        Self::from_url(&Self::url_from_id(id))
    }

    fn from_id_with_token(id: &str, token: &str) -> Result<Self> {
        Self::from_url(&Self::url_from_id_and_token(id, token))
    }
}

#[derive(Deserialize)]
pub struct DefEsrFrom;
impl EsrFrom for DefEsrFrom {}
<commit_msg>esr_from: Remove old comment<commit_after>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use serde_json;
use serde::de::DeserializeOwned;

use reqwest::Client;
use reqwest::header::UserAgent;

use pipeliner::Pipeline;

use std::io::Read;
use std::collections::HashMap;

use esr_errors::Result;

pub trait EsrFromMulti: EsrFrom + Send + 'static {
    type Inner: Clone;
    type Inner2: Clone;

    fn from_url_multi(url: &str, multi_page: bool) -> Result<Self> {
        let url = url.to_string();

        let mut initial_self = Self::from_url(&url)?;
        let total = initial_self.total_from_meta()?;

        // per_page=100 is the maximum number allowed.
        // If total > 100, GET all pages and append all results to initial_self inner vec
        if multi_page && total > 100 {
            let num_pages = (total as f64 / 100.0).ceil() as usize;

            // with_threads() is provided by the pipeliner::Pipeline trait
            let more_pages = (2..=num_pages)
                .map(move |page| url.clone() + &format!("&page={}", page))
                .with_threads(8)
                .map(|page_url| Self::from_url(&page_url));

            for page_res in more_pages {
                let page = page_res?;
                initial_self.get_inner_mut().extend_from_slice(&*page.get_inner());

                // If inner2 exists
                match (initial_self.get_inner2_mut_opt(), page.get_inner2_opt()) {
                    (Some(initial_inner2_mut), Some(page_inner2)) => initial_inner2_mut.extend_from_slice(&*page_inner2),
                    (Some(_), None) | (None, Some(_)) => Err("Wrong trait implementation!")?,
                    (None, None) => (),
                }
            }

        }

        if multi_page && initial_self.get_inner().len() != total {
            Err("Total no. of results does not match total reported")?;
        }

        if let Some(inner2) = initial_self.get_inner2_opt() {
            if inner2.len() != initial_self.get_inner().len() {
                Err("Inner/Inner2 length mismatch")?;
            }
        }

        Ok(initial_self)
    }

    fn total_from_meta(&self) -> Result<usize> {
        let num = self.get_meta().get("total").ok_or("total num of dependants missing")?;
        Ok(*num)
    }

    fn get_meta(&self) -> &HashMap<String, usize>;
    fn get_inner(&self) -> &Vec<Self::Inner>;
    fn get_inner_mut(&mut self) -> &mut Vec<Self::Inner>;

    fn get_inner2_opt(&self) -> Option<&Vec<Self::Inner2>> {
        None
    }

    fn get_inner2_mut_opt(&mut self) -> Option<&mut Vec<Self::Inner2>> {
        None
    }
}

pub trait EsrFrom: Sized + DeserializeOwned {
    // url=id by default
    fn url_from_id(id: &str) -> String {
        String::from(id)
    }

    fn url_from_id_and_token(id: &str, token: &str) -> String {
        let url = Self::url_from_id(id);
        if url.find('?').is_some() {
            url + "&access_token=" + token
        } else {
            url + "?access_token=" + token
        }
    }

    fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
        let client = Client::builder().build()?;

        // Creating an outgoing request.
        let mut resp = client.get(url)
            .header(UserAgent::new("cargo-esr/0.1"))
            .send()?;

        // Read the Response.
        let mut buf = Vec::with_capacity(256 * 1024);
        resp.read_to_end(&mut buf)?;
        Ok(buf)
    }

    fn bytes_from_id(id: &str) -> Result<Vec<u8>> {
        Self::bytes_from_url(&Self::url_from_id(id))
    }

    fn bytes_from_id_with_token(id: &str, token: &str) -> Result<Vec<u8>> {
        Self::bytes_from_url(&Self::url_from_id_and_token(id, token))
    }

    fn from_bytes(bytes: &[u8]) -> Result<Self> {
        // Deserialize
        let info = serde_json::from_slice(bytes)?;
        Ok(info)
    }

    fn from_url(url: &str) -> Result<Self> {
        let bytes = Self::bytes_from_url(url)?;
        Self::from_bytes(&*bytes)
    }

    fn from_id(id: &str) -> Result<Self> {
        Self::from_url(&Self::url_from_id(id))
    }

    fn from_id_with_token(id: &str, token: &str) -> Result<Self> {
        Self::from_url(&Self::url_from_id_and_token(id, token))
    }
}

#[derive(Deserialize)]
pub struct DefEsrFrom;
impl EsrFrom for DefEsrFrom {}
<|endoftext|>


<commit_before>use std::fmt;

// TODO: figure out how to use failure for error (or some other pattern)
#[derive(Debug)]
pub enum Error {
    NotAnInstruction,
    LongInstruction,
}

/// FlowMeta is metadata that describes code flow for an instruction.
///
/// The metadata is packed into a single byte, with the expectation that,
///  there may be one `FlowMeta` instance for each (code) offset in a program.
/// However, the you should not be worried about the representation, just the interface.
#[derive(Debug, Clone)]
pub struct FlowMeta(u8);

impl FlowMeta {
    pub fn zero() -> FlowMeta {
        FlowMeta(0x0)
    }

    /// Create a new FlowMeta.
    ///
    /// Args:
    ///   - insn_length: size of instruction, or 0 if not an instruction, or 0xF if 0xF or larger.
    ///   - does_fallthrough: is there a fallthrough code flow to the next instruction?
    ///   - has_xrefs_from: are there code xrefs from this instruction (non-fallthrough)?
    pub fn new(insn_length: u8, does_fallthrough: bool, has_xrefs_from: bool) -> FlowMeta {
        let len = if insn_length >= 0xF {
            // instrunction length too long
            0x0F
        } else if insn_length == 0x0 {
            // not an instruction
            0x00
        } else {
            // good flow
            insn_length & 0x0F
        };

        let fallthrough = if does_fallthrough {
            0b0001_0000
        } else {
            0b0000_0000
        };

        let xfrom = if has_xrefs_from {
            0b0010_0000
        } else {
            0b0000_0000
        };

        FlowMeta(len | fallthrough | xfrom)
    }

    /// Fetch the cached length of the instruction.
    ///
    /// If longer than 14 bytes, then will return `Error::LongInstruction` and you'll have to decode
    ///  the instruction yourself.
    ///
    /// Errors:
    ///   - NotAnInstruction
    ///   - LongInstruction
    ///
    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    /// assert_eq!(FlowMeta::new(0x01, true, true).get_insn_length().unwrap(),
    ///            0x01);
    /// assert!(matches!(FlowMeta::new(0x00, true, true).get_insn_length().err().unwrap(),
    ///                  Error::NotAnInstruction));
    /// assert!(matches!(FlowMeta::new(0x0F, true, true).get_insn_length().err().unwrap(),
    ///                  Error::LongInstruction));
    /// ```
    pub fn get_insn_length(&self) -> Result<u8, Error> {
        let v = self.0 & 0b0000_1111;
        match v {
            0x00 => Err(Error::NotAnInstruction),
            0x0F => Err(Error::LongInstruction),
            v @ _ => Ok(v)
        }
    }

    pub fn is_insn(&self) -> bool {
        self.0 & 0b0000_1111 != 0
    }

    /// Does the instruction fallthrough?
    pub fn does_fallthrough(&self) -> bool {
        self.0 & 0b0001_0000 > 0
    }

    /// Does the instruction have flow xrefs from it?
    /// This does not include the fallthrough flow.
    pub fn has_xrefs_from(&self) -> bool {
        self.0 & 0b0010_0000 > 0
    }

    /// Does the instruction have flow xrefs to it?
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// assert_eq!(FlowMeta::new(0x01, false, false).has_xrefs_to(), false);
    /// ```
    pub fn has_xrefs_to(&self) -> bool {
        self.0 & 0b0100_0000 > 0
    }

    /// Set the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::new(0x01, false, false);
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    /// ```
    pub fn set_xrefs_to(&mut self) {
        self.0 = self.0 | 0b0100_0000;
    }

    /// Unset the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::new(0x01, false, false);
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    ///
    /// m.unset_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), false);
    /// ```
    pub fn unset_xrefs_to(&mut self) {
        self.0 = self.0 & 0b1011_1111
    }
}

impl fmt::Display for FlowMeta {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FlowMeta{{length: {}, fallthrough: {}, xrefs to: {}, xrefs from: {}}}",
               match self.get_insn_length() {
                   Ok(v) => format!("0x{:x}", v),
                   Err(Error::LongInstruction) => ">=0xF".to_string(),
                   Err(Error::NotAnInstruction) => "not an instruction".to_string(),
               },
               self.does_fallthrough(),
               self.has_xrefs_to(),
               self.has_xrefs_from())
    }
}
<commit_msg>flowmeta: implement mutators<commit_after>use std::fmt;

// TODO: figure out how to use failure for error (or some other pattern)
#[derive(Debug)]
pub enum Error {
    NotAnInstruction,
    LongInstruction,
}

/// FlowMeta is metadata that describes code flow for an instruction.
///
/// The metadata is packed into a single byte, with the expectation that,
///  there may be one `FlowMeta` instance for each (code) offset in a program.
/// However, the you should not be worried about the representation, just the interface.
#[derive(Debug, Clone)]
pub struct FlowMeta(u8);

impl FlowMeta {
    // layout:
    //
    //     +-+-+-+-+-+-+-+-+
    //     |A|B|C|D|   E   |
    //     +-+-+-+-+-+-+-+-+
    //
    //  A - unused
    //  B - has xrefs to
    //  C - has xrefs from
    //  D - does fallthrough
    //  E - insn size

    pub fn zero() -> FlowMeta {
        FlowMeta(0x0)
    }

    /// Create a new FlowMeta.
    ///
    /// Args:
    ///   - insn_length: size of instruction, or 0 if not an instruction, or 0xF if 0xF or larger.
    ///   - does_fallthrough: is there a fallthrough code flow to the next instruction?
    ///   - has_xrefs_from: are there code xrefs from this instruction (non-fallthrough)?
    pub fn new(insn_length: u8, does_fallthrough: bool, has_xrefs_from: bool) -> FlowMeta {
        let len = if insn_length >= 0xF {
            // instrunction length too long
            0x0F
        } else if insn_length == 0x0 {
            // not an instruction
            0x00
        } else {
            // good flow
            insn_length & 0x0F
        };

        let fallthrough = if does_fallthrough {
            0b0001_0000
        } else {
            0b0000_0000
        };

        let xfrom = if has_xrefs_from {
            0b0010_0000
        } else {
            0b0000_0000
        };

        FlowMeta(len | fallthrough | xfrom)
    }

    /// Fetch the cached length of the instruction.
    ///
    /// If longer than 14 bytes, then will return `Error::LongInstruction` and you'll have to decode
    ///  the instruction yourself.
    ///
    /// Errors:
    ///   - NotAnInstruction
    ///   - LongInstruction
    ///
    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    /// assert_eq!(FlowMeta::new(0x01, true, true).get_insn_length().unwrap(),
    ///            0x01);
    /// assert!(matches!(FlowMeta::new(0x00, true, true).get_insn_length().err().unwrap(),
    ///                  Error::NotAnInstruction));
    /// assert!(matches!(FlowMeta::new(0x0F, true, true).get_insn_length().err().unwrap(),
    ///                  Error::LongInstruction));
    /// ```
    pub fn get_insn_length(&self) -> Result<u8, Error> {
        let v = self.0 & 0b0000_1111;
        match v {
            0x00 => Err(Error::NotAnInstruction),
            0x0F => Err(Error::LongInstruction),
            v @ _ => Ok(v)
        }
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    ///
    /// m.set_insn_length(0);
    /// assert_eq!(m.is_insn(), false);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::NotAnInstruction));
    ///
    /// m.set_insn_length(1);
    /// assert_eq!(m.is_insn(), true);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x1);
    ///
    /// m.set_insn_length(2);
    /// assert_eq!(m.get_insn_length().unwrap(), 0x2);
    ///
    /// m.set_insn_length(0xE);
    /// assert_eq!(m.get_insn_length().unwrap(), 0xE);
    ///
    /// m.set_insn_length(0xF);
    /// assert_eq!(m.is_insn(), true);
    /// assert!(matches!(m.get_insn_length().err().unwrap(), Error::LongInstruction));
    /// ```
    pub fn set_insn_length(&mut self, length: u8) {
        let len = if length >= 0xF {
            // instrunction length too long
            0x0F
        } else if length == 0x0 {
            // not an instruction
            0x00
        } else {
            // good flow
            length & 0x0F
        };

        self.0 = (self.0 & 0b1111_0000) | len;
    }

    pub fn is_insn(&self) -> bool {
        self.0 & 0b0000_1111 != 0
    }

    /// Does the instruction fallthrough?
    pub fn does_fallthrough(&self) -> bool {
        self.0 & 0b0001_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.does_fallthrough(), false);
    ///
    /// m.set_fallthrough();
    /// assert_eq!(m.does_fallthrough(), true);
    /// ```
    pub fn set_fallthrough(&mut self) {
        self.0 = self.0 | 0b0001_0000;
    }

    /// Does the instruction have flow xrefs from it?
    /// This does not include the fallthrough flow.
    pub fn has_xrefs_from(&self) -> bool {
        self.0 & 0b0010_0000 > 0
    }

    /// ```
    /// use matches::matches;
    /// use lancelot::flowmeta::*;
    ///
    /// let mut m = FlowMeta::zero();
    /// assert_eq!(m.has_xrefs_from(), false);
    ///
    /// m.set_xrefs_from();
    /// assert_eq!(m.has_xrefs_from(), true);
    /// ```
    pub fn set_xrefs_from(&mut self) {
        self.0 = self.0 | 0b0010_0000;
    }

    /// Does the instruction have flow xrefs to it?
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// assert_eq!(FlowMeta::new(0x01, false, false).has_xrefs_to(), false);
    /// ```
    pub fn has_xrefs_to(&self) -> bool {
        self.0 & 0b0100_0000 > 0
    }

    /// Set the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::new(0x01, false, false);
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    /// ```
    pub fn set_xrefs_to(&mut self) {
        self.0 = self.0 | 0b0100_0000;
    }

    /// Unset the bit indicating that there are flow xrefs to this instruction.
    ///
    /// ```
    /// use lancelot::flowmeta::*;
    /// let mut m = FlowMeta::new(0x01, false, false);
    /// assert_eq!(m.has_xrefs_to(), false);
    ///
    /// m.set_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), true);
    ///
    /// m.unset_xrefs_to();
    /// assert_eq!(m.has_xrefs_to(), false);
    /// ```
    pub fn unset_xrefs_to(&mut self) {
        self.0 = self.0 & 0b1011_1111
    }
}

impl fmt::Display for FlowMeta {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FlowMeta{{length: {}, fallthrough: {}, xrefs to: {}, xrefs from: {}}}",
               match self.get_insn_length() {
                   Ok(v) => format!("0x{:x}", v),
                   Err(Error::LongInstruction) => ">=0xF".to_string(),
                   Err(Error::NotAnInstruction) => "not an instruction".to_string(),
               },
               self.does_fallthrough(),
               self.has_xrefs_to(),
               self.has_xrefs_from())
    }
}
<|endoftext|>


<commit_before>extern crate find_folder;

use screen::{self, Screen};

use piston_window::{self, PistonWindow};

type Screens = Vec<Box<screen::Screen>>;

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

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

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

        let screens = &mut self.screens;

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

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

fn handle_input(screens: &mut Screens,
                input: &piston_window::Input,
                window: &PistonWindow,
                context: &mut screen::Context) {
    for action in last(screens).on_input(&input, &window, context) {
        match action {
            screen::InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            screen::InputResult::PopScreen => {
                screens.pop();
            }
        }
    }
}
<commit_msg>Comment has been removed<commit_after>extern crate find_folder;

use screen::{self, Screen};

use piston_window::{self, PistonWindow};

type Screens = Vec<Box<screen::Screen>>;

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

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

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

        let screens = &mut self.screens;

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

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

fn handle_input(screens: &mut Screens,
                input: &piston_window::Input,
                window: &PistonWindow,
                context: &mut screen::Context) {
    for action in last(screens).on_input(&input, &window, context) {
        match action {
            screen::InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            screen::InputResult::PopScreen => {
                screens.pop();
            }
        }
    }
}
<|endoftext|>


<commit_before>use structs::{CliError, Config, Member, Team, PublicKey};
use std;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use toml;
use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;

pub struct GithubClient {
    client: reqwest::Client,
    pub conf: Config
}

impl GithubClient {
    pub fn new(configpath:&str) -> Result<GithubClient, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        let config = toml::from_str::<Config>(contents.as_str()).unwrap();
        match std::env::var("SSL_CERT_FILE") {
            Ok(_) => (),
            Err(_) => std::env::set_var("SSL_CERT_FILE", config.cert_path.clone()),
        }
        let client = reqwest::Client::new()?;
        Ok(GithubClient {client:client, conf:config})
    }

    fn get_cache_path(url:&String) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        path
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let (_,members) = self.get_team_members()?;
        Ok(members.contains_key(user))
    }

    pub fn get_team_members(&self) -> Result<(Team,HashMap<String,Member>),CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            Ok((team.clone(),self.get_members(team.id)?))
        } else {
            Err(CliError::from(std::io::Error::new(std::io::ErrorKind::NotFound, "Team not found")))
        }
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<HashMap<String,Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        let mut member_map = HashMap::new();
        for member in members { member_map.insert(member.login.clone(), member); }
        Ok(member_map)
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}
<commit_msg>Simplify conditional block<commit_after>use structs::{CliError, Config, Member, Team, PublicKey};
use std;
use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

use toml;
use glob::glob;
use reqwest;
use reqwest::header::Authorization;
use serde_json;

pub struct GithubClient {
    client: reqwest::Client,
    pub conf: Config
}

impl GithubClient {
    pub fn new(configpath:&str) -> Result<GithubClient, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        let config = toml::from_str::<Config>(contents.as_str()).unwrap();
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", config.cert_path.as_str());
        }
        let client = reqwest::Client::new()?;
        Ok(GithubClient {client:client, conf:config})
    }

    fn get_cache_path(url:&String) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        path
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let (_,members) = self.get_team_members()?;
        Ok(members.contains_key(user))
    }

    pub fn get_team_members(&self) -> Result<(Team,HashMap<String,Member>),CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            Ok((team.clone(),self.get_members(team.id)?))
        } else {
            Err(CliError::from(std::io::Error::new(std::io::ErrorKind::NotFound, "Team not found")))
        }
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<HashMap<String,Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        let mut member_map = HashMap::new();
        for member in members { member_map.insert(member.login.clone(), member); }
        Ok(member_map)
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}
<|endoftext|>


<commit_before>extern crate builtins;

use std::str::Chars;

pub fn read(command_line: &str) {
	let mut tree = parse_expression(&mut command_line.chars());

	tree.execute_command();
}

fn parse_expression(char_it: &mut Chars) -> Command {
	let mut cmd = Command::new();

	let mut tokens_are_args = false;
	let mut in_leading_whitespace = true;
	let mut current_arg: Option<String> = None;

	while let Some(char) = char_it.next() {
		match char {
			'(' => cmd.params.push(Param::Cmd(parse_expression(char_it))),
			')' => return cmd,
			' ' | '\t' => { // TODO: add support for other types of whitespace
				if !in_leading_whitespace { // ignore leading whitespace
					tokens_are_args = true;
				} else if let Some(arg_str) = current_arg {
					current_arg = None;
					cmd.params.push(Param::Arg(arg_str));
				}
			},
			_ => {
				in_leading_whitespace = false;
				if tokens_are_args {
					match current_arg {
						Some(ref mut arg_str) => arg_str.push(char),
						None => {
							let mut arg_str = String::new();
							arg_str.push(char);
							current_arg = Option::Some(arg_str);
						},
					}
				} else {
					cmd.cmd.push(char) //TODO: use a &str instead by marking the first `_` byte, more efficient
				}
			},
		}
	}

	cmd
}

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

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

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

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

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

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

	String::from_utf8(output.stdout).unwrap()
}
<commit_msg>Replace half-assed tokenization algorithm by a FSM<commit_after>extern crate builtins;

use std::str::Chars;

pub fn read(command_line: &str) {
	match control_machine(&mut command_line.chars()) {
		Ok(mut tree) => tree.execute_command(),
		Err(err) => println!("{}", err),
	}

}

#[derive(PartialEq, Copy, Clone)] // this enum takes 1B therefore copying it is better than having a 4B pointer (on 32bit machines) or a 8B pointer (on 64 bit machines)
pub enum State {
	Start,
	StrArg,
	SubcommandEnd,
}

fn tokenize(char_it: &mut Chars) -> (Result<Command, &'static str>, State) { // uses a recursive automaton
	use self::State::*;
	let mut cmd = Command::new();

	let mut state = State::Start;

	loop {
		if let Some(curr_char) = char_it.next() {
			match (state, curr_char) {
				(Start, ')') => {
					state = SubcommandEnd;
					return (Ok(cmd), state);
				},
				(Start, ' ') | (Start, '\t') => {},
				(Start, '(') => {
					// do recursion
					let (res, recurState) = tokenize(char_it);
					if recurState != SubcommandEnd {
						panic!("ERROR");
					} else if let Err(_) = res {
						return (res, state);
					}
				},
				(Start, _) => {
					state = StrArg
					// create string
					// push character
				},

				(StrArg, ')') => {
					state = SubcommandEnd;
					return (Ok(cmd), state);
				},
				(StrArg, ' ') | (StrArg, '\t') => {
					state = Start;
					// append string to arg vector
				},
				(StrArg, _) => {
					//push character
				},

				(SubcommandEnd, _) => {
					unreachable!();
				},
			}
		} else {
			if state == StrArg {
				// append string to arg array
			}
			break;
		}
	}

	(Ok(cmd), state)
}

fn control_machine(char_it: &mut Chars) -> Result<Command, &'static str> {
	use self::State::*;

	let (res, state) = tokenize(char_it);

	if state != Start && state != StrArg {
		Err("There is an error")
	} else {
		res
	}
}

//TODO:
//struct Command(Vec<Param>);
//https://doc.rust-lang.org/book/structs.html

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

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

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

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

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

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

	String::from_utf8(output.stdout).unwrap()
}
<|endoftext|>