2015-01-10 21:00:15 +00:00
|
|
|
#![crate_name = "sync"]
|
2015-01-10 19:31:55 +00:00
|
|
|
|
2014-06-15 14:25:00 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2015-01-08 12:54:22 +00:00
|
|
|
#[path = "../common/util.rs"] #[macro_use] mod util;
|
2015-07-20 20:40:29 +00:00
|
|
|
#[cfg(windows)] #[path = "../common/wide.rs"] mod wide;
|
2014-06-20 12:44:35 +00:00
|
|
|
|
2014-08-15 22:53:23 +00:00
|
|
|
static NAME: &'static str = "sync";
|
|
|
|
static VERSION: &'static str = "1.0.0";
|
|
|
|
|
2014-06-20 12:44:35 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
mod platform {
|
|
|
|
use super::libc;
|
|
|
|
|
|
|
|
extern {
|
|
|
|
fn sync() -> libc::c_void;
|
|
|
|
}
|
|
|
|
|
2015-01-10 18:07:08 +00:00
|
|
|
pub unsafe fn do_sync() -> isize {
|
2014-06-20 12:44:35 +00:00
|
|
|
sync();
|
|
|
|
0
|
|
|
|
}
|
2014-06-15 14:25:00 +00:00
|
|
|
}
|
|
|
|
|
2014-06-20 12:44:35 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
mod platform {
|
2015-07-20 00:25:48 +00:00
|
|
|
extern crate winapi;
|
|
|
|
extern crate kernel32;
|
|
|
|
use std::{mem};
|
|
|
|
use std::fs::OpenOptions;
|
|
|
|
use std::io::{Write};
|
|
|
|
use std::os::windows::prelude::*;
|
2015-07-20 20:40:29 +00:00
|
|
|
use wide::{FromWide, ToWide};
|
2014-06-20 12:44:35 +00:00
|
|
|
|
|
|
|
unsafe fn flush_volume(name: &str) {
|
2015-07-20 00:25:48 +00:00
|
|
|
let name_wide = name.to_wide_null();
|
|
|
|
if kernel32::GetDriveTypeW(name_wide.as_ptr()) == winapi::DRIVE_FIXED {
|
2015-01-25 06:46:55 +00:00
|
|
|
let sliced_name = &name[..name.len() - 1]; // eliminate trailing backslash
|
2015-07-20 00:25:48 +00:00
|
|
|
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")
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
2014-09-24 05:28:07 +00:00
|
|
|
}
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 00:25:48 +00:00
|
|
|
unsafe fn find_first_volume() -> (String, winapi::HANDLE) {
|
|
|
|
let mut name: [winapi::WCHAR; winapi::MAX_PATH] = mem::uninitialized();
|
|
|
|
let handle = kernel32::FindFirstVolumeW(name.as_mut_ptr(), name.len() as winapi::DWORD);
|
|
|
|
if handle == winapi::INVALID_HANDLE_VALUE {
|
|
|
|
crash!(kernel32::GetLastError() as i32, "failed to find first volume");
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
2015-07-20 00:25:48 +00:00
|
|
|
(String::from_wide_null(&name), handle)
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn find_all_volumes() -> Vec<String> {
|
2015-07-20 00:25:48 +00:00
|
|
|
let (first_volume, next_volume_handle) = find_first_volume();
|
|
|
|
let mut volumes = vec![first_volume];
|
|
|
|
loop {
|
|
|
|
let mut name: [winapi::WCHAR; winapi::MAX_PATH] = mem::uninitialized();
|
|
|
|
if kernel32::FindNextVolumeW(
|
|
|
|
next_volume_handle, name.as_mut_ptr(), name.len() as winapi::DWORD
|
|
|
|
) == 0 {
|
|
|
|
match kernel32::GetLastError() {
|
|
|
|
winapi::ERROR_NO_MORE_FILES => {
|
|
|
|
kernel32::FindVolumeClose(next_volume_handle);
|
|
|
|
return volumes
|
|
|
|
},
|
|
|
|
err => crash!(err as i32, "failed to find next volume"),
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
2015-07-20 00:25:48 +00:00
|
|
|
} else {
|
|
|
|
volumes.push(String::from_wide_null(&name));
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-20 00:25:48 +00:00
|
|
|
pub unsafe fn do_sync() -> isize {
|
2014-06-20 12:44:35 +00:00
|
|
|
let volumes = find_all_volumes();
|
2015-07-20 00:25:48 +00:00
|
|
|
for vol in &volumes {
|
|
|
|
flush_volume(vol);
|
2014-06-20 12:44:35 +00:00
|
|
|
}
|
|
|
|
0
|
|
|
|
}
|
2014-06-15 14:25:00 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:48:07 +00:00
|
|
|
pub fn uumain(args: Vec<String>) -> i32 {
|
2015-05-21 18:42:42 +00:00
|
|
|
let mut opts = getopts::Options::new();
|
2014-06-15 14:25:00 +00:00
|
|
|
|
2015-05-21 18:42:42 +00:00
|
|
|
opts.optflag("h", "help", "display this help and exit");
|
|
|
|
opts.optflag("V", "version", "output version information and exit");
|
2014-06-15 14:25:00 +00:00
|
|
|
|
2015-05-21 18:42:42 +00:00
|
|
|
let matches = match opts.parse(&args[1..]) {
|
2014-06-15 14:25:00 +00:00
|
|
|
Ok(m) => { m }
|
2015-05-21 18:42:42 +00:00
|
|
|
_ => { help(&opts); return 1 }
|
2014-06-15 14:25:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if matches.opt_present("h") {
|
2015-05-21 18:42:42 +00:00
|
|
|
help(&opts);
|
2014-06-15 14:25:00 +00:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if matches.opt_present("V") {
|
|
|
|
version();
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2015-01-10 21:00:15 +00:00
|
|
|
sync();
|
2014-06-15 14:25:00 +00:00
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn version() {
|
2014-09-17 03:08:40 +00:00
|
|
|
println!("{} (uutils) {}", NAME, VERSION);
|
2014-06-15 14:25:00 +00:00
|
|
|
println!("The MIT License");
|
|
|
|
println!("");
|
|
|
|
println!("Author -- Alexander Fomin.");
|
|
|
|
}
|
|
|
|
|
2015-05-21 18:42:42 +00:00
|
|
|
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));
|
2014-06-15 14:25:00 +00:00
|
|
|
}
|
2014-06-20 12:44:35 +00:00
|
|
|
|
2015-01-10 21:00:15 +00:00
|
|
|
fn sync() -> isize {
|
2014-06-20 12:44:35 +00:00
|
|
|
unsafe {
|
|
|
|
platform::do_sync()
|
|
|
|
}
|
2014-06-26 05:56:03 +00:00
|
|
|
}
|