Implement blocking file locking API for windows
parent
9af0590a28
commit
e1868029e9
132
lib/std/fs.zig
132
lib/std/fs.zig
|
@ -708,7 +708,12 @@ pub const Dir = struct {
|
||||||
const access_mask = w.SYNCHRONIZE |
|
const access_mask = w.SYNCHRONIZE |
|
||||||
(if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
|
(if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
|
||||||
(if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
|
(if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
|
||||||
return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN);
|
const share_access = if (flags.lock)
|
||||||
|
w.FILE_SHARE_DELETE |
|
||||||
|
(if (flags.write) @as(os.windows.ULONG, 0) else w.FILE_SHARE_READ)
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
return self.openFileWindows(sub_path_w, access_mask, share_access, w.FILE_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates, opens, or overwrites a file with write access.
|
/// Creates, opens, or overwrites a file with write access.
|
||||||
|
@ -753,7 +758,7 @@ pub const Dir = struct {
|
||||||
@as(u32, w.FILE_OVERWRITE_IF)
|
@as(u32, w.FILE_OVERWRITE_IF)
|
||||||
else
|
else
|
||||||
@as(u32, w.FILE_OPEN_IF);
|
@as(u32, w.FILE_OPEN_IF);
|
||||||
return self.openFileWindows(sub_path_w, access_mask, creation);
|
return self.openFileWindows(sub_path_w, access_mask, null, creation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated; call `openFile` directly.
|
/// Deprecated; call `openFile` directly.
|
||||||
|
@ -775,65 +780,80 @@ pub const Dir = struct {
|
||||||
self: Dir,
|
self: Dir,
|
||||||
sub_path_w: [*:0]const u16,
|
sub_path_w: [*:0]const u16,
|
||||||
access_mask: os.windows.ACCESS_MASK,
|
access_mask: os.windows.ACCESS_MASK,
|
||||||
|
share_access_opt: ?os.windows.ULONG,
|
||||||
creation: os.windows.ULONG,
|
creation: os.windows.ULONG,
|
||||||
) File.OpenError!File {
|
) File.OpenError!File {
|
||||||
const w = os.windows;
|
var delay: usize = 1;
|
||||||
|
while (true) {
|
||||||
|
const w = os.windows;
|
||||||
|
|
||||||
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
|
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
|
||||||
return error.IsDir;
|
return error.IsDir;
|
||||||
}
|
}
|
||||||
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
|
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
|
||||||
return error.IsDir;
|
return error.IsDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = File{
|
var result = File{
|
||||||
.handle = undefined,
|
.handle = undefined,
|
||||||
.io_mode = .blocking,
|
.io_mode = .blocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
|
const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
|
||||||
error.Overflow => return error.NameTooLong,
|
error.Overflow => return error.NameTooLong,
|
||||||
};
|
};
|
||||||
var nt_name = w.UNICODE_STRING{
|
var nt_name = w.UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
|
.Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
|
||||||
};
|
};
|
||||||
var attr = w.OBJECT_ATTRIBUTES{
|
var attr = w.OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
||||||
.RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
|
.RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
|
||||||
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
|
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
|
||||||
.ObjectName = &nt_name,
|
.ObjectName = &nt_name,
|
||||||
.SecurityDescriptor = null,
|
.SecurityDescriptor = null,
|
||||||
.SecurityQualityOfService = null,
|
.SecurityQualityOfService = null,
|
||||||
};
|
};
|
||||||
var io: w.IO_STATUS_BLOCK = undefined;
|
var io: w.IO_STATUS_BLOCK = undefined;
|
||||||
const rc = w.ntdll.NtCreateFile(
|
const share_access = share_access_opt orelse w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE;
|
||||||
&result.handle,
|
const rc = w.ntdll.NtCreateFile(
|
||||||
access_mask,
|
&result.handle,
|
||||||
&attr,
|
access_mask,
|
||||||
&io,
|
&attr,
|
||||||
null,
|
&io,
|
||||||
w.FILE_ATTRIBUTE_NORMAL,
|
null,
|
||||||
w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
|
w.FILE_ATTRIBUTE_NORMAL,
|
||||||
creation,
|
share_access,
|
||||||
w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
|
creation,
|
||||||
null,
|
w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
|
||||||
0,
|
null,
|
||||||
);
|
0,
|
||||||
switch (rc) {
|
);
|
||||||
.SUCCESS => return result,
|
switch (rc) {
|
||||||
.OBJECT_NAME_INVALID => unreachable,
|
.SUCCESS => return result,
|
||||||
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
|
.OBJECT_NAME_INVALID => unreachable,
|
||||||
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
|
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
|
||||||
.NO_MEDIA_IN_DEVICE => return error.NoDevice,
|
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
|
||||||
.INVALID_PARAMETER => unreachable,
|
.NO_MEDIA_IN_DEVICE => return error.NoDevice,
|
||||||
.SHARING_VIOLATION => return error.SharingViolation,
|
.INVALID_PARAMETER => unreachable,
|
||||||
.ACCESS_DENIED => return error.AccessDenied,
|
.SHARING_VIOLATION => {
|
||||||
.PIPE_BUSY => return error.PipeBusy,
|
// TODO: check if async or blocking
|
||||||
.OBJECT_PATH_SYNTAX_BAD => unreachable,
|
//return error.SharingViolation
|
||||||
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
|
// Sleep so we don't consume a ton of CPU waiting to get lock on file
|
||||||
else => return w.unexpectedStatus(rc),
|
std.time.sleep(delay);
|
||||||
|
// Increase sleep time as long as it is less than 5 seconds
|
||||||
|
if (delay < 5 * std.time.ns_per_s) {
|
||||||
|
delay *= 2;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
.ACCESS_DENIED => return error.AccessDenied,
|
||||||
|
.PIPE_BUSY => return error.PipeBusy,
|
||||||
|
.OBJECT_PATH_SYNTAX_BAD => unreachable,
|
||||||
|
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
|
||||||
|
else => return w.unexpectedStatus(rc),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1141,8 +1141,8 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to get lock the file, blocking if the file is locked.
|
/// Attempts to get lock the file, blocking if the file is locked.
|
||||||
pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *flock) OpenError!void {
|
pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *const flock) OpenError!void {
|
||||||
const rc = system.fcntlFlock(fd, F_SETLKW, flock_p);
|
const rc = system.fcntl(fd, F_SETLKW, flock_p);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
std.debug.panic("fcntl error: {}\n", .{rc});
|
std.debug.panic("fcntl error: {}\n", .{rc});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ const iovec = linux.iovec;
|
||||||
const iovec_const = linux.iovec_const;
|
const iovec_const = linux.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
|
const pid_t = linux.pid_t;
|
||||||
const stack_t = linux.stack_t;
|
const stack_t = linux.stack_t;
|
||||||
const sigset_t = linux.sigset_t;
|
const sigset_t = linux.sigset_t;
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fcntlFlock(fd: fd_t, cmd: i32, flock_p: *flock) usize {
|
pub fn fcntl(fd: fd_t, cmd: i32, flock_p: *const c_void) usize {
|
||||||
return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(flock_p));
|
return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(flock_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue