| ... | @@ -405,7 +405,7 @@ pub const Dir = struct { | ... | @@ -405,7 +405,7 @@ pub const Dir = struct { |
| 405 | else => false, | 405 | else => false, |
| 406 | }; | 406 | }; |
| 407 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or | 407 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or |
| 408 | (skip_zero_fileno and bsd_entry.d_fileno == 0)) | 408 | (skip_zero_fileno and bsd_entry.d_fileno == 0)) |
| 409 | { | 409 | { |
| 410 | continue :start_over; | 410 | continue :start_over; |
| 411 | } | 411 | } |
| ... | @@ -729,14 +729,16 @@ pub const Dir = struct { | ... | @@ -729,14 +729,16 @@ pub const Dir = struct { |
| 729 | } | 729 | } |
| 730 | | 730 | |
| 731 | var os_flags: u32 = os.O_CLOEXEC; | 731 | var os_flags: u32 = os.O_CLOEXEC; |
| 732 | // Use the O_ locking flags if the os supports them | 732 | // Use the O_ locking flags if the os supports them to acquire the lock |
| 733 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) | 733 | // atomically. |
| 734 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; | 734 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 735 | if (has_flock_open_flags) { | 735 | if (has_flock_open_flags) { |
| 736 | const nonblocking_lock_flag = if (flags.lock_nonblocking) | 736 | // Note that the O_NONBLOCK flag is removed after the openat() call |
| 737 | os.O_NONBLOCK | os.O_SYNC | 737 | // is successful. |
| | 738 | const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking) |
| | 739 | os.O_NONBLOCK |
| 738 | else | 740 | else |
| 739 | @as(u32, 0); | 741 | 0; |
| 740 | os_flags |= switch (flags.lock) { | 742 | os_flags |= switch (flags.lock) { |
| 741 | .None => @as(u32, 0), | 743 | .None => @as(u32, 0), |
| 742 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, | 744 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| ... | @@ -771,6 +773,22 @@ pub const Dir = struct { | ... | @@ -771,6 +773,22 @@ pub const Dir = struct { |
| 771 | }); | 773 | }); |
| 772 | } | 774 | } |
| 773 | | 775 | |
| | 776 | if (has_flock_open_flags and flags.lock_nonblocking) { |
| | 777 | var fl_flags = os.fcntl(fd, os.F_GETFL, 0) catch |err| switch (err) { |
| | 778 | error.FileBusy => unreachable, |
| | 779 | error.Locked => unreachable, |
| | 780 | error.PermissionDenied => unreachable, |
| | 781 | else => |e| return e, |
| | 782 | }; |
| | 783 | fl_flags &= ~@as(usize, os.O_NONBLOCK); |
| | 784 | _ = os.fcntl(fd, os.F_SETFL, fl_flags) catch |err| switch (err) { |
| | 785 | error.FileBusy => unreachable, |
| | 786 | error.Locked => unreachable, |
| | 787 | error.PermissionDenied => unreachable, |
| | 788 | else => |e| return e, |
| | 789 | }; |
| | 790 | } |
| | 791 | |
| 774 | return File{ | 792 | return File{ |
| 775 | .handle = fd, | 793 | .handle = fd, |
| 776 | .capable_io_mode = .blocking, | 794 | .capable_io_mode = .blocking, |
| ... | @@ -854,17 +872,19 @@ pub const Dir = struct { | ... | @@ -854,17 +872,19 @@ pub const Dir = struct { |
| 854 | return self.createFileW(path_w.span(), flags); | 872 | return self.createFileW(path_w.span(), flags); |
| 855 | } | 873 | } |
| 856 | | 874 | |
| 857 | // Use the O_ locking flags if the os supports them | 875 | // Use the O_ locking flags if the os supports them to acquire the lock |
| 858 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) | 876 | // atomically. |
| 859 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; | 877 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| | 878 | // Note that the O_NONBLOCK flag is removed after the openat() call |
| | 879 | // is successful. |
| 860 | const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking) | 880 | const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking) |
| 861 | os.O_NONBLOCK | os.O_SYNC | 881 | os.O_NONBLOCK |
| 862 | else | 882 | else |
| 863 | 0; | 883 | 0; |
| 864 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { | 884 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 865 | .None => @as(u32, 0), | 885 | .None => @as(u32, 0), |
| 866 | .Shared => os.O_SHLOCK, | 886 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| 867 | .Exclusive => os.O_EXLOCK, | 887 | .Exclusive => os.O_EXLOCK | nonblocking_lock_flag, |
| 868 | } else 0; | 888 | } else 0; |
| 869 | | 889 | |
| 870 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 890 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| ... | @@ -876,6 +896,7 @@ pub const Dir = struct { | ... | @@ -876,6 +896,7 @@ pub const Dir = struct { |
| 876 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) | 896 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) |
| 877 | else | 897 | else |
| 878 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); | 898 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); |
| | 899 | errdefer os.close(fd); |
| 879 | | 900 | |
| 880 | if (!has_flock_open_flags and flags.lock != .None) { | 901 | if (!has_flock_open_flags and flags.lock != .None) { |
| 881 | // TODO: integrate async I/O | 902 | // TODO: integrate async I/O |
| ... | @@ -887,6 +908,22 @@ pub const Dir = struct { | ... | @@ -887,6 +908,22 @@ pub const Dir = struct { |
| 887 | }); | 908 | }); |
| 888 | } | 909 | } |
| 889 | | 910 | |
| | 911 | if (has_flock_open_flags and flags.lock_nonblocking) { |
| | 912 | var fl_flags = os.fcntl(fd, os.F_GETFL, 0) catch |err| switch (err) { |
| | 913 | error.FileBusy => unreachable, |
| | 914 | error.Locked => unreachable, |
| | 915 | error.PermissionDenied => unreachable, |
| | 916 | else => |e| return e, |
| | 917 | }; |
| | 918 | fl_flags &= ~@as(usize, os.O_NONBLOCK); |
| | 919 | _ = os.fcntl(fd, os.F_SETFL, fl_flags) catch |err| switch (err) { |
| | 920 | error.FileBusy => unreachable, |
| | 921 | error.Locked => unreachable, |
| | 922 | error.PermissionDenied => unreachable, |
| | 923 | else => |e| return e, |
| | 924 | }; |
| | 925 | } |
| | 926 | |
| 890 | return File{ | 927 | return File{ |
| 891 | .handle = fd, | 928 | .handle = fd, |
| 892 | .capable_io_mode = .blocking, | 929 | .capable_io_mode = .blocking, |
| ... | @@ -1178,6 +1215,7 @@ pub const Dir = struct { | ... | @@ -1178,6 +1215,7 @@ pub const Dir = struct { |
| 1178 | error.NoSpaceLeft => unreachable, // not providing O_CREAT | 1215 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| 1179 | error.PathAlreadyExists => unreachable, // not providing O_CREAT | 1216 | error.PathAlreadyExists => unreachable, // not providing O_CREAT |
| 1180 | error.FileLocksNotSupported => unreachable, // locking folders is not supported | 1217 | error.FileLocksNotSupported => unreachable, // locking folders is not supported |
| | 1218 | error.WouldBlock => unreachable, // can't happen for directories |
| 1181 | else => |e| return e, | 1219 | else => |e| return e, |
| 1182 | }; | 1220 | }; |
| 1183 | return Dir{ .fd = fd }; | 1221 | return Dir{ .fd = fd }; |
| ... | @@ -1221,6 +1259,7 @@ pub const Dir = struct { | ... | @@ -1221,6 +1259,7 @@ pub const Dir = struct { |
| 1221 | error.NoSpaceLeft => unreachable, // not providing O_CREAT | 1259 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| 1222 | error.PathAlreadyExists => unreachable, // not providing O_CREAT | 1260 | error.PathAlreadyExists => unreachable, // not providing O_CREAT |
| 1223 | error.FileLocksNotSupported => unreachable, // locking folders is not supported | 1261 | error.FileLocksNotSupported => unreachable, // locking folders is not supported |
| | 1262 | error.WouldBlock => unreachable, // can't happen for directories |
| 1224 | else => |e| return e, | 1263 | else => |e| return e, |
| 1225 | }; | 1264 | }; |
| 1226 | return Dir{ .fd = fd }; | 1265 | return Dir{ .fd = fd }; |