Skip to content

Commit 21c69d4

Browse files
bogglebrson
authored andcommitted
Added cross-platform fsync api to io; win32 impl needs to be refined
No tests, need mktmpfile first
1 parent 46e5e2f commit 21c69d4

File tree

4 files changed

+147
-13
lines changed

4 files changed

+147
-13
lines changed

src/lib/io.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ type buf_reader =
2525
fn eof() -> bool;
2626
fn seek(int, seek_style);
2727
fn tell() -> uint;
28+
// Needed on readers in case one needs to flush metadata
29+
// changes (atime)
30+
fn fsync(level: fsync::level) -> int;
2831
};
2932

3033

@@ -58,7 +61,9 @@ fn convert_whence(whence: seek_style) -> i32 {
5861
};
5962
}
6063

61-
resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); }
64+
resource FILE_res(f: os::libc::FILE) {
65+
os::libc::fclose(f);
66+
}
6267

6368
obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) {
6469
fn read(len: uint) -> [u8] unsafe {
@@ -76,6 +81,9 @@ obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) {
7681
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
7782
}
7883
fn tell() -> uint { ret os::libc::ftell(f) as uint; }
84+
fn fsync(level: fsync::level) -> int {
85+
ret os::fsync_fd(os::libc::fileno(f), level) as int;
86+
}
7987
}
8088

8189

@@ -219,6 +227,7 @@ obj byte_buf_reader(bbuf: byte_buf) {
219227
bbuf.pos = seek_in_buf(offset, pos, len, whence);
220228
}
221229
fn tell() -> uint { ret bbuf.pos; }
230+
fn fsync(_level: fsync::level) -> int { ret 0; }
222231
}
223232

224233
fn new_byte_buf_reader(buf: [u8]) -> buf_reader {
@@ -242,6 +251,8 @@ type buf_writer =
242251
fn write([u8]);
243252
fn seek(int, seek_style);
244253
fn tell() -> uint;
254+
fn flush() -> int;
255+
fn fsync(level: fsync::level) -> int;
245256
};
246257

247258
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>) {
255266
assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
256267
}
257268
fn tell() -> uint { ret os::libc::ftell(f) as uint; }
269+
fn flush() -> int { ret os::libc::fflush(f) as int; }
270+
fn fsync(level: fsync::level) -> int {
271+
ret os::fsync_fd(os::libc::fileno(f), level) as int;
272+
}
258273
}
259274

260275
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>) {
283298
log_err "need 64-bit native calls for tell, sorry";
284299
fail;
285300
}
301+
302+
fn flush() -> int { ret 0; }
303+
304+
fn fsync(level: fsync::level) -> int {
305+
ret os::fsync_fd(fd, level) as int;
306+
}
286307
}
287308

288309
fn file_buf_writer(path: str,
@@ -433,6 +454,8 @@ obj byte_buf_writer(buf: mutable_byte_buf) {
433454
buf.pos = seek_in_buf(offset, pos, len, whence);
434455
}
435456
fn tell() -> uint { ret buf.pos; }
457+
fn flush() -> int { ret 0; }
458+
fn fsync(_level: fsync::level) -> int { ret 0; }
436459
}
437460

438461
fn string_writer() -> str_writer {
@@ -477,6 +500,75 @@ fn read_whole_file(file: str) -> result::t<[u8], str> {
477500
})
478501
}
479502

503+
// fsync related
504+
505+
mod fsync {
506+
507+
tag level {
508+
// whatever fsync does on that platform
509+
fsync;
510+
511+
// fdatasync on linux, similiar or more on other platforms
512+
fdatasync;
513+
514+
// full fsync
515+
//
516+
// You must additionally sync the parent directory as well!
517+
fullfsync;
518+
}
519+
520+
521+
// Resource of artifacts that need to fsync on destruction
522+
resource res<t>(arg: arg<t>) {
523+
alt arg.opt_level {
524+
option::none::<level>. { }
525+
option::some::<level>(level) {
526+
// fail hard if not succesful
527+
assert(arg.fsync_fn(arg.val, level) != -1);
528+
}
529+
}
530+
}
531+
532+
type arg<t> = {
533+
val: t,
534+
opt_level: option::t<level>,
535+
fsync_fn: fn(t, level) -> int
536+
};
537+
538+
// fsync file after executing blk
539+
// FIXME find better way to create resources within lifetime of outer res
540+
fn FILE_res_sync(&&file: FILE_res, opt_level: option::t<level>,
541+
blk: block(&&res<os::libc::FILE>)) {
542+
blk(res({
543+
val: *file, opt_level: opt_level,
544+
fsync_fn: fn(&&file: os::libc::FILE, l: level) -> int {
545+
ret os::fsync_fd(os::libc::fileno(file), l) as int;
546+
}
547+
}));
548+
}
549+
550+
// fsync fd after executing blk
551+
fn fd_res_sync(&&fd: fd_res, opt_level: option::t<level>,
552+
blk: block(&&res<fd_t>)) {
553+
blk(res({
554+
val: *fd, opt_level: opt_level,
555+
fsync_fn: fn(&&fd: fd_t, l: level) -> int {
556+
ret os::fsync_fd(fd, l) as int;
557+
}
558+
}));
559+
}
560+
561+
// Type of objects that may want to fsync
562+
type t = obj { fn fsync(l: level) -> int; };
563+
564+
// Call o.fsync after executing blk
565+
fn obj_sync(&&o: t, opt_level: option::t<level>, blk: block(&&res<t>)) {
566+
blk(res({
567+
val: o, opt_level: opt_level,
568+
fsync_fn: fn(&&o: t, l: level) -> int { ret o.fsync(l); }
569+
}));
570+
}
571+
}
480572

481573

482574
//

src/lib/linux_os.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export exec_suffix;
1818
export target_os;
1919
export dylib_filename;
2020
export get_exe_path;
21+
export fsync_fd;
2122

2223
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
2324
// by https://github.com/graydon/rust/issues#issue/268
@@ -35,6 +36,10 @@ native mod libc {
3536
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
3637
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
3738
fn fclose(f: FILE);
39+
fn fflush(f: FILE) -> c_int;
40+
fn fsync(fd: fd_t) -> c_int;
41+
fn fdatasync(fd: fd_t) -> c_int;
42+
fn fileno(f: FILE) -> fd_t;
3843
fn fgetc(f: FILE) -> c_int;
3944
fn ungetc(c: c_int, f: FILE);
4045
fn feof(f: FILE) -> c_int;
@@ -89,6 +94,13 @@ fn fclose(file: libc::FILE) {
8994
libc::fclose(file)
9095
}
9196

97+
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
98+
alt level {
99+
io::fsync::fsync. | io::fsync::fullfsync. { ret libc::fsync(fd); }
100+
io::fsync::fdatasync. { ret libc::fdatasync(fd); }
101+
}
102+
}
103+
92104
fn waitpid(pid: pid_t) -> i32 {
93105
let status = 0i32;
94106
assert (os::libc::waitpid(pid, status, 0i32) != -1i32);

src/lib/macos_os.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export exec_suffix;
1212
export target_os;
1313
export dylib_filename;
1414
export get_exe_path;
15+
export fsync_fd;
1516

1617
// FIXME Refactor into unix_os module or some such. Doesn't
1718
// seem to work right now.
@@ -28,6 +29,9 @@ native mod libc {
2829
type FILE;
2930
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
3031
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
32+
fn fflush(f: FILE) -> c_int;
33+
fn fsync(fd: fd_t) -> c_int;
34+
fn fileno(f: FILE) -> fd_t;
3135
fn fclose(f: FILE);
3236
fn fgetc(f: FILE) -> c_int;
3337
fn ungetc(c: c_int, f: FILE);
@@ -47,21 +51,26 @@ native mod libc {
4751
fn mkdir(s: str::sbuf, mode: c_int) -> c_int;
4852
fn rmdir(s: str::sbuf) -> c_int;
4953
fn chdir(s: str::sbuf) -> c_int;
54+
55+
// FIXME: Needs varags
56+
fn fcntl(fd: fd_t, cmd: c_int) -> c_int;
5057
}
5158

5259
mod libc_constants {
53-
const O_RDONLY: c_int = 0i32;
54-
const O_WRONLY: c_int = 1i32;
55-
const O_RDWR: c_int = 2i32;
56-
const O_APPEND: c_int = 8i32;
57-
const O_CREAT: c_int = 512i32;
58-
const O_EXCL: c_int = 2048i32;
59-
const O_TRUNC: c_int = 1024i32;
60-
const O_TEXT: c_int = 0i32; // nonexistent in darwin libc
61-
const O_BINARY: c_int = 0i32; // nonexistent in darwin libc
62-
63-
const S_IRUSR: unsigned = 256u32;
64-
const S_IWUSR: unsigned = 128u32;
60+
const O_RDONLY: c_int = 0i32;
61+
const O_WRONLY: c_int = 1i32;
62+
const O_RDWR: c_int = 2i32;
63+
const O_APPEND: c_int = 8i32;
64+
const O_CREAT: c_int = 512i32;
65+
const O_EXCL: c_int = 2048i32;
66+
const O_TRUNC: c_int = 1024i32;
67+
const O_TEXT: c_int = 0i32; // nonexistent in darwin libc
68+
const O_BINARY: c_int = 0i32; // nonexistent in darwin libc
69+
70+
const S_IRUSR: unsigned = 256u32;
71+
const S_IWUSR: unsigned = 128u32;
72+
73+
const F_FULLFSYNC: c_int = 51i32;
6574
}
6675

6776
fn pipe() -> {in: fd_t, out: fd_t} {
@@ -88,6 +97,19 @@ fn waitpid(pid: pid_t) -> i32 {
8897
ret status;
8998
}
9099

100+
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
101+
alt level {
102+
io::fsync::fsync. { ret libc::fsync(fd); }
103+
_ {
104+
// According to man fnctl, the ok retval is only specified to be !=-1
105+
if (libc::fcntl(libc_constants::F_FULLFSYNC, fd) == -1 as c_int)
106+
{ ret -1 as c_int; }
107+
else
108+
{ ret 0 as c_int; }
109+
}
110+
}
111+
}
112+
91113
#[abi = "cdecl"]
92114
native mod rustrt {
93115
fn rust_getcwd() -> str;

src/lib/win32_os.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ native mod libc {
1515
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
1616
fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
1717
fn fclose(f: FILE);
18+
fn fflush(f: FILE) -> c_int;
19+
fn fsync(fd: fd_t) -> c_int;
20+
fn fileno(f: FILE) -> fd_t;
1821
fn fgetc(f: FILE) -> c_int;
1922
fn ungetc(c: c_int, f: FILE);
2023
fn feof(f: FILE) -> c_int;
@@ -93,6 +96,11 @@ fn fclose(file: libc::FILE) {
9396
libc::fclose(file)
9497
}
9598

99+
fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
100+
// FIXME do something more apropriate
101+
ret libc::fsync(fd);
102+
}
103+
96104
#[abi = "cdecl"]
97105
native mod rustrt {
98106
fn rust_process_wait(handle: c_int) -> c_int;

0 commit comments

Comments
 (0)