coreutils/src/sync/sync.rs

154 lines
4.1 KiB
Rust

#![crate_name = "uu_sync"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alexander Fomin <xander.fomin@ya.ru>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* Last synced with: sync (GNU coreutils) 8.13 */
extern crate getopts;
extern crate libc;
#[cfg(windows)]
#[macro_use]
extern crate uucore;
#[cfg(not(windows))]
extern crate uucore;
static NAME: &'static str = "sync";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[cfg(unix)]
mod platform {
use super::libc;
extern {
fn sync() -> libc::c_void;
}
pub unsafe fn do_sync() -> isize {
sync();
0
}
}
#[cfg(windows)]
mod platform {
extern crate winapi;
extern crate kernel32;
use std::{mem};
use std::fs::OpenOptions;
use std::os::windows::prelude::*;
use uucore::wide::{FromWide, ToWide};
use self::winapi::um::winbase;
use self::winapi::um::winnt;
use self::winapi::shared::minwindef;
use self::winapi::um::handleapi;
use self::winapi::shared::winerror;
unsafe fn flush_volume(name: &str) {
let name_wide = name.to_wide_null();
if kernel32::GetDriveTypeW(name_wide.as_ptr()) == winbase::DRIVE_FIXED {
let sliced_name = &name[..name.len() - 1]; // eliminate trailing backslash
match OpenOptions::new().write(true).open(sliced_name) {
Ok(file) => if kernel32::FlushFileBuffers(file.as_raw_handle()) == 0 {
crash!(kernel32::GetLastError() as i32, "failed to flush file buffer");
},
Err(e) => crash!(e.raw_os_error().unwrap_or(1), "failed to create volume handle")
}
}
}
unsafe fn find_first_volume() -> (String, winnt::HANDLE) {
let mut name: [winnt::WCHAR; minwindef::MAX_PATH] = mem::uninitialized();
let handle = kernel32::FindFirstVolumeW(name.as_mut_ptr(), name.len() as minwindef::DWORD);
if handle == handleapi::INVALID_HANDLE_VALUE {
crash!(kernel32::GetLastError() as i32, "failed to find first volume");
}
(String::from_wide_null(&name), handle)
}
unsafe fn find_all_volumes() -> Vec<String> {
let (first_volume, next_volume_handle) = find_first_volume();
let mut volumes = vec![first_volume];
loop {
let mut name: [winnt::WCHAR; minwindef::MAX_PATH] = mem::uninitialized();
if kernel32::FindNextVolumeW(
next_volume_handle, name.as_mut_ptr(), name.len() as minwindef::DWORD
) == 0 {
match kernel32::GetLastError() {
winerror::ERROR_NO_MORE_FILES => {
kernel32::FindVolumeClose(next_volume_handle);
return volumes
},
err => crash!(err as i32, "failed to find next volume"),
}
} else {
volumes.push(String::from_wide_null(&name));
}
}
}
pub unsafe fn do_sync() -> isize {
let volumes = find_all_volumes();
for vol in &volumes {
flush_volume(vol);
}
0
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
_ => { help(&opts); return 1 }
};
if matches.opt_present("h") {
help(&opts);
return 0
}
if matches.opt_present("V") {
version();
return 0
}
sync();
0
}
fn version() {
println!("{} (uutils) {}", NAME, VERSION);
println!("The MIT License");
println!("");
println!("Author -- Alexander Fomin.");
}
fn help(opts: &getopts::Options) {
let msg = format!("{0} {1}
Usage:
{0} [OPTION]
Force changed blocks to disk, update the super block.", NAME, VERSION);
print!("{}", opts.usage(&msg));
}
fn sync() -> isize {
unsafe {
platform::do_sync()
}
}