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 {
708708 const access_mask = w.SYNCHRONIZE |
709709 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
710710 (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);
712717 }
713718
714719 /// Creates, opens, or overwrites a file with write access.
......@@ -753,7 +758,7 @@ pub const Dir = struct {
753758 @as(u32, w.FILE_OVERWRITE_IF)
754759 else
755760 @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);
757762 }
758763
759764 /// Deprecated; call `openFile` directly.
......@@ -775,65 +780,80 @@ pub const Dir = struct {
775780 self: Dir,
776781 sub_path_w: [*:0]const u16,
777782 access_mask: os.windows.ACCESS_MASK,
783 share_access_opt: ?os.windows.ULONG,
778784 creation: os.windows.ULONG,
779785 ) 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) {
783 return error.IsDir;
784 }
785 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
786 return error.IsDir;
787 }
790 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
791 return error.IsDir;
792 }
793 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
794 return error.IsDir;
795 }
788796
789 var result = File{
790 .handle = undefined,
791 .io_mode = .blocking,
792 };
797 var result = File{
798 .handle = undefined,
799 .io_mode = .blocking,
800 };
793801
794 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,
796 };
797 var nt_name = w.UNICODE_STRING{
798 .Length = path_len_bytes,
799 .MaximumLength = path_len_bytes,
800 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
801 };
802 var attr = w.OBJECT_ATTRIBUTES{
803 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
804 .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
805 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
806 .ObjectName = &nt_name,
807 .SecurityDescriptor = null,
808 .SecurityQualityOfService = null,
809 };
810 var io: w.IO_STATUS_BLOCK = undefined;
811 const rc = w.ntdll.NtCreateFile(
812 &result.handle,
813 access_mask,
814 &attr,
815 &io,
816 null,
817 w.FILE_ATTRIBUTE_NORMAL,
818 w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
819 creation,
820 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
821 null,
822 0,
823 );
824 switch (rc) {
825 .SUCCESS => return result,
826 .OBJECT_NAME_INVALID => unreachable,
827 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
828 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
829 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
830 .INVALID_PARAMETER => unreachable,
831 .SHARING_VIOLATION => return error.SharingViolation,
832 .ACCESS_DENIED => return error.AccessDenied,
833 .PIPE_BUSY => return error.PipeBusy,
834 .OBJECT_PATH_SYNTAX_BAD => unreachable,
835 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
836 else => return w.unexpectedStatus(rc),
802 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
803 error.Overflow => return error.NameTooLong,
804 };
805 var nt_name = w.UNICODE_STRING{
806 .Length = path_len_bytes,
807 .MaximumLength = path_len_bytes,
808 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
809 };
810 var attr = w.OBJECT_ATTRIBUTES{
811 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
812 .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
813 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
814 .ObjectName = &nt_name,
815 .SecurityDescriptor = null,
816 .SecurityQualityOfService = null,
817 };
818 var io: w.IO_STATUS_BLOCK = undefined;
819 const share_access = share_access_opt orelse w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE;
820 const rc = w.ntdll.NtCreateFile(
821 &result.handle,
822 access_mask,
823 &attr,
824 &io,
825 null,
826 w.FILE_ATTRIBUTE_NORMAL,
827 share_access,
828 creation,
829 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
830 null,
831 0,
832 );
833 switch (rc) {
834 .SUCCESS => return result,
835 .OBJECT_NAME_INVALID => unreachable,
836 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
837 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
838 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
839 .INVALID_PARAMETER => unreachable,
840 .SHARING_VIOLATION => {
841 // TODO: check if async or blocking
842 //return error.SharingViolation
843 // Sleep so we don't consume a ton of CPU waiting to get lock on file
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 }
837857 }
838858 }
839859
lib/std/os.zig+2-2
......@@ -1141,8 +1141,8 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)
11411141}
11421142
11431143/// Attempts to get lock the file, blocking if the file is locked.
1144pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *flock) OpenError!void {
1145 const rc = system.fcntlFlock(fd, F_SETLKW, flock_p);
1144pub fn fcntlFlockBlocking(fd: fd_t, flock_p: *const flock) OpenError!void {
1145 const rc = system.fcntl(fd, F_SETLKW, flock_p);
11461146 if (rc < 0) {
11471147 std.debug.panic("fcntl error: {}\n", .{rc});
11481148 }
lib/std/os/bits/linux/i386.zig+1
......@@ -8,6 +8,7 @@ const iovec = linux.iovec;
88const iovec_const = linux.iovec_const;
99const uid_t = linux.uid_t;
1010const gid_t = linux.gid_t;
11const pid_t = linux.pid_t;
1112const stack_t = linux.stack_t;
1213const 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
219219 }
220220}
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 {
223223 return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(flock_p));
224224}
225225