| ... | ... | @@ -405,7 +405,7 @@ pub const Dir = struct { |
| 405 | 405 | else => false, |
| 406 | 406 | }; |
| 407 | 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 | 410 | continue :start_over; |
| 411 | 411 | } |
| ... | ... | @@ -729,14 +729,16 @@ pub const Dir = struct { |
| 729 | 729 | } |
| 730 | 730 | |
| 731 | 731 | var os_flags: u32 = os.O_CLOEXEC; |
| 732 | | // Use the O_ locking flags if the os supports them |
| 733 | | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) |
| 734 | | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; |
| 732 | // Use the O_ locking flags if the os supports them to acquire the lock |
| 733 | // atomically. |
| 734 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 735 | 735 | if (has_flock_open_flags) { |
| 736 | | const nonblocking_lock_flag = if (flags.lock_nonblocking) |
| 737 | | os.O_NONBLOCK | os.O_SYNC |
| 736 | // Note that the O_NONBLOCK flag is removed after the openat() call |
| 737 | // is successful. |
| 738 | const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking) |
| 739 | os.O_NONBLOCK |
| 738 | 740 | else |
| 739 | | @as(u32, 0); |
| 741 | 0; |
| 740 | 742 | os_flags |= switch (flags.lock) { |
| 741 | 743 | .None => @as(u32, 0), |
| 742 | 744 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| ... | ... | @@ -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 | 792 | return File{ |
| 775 | 793 | .handle = fd, |
| 776 | 794 | .capable_io_mode = .blocking, |
| ... | ... | @@ -854,17 +872,19 @@ pub const Dir = struct { |
| 854 | 872 | return self.createFileW(path_w.span(), flags); |
| 855 | 873 | } |
| 856 | 874 | |
| 857 | | // Use the O_ locking flags if the os supports them |
| 858 | | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) |
| 859 | | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !is_darwin; |
| 875 | // Use the O_ locking flags if the os supports them to acquire the lock |
| 876 | // atomically. |
| 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 | 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 | 882 | else |
| 863 | 883 | 0; |
| 864 | 884 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 865 | 885 | .None => @as(u32, 0), |
| 866 | | .Shared => os.O_SHLOCK, |
| 867 | | .Exclusive => os.O_EXLOCK, |
| 886 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| 887 | .Exclusive => os.O_EXLOCK | nonblocking_lock_flag, |
| 868 | 888 | } else 0; |
| 869 | 889 | |
| 870 | 890 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| ... | ... | @@ -876,6 +896,7 @@ pub const Dir = struct { |
| 876 | 896 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) |
| 877 | 897 | else |
| 878 | 898 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); |
| 899 | errdefer os.close(fd); |
| 879 | 900 | |
| 880 | 901 | if (!has_flock_open_flags and flags.lock != .None) { |
| 881 | 902 | // TODO: integrate async I/O |
| ... | ... | @@ -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 | 927 | return File{ |
| 891 | 928 | .handle = fd, |
| 892 | 929 | .capable_io_mode = .blocking, |
| ... | ... | @@ -1178,6 +1215,7 @@ pub const Dir = struct { |
| 1178 | 1215 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| 1179 | 1216 | error.PathAlreadyExists => unreachable, // not providing O_CREAT |
| 1180 | 1217 | error.FileLocksNotSupported => unreachable, // locking folders is not supported |
| 1218 | error.WouldBlock => unreachable, // can't happen for directories |
| 1181 | 1219 | else => |e| return e, |
| 1182 | 1220 | }; |
| 1183 | 1221 | return Dir{ .fd = fd }; |
| ... | ... | @@ -1221,6 +1259,7 @@ pub const Dir = struct { |
| 1221 | 1259 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| 1222 | 1260 | error.PathAlreadyExists => unreachable, // not providing O_CREAT |
| 1223 | 1261 | error.FileLocksNotSupported => unreachable, // locking folders is not supported |
| 1262 | error.WouldBlock => unreachable, // can't happen for directories |
| 1224 | 1263 | else => |e| return e, |
| 1225 | 1264 | }; |
| 1226 | 1265 | return Dir{ .fd = fd }; |