Merge pull request #6238 from Aransentin/master

Add the "sync" family of functions
This commit is contained in:
Andrew Kelley 2020-09-03 14:07:36 -04:00 committed by GitHub
commit 39a80cf59e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 0 deletions

View File

@ -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;

View File

@ -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),
}
}

View File

@ -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");

View File

@ -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);
}

View File

@ -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;