aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-09-03 14:07:36 -0400
committerGitHub <noreply@github.com>2020-09-03 14:07:36 -0400
commit39a80cf59e082b57606e5ddc074b5ae1337c0d79 (patch)
tree2ef26ef912e20e10b032671af332bc0695b36d33 /lib
parent50e39069518a0c2643cd5e3189ad087b5fbed0c6 (diff)
parent68818983aef0d44f43f9575d8207053d5b7250ba (diff)
downloadzig-39a80cf59e082b57606e5ddc074b5ae1337c0d79.tar.gz
zig-39a80cf59e082b57606e5ddc074b5ae1337c0d79.zip
Merge pull request #6238 from Aransentin/master
Add the "sync" family of functions
Diffstat (limited to 'lib')
-rw-r--r--lib/std/c.zig5
-rw-r--r--lib/std/os.zig68
-rw-r--r--lib/std/os/linux.zig16
-rw-r--r--lib/std/os/test.zig36
-rw-r--r--lib/std/os/windows/kernel32.zig2
5 files changed, 127 insertions, 0 deletions
diff --git a/lib/std/c.zig b/lib/std/c.zig
index b4e5fc7392..1b3f403ab5 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -330,3 +330,8 @@ pub const FILE = @Type(.Opaque);
pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;
pub extern "c" fn dlclose(handle: *c_void) c_int;
pub extern "c" fn dlsym(handle: ?*c_void, symbol: [*:0]const u8) ?*c_void;
+
+pub extern "c" fn sync() void;
+pub extern "c" fn syncfs(fd: c_int) c_int;
+pub extern "c" fn fsync(fd: c_int) c_int;
+pub extern "c" fn fdatasync(fd: c_int) c_int;
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 2e4cc3aed0..fdb4a0f473 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -5331,3 +5331,71 @@ pub fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) !fd_t {
else => |err| return std.os.unexpectedErrno(err),
}
}
+
+pub const SyncError = error{
+ InputOutput,
+ NoSpaceLeft,
+ DiskQuota,
+ AccessDenied,
+} || UnexpectedError;
+
+/// Write all pending file contents and metadata modifications to all filesystems.
+pub fn sync() void {
+ system.sync();
+}
+
+/// Write all pending file contents and metadata modifications to the filesystem which contains the specified file.
+pub fn syncfs(fd: fd_t) SyncError!void {
+ const rc = system.syncfs(fd);
+ switch (errno(rc)) {
+ 0 => return,
+ EBADF, EINVAL, EROFS => unreachable,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EDQUOT => return error.DiskQuota,
+ else => |err| return std.os.unexpectedErrno(err),
+ }
+}
+
+/// Write all pending file contents and metadata modifications for the specified file descriptor to the underlying filesystem.
+pub fn fsync(fd: fd_t) SyncError!void {
+ if (std.Target.current.os.tag == .windows) {
+ if (windows.kernel32.FlushFileBuffers(fd) != 0)
+ return;
+ switch (windows.kernel32.GetLastError()) {
+ .SUCCESS => return,
+ .INVALID_HANDLE => unreachable,
+ .ACCESS_DENIED => return error.AccessDenied, // a sync was performed but the system couldn't update the access time
+ .UNEXP_NET_ERR => return error.InputOutput,
+ else => return error.InputOutput,
+ }
+ }
+ const rc = system.fsync(fd);
+ switch (errno(rc)) {
+ 0 => return,
+ EBADF, EINVAL, EROFS => unreachable,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EDQUOT => return error.DiskQuota,
+ else => |err| return std.os.unexpectedErrno(err),
+ }
+}
+
+/// Write all pending file contents for the specified file descriptor to the underlying filesystem, but not necessarily the metadata.
+pub fn fdatasync(fd: fd_t) SyncError!void {
+ if (std.Target.current.os.tag == .windows) {
+ return fsync(fd) catch |err| switch (err) {
+ SyncError.AccessDenied => return, // fdatasync doesn't promise that the access time was synced
+ else => return err,
+ };
+ }
+ const rc = system.fdatasync(fd);
+ switch (errno(rc)) {
+ 0 => return,
+ EBADF, EINVAL, EROFS => unreachable,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EDQUOT => return error.DiskQuota,
+ else => |err| return std.os.unexpectedErrno(err),
+ }
+}
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 13094b3a3a..1f916876cf 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -1226,6 +1226,22 @@ pub fn bpf(cmd: BPF.Cmd, attr: *BPF.Attr, size: u32) usize {
return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size);
}
+pub fn sync() void {
+ _ = syscall0(.sync);
+}
+
+pub fn syncfs(fd: fd_t) usize {
+ return syscall1(.syncfs, @bitCast(usize, @as(isize, fd)));
+}
+
+pub fn fsync(fd: fd_t) usize {
+ return syscall1(.fsync, @bitCast(usize, @as(isize, fd)));
+}
+
+pub fn fdatasync(fd: fd_t) usize {
+ return syscall1(.fdatasync, @bitCast(usize, @as(isize, fd)));
+}
+
test "" {
if (builtin.os.tag == .linux) {
_ = @import("linux/test.zig");
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 576125e2a3..0a453d8b2e 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -555,3 +555,39 @@ test "signalfd" {
return error.SkipZigTest;
_ = std.os.signalfd;
}
+
+test "sync" {
+ if (builtin.os.tag != .linux)
+ return error.SkipZigTest;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ const test_out_file = "os_tmp_test";
+ const file = try tmp.dir.createFile(test_out_file, .{});
+ defer {
+ file.close();
+ tmp.dir.deleteFile(test_out_file) catch {};
+ }
+
+ os.sync();
+ try os.syncfs(file.handle);
+}
+
+test "fsync" {
+ if (builtin.os.tag != .linux and builtin.os.tag != .windows)
+ return error.SkipZigTest;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ const test_out_file = "os_tmp_test";
+ const file = try tmp.dir.createFile(test_out_file, .{});
+ defer {
+ file.close();
+ tmp.dir.deleteFile(test_out_file) catch {};
+ }
+
+ try os.fsync(file.handle);
+ try os.fdatasync(file.handle);
+}
diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig
index fce9eea908..05d160485d 100644
--- a/lib/std/os/windows/kernel32.zig
+++ b/lib/std/os/windows/kernel32.zig
@@ -287,3 +287,5 @@ pub extern "kernel32" fn K32GetWsChangesEx(hProcess: HANDLE, lpWatchInfoEx: PPSA
pub extern "kernel32" fn K32InitializeProcessForWsWatch(hProcess: HANDLE) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn K32QueryWorkingSet(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn K32QueryWorkingSetEx(hProcess: HANDLE, pv: PVOID, cb: DWORD) callconv(.Stdcall) BOOL;
+
+pub extern "kernel32" fn FlushFileBuffers(hFile: HANDLE) callconv(.Stdcall) BOOL;