mirror of
https://github.com/uutils/coreutils
synced 2024-12-22 19:13:25 +00:00
509a35ff7a
I switched over to the getopts crate on crates.io, instead of Rust's private implementation. This will allow coreutils to build for Rust 1.0. I'm splitting the updates into several commits for better reviewing.
187 lines
5.8 KiB
Rust
187 lines
5.8 KiB
Rust
#![crate_name = "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;
|
|
|
|
#[path = "../common/util.rs"] #[macro_use] mod util;
|
|
|
|
static NAME: &'static str = "sync";
|
|
static VERSION: &'static str = "1.0.0";
|
|
|
|
#[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 {
|
|
pub use super::libc;
|
|
use std::{mem, string};
|
|
use std::ptr::null;
|
|
|
|
extern "system" {
|
|
fn CreateFileA(lpFileName: *const libc::c_char,
|
|
dwDesiredAccess: libc::uint32_t,
|
|
dwShareMode: libc::uint32_t,
|
|
lpSecurityAttributes: *const libc::c_void, // *LPSECURITY_ATTRIBUTES
|
|
dwCreationDisposition: libc::uint32_t,
|
|
dwFlagsAndAttributes: libc::uint32_t,
|
|
hTemplateFile: *const libc::c_void) -> *const libc::c_void;
|
|
fn GetDriveTypeA(lpRootPathName: *const libc::c_char) -> libc::c_uint;
|
|
fn GetLastError() -> libc::uint32_t;
|
|
fn FindFirstVolumeA(lpszVolumeName: *mut libc::c_char,
|
|
cchBufferLength: libc::uint32_t) -> *const libc::c_void;
|
|
fn FindNextVolumeA(hFindVolume: *const libc::c_void,
|
|
lpszVolumeName: *mut libc::c_char,
|
|
cchBufferLength: libc::uint32_t) -> libc::c_int;
|
|
fn FindVolumeClose(hFindVolume: *const libc::c_void) -> libc::c_int;
|
|
fn FlushFileBuffers(hFile: *const libc::c_void) -> libc::c_int;
|
|
}
|
|
|
|
#[allow(unused_unsafe)]
|
|
unsafe fn flush_volume(name: &str) {
|
|
let name_buffer = name.to_c_str().as_ptr();
|
|
if 0x00000003 == GetDriveTypeA(name_buffer) { // DRIVE_FIXED
|
|
let sliced_name = &name[..name.len() - 1]; // eliminate trailing backslash
|
|
let sliced_name_buffer = sliced_name.to_c_str().as_ptr();
|
|
match CreateFileA(sliced_name_buffer,
|
|
0xC0000000, // GENERIC_WRITE
|
|
0x00000003, // FILE_SHARE_WRITE,
|
|
null(),
|
|
0x00000003, // OPEN_EXISTING
|
|
0,
|
|
null()) {
|
|
-1 => { // INVALID_HANDLE_VALUE
|
|
crash!(GetLastError(), "failed to create volume handle");
|
|
}
|
|
handle => {
|
|
if FlushFileBuffers(handle) == 0 {
|
|
crash!(GetLastError(), "failed to flush file buffer");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused_unsafe)]
|
|
unsafe fn find_first_volume() -> (String, *const libc::c_void) {
|
|
let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
|
|
match FindFirstVolumeA(name.as_mut_ptr(),
|
|
name.len() as libc::uint32_t) {
|
|
-1 => { // INVALID_HANDLE_VALUE
|
|
crash!(GetLastError(), "failed to find first volume");
|
|
}
|
|
handle => {
|
|
(string::raw::from_buf(name.as_ptr() as *const u8), handle)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused_unsafe)]
|
|
unsafe fn find_all_volumes() -> Vec<String> {
|
|
match find_first_volume() {
|
|
(first_volume, next_volume_handle) => {
|
|
let mut volumes = vec![first_volume];
|
|
loop {
|
|
let mut name: [libc::c_char; 260] = mem::uninitialized(); // MAX_PATH
|
|
match FindNextVolumeA(next_volume_handle,
|
|
name.as_mut_ptr(),
|
|
name.len() as libc::uint32_t) {
|
|
0 => {
|
|
match GetLastError() {
|
|
0x12 => { // ERROR_NO_MORE_FILES
|
|
FindVolumeClose(next_volume_handle); // ignore FindVolumeClose() failures
|
|
break;
|
|
}
|
|
err => {
|
|
crash!(err, "failed to find next volume");
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
volumes.push(string::raw::from_buf(name.as_ptr() as *const u8));
|
|
}
|
|
}
|
|
}
|
|
volumes
|
|
}
|
|
}
|
|
}
|
|
|
|
pub unsafe fn do_sync() -> int {
|
|
let volumes = find_all_volumes();
|
|
for vol in volumes.iter() {
|
|
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()
|
|
}
|
|
}
|