Added cross-platform fsync api to io; win32 impl needs to be refined

No tests, need mktmpfile first
This commit is contained in:
Stefan Plantikow 2011-11-16 23:14:18 +01:00 committed by Brian Anderson
parent 46e5e2f685
commit 21c69d4ba4
4 changed files with 146 additions and 12 deletions

View File

@ -25,6 +25,9 @@ type buf_reader =
fn eof() -> bool;
fn seek(int, seek_style);
fn tell() -> uint;
// Needed on readers in case one needs to flush metadata
// changes (atime)
fn fsync(level: fsync::level) -> int;
};
@ -58,7 +61,9 @@ fn convert_whence(whence: seek_style) -> i32 {
};
}
resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); }
resource FILE_res(f: os::libc::FILE) {
os::libc::fclose(f);
}
obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) {
fn read(len: uint) -> [u8] unsafe {
@ -76,6 +81,9 @@ obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) {
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
}
fn tell() -> uint { ret os::libc::ftell(f) as uint; }
fn fsync(level: fsync::level) -> int {
ret os::fsync_fd(os::libc::fileno(f), level) as int;
}
}
@ -219,6 +227,7 @@ obj byte_buf_reader(bbuf: byte_buf) {
bbuf.pos = seek_in_buf(offset, pos, len, whence);
}
fn tell() -> uint { ret bbuf.pos; }
fn fsync(_level: fsync::level) -> int { ret 0; }
}
fn new_byte_buf_reader(buf: [u8]) -> buf_reader {
@ -242,6 +251,8 @@ type buf_writer =
fn write([u8]);
fn seek(int, seek_style);
fn tell() -> uint;
fn flush() -> int;
fn fsync(level: fsync::level) -> int;
};
obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) {
@ -255,6 +266,10 @@ obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) {
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
}
fn tell() -> uint { ret os::libc::ftell(f) as uint; }
fn flush() -> int { ret os::libc::fflush(f) as int; }
fn fsync(level: fsync::level) -> int {
ret os::fsync_fd(os::libc::fileno(f), level) as int;
}
}
resource fd_res(fd: fd_t) { os::libc::close(fd); }
@ -283,6 +298,12 @@ obj fd_buf_writer(fd: fd_t, res: option::t<@fd_res>) {
log_err "need 64-bit native calls for tell, sorry";
fail;
}
fn flush() -> int { ret 0; }
fn fsync(level: fsync::level) -> int {
ret os::fsync_fd(fd, level) as int;
}
}
fn file_buf_writer(path: str,
@ -433,6 +454,8 @@ obj byte_buf_writer(buf: mutable_byte_buf) {
buf.pos = seek_in_buf(offset, pos, len, whence);
}
fn tell() -> uint { ret buf.pos; }
fn flush() -> int { ret 0; }
fn fsync(_level: fsync::level) -> int { ret 0; }
}
fn string_writer() -> str_writer {
@ -477,6 +500,75 @@ fn read_whole_file(file: str) -> result::t<[u8], str> {
})
}
// fsync related
mod fsync {
tag level {
// whatever fsync does on that platform
fsync;
// fdatasync on linux, similiar or more on other platforms
fdatasync;
// full fsync
//
// You must additionally sync the parent directory as well!
fullfsync;
}
// Resource of artifacts that need to fsync on destruction
resource res<t>(arg: arg<t>) {
alt arg.opt_level {
option::none::<level>. { }
option::some::<level>(level) {
// fail hard if not succesful
assert(arg.fsync_fn(arg.val, level) != -1);
}
}
}
type arg<t> = {
val: t,
opt_level: option::t<level>,
fsync_fn: fn(t, level) -> int
};
// fsync file after executing blk
// FIXME find better way to create resources within lifetime of outer res
fn FILE_res_sync(&&file: FILE_res, opt_level: option::t<level>,
blk: block(&&res<os::libc::FILE>)) {
blk(res({
val: *file, opt_level: opt_level,
fsync_fn: fn(&&file: os::libc::FILE, l: level) -> int {
ret os::fsync_fd(os::libc::fileno(file), l) as int;
}
}));
}
// fsync fd after executing blk
fn fd_res_sync(&&fd: fd_res, opt_level: option::t<level>,
blk: block(&&res<fd_t>)) {
blk(res({
val: *fd, opt_level: opt_level,
fsync_fn: fn(&&fd: fd_t, l: level) -> int {
ret os::fsync_fd(fd, l) as int;
}
}));
}
// Type of objects that may want to fsync
type t = obj { fn fsync(l: level) -> int; };
// Call o.fsync after executing blk
fn obj_sync(&&o: t, opt_level: option::t<level>, blk: block(&&res<t>)) {
blk(res({
val: o, opt_level: opt_level,
fsync_fn: fn(&&o: t, l: level) -> int { ret o.fsync(l); }
}));
}
}
//

View File

@ -18,6 +18,7 @@ export exec_suffix;
export target_os;
export dylib_filename;
export get_exe_path;
export fsync_fd;
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
// by https://github.com/graydon/rust/issues#issue/268
@ -35,6 +36,10 @@ native mod libc {
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fclose(f: FILE);
fn fflush(f: FILE) -> c_int;
fn fsync(fd: fd_t) -> c_int;
fn fdatasync(fd: fd_t) -> c_int;
fn fileno(f: FILE) -> fd_t;
fn fgetc(f: FILE) -> c_int;
fn ungetc(c: c_int, f: FILE);
fn feof(f: FILE) -> c_int;
@ -89,6 +94,13 @@ fn fclose(file: libc::FILE) {
libc::fclose(file)
}
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
alt level {
io::fsync::fsync. | io::fsync::fullfsync. { ret libc::fsync(fd); }
io::fsync::fdatasync. { ret libc::fdatasync(fd); }
}
}
fn waitpid(pid: pid_t) -> i32 {
let status = 0i32;
assert (os::libc::waitpid(pid, status, 0i32) != -1i32);

View File

@ -12,6 +12,7 @@ export exec_suffix;
export target_os;
export dylib_filename;
export get_exe_path;
export fsync_fd;
// FIXME Refactor into unix_os module or some such. Doesn't
// seem to work right now.
@ -28,6 +29,9 @@ native mod libc {
type FILE;
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fflush(f: FILE) -> c_int;
fn fsync(fd: fd_t) -> c_int;
fn fileno(f: FILE) -> fd_t;
fn fclose(f: FILE);
fn fgetc(f: FILE) -> c_int;
fn ungetc(c: c_int, f: FILE);
@ -47,21 +51,26 @@ native mod libc {
fn mkdir(s: str::sbuf, mode: c_int) -> c_int;
fn rmdir(s: str::sbuf) -> c_int;
fn chdir(s: str::sbuf) -> c_int;
// FIXME: Needs varags
fn fcntl(fd: fd_t, cmd: c_int) -> c_int;
}
mod libc_constants {
const O_RDONLY: c_int = 0i32;
const O_WRONLY: c_int = 1i32;
const O_RDWR: c_int = 2i32;
const O_APPEND: c_int = 8i32;
const O_CREAT: c_int = 512i32;
const O_EXCL: c_int = 2048i32;
const O_TRUNC: c_int = 1024i32;
const O_TEXT: c_int = 0i32; // nonexistent in darwin libc
const O_BINARY: c_int = 0i32; // nonexistent in darwin libc
const O_RDONLY: c_int = 0i32;
const O_WRONLY: c_int = 1i32;
const O_RDWR: c_int = 2i32;
const O_APPEND: c_int = 8i32;
const O_CREAT: c_int = 512i32;
const O_EXCL: c_int = 2048i32;
const O_TRUNC: c_int = 1024i32;
const O_TEXT: c_int = 0i32; // nonexistent in darwin libc
const O_BINARY: c_int = 0i32; // nonexistent in darwin libc
const S_IRUSR: unsigned = 256u32;
const S_IWUSR: unsigned = 128u32;
const S_IRUSR: unsigned = 256u32;
const S_IWUSR: unsigned = 128u32;
const F_FULLFSYNC: c_int = 51i32;
}
fn pipe() -> {in: fd_t, out: fd_t} {
@ -88,6 +97,19 @@ fn waitpid(pid: pid_t) -> i32 {
ret status;
}
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
alt level {
io::fsync::fsync. { ret libc::fsync(fd); }
_ {
// According to man fnctl, the ok retval is only specified to be !=-1
if (libc::fcntl(libc_constants::F_FULLFSYNC, fd) == -1 as c_int)
{ ret -1 as c_int; }
else
{ ret 0 as c_int; }
}
}
}
#[abi = "cdecl"]
native mod rustrt {
fn rust_getcwd() -> str;

View File

@ -15,6 +15,9 @@ native mod libc {
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fclose(f: FILE);
fn fflush(f: FILE) -> c_int;
fn fsync(fd: fd_t) -> c_int;
fn fileno(f: FILE) -> fd_t;
fn fgetc(f: FILE) -> c_int;
fn ungetc(c: c_int, f: FILE);
fn feof(f: FILE) -> c_int;
@ -93,6 +96,11 @@ fn fclose(file: libc::FILE) {
libc::fclose(file)
}
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
// FIXME do something more apropriate
ret libc::fsync(fd);
}
#[abi = "cdecl"]
native mod rustrt {
fn rust_process_wait(handle: c_int) -> c_int;