| ... | ... | @@ -596,13 +596,12 @@ pub const Dir = struct { |
| 596 | 596 | } |
| 597 | 597 | |
| 598 | 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"); |
| 600 | | const lock_flag: u32 = lock_flag: { |
| 601 | | if (has_flock_open_flags and flags.lock) { |
| 602 | | break :lock_flag if (flags.write) @as(u32, os.O_EXLOCK) else @as(u32, os.O_SHLOCK); |
| 603 | | } |
| 604 | | break :lock_flag @as(u32, 0); |
| 605 | | }; |
| 599 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 600 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 601 | .None => @as(u32, 0), |
| 602 | .Shared => os.O_SHLOCK, |
| 603 | .Exclusive => os.O_EXLOCK, |
| 604 | } else 0; |
| 606 | 605 | |
| 607 | 606 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 608 | 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 | 615 | else |
| 617 | 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 | 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 | 627 | return File{ |
| ... | ... | @@ -638,11 +641,13 @@ pub const Dir = struct { |
| 638 | 641 | const access_mask = w.SYNCHRONIZE | |
| 639 | 642 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 640 | 643 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); |
| 641 | | const share_access = if (flags.lock) |
| 642 | | w.FILE_SHARE_DELETE | |
| 643 | | (if (flags.write) @as(os.windows.ULONG, 0) else w.FILE_SHARE_READ) |
| 644 | | else |
| 645 | | null; |
| 644 | |
| 645 | const share_access = switch (flags.lock) { |
| 646 | .None => @as(?w.ULONG, null), |
| 647 | .Shared => w.FILE_SHARE_READ, |
| 648 | .Exclusive => @as(?w.ULONG, 0), |
| 649 | }; |
| 650 | |
| 646 | 651 | return @as(File, .{ |
| 647 | 652 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, w.FILE_OPEN), |
| 648 | 653 | .io_mode = .blocking, |
| ... | ... | @@ -672,7 +677,11 @@ pub const Dir = struct { |
| 672 | 677 | |
| 673 | 678 | // Use the O_ locking flags if the os supports them |
| 674 | 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 | 686 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 678 | 687 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | |
| ... | ... | @@ -684,9 +693,13 @@ pub const Dir = struct { |
| 684 | 693 | else |
| 685 | 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 | 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 | 705 | return File{ .handle = fd, .io_mode = .blocking }; |
| ... | ... | @@ -705,10 +718,12 @@ pub const Dir = struct { |
| 705 | 718 | else |
| 706 | 719 | @as(u32, w.FILE_OPEN_IF); |
| 707 | 720 | |
| 708 | | const share_access = if (flags.lock) |
| 709 | | @as(os.windows.ULONG, w.FILE_SHARE_DELETE) |
| 710 | | else |
| 711 | | null; |
| 721 | const share_access = switch (flags.lock) { |
| 722 | .None => @as(?w.ULONG, null), |
| 723 | .Shared => w.FILE_SHARE_READ, |
| 724 | .Exclusive => @as(?w.ULONG, 0), |
| 725 | }; |
| 726 | |
| 712 | 727 | return @as(File, .{ |
| 713 | 728 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, creation), |
| 714 | 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 | 1686 | const filename = "file_lock_test.txt"; |
| 1672 | 1687 | |
| 1673 | 1688 | var contexts = [_]FileLockTestContext{ |
| 1674 | | .{ .filename = filename, .create = true, .exclusive = true }, |
| 1675 | | .{ .filename = filename, .create = true, .exclusive = true }, |
| 1689 | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1690 | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1676 | 1691 | }; |
| 1677 | 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 | 1718 | try std.fs.cwd().writeFile(filename, filedata); |
| 1704 | 1719 | |
| 1705 | 1720 | var contexts = [_]FileLockTestContext{ |
| 1706 | | .{ .filename = filename, .create = false, .exclusive = false }, |
| 1707 | | .{ .filename = filename, .create = false, .exclusive = false }, |
| 1708 | | .{ .filename = filename, .create = false, .exclusive = true }, |
| 1721 | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1722 | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1723 | .{ .filename = filename, .create = false, .lock = .Exclusive }, |
| 1709 | 1724 | }; |
| 1710 | 1725 | |
| 1711 | 1726 | try run_lock_file_test(&contexts); |
| ... | ... | @@ -1740,8 +1755,8 @@ const FileLockTestContext = struct { |
| 1740 | 1755 | |
| 1741 | 1756 | // use file.createFile |
| 1742 | 1757 | create: bool, |
| 1743 | | // get a read/write lock, instead of just a read lock |
| 1744 | | exclusive: bool, |
| 1758 | // the type of lock to use |
| 1759 | lock: File.Lock, |
| 1745 | 1760 | |
| 1746 | 1761 | // Output variables |
| 1747 | 1762 | err: ?(File.OpenError || std.os.ReadError) = null, |
| ... | ... | @@ -1756,12 +1771,12 @@ const FileLockTestContext = struct { |
| 1756 | 1771 | fn run(ctx: *@This()) void { |
| 1757 | 1772 | var file: File = undefined; |
| 1758 | 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 | 1775 | ctx.err = err; |
| 1761 | 1776 | return; |
| 1762 | 1777 | }; |
| 1763 | 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 | 1780 | ctx.err = err; |
| 1766 | 1781 | return; |
| 1767 | 1782 | }; |