Merge pull request #7198 from LemonBoy/freebsd-lock
std: Fix file locking logic for BSD targetsmaster
commit
9e4360c335
|
@ -368,6 +368,7 @@ pub const ChildProcess = struct {
|
|||
error.DeviceBusy => unreachable,
|
||||
error.FileLocksNotSupported => unreachable,
|
||||
error.BadPathName => unreachable, // Windows-only
|
||||
error.WouldBlock => unreachable,
|
||||
else => |e| return e,
|
||||
}
|
||||
else
|
||||
|
|
|
@ -405,7 +405,7 @@ pub const Dir = struct {
|
|||
else => false,
|
||||
};
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or
|
||||
(skip_zero_fileno and bsd_entry.d_fileno == 0))
|
||||
(skip_zero_fileno and bsd_entry.d_fileno == 0))
|
||||
{
|
||||
continue :start_over;
|
||||
}
|
||||
|
@ -729,14 +729,16 @@ pub const Dir = struct {
|
|||
}
|
||||
|
||||
var os_flags: u32 = os.O_CLOEXEC;
|
||||
// Use the O_ locking flags if the os supports them
|
||||
// (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag)
|
||||
const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin;
|
||||
// Use the O_ locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasDecl(os, "O_EXLOCK");
|
||||
if (has_flock_open_flags) {
|
||||
const nonblocking_lock_flag = if (flags.lock_nonblocking)
|
||||
os.O_NONBLOCK | os.O_SYNC
|
||||
// Note that the O_NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking)
|
||||
os.O_NONBLOCK
|
||||
else
|
||||
@as(u32, 0);
|
||||
0;
|
||||
os_flags |= switch (flags.lock) {
|
||||
.None => @as(u32, 0),
|
||||
.Shared => os.O_SHLOCK | nonblocking_lock_flag,
|
||||
|
@ -771,6 +773,22 @@ pub const Dir = struct {
|
|||
});
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
var fl_flags = os.fcntl(fd, os.F_GETFL, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, os.O_NONBLOCK);
|
||||
_ = os.fcntl(fd, os.F_SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
return File{
|
||||
.handle = fd,
|
||||
.capable_io_mode = .blocking,
|
||||
|
@ -854,17 +872,19 @@ pub const Dir = struct {
|
|||
return self.createFileW(path_w.span(), flags);
|
||||
}
|
||||
|
||||
// Use the O_ locking flags if the os supports them
|
||||
// (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag)
|
||||
const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin;
|
||||
// Use the O_ locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasDecl(os, "O_EXLOCK");
|
||||
// Note that the O_NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking)
|
||||
os.O_NONBLOCK | os.O_SYNC
|
||||
os.O_NONBLOCK
|
||||
else
|
||||
0;
|
||||
const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) {
|
||||
.None => @as(u32, 0),
|
||||
.Shared => os.O_SHLOCK,
|
||||
.Exclusive => os.O_EXLOCK,
|
||||
.Shared => os.O_SHLOCK | nonblocking_lock_flag,
|
||||
.Exclusive => os.O_EXLOCK | nonblocking_lock_flag,
|
||||
} else 0;
|
||||
|
||||
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
|
||||
|
@ -876,6 +896,7 @@ pub const Dir = struct {
|
|||
try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode)
|
||||
else
|
||||
try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
|
||||
errdefer os.close(fd);
|
||||
|
||||
if (!has_flock_open_flags and flags.lock != .None) {
|
||||
// TODO: integrate async I/O
|
||||
|
@ -887,6 +908,22 @@ pub const Dir = struct {
|
|||
});
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
var fl_flags = os.fcntl(fd, os.F_GETFL, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, os.O_NONBLOCK);
|
||||
_ = os.fcntl(fd, os.F_SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
return File{
|
||||
.handle = fd,
|
||||
.capable_io_mode = .blocking,
|
||||
|
@ -1178,6 +1215,7 @@ pub const Dir = struct {
|
|||
error.NoSpaceLeft => unreachable, // not providing O_CREAT
|
||||
error.PathAlreadyExists => unreachable, // not providing O_CREAT
|
||||
error.FileLocksNotSupported => unreachable, // locking folders is not supported
|
||||
error.WouldBlock => unreachable, // can't happen for directories
|
||||
else => |e| return e,
|
||||
};
|
||||
return Dir{ .fd = fd };
|
||||
|
@ -1221,6 +1259,7 @@ pub const Dir = struct {
|
|||
error.NoSpaceLeft => unreachable, // not providing O_CREAT
|
||||
error.PathAlreadyExists => unreachable, // not providing O_CREAT
|
||||
error.FileLocksNotSupported => unreachable, // locking folders is not supported
|
||||
error.WouldBlock => unreachable, // can't happen for directories
|
||||
else => |e| return e,
|
||||
};
|
||||
return Dir{ .fd = fd };
|
||||
|
|
|
@ -691,9 +691,6 @@ test "realpath" {
|
|||
test "open file with exclusive nonblocking lock twice" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
const filename = "file_nonblocking_lock_test.txt";
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
|
@ -709,9 +706,6 @@ test "open file with exclusive nonblocking lock twice" {
|
|||
test "open file with shared and exclusive nonblocking lock" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
const filename = "file_nonblocking_lock_test.txt";
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
|
@ -727,9 +721,6 @@ test "open file with shared and exclusive nonblocking lock" {
|
|||
test "open file with exclusive and shared nonblocking lock" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
const filename = "file_nonblocking_lock_test.txt";
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
|
@ -791,9 +782,6 @@ test "open file with exclusive lock twice, make sure it waits" {
|
|||
test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"};
|
||||
|
|
|
@ -1020,6 +1020,8 @@ pub const OpenError = error{
|
|||
|
||||
BadPathName,
|
||||
InvalidUtf8,
|
||||
|
||||
WouldBlock,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||
|
@ -1201,6 +1203,7 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
|
|||
EEXIST => return error.PathAlreadyExists,
|
||||
EBUSY => return error.DeviceBusy,
|
||||
EOPNOTSUPP => return error.FileLocksNotSupported,
|
||||
EWOULDBLOCK => return error.WouldBlock,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
@ -4187,6 +4190,7 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
|
|||
const flags = if (builtin.os.tag == .linux) O_PATH | O_NONBLOCK | O_CLOEXEC else O_NONBLOCK | O_CLOEXEC;
|
||||
const fd = openZ(pathname, flags, 0) catch |err| switch (err) {
|
||||
error.FileLocksNotSupported => unreachable,
|
||||
error.WouldBlock => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer close(fd);
|
||||
|
|
Loading…
Reference in New Issue