authorgravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-09 20:48:00-06:00
committergravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 10:12:46-06:00
loge1868029e9c861fa6b1382ba52052264fc5f9c31
tree06fcece1996aa0ee6b8c6d44493c4bf7e86c58cf
parent9af0590a282e3cf1aa209f4de35402a50effe7a8

Implement blocking file locking API for windows


4 files changed, 80 insertions(+), 59 deletions(-)

lib/std/fs.zig+76-56
...@@ -708,7 +708,12 @@ pub const Dir = struct {...@@ -708,7 +708,12 @@ pub const Dir = struct {
708 const access_mask = w.SYNCHRONIZE |708 const access_mask = w.SYNCHRONIZE |
709 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |709 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
710 (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);710 (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
711 return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN);711 const share_access = if (flags.lock)
712 w.FILE_SHARE_DELETE |
713 (if (flags.write) @as(os.windows.ULONG, 0) else w.FILE_SHARE_READ)
714 else
715 null;
716 return self.openFileWindows(sub_path_w, access_mask, share_access, w.FILE_OPEN);
712 }717 }
713718
714 /// Creates, opens, or overwrites a file with write access.719 /// Creates, opens, or overwrites a file with write access.
...@@ -753,7 +758,7 @@ pub const Dir = struct {...@@ -753,7 +758,7 @@ pub const Dir = struct {
753 @as(u32, w.FILE_OVERWRITE_IF)758 @as(u32, w.FILE_OVERWRITE_IF)
754 else759 else
755 @as(u32, w.FILE_OPEN_IF);760 @as(u32, w.FILE_OPEN_IF);
756 return self.openFileWindows(sub_path_w, access_mask, creation);761 return self.openFileWindows(sub_path_w, access_mask, null, creation);
757 }762 }
758763
759 /// Deprecated; call `openFile` directly.764 /// Deprecated; call `openFile` directly.
...@@ -775,65 +780,80 @@ pub const Dir = struct {...@@ -775,65 +780,80 @@ pub const Dir = struct {
775 self: Dir,780 self: Dir,
776 sub_path_w: [*:0]const u16,781 sub_path_w: [*:0]const u16,
777 access_mask: os.windows.ACCESS_MASK,782 access_mask: os.windows.ACCESS_MASK,
783 share_access_opt: ?os.windows.ULONG,
778 creation: os.windows.ULONG,784 creation: os.windows.ULONG,
779 ) File.OpenError!File {785 ) File.OpenError!File {
780 const w = os.windows;786 var delay: usize = 1;
787 while (true) {
788 const w = os.windows;
781789
782 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {790 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
783 return error.IsDir;791 return error.IsDir;
784 }792 }
785 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {793 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
786 return error.IsDir;794 return error.IsDir;
787 }795 }
788796
789 var result = File{797 var result = File{
790 .handle = undefined,798 .handle = undefined,
791 .io_mode = .blocking,799 .io_mode = .blocking,
792 };800 };
793801
794 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {802 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
795 error.Overflow => return error.NameTooLong,803 error.Overflow => return error.NameTooLong,
796 };804 };
797 var nt_name = w.UNICODE_STRING{805 var nt_name = w.UNICODE_STRING{
798 .Length = path_len_bytes,806 .Length = path_len_bytes,
799 .MaximumLength = path_len_bytes,807 .MaximumLength = path_len_bytes,
800 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),808 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
801 };809 };
802 var attr = w.OBJECT_ATTRIBUTES{810 var attr = w.OBJECT_ATTRIBUTES{
803 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),811 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
804 .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,812 .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
805 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.813 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
806 .ObjectName = &nt_name,814 .ObjectName = &nt_name,
807 .SecurityDescriptor = null,815 .SecurityDescriptor = null,
808 .SecurityQualityOfService = null,816 .SecurityQualityOfService = null,
809 };817 };
810 var io: w.IO_STATUS_BLOCK = undefined;818 var io: w.IO_STATUS_BLOCK = undefined;
811 const rc = w.ntdll.NtCreateFile(819 const share_access = share_access_opt orelse w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE;
812 &result.handle,820 const rc = w.ntdll.NtCreateFile(
813 access_mask,821 &result.handle,
814 &attr,822 access_mask,
815 &io,823 &attr,
816 null,824 &io,
817 w.FILE_ATTRIBUTE_NORMAL,825 null,
818 w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,826 w.FILE_ATTRIBUTE_NORMAL,
819 creation,827 share_access,
820 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,828 creation,
821 null,829 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
822 0,830 null,
823 );831 0,
824 switch (rc) {832 );
825 .SUCCESS => return result,833 switch (rc) {
826 .OBJECT_NAME_INVALID => unreachable,834 .SUCCESS => return result,
827 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,835 .OBJECT_NAME_INVALID => unreachable,
828 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,836 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
829 .NO_MEDIA_IN_DEVICE => return error.NoDevice,837 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
830 .INVALID_PARAMETER => unreachable,838 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
831 .SHARING_VIOLATION => return error.SharingViolation,839 .INVALID_PARAMETER => unreachable,
832 .ACCESS_DENIED => return error.AccessDenied,840 .SHARING_VIOLATION => {
833 .PIPE_BUSY => return error.PipeBusy,841 // TODO: check if async or blocking
834 .OBJECT_PATH_SYNTAX_BAD => unreachable,842 //return error.SharingViolation
835 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,843 // Sleep so we don't consume a ton of CPU waiting to get lock on file
836 else => return w.unexpectedStatus(rc),844 std.time.sleep(delay);
845 // Increase sleep time as long as it is less than 5 seconds
846 if (delay < 5 * std.time.ns_per_s) {
847 delay *= 2;
848 }
849 continue;
850 },
851 .ACCESS_DENIED => return error.AccessDenied,
852 .PIPE_BUSY => return error.PipeBusy,
853 .OBJECT_PATH_SYNTAX_BAD => unreachable,
854 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
855 else => return w.unexpectedStatus(rc),
856 }
837 }857 }
838 }858 }
839859
lib/std/os.zig+2-2
...@@ -1141,8 +1141,8 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)...@@ -1141,8 +1141,8 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)
1141}1141}
11421142
1143/// Attempts to get lock the file, blocking if the file is locked.1143/// Attempts to get lock the file, blocking if the file is locked.
1144pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *flock) OpenError!void {1144pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *const flock) OpenError!void {
1145 const rc = system.fcntlFlock(fd, F_SETLKW, flock_p);1145 const rc = system.fcntl(fd, F_SETLKW, flock_p);
1146 if (rc < 0) {1146 if (rc < 0) {
1147 std.debug.panic("fcntl error: {}\n", .{rc});1147 std.debug.panic("fcntl error: {}\n", .{rc});
1148 }1148 }
lib/std/os/bits/linux/i386.zig+1
...@@ -8,6 +8,7 @@ const iovec = linux.iovec;...@@ -8,6 +8,7 @@ const iovec = linux.iovec;
8const iovec_const = linux.iovec_const;8const iovec_const = linux.iovec_const;
9const uid_t = linux.uid_t;9const uid_t = linux.uid_t;
10const gid_t = linux.gid_t;10const gid_t = linux.gid_t;
11const pid_t = linux.pid_t;
11const stack_t = linux.stack_t;12const stack_t = linux.stack_t;
12const sigset_t = linux.sigset_t;13const sigset_t = linux.sigset_t;
1314
lib/std/os/linux.zig+1-1
...@@ -219,7 +219,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of...@@ -219,7 +219,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
219 }219 }
220}220}
221221
222pub fn fcntlFlock(fd: fd_t, cmd: i32, flock_p: *flock) usize {222pub fn fcntl(fd: fd_t, cmd: i32, flock_p: *const c_void) usize {
223 return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(flock_p));223 return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(flock_p));
224}224}
225225