Convert several commands to use raw system calls instead of libc
functions
This commit is contained in:
parent
fcc8abb67b
commit
6963ba4a4b
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -121,17 +121,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hostname"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"match_cfg",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -166,22 +155,6 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "match_cfg"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.2.6",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.4.1"
|
version = "6.4.1"
|
||||||
@ -217,6 +190,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sc"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shitbox"
|
name = "shitbox"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -227,9 +206,8 @@ dependencies = [
|
|||||||
"clap_complete_nushell",
|
"clap_complete_nushell",
|
||||||
"clap_mangen",
|
"clap_mangen",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"hostname",
|
|
||||||
"libc",
|
"libc",
|
||||||
"num_cpus",
|
"sc",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
|
@ -12,9 +12,8 @@ clap_complete = "4.0"
|
|||||||
clap_complete_nushell = "0.1"
|
clap_complete_nushell = "0.1"
|
||||||
clap_mangen = "0.2"
|
clap_mangen = "0.2"
|
||||||
data-encoding = "2.3"
|
data-encoding = "2.3"
|
||||||
hostname = { version = "0.3", features = ["set"] }
|
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
num_cpus = "1.15"
|
sc = "0.2"
|
||||||
termcolor = "1.1"
|
termcolor = "1.1"
|
||||||
textwrap = { version = "0.16", default-features = false, features = ["smawk"] }
|
textwrap = { version = "0.16", default-features = false, features = ["smawk"] }
|
||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
|
53
src/cmd/expand/mod.rs
Normal file
53
src/cmd/expand/mod.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
use super::Cmd;
|
||||||
|
use clap::{Arg, ArgAction, Command, ValueHint};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Expand;
|
||||||
|
|
||||||
|
impl Cmd for Expand {
|
||||||
|
fn cli(&self) -> clap::Command {
|
||||||
|
Command::new("expand")
|
||||||
|
.about("convert tabs to spaces")
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.args([
|
||||||
|
Arg::new("file")
|
||||||
|
.num_args(1..)
|
||||||
|
.default_value("-")
|
||||||
|
.value_name("FILE")
|
||||||
|
.value_hint(ValueHint::FilePath),
|
||||||
|
Arg::new("initial")
|
||||||
|
.short('i')
|
||||||
|
.long("initial")
|
||||||
|
.help("do not convert tabs after non blanks")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("tabs")
|
||||||
|
.short('t')
|
||||||
|
.long("tabs")
|
||||||
|
.default_value("8")
|
||||||
|
.help(
|
||||||
|
"Specify the tab stops. The application shall ensure that \
|
||||||
|
the argument tablist consists of either a single positive \
|
||||||
|
decimal integer or a list of tabstops. If a single number \
|
||||||
|
is given, tabs shall be set that number of column positions \
|
||||||
|
apart instead of the default 8.",
|
||||||
|
)
|
||||||
|
.value_name("tablist")
|
||||||
|
.value_delimiter(',')
|
||||||
|
.num_args(1..),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let Some(matches) = matches else {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "no input").into());
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> Option<crate::Path> {
|
||||||
|
Some(crate::Path::UsrBin)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
|
use crate::unistd;
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
use std::{error::Error, io};
|
use std::{error::Error, io};
|
||||||
|
|
||||||
@ -24,14 +25,14 @@ impl Cmd for Hostname {
|
|||||||
fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>> {
|
fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>> {
|
||||||
let matches = matches.unwrap();
|
let matches = matches.unwrap();
|
||||||
if let Some(name) = matches.get_one::<String>("NAME") {
|
if let Some(name) = matches.get_one::<String>("NAME") {
|
||||||
hostname::set(name)?;
|
unistd::sethostname(name)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let hostname = hostname::get()?;
|
let hostname = unistd::gethostname()?;
|
||||||
if matches.get_flag("STRIP") {
|
if matches.get_flag("STRIP") {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
if let Some(s) = hostname.to_string_lossy().split('.').next() {
|
if let Some(s) = hostname.split('.').next() {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
@ -42,7 +43,7 @@ impl Cmd for Hostname {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", hostname.to_string_lossy());
|
println!("{hostname}");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
use crate::{args, mode::Parser};
|
use crate::{args, mode::Parser, stat};
|
||||||
use clap::{Arg, ArgMatches, Command};
|
use clap::{Arg, ArgMatches, Command};
|
||||||
use std::{error::Error, ffi::CString, io};
|
use std::{error::Error, io};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MkFifo;
|
pub struct MkFifo;
|
||||||
@ -46,11 +46,7 @@ impl Cmd for MkFifo {
|
|||||||
};
|
};
|
||||||
if let Some(files) = matches.get_many::<String>("file") {
|
if let Some(files) = matches.get_many::<String>("file") {
|
||||||
for f in files {
|
for f in files {
|
||||||
let fname = CString::new(f.as_str())?;
|
stat::mkfifo(f.as_str(), mode)?;
|
||||||
let res = unsafe { libc::mkfifo(fname.as_ptr(), mode) };
|
|
||||||
if res != 0 {
|
|
||||||
return Err(io::Error::last_os_error().into());
|
|
||||||
}
|
|
||||||
if matches.get_flag("verbose") {
|
if matches.get_flag("verbose") {
|
||||||
println!(
|
println!(
|
||||||
"{}: created pipe '{f}' with mode {mode:o}",
|
"{}: created pipe '{f}' with mode {mode:o}",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
use crate::{
|
use crate::{
|
||||||
args,
|
args,
|
||||||
mode::{get_umask, Parser},
|
mode::{get_umask, Parser}, stat,
|
||||||
};
|
};
|
||||||
use clap::{value_parser, Arg, ArgMatches, Command};
|
use clap::{value_parser, Arg, ArgMatches, Command};
|
||||||
use std::{convert::Infallible, error::Error, ffi::CString, io, str::FromStr};
|
use std::{convert::Infallible, error::Error, io, str::FromStr};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MkNod;
|
pub struct MkNod;
|
||||||
@ -69,11 +69,7 @@ impl Cmd for MkNod {
|
|||||||
}
|
}
|
||||||
Special::Pipe => 0,
|
Special::Pipe => 0,
|
||||||
};
|
};
|
||||||
let fname = CString::new(file.as_str())?;
|
stat::mknod(file.as_str(), mode, dev_t)?;
|
||||||
let ret = unsafe { libc::mknod(fname.as_ptr(), mode, dev_t) };
|
|
||||||
if ret != 0 {
|
|
||||||
return Err(io::Error::last_os_error().into());
|
|
||||||
}
|
|
||||||
if matches.get_flag("verbose") {
|
if matches.get_flag("verbose") {
|
||||||
match special {
|
match special {
|
||||||
Special::Block => {
|
Special::Block => {
|
||||||
|
@ -24,9 +24,9 @@ impl Cmd for Nproc {
|
|||||||
return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input")));
|
return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input")));
|
||||||
};
|
};
|
||||||
if matches.get_flag("ALL") {
|
if matches.get_flag("ALL") {
|
||||||
println!("{}", num_cpus::get());
|
println!("{}", unsafe { get_nprocs_conf() });
|
||||||
} else {
|
} else {
|
||||||
println!("{}", num_cpus::get_physical());
|
println!("{}", unsafe { get_nprocs() });
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -35,3 +35,8 @@ impl Cmd for Nproc {
|
|||||||
Some(crate::Path::UsrBin)
|
Some(crate::Path::UsrBin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn get_nprocs() -> libc::c_int;
|
||||||
|
fn get_nprocs_conf() -> libc::c_int;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use crate::unistd;
|
||||||
|
|
||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
use clap::{Arg, ArgAction, Command};
|
use clap::{Arg, ArgAction, Command};
|
||||||
use std::{error::Error, ffi::CString, io};
|
use std::{error::Error, io, fs::OpenOptions};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Sync;
|
pub struct Sync;
|
||||||
@ -38,37 +40,19 @@ impl Cmd for Sync {
|
|||||||
};
|
};
|
||||||
if let Some(files) = matches.get_many::<String>("FILE") {
|
if let Some(files) = matches.get_many::<String>("FILE") {
|
||||||
for f in files {
|
for f in files {
|
||||||
let file = CString::new(f.as_bytes())?;
|
let mut opts = OpenOptions::new();
|
||||||
|
let opts = opts.read(true).write(true);
|
||||||
|
let fd = opts.open(f)?;
|
||||||
if matches.get_flag("data") {
|
if matches.get_flag("data") {
|
||||||
let rc = unsafe {
|
unistd::fdatasync(&fd)?;
|
||||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
|
||||||
libc::fdatasync(fd)
|
|
||||||
};
|
|
||||||
if rc != 0 {
|
|
||||||
return Err(Box::new(io::Error::last_os_error()));
|
|
||||||
}
|
|
||||||
} else if matches.get_flag("fs") {
|
} else if matches.get_flag("fs") {
|
||||||
let rc = unsafe {
|
unistd::syncfs(&fd)?;
|
||||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
|
||||||
libc::syncfs(fd)
|
|
||||||
};
|
|
||||||
if rc != 0 {
|
|
||||||
return Err(Box::new(io::Error::last_os_error()));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let rc = unsafe {
|
unistd::fsync(&fd)?;
|
||||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
|
||||||
libc::fsync(fd)
|
|
||||||
};
|
|
||||||
if rc != 0 {
|
|
||||||
return Err(Box::new(io::Error::last_os_error()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unistd::sync();
|
||||||
libc::sync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::Cmd;
|
use super::Cmd;
|
||||||
use crate::args;
|
use crate::{args, unistd};
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use std::{ffi::CString, io, process};
|
use std::io;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Unlink;
|
pub struct Unlink;
|
||||||
@ -27,14 +27,9 @@ impl Cmd for Unlink {
|
|||||||
};
|
};
|
||||||
if let Some(files) = matches.get_many::<String>("file") {
|
if let Some(files) = matches.get_many::<String>("file") {
|
||||||
for f in files {
|
for f in files {
|
||||||
let fname = CString::new(f.as_str())?;
|
unistd::unlink(f)?;
|
||||||
let ret = unsafe { libc::unlink(fname.as_ptr()) };
|
if matches.get_flag("verbose") {
|
||||||
if matches.get_flag("verbose") && ret == 0 {
|
|
||||||
println!("unlink: {f}");
|
println!("unlink: {f}");
|
||||||
} else if ret != 0 {
|
|
||||||
let err = io::Error::last_os_error();
|
|
||||||
eprintln!("unlink: cannot unlink {f}: {err}");
|
|
||||||
process::exit(ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ pub mod fs;
|
|||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod mode;
|
pub mod mode;
|
||||||
pub mod pw;
|
pub mod pw;
|
||||||
|
pub mod stat;
|
||||||
|
pub mod unistd;
|
||||||
|
|
||||||
pub use cmd::Cmd;
|
pub use cmd::Cmd;
|
||||||
|
|
||||||
|
22
src/stat/mod.rs
Normal file
22
src/stat/mod.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use sc::*;
|
||||||
|
use std::{ffi::CString, io};
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn mknod(path: &str, mode: u32, dev: u64) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(MKNOD, CString::new(path)?.as_ptr(), mode, dev) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn mkfifo(path: &str, mode: u32) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(MKNOD, CString::new(path)?.as_ptr(), mode | libc::S_IFIFO, 0) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
115
src/unistd/mod.rs
Normal file
115
src/unistd/mod.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use libc::utsname;
|
||||||
|
use sc::syscall;
|
||||||
|
use std::{ffi::CString, io, u8, fs::File, os::fd::AsRawFd};
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn new_utsname() -> utsname {
|
||||||
|
utsname {
|
||||||
|
sysname: [0; 65],
|
||||||
|
nodename: [0; 65],
|
||||||
|
release: [0; 65],
|
||||||
|
version: [0; 65],
|
||||||
|
machine: [0; 65],
|
||||||
|
domainname: [0; 65],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn gethostname() -> io::Result<String> {
|
||||||
|
let mut uts = new_utsname();
|
||||||
|
unsafe {
|
||||||
|
if syscall!(UNAME, &mut uts as *mut utsname) != 0 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let name = uts
|
||||||
|
.nodename
|
||||||
|
.iter()
|
||||||
|
.map(|x| *x as u8)
|
||||||
|
.take_while(|x| *x != 0)
|
||||||
|
.collect();
|
||||||
|
String::from_utf8(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sethostname(name: &str) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(SETHOSTNAME, name.as_ptr(), name.len()) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn link(source: &str, dest: &str) -> io::Result<()> {
|
||||||
|
let ret = unsafe {
|
||||||
|
syscall!(
|
||||||
|
LINK,
|
||||||
|
CString::new(source)?.as_ptr(),
|
||||||
|
CString::new(dest)?.as_ptr()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn unlink(name: &str) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(UNLINK, CString::new(name)?.as_ptr()) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn readlink(name: &str) -> io::Result<String> {
|
||||||
|
let mut buf = Vec::<i8>::with_capacity(1024);
|
||||||
|
let ret = unsafe { syscall!(READLINK, CString::new(name)?.as_ptr(), buf.as_mut_ptr(), 1024) };
|
||||||
|
if ret == 0 {
|
||||||
|
let path = buf.iter().map(|x| *x as u8).take_while(|x| *x != 0).collect();
|
||||||
|
String::from_utf8(path).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fdatasync(fd: &File) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(FDATASYNC, fd.as_raw_fd()) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn syncfs(fd: &File) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(SYNCFS, fd.as_raw_fd()) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fsync(fd: &File) -> io::Result<()> {
|
||||||
|
let ret = unsafe { syscall!(FSYNC, fd.as_raw_fd()) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sync() {
|
||||||
|
unsafe { syscall!(SYNC) };
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user