| ... | @@ -596,13 +596,12 @@ pub const Dir = struct { | ... | @@ -596,13 +596,12 @@ pub const Dir = struct { |
| 596 | } | 596 | } |
| 597 | | 597 | |
| 598 | // Use the O_ locking flags if the os supports them | 598 | // Use the O_ locking flags if the os supports them |
| 599 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and @hasDecl(os, "O_SHLOCK"); | 599 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 600 | const lock_flag: u32 = lock_flag: { | 600 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 601 | if (has_flock_open_flags and flags.lock) { | 601 | .None => @as(u32, 0), |
| 602 | break :lock_flag if (flags.write) @as(u32, os.O_EXLOCK) else @as(u32, os.O_SHLOCK); | 602 | .Shared => os.O_SHLOCK, |
| 603 | } | 603 | .Exclusive => os.O_EXLOCK, |
| 604 | break :lock_flag @as(u32, 0); | 604 | } else 0; |
| 605 | }; | | |
| 606 | | 605 | |
| 607 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 606 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 608 | const os_flags = lock_flag | O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) | 607 | const os_flags = lock_flag | O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) |
| ... | @@ -616,9 +615,13 @@ pub const Dir = struct { | ... | @@ -616,9 +615,13 @@ pub const Dir = struct { |
| 616 | else | 615 | else |
| 617 | try os.openatZ(self.fd, sub_path, os_flags, 0); | 616 | try os.openatZ(self.fd, sub_path, os_flags, 0); |
| 618 | | 617 | |
| 619 | if (!has_flock_open_flags and flags.lock) { | 618 | if (!has_flock_open_flags and flags.lock != .None) { |
| 620 | // TODO: integrate async I/O | 619 | // TODO: integrate async I/O |
| 621 | try os.flock(fd, if (flags.write) os.LOCK_EX else os.LOCK_SH); | 620 | try os.flock(fd, switch (flags.lock) { |
| | 621 | .None => unreachable, |
| | 622 | .Shared => os.LOCK_SH, |
| | 623 | .Exclusive => os.LOCK_EX, |
| | 624 | }); |
| 622 | } | 625 | } |
| 623 | | 626 | |
| 624 | return File{ | 627 | return File{ |
| ... | @@ -638,11 +641,13 @@ pub const Dir = struct { | ... | @@ -638,11 +641,13 @@ pub const Dir = struct { |
| 638 | const access_mask = w.SYNCHRONIZE | | 641 | const access_mask = w.SYNCHRONIZE | |
| 639 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | | 642 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 640 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); | 643 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); |
| 641 | const share_access = if (flags.lock) | 644 | |
| 642 | w.FILE_SHARE_DELETE | | 645 | const share_access = switch (flags.lock) { |
| 643 | (if (flags.write) @as(os.windows.ULONG, 0) else w.FILE_SHARE_READ) | 646 | .None => @as(?w.ULONG, null), |
| 644 | else | 647 | .Shared => w.FILE_SHARE_READ, |
| 645 | null; | 648 | .Exclusive => @as(?w.ULONG, 0), |
| | 649 | }; |
| | 650 | |
| 646 | return @as(File, .{ | 651 | return @as(File, .{ |
| 647 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, w.FILE_OPEN), | 652 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, w.FILE_OPEN), |
| 648 | .io_mode = .blocking, | 653 | .io_mode = .blocking, |
| ... | @@ -672,7 +677,11 @@ pub const Dir = struct { | ... | @@ -672,7 +677,11 @@ pub const Dir = struct { |
| 672 | | 677 | |
| 673 | // Use the O_ locking flags if the os supports them | 678 | // Use the O_ locking flags if the os supports them |
| 674 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); | 679 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 675 | const lock_flag: u32 = if (has_flock_open_flags and flags.lock) os.O_EXLOCK else 0; | 680 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| | 681 | .None => @as(u32, 0), |
| | 682 | .Shared => os.O_SHLOCK, |
| | 683 | .Exclusive => os.O_EXLOCK, |
| | 684 | } else 0; |
| 676 | | 685 | |
| 677 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 686 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 678 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | 687 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | |
| ... | @@ -684,9 +693,13 @@ pub const Dir = struct { | ... | @@ -684,9 +693,13 @@ pub const Dir = struct { |
| 684 | else | 693 | else |
| 685 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); | 694 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); |
| 686 | | 695 | |
| 687 | if (!has_flock_open_flags and flags.lock) { | 696 | if (!has_flock_open_flags and flags.lock != .None) { |
| 688 | // TODO: integrate async I/O | 697 | // TODO: integrate async I/O |
| 689 | try os.flock(fd, os.LOCK_EX); | 698 | try os.flock(fd, switch (flags.lock) { |
| | 699 | .None => unreachable, |
| | 700 | .Shared => os.LOCK_SH, |
| | 701 | .Exclusive => os.LOCK_EX, |
| | 702 | }); |
| 690 | } | 703 | } |
| 691 | | 704 | |
| 692 | return File{ .handle = fd, .io_mode = .blocking }; | 705 | return File{ .handle = fd, .io_mode = .blocking }; |
| ... | @@ -705,10 +718,12 @@ pub const Dir = struct { | ... | @@ -705,10 +718,12 @@ pub const Dir = struct { |
| 705 | else | 718 | else |
| 706 | @as(u32, w.FILE_OPEN_IF); | 719 | @as(u32, w.FILE_OPEN_IF); |
| 707 | | 720 | |
| 708 | const share_access = if (flags.lock) | 721 | const share_access = switch (flags.lock) { |
| 709 | @as(os.windows.ULONG, w.FILE_SHARE_DELETE) | 722 | .None => @as(?w.ULONG, null), |
| 710 | else | 723 | .Shared => w.FILE_SHARE_READ, |
| 711 | null; | 724 | .Exclusive => @as(?w.ULONG, 0), |
| | 725 | }; |
| | 726 | |
| 712 | return @as(File, .{ | 727 | return @as(File, .{ |
| 713 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, creation), | 728 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, creation), |
| 714 | .io_mode = .blocking, | 729 | .io_mode = .blocking, |
| ... | @@ -1671,8 +1686,8 @@ test "open file with lock twice, make sure it wasn't open at the same time" { | ... | @@ -1671,8 +1686,8 @@ test "open file with lock twice, make sure it wasn't open at the same time" { |
| 1671 | const filename = "file_lock_test.txt"; | 1686 | const filename = "file_lock_test.txt"; |
| 1672 | | 1687 | |
| 1673 | var contexts = [_]FileLockTestContext{ | 1688 | var contexts = [_]FileLockTestContext{ |
| 1674 | .{ .filename = filename, .create = true, .exclusive = true }, | 1689 | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1675 | .{ .filename = filename, .create = true, .exclusive = true }, | 1690 | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1676 | }; | 1691 | }; |
| 1677 | try run_lock_file_test(&contexts); | 1692 | try run_lock_file_test(&contexts); |
| 1678 | | 1693 | |
| ... | @@ -1703,9 +1718,9 @@ test "create file, lock and read from multiple process at once" { | ... | @@ -1703,9 +1718,9 @@ test "create file, lock and read from multiple process at once" { |
| 1703 | try std.fs.cwd().writeFile(filename, filedata); | 1718 | try std.fs.cwd().writeFile(filename, filedata); |
| 1704 | | 1719 | |
| 1705 | var contexts = [_]FileLockTestContext{ | 1720 | var contexts = [_]FileLockTestContext{ |
| 1706 | .{ .filename = filename, .create = false, .exclusive = false }, | 1721 | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1707 | .{ .filename = filename, .create = false, .exclusive = false }, | 1722 | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1708 | .{ .filename = filename, .create = false, .exclusive = true }, | 1723 | .{ .filename = filename, .create = false, .lock = .Exclusive }, |
| 1709 | }; | 1724 | }; |
| 1710 | | 1725 | |
| 1711 | try run_lock_file_test(&contexts); | 1726 | try run_lock_file_test(&contexts); |
| ... | @@ -1740,8 +1755,8 @@ const FileLockTestContext = struct { | ... | @@ -1740,8 +1755,8 @@ const FileLockTestContext = struct { |
| 1740 | | 1755 | |
| 1741 | // use file.createFile | 1756 | // use file.createFile |
| 1742 | create: bool, | 1757 | create: bool, |
| 1743 | // get a read/write lock, instead of just a read lock | 1758 | // the type of lock to use |
| 1744 | exclusive: bool, | 1759 | lock: File.Lock, |
| 1745 | | 1760 | |
| 1746 | // Output variables | 1761 | // Output variables |
| 1747 | err: ?(File.OpenError || std.os.ReadError) = null, | 1762 | err: ?(File.OpenError || std.os.ReadError) = null, |
| ... | @@ -1756,12 +1771,12 @@ const FileLockTestContext = struct { | ... | @@ -1756,12 +1771,12 @@ const FileLockTestContext = struct { |
| 1756 | fn run(ctx: *@This()) void { | 1771 | fn run(ctx: *@This()) void { |
| 1757 | var file: File = undefined; | 1772 | var file: File = undefined; |
| 1758 | if (ctx.create) { | 1773 | if (ctx.create) { |
| 1759 | file = cwd().createFile(ctx.filename, .{ .lock = true }) catch |err| { | 1774 | file = cwd().createFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { |
| 1760 | ctx.err = err; | 1775 | ctx.err = err; |
| 1761 | return; | 1776 | return; |
| 1762 | }; | 1777 | }; |
| 1763 | } else { | 1778 | } else { |
| 1764 | file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch |err| { | 1779 | file = cwd().openFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { |
| 1765 | ctx.err = err; | 1780 | ctx.err = err; |
| 1766 | return; | 1781 | return; |
| 1767 | }; | 1782 | }; |