diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-09-03 14:07:36 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-03 14:07:36 -0400 |
| commit | 39a80cf59e082b57606e5ddc074b5ae1337c0d79 (patch) | |
| tree | 2ef26ef912e20e10b032671af332bc0695b36d33 /lib | |
| parent | 50e39069518a0c2643cd5e3189ad087b5fbed0c6 (diff) | |
| parent | 68818983aef0d44f43f9575d8207053d5b7250ba (diff) | |
| download | zig-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.zig | 5 | ||||
| -rw-r--r-- | lib/std/os.zig | 68 | ||||
| -rw-r--r-- | lib/std/os/linux.zig | 16 | ||||
| -rw-r--r-- | lib/std/os/test.zig | 36 | ||||
| -rw-r--r-- | lib/std/os/windows/kernel32.zig | 2 |
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; |
