| author | |
| committer | |
| log | a6e288d5fe51d5373fa995b5eec2dd2325c1ea9f |
| tree | 583c2fbf0a708c222e3cc7a493f93b0a2e9da16b |
| parent | 121307679bd1ffeaa8a290a826396662f26a4ac1 |
| parent | 5951211d3fc348fc37a86abc9906acf4ee796883 |
| signature |
Add lock option to File.OpenFlags and File.CreateFlags21 files changed, 526 insertions(+), 34 deletions(-)
lib/std/c.zig+1| ... | ... | @@ -122,6 +122,7 @@ pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*u |
| 122 | 122 | pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; |
| 123 | 123 | pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; |
| 124 | 124 | pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; |
| 125 | pub extern "c" fn flock(fd: fd_t, operation: c_int) c_int; | |
| 125 | 126 | pub extern "c" fn uname(buf: *utsname) c_int; |
| 126 | 127 | |
| 127 | 128 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; |
lib/std/child_process.zig+1| ... | ... | @@ -357,6 +357,7 @@ pub const ChildProcess = struct { |
| 357 | 357 | error.NoSpaceLeft => unreachable, |
| 358 | 358 | error.FileTooBig => unreachable, |
| 359 | 359 | error.DeviceBusy => unreachable, |
| 360 | error.FileLocksNotSupported => unreachable, | |
| 360 | 361 | else => |e| return e, |
| 361 | 362 | } |
| 362 | 363 | else |
lib/std/fs.zig+219-5| ... | ... | @@ -594,8 +594,19 @@ pub const Dir = struct { |
| 594 | 594 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path); |
| 595 | 595 | return self.openFileW(&path_w, flags); |
| 596 | 596 | } |
| 597 | ||
| 598 | // Use the O_ locking flags if the os supports them | |
| 599 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) | |
| 600 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !builtin.os.tag.isDarwin(); | |
| 601 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); | |
| 602 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { | |
| 603 | .None => @as(u32, 0), | |
| 604 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, | |
| 605 | .Exclusive => os.O_EXLOCK | nonblocking_lock_flag, | |
| 606 | } else 0; | |
| 607 | ||
| 597 | 608 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 598 | const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) | |
| 609 | const os_flags = lock_flag | O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) | |
| 599 | 610 | @as(u32, os.O_RDWR) |
| 600 | 611 | else if (flags.write) |
| 601 | 612 | @as(u32, os.O_WRONLY) |
| ... | ... | @@ -605,6 +616,17 @@ pub const Dir = struct { |
| 605 | 616 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0) |
| 606 | 617 | else |
| 607 | 618 | try os.openatZ(self.fd, sub_path, os_flags, 0); |
| 619 | ||
| 620 | if (!has_flock_open_flags and flags.lock != .None) { | |
| 621 | // TODO: integrate async I/O | |
| 622 | const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0); | |
| 623 | try os.flock(fd, switch (flags.lock) { | |
| 624 | .None => unreachable, | |
| 625 | .Shared => os.LOCK_SH | lock_nonblocking, | |
| 626 | .Exclusive => os.LOCK_EX | lock_nonblocking, | |
| 627 | }); | |
| 628 | } | |
| 629 | ||
| 608 | 630 | return File{ |
| 609 | 631 | .handle = fd, |
| 610 | 632 | .io_mode = .blocking, |
| ... | ... | @@ -622,8 +644,15 @@ pub const Dir = struct { |
| 622 | 644 | const access_mask = w.SYNCHRONIZE | |
| 623 | 645 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 624 | 646 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); |
| 647 | ||
| 648 | const share_access = switch (flags.lock) { | |
| 649 | .None => @as(?w.ULONG, null), | |
| 650 | .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, | |
| 651 | .Exclusive => w.FILE_SHARE_DELETE, | |
| 652 | }; | |
| 653 | ||
| 625 | 654 | return @as(File, .{ |
| 626 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, w.FILE_OPEN), | |
| 655 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, flags.lock_nonblocking, w.FILE_OPEN), | |
| 627 | 656 | .io_mode = .blocking, |
| 628 | 657 | }); |
| 629 | 658 | } |
| ... | ... | @@ -648,8 +677,19 @@ pub const Dir = struct { |
| 648 | 677 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 649 | 678 | return self.createFileW(&path_w, flags); |
| 650 | 679 | } |
| 680 | ||
| 681 | // Use the O_ locking flags if the os supports them | |
| 682 | // (Or if it's darwin, as darwin's `open` doesn't support the O_SYNC flag) | |
| 683 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK") and !builtin.os.tag.isDarwin(); | |
| 684 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); | |
| 685 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { | |
| 686 | .None => @as(u32, 0), | |
| 687 | .Shared => os.O_SHLOCK, | |
| 688 | .Exclusive => os.O_EXLOCK, | |
| 689 | } else 0; | |
| 690 | ||
| 651 | 691 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 652 | const os_flags = O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | |
| 692 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | |
| 653 | 693 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | |
| 654 | 694 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | |
| 655 | 695 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); |
| ... | ... | @@ -657,6 +697,17 @@ pub const Dir = struct { |
| 657 | 697 | try std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, flags.mode) |
| 658 | 698 | else |
| 659 | 699 | try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode); |
| 700 | ||
| 701 | if (!has_flock_open_flags and flags.lock != .None) { | |
| 702 | // TODO: integrate async I/O | |
| 703 | const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0); | |
| 704 | try os.flock(fd, switch (flags.lock) { | |
| 705 | .None => unreachable, | |
| 706 | .Shared => os.LOCK_SH | lock_nonblocking, | |
| 707 | .Exclusive => os.LOCK_EX | lock_nonblocking, | |
| 708 | }); | |
| 709 | } | |
| 710 | ||
| 660 | 711 | return File{ .handle = fd, .io_mode = .blocking }; |
| 661 | 712 | } |
| 662 | 713 | |
| ... | ... | @@ -672,8 +723,15 @@ pub const Dir = struct { |
| 672 | 723 | @as(u32, w.FILE_OVERWRITE_IF) |
| 673 | 724 | else |
| 674 | 725 | @as(u32, w.FILE_OPEN_IF); |
| 726 | ||
| 727 | const share_access = switch (flags.lock) { | |
| 728 | .None => @as(?w.ULONG, null), | |
| 729 | .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, | |
| 730 | .Exclusive => w.FILE_SHARE_DELETE, | |
| 731 | }; | |
| 732 | ||
| 675 | 733 | return @as(File, .{ |
| 676 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, creation), | |
| 734 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, flags.lock_nonblocking, creation), | |
| 677 | 735 | .io_mode = .blocking, |
| 678 | 736 | }); |
| 679 | 737 | } |
| ... | ... | @@ -802,6 +860,7 @@ pub const Dir = struct { |
| 802 | 860 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| 803 | 861 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| 804 | 862 | error.PathAlreadyExists => unreachable, // not providing O_CREAT |
| 863 | error.FileLocksNotSupported => unreachable, // locking folders is not supported | |
| 805 | 864 | else => |e| return e, |
| 806 | 865 | }; |
| 807 | 866 | return Dir{ .fd = fd }; |
| ... | ... | @@ -1508,7 +1567,7 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1508 | 1567 | return walker; |
| 1509 | 1568 | } |
| 1510 | 1569 | |
| 1511 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; | |
| 1570 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError || os.FlockError; | |
| 1512 | 1571 | |
| 1513 | 1572 | pub fn openSelfExe() OpenSelfExeError!File { |
| 1514 | 1573 | if (builtin.os.tag == .linux) { |
| ... | ... | @@ -1624,3 +1683,158 @@ test "" { |
| 1624 | 1683 | _ = @import("fs/get_app_data_dir.zig"); |
| 1625 | 1684 | _ = @import("fs/watch.zig"); |
| 1626 | 1685 | } |
| 1686 | ||
| 1687 | const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.millisecond; | |
| 1688 | ||
| 1689 | test "open file with exclusive nonblocking lock twice" { | |
| 1690 | const dir = cwd(); | |
| 1691 | const filename = "file_nonblocking_lock_test.txt"; | |
| 1692 | ||
| 1693 | const file1 = try dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); | |
| 1694 | defer file1.close(); | |
| 1695 | ||
| 1696 | const file2 = dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); | |
| 1697 | std.debug.assert(std.meta.eql(file2, error.WouldBlock)); | |
| 1698 | ||
| 1699 | dir.deleteFile(filename) catch |err| switch (err) { | |
| 1700 | error.FileNotFound => {}, | |
| 1701 | else => return err, | |
| 1702 | }; | |
| 1703 | } | |
| 1704 | ||
| 1705 | test "open file with lock twice, make sure it wasn't open at the same time" { | |
| 1706 | if (builtin.single_threaded) return; | |
| 1707 | ||
| 1708 | const filename = "file_lock_test.txt"; | |
| 1709 | ||
| 1710 | var contexts = [_]FileLockTestContext{ | |
| 1711 | .{ .filename = filename, .create = true, .lock = .Exclusive }, | |
| 1712 | .{ .filename = filename, .create = true, .lock = .Exclusive }, | |
| 1713 | }; | |
| 1714 | try run_lock_file_test(&contexts); | |
| 1715 | ||
| 1716 | // Check for an error | |
| 1717 | var was_error = false; | |
| 1718 | for (contexts) |context, idx| { | |
| 1719 | if (context.err) |err| { | |
| 1720 | was_error = true; | |
| 1721 | std.debug.warn("\nError in context {}: {}\n", .{ idx, err }); | |
| 1722 | } | |
| 1723 | } | |
| 1724 | if (was_error) builtin.panic("There was an error in contexts", null); | |
| 1725 | ||
| 1726 | std.debug.assert(!contexts[0].overlaps(&contexts[1])); | |
| 1727 | ||
| 1728 | cwd().deleteFile(filename) catch |err| switch (err) { | |
| 1729 | error.FileNotFound => {}, | |
| 1730 | else => return err, | |
| 1731 | }; | |
| 1732 | } | |
| 1733 | ||
| 1734 | test "create file, lock and read from multiple process at once" { | |
| 1735 | if (builtin.single_threaded) return; | |
| 1736 | ||
| 1737 | const filename = "file_read_lock_test.txt"; | |
| 1738 | const filedata = "Hello, world!\n"; | |
| 1739 | ||
| 1740 | try std.fs.cwd().writeFile(filename, filedata); | |
| 1741 | ||
| 1742 | var contexts = [_]FileLockTestContext{ | |
| 1743 | .{ .filename = filename, .create = false, .lock = .Shared }, | |
| 1744 | .{ .filename = filename, .create = false, .lock = .Shared }, | |
| 1745 | .{ .filename = filename, .create = false, .lock = .Exclusive }, | |
| 1746 | }; | |
| 1747 | ||
| 1748 | try run_lock_file_test(&contexts); | |
| 1749 | ||
| 1750 | var was_error = false; | |
| 1751 | for (contexts) |context, idx| { | |
| 1752 | if (context.err) |err| { | |
| 1753 | was_error = true; | |
| 1754 | std.debug.warn("\nError in context {}: {}\n", .{ idx, err }); | |
| 1755 | } | |
| 1756 | } | |
| 1757 | if (was_error) builtin.panic("There was an error in contexts", null); | |
| 1758 | ||
| 1759 | std.debug.assert(contexts[0].overlaps(&contexts[1])); | |
| 1760 | std.debug.assert(!contexts[2].overlaps(&contexts[0])); | |
| 1761 | std.debug.assert(!contexts[2].overlaps(&contexts[1])); | |
| 1762 | if (contexts[0].bytes_read.? != filedata.len) { | |
| 1763 | std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ contexts[0].bytes_read, filedata.len }); | |
| 1764 | } | |
| 1765 | std.debug.assert(contexts[0].bytes_read.? == filedata.len); | |
| 1766 | std.debug.assert(contexts[1].bytes_read.? == filedata.len); | |
| 1767 | ||
| 1768 | cwd().deleteFile(filename) catch |err| switch (err) { | |
| 1769 | error.FileNotFound => {}, | |
| 1770 | else => return err, | |
| 1771 | }; | |
| 1772 | } | |
| 1773 | ||
| 1774 | const FileLockTestContext = struct { | |
| 1775 | filename: []const u8, | |
| 1776 | pid: if (builtin.os.tag == .windows) ?void else ?std.os.pid_t = null, | |
| 1777 | ||
| 1778 | // use file.createFile | |
| 1779 | create: bool, | |
| 1780 | // the type of lock to use | |
| 1781 | lock: File.Lock, | |
| 1782 | ||
| 1783 | // Output variables | |
| 1784 | err: ?(File.OpenError || std.os.ReadError) = null, | |
| 1785 | start_time: u64 = 0, | |
| 1786 | end_time: u64 = 0, | |
| 1787 | bytes_read: ?usize = null, | |
| 1788 | ||
| 1789 | fn overlaps(self: *const @This(), other: *const @This()) bool { | |
| 1790 | return (self.start_time < other.end_time) and (self.end_time > other.start_time); | |
| 1791 | } | |
| 1792 | ||
| 1793 | fn run(ctx: *@This()) void { | |
| 1794 | var file: File = undefined; | |
| 1795 | if (ctx.create) { | |
| 1796 | file = cwd().createFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { | |
| 1797 | ctx.err = err; | |
| 1798 | return; | |
| 1799 | }; | |
| 1800 | } else { | |
| 1801 | file = cwd().openFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { | |
| 1802 | ctx.err = err; | |
| 1803 | return; | |
| 1804 | }; | |
| 1805 | } | |
| 1806 | defer file.close(); | |
| 1807 | ||
| 1808 | ctx.start_time = std.time.milliTimestamp(); | |
| 1809 | ||
| 1810 | if (!ctx.create) { | |
| 1811 | var buffer: [100]u8 = undefined; | |
| 1812 | ctx.bytes_read = 0; | |
| 1813 | while (true) { | |
| 1814 | const amt = file.read(buffer[0..]) catch |err| { | |
| 1815 | ctx.err = err; | |
| 1816 | return; | |
| 1817 | }; | |
| 1818 | if (amt == 0) break; | |
| 1819 | ctx.bytes_read.? += amt; | |
| 1820 | } | |
| 1821 | } | |
| 1822 | ||
| 1823 | std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME); | |
| 1824 | ||
| 1825 | ctx.end_time = std.time.milliTimestamp(); | |
| 1826 | } | |
| 1827 | }; | |
| 1828 | ||
| 1829 | fn run_lock_file_test(contexts: []FileLockTestContext) !void { | |
| 1830 | var threads = std.ArrayList(*std.Thread).init(std.testing.allocator); | |
| 1831 | defer { | |
| 1832 | for (threads.toSlice()) |thread| { | |
| 1833 | thread.wait(); | |
| 1834 | } | |
| 1835 | threads.deinit(); | |
| 1836 | } | |
| 1837 | for (contexts) |*ctx, idx| { | |
| 1838 | try threads.append(try std.Thread.spawn(ctx, FileLockTestContext.run)); | |
| 1839 | } | |
| 1840 | } |
lib/std/fs/file.zig+45-1| ... | ... | @@ -34,13 +34,37 @@ pub const File = struct { |
| 34 | 34 | else => 0o666, |
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | pub const OpenError = windows.CreateFileError || os.OpenError; | |
| 37 | pub const OpenError = windows.CreateFileError || os.OpenError || os.FlockError; | |
| 38 | ||
| 39 | pub const Lock = enum { | |
| 40 | None, Shared, Exclusive | |
| 41 | }; | |
| 38 | 42 | |
| 39 | 43 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| 40 | 44 | pub const OpenFlags = struct { |
| 41 | 45 | read: bool = true, |
| 42 | 46 | write: bool = false, |
| 43 | 47 | |
| 48 | /// Open the file with a lock to prevent other processes from accessing it at the | |
| 49 | /// same time. An exclusive lock will prevent other processes from acquiring a lock. | |
| 50 | /// A shared lock will prevent other processes from acquiring a exclusive lock, but | |
| 51 | /// doesn't prevent other process from getting their own shared locks. | |
| 52 | /// | |
| 53 | /// Note that the lock is only advisory on Linux, except in very specific cirsumstances[1]. | |
| 54 | /// This means that a process that does not respect the locking API can still get access | |
| 55 | /// to the file, despite the lock. | |
| 56 | /// | |
| 57 | /// Windows' file locks are mandatory, and any process attempting to access the file will | |
| 58 | /// receive an error. | |
| 59 | /// | |
| 60 | /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt | |
| 61 | lock: Lock = .None, | |
| 62 | ||
| 63 | /// Sets whether or not to wait until the file is locked to return. If set to true, | |
| 64 | /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file | |
| 65 | /// is available to proceed. | |
| 66 | lock_nonblocking: bool = false, | |
| 67 | ||
| 44 | 68 | /// This prevents `O_NONBLOCK` from being passed even if `std.io.is_async`. |
| 45 | 69 | /// It allows the use of `noasync` when calling functions related to opening |
| 46 | 70 | /// the file, reading, and writing. |
| ... | ... | @@ -60,6 +84,26 @@ pub const File = struct { |
| 60 | 84 | /// `error.FileAlreadyExists` to be returned. |
| 61 | 85 | exclusive: bool = false, |
| 62 | 86 | |
| 87 | /// Open the file with a lock to prevent other processes from accessing it at the | |
| 88 | /// same time. An exclusive lock will prevent other processes from acquiring a lock. | |
| 89 | /// A shared lock will prevent other processes from acquiring a exclusive lock, but | |
| 90 | /// doesn't prevent other process from getting their own shared locks. | |
| 91 | /// | |
| 92 | /// Note that the lock is only advisory on Linux, except in very specific cirsumstances[1]. | |
| 93 | /// This means that a process that does not respect the locking API can still get access | |
| 94 | /// to the file, despite the lock. | |
| 95 | /// | |
| 96 | /// Windows' file locks are mandatory, and any process attempting to access the file will | |
| 97 | /// receive an error. | |
| 98 | /// | |
| 99 | /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt | |
| 100 | lock: Lock = .None, | |
| 101 | ||
| 102 | /// Sets whether or not to wait until the file is locked to return. If set to true, | |
| 103 | /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file | |
| 104 | /// is available to proceed. | |
| 105 | lock_nonblocking: bool = false, | |
| 106 | ||
| 63 | 107 | /// For POSIX systems this is the file system mode the file will |
| 64 | 108 | /// be created with. |
| 65 | 109 | mode: Mode = default_mode, |
lib/std/os.zig+34-2| ... | ... | @@ -846,6 +846,9 @@ pub const OpenError = error{ |
| 846 | 846 | /// The path already exists and the `O_CREAT` and `O_EXCL` flags were provided. |
| 847 | 847 | PathAlreadyExists, |
| 848 | 848 | DeviceBusy, |
| 849 | ||
| 850 | /// The underlying filesystem does not support file locks | |
| 851 | FileLocksNotSupported, | |
| 849 | 852 | } || UnexpectedError; |
| 850 | 853 | |
| 851 | 854 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| ... | ... | @@ -931,6 +934,7 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) |
| 931 | 934 | EPERM => return error.AccessDenied, |
| 932 | 935 | EEXIST => return error.PathAlreadyExists, |
| 933 | 936 | EBUSY => return error.DeviceBusy, |
| 937 | EOPNOTSUPP => return error.FileLocksNotSupported, | |
| 934 | 938 | else => |err| return unexpectedErrno(err), |
| 935 | 939 | } |
| 936 | 940 | } |
| ... | ... | @@ -1676,7 +1680,10 @@ pub fn renameatW( |
| 1676 | 1680 | ReplaceIfExists: windows.BOOLEAN, |
| 1677 | 1681 | ) RenameError!void { |
| 1678 | 1682 | const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE; |
| 1679 | const src_fd = try windows.OpenFileW(old_dir_fd, old_path, null, access_mask, windows.FILE_OPEN); | |
| 1683 | const src_fd = windows.OpenFileW(old_dir_fd, old_path, null, access_mask, null, false, windows.FILE_OPEN) catch |err| switch (err) { | |
| 1684 | error.WouldBlock => unreachable, | |
| 1685 | else => |e| return e, | |
| 1686 | }; | |
| 1680 | 1687 | defer windows.CloseHandle(src_fd); |
| 1681 | 1688 | |
| 1682 | 1689 | const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1); |
| ... | ... | @@ -3218,6 +3225,28 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { |
| 3218 | 3225 | } |
| 3219 | 3226 | } |
| 3220 | 3227 | |
| 3228 | pub const FlockError = error{ | |
| 3229 | WouldBlock, | |
| 3230 | ||
| 3231 | /// The kernel ran out of memory for allocating file locks | |
| 3232 | SystemResources, | |
| 3233 | } || UnexpectedError; | |
| 3234 | ||
| 3235 | pub fn flock(fd: fd_t, operation: i32) FlockError!void { | |
| 3236 | while (true) { | |
| 3237 | const rc = system.flock(fd, operation); | |
| 3238 | switch (errno(rc)) { | |
| 3239 | 0 => return, | |
| 3240 | EBADF => unreachable, | |
| 3241 | EINTR => continue, | |
| 3242 | EINVAL => unreachable, // invalid parameters | |
| 3243 | ENOLCK => return error.SystemResources, | |
| 3244 | EWOULDBLOCK => return error.WouldBlock, // TODO: integrate with async instead of just returning an error | |
| 3245 | else => |err| return unexpectedErrno(err), | |
| 3246 | } | |
| 3247 | } | |
| 3248 | } | |
| 3249 | ||
| 3221 | 3250 | pub const RealPathError = error{ |
| 3222 | 3251 | FileNotFound, |
| 3223 | 3252 | AccessDenied, |
| ... | ... | @@ -3269,7 +3298,10 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP |
| 3269 | 3298 | return realpathW(&pathname_w, out_buffer); |
| 3270 | 3299 | } |
| 3271 | 3300 | if (builtin.os.tag == .linux and !builtin.link_libc) { |
| 3272 | const fd = try openZ(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0); | |
| 3301 | const fd = openZ(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0) catch |err| switch (err) { | |
| 3302 | error.FileLocksNotSupported => unreachable, | |
| 3303 | else => |e| return e, | |
| 3304 | }; | |
| 3273 | 3305 | defer close(fd); |
| 3274 | 3306 | |
| 3275 | 3307 | var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined; |
lib/std/os/bits/darwin.zig+13| ... | ... | @@ -55,6 +55,14 @@ pub const mach_timebase_info_data = extern struct { |
| 55 | 55 | pub const off_t = i64; |
| 56 | 56 | pub const ino_t = u64; |
| 57 | 57 | |
| 58 | pub const Flock = extern struct { | |
| 59 | l_start: off_t, | |
| 60 | l_len: off_t, | |
| 61 | l_pid: pid_t, | |
| 62 | l_type: i16, | |
| 63 | l_whence: i16, | |
| 64 | }; | |
| 65 | ||
| 58 | 66 | /// Renamed to Stat to not conflict with the stat function. |
| 59 | 67 | /// atime, mtime, and ctime have functions to return `timespec`, |
| 60 | 68 | /// because although this is a POSIX API, the layout and names of |
| ... | ... | @@ -1386,3 +1394,8 @@ pub const F_UNLCK = 2; |
| 1386 | 1394 | |
| 1387 | 1395 | /// exclusive or write lock |
| 1388 | 1396 | pub const F_WRLCK = 3; |
| 1397 | ||
| 1398 | pub const LOCK_SH = 1; | |
| 1399 | pub const LOCK_EX = 2; | |
| 1400 | pub const LOCK_UN = 8; | |
| 1401 | pub const LOCK_NB = 4; |
lib/std/os/bits/dragonfly.zig+5| ... | ... | @@ -697,6 +697,11 @@ pub const F_DUP2FD = 10; |
| 697 | 697 | pub const F_DUPFD_CLOEXEC = 17; |
| 698 | 698 | pub const F_DUP2FD_CLOEXEC = 18; |
| 699 | 699 | |
| 700 | pub const LOCK_SH = 1; | |
| 701 | pub const LOCK_EX = 2; | |
| 702 | pub const LOCK_UN = 8; | |
| 703 | pub const LOCK_NB = 4; | |
| 704 | ||
| 700 | 705 | pub const Flock = extern struct { |
| 701 | 706 | l_start: off_t, |
| 702 | 707 | l_len: off_t, |
lib/std/os/bits/freebsd.zig+22| ... | ... | @@ -51,6 +51,16 @@ pub const dl_phdr_info = extern struct { |
| 51 | 51 | dlpi_phnum: u16, |
| 52 | 52 | }; |
| 53 | 53 | |
| 54 | pub const Flock = extern struct { | |
| 55 | l_start: off_t, | |
| 56 | l_len: off_t, | |
| 57 | l_pid: pid_t, | |
| 58 | l_type: i16, | |
| 59 | l_whence: i16, | |
| 60 | l_sysid: i32, | |
| 61 | __unused: [4]u8, | |
| 62 | }; | |
| 63 | ||
| 54 | 64 | pub const msghdr = extern struct { |
| 55 | 65 | /// optional address |
| 56 | 66 | msg_name: ?*sockaddr, |
| ... | ... | @@ -315,6 +325,9 @@ pub const O_WRONLY = 0x0001; |
| 315 | 325 | pub const O_RDWR = 0x0002; |
| 316 | 326 | pub const O_ACCMODE = 0x0003; |
| 317 | 327 | |
| 328 | pub const O_SHLOCK = 0x0010; | |
| 329 | pub const O_EXLOCK = 0x0020; | |
| 330 | ||
| 318 | 331 | pub const O_CREAT = 0x0200; |
| 319 | 332 | pub const O_EXCL = 0x0800; |
| 320 | 333 | pub const O_NOCTTY = 0x8000; |
| ... | ... | @@ -350,6 +363,15 @@ pub const F_GETLK = 5; |
| 350 | 363 | pub const F_SETLK = 6; |
| 351 | 364 | pub const F_SETLKW = 7; |
| 352 | 365 | |
| 366 | pub const F_RDLCK = 1; | |
| 367 | pub const F_WRLCK = 3; | |
| 368 | pub const F_UNLCK = 2; | |
| 369 | ||
| 370 | pub const LOCK_SH = 1; | |
| 371 | pub const LOCK_EX = 2; | |
| 372 | pub const LOCK_UN = 8; | |
| 373 | pub const LOCK_NB = 4; | |
| 374 | ||
| 353 | 375 | pub const F_SETOWN_EX = 15; |
| 354 | 376 | pub const F_GETOWN_EX = 16; |
| 355 | 377 |
lib/std/os/bits/linux/arm-eabi.zig+20| ... | ... | @@ -8,6 +8,7 @@ const stack_t = linux.stack_t; |
| 8 | 8 | const sigset_t = linux.sigset_t; |
| 9 | 9 | const uid_t = linux.uid_t; |
| 10 | 10 | const gid_t = linux.gid_t; |
| 11 | const pid_t = linux.pid_t; | |
| 11 | 12 | |
| 12 | 13 | pub const SYS = extern enum(usize) { |
| 13 | 14 | restart_syscall = 0, |
| ... | ... | @@ -452,11 +453,20 @@ pub const F_GETLK = 12; |
| 452 | 453 | pub const F_SETLK = 13; |
| 453 | 454 | pub const F_SETLKW = 14; |
| 454 | 455 | |
| 456 | pub const F_RDLCK = 0; | |
| 457 | pub const F_WRLCK = 1; | |
| 458 | pub const F_UNLCK = 2; | |
| 459 | ||
| 455 | 460 | pub const F_SETOWN_EX = 15; |
| 456 | 461 | pub const F_GETOWN_EX = 16; |
| 457 | 462 | |
| 458 | 463 | pub const F_GETOWNER_UIDS = 17; |
| 459 | 464 | |
| 465 | pub const LOCK_SH = 1; | |
| 466 | pub const LOCK_EX = 2; | |
| 467 | pub const LOCK_UN = 8; | |
| 468 | pub const LOCK_NB = 4; | |
| 469 | ||
| 460 | 470 | /// stack-like segment |
| 461 | 471 | pub const MAP_GROWSDOWN = 0x0100; |
| 462 | 472 | |
| ... | ... | @@ -499,6 +509,16 @@ pub const HWCAP_IDIV = HWCAP_IDIVA | HWCAP_IDIVT; |
| 499 | 509 | pub const HWCAP_LPAE = 1 << 20; |
| 500 | 510 | pub const HWCAP_EVTSTRM = 1 << 21; |
| 501 | 511 | |
| 512 | pub const Flock = extern struct { | |
| 513 | l_type: i16, | |
| 514 | l_whence: i16, | |
| 515 | __pad0: [4]u8, | |
| 516 | l_start: off_t, | |
| 517 | l_len: off_t, | |
| 518 | l_pid: pid_t, | |
| 519 | __unused: [4]u8, | |
| 520 | }; | |
| 521 | ||
| 502 | 522 | pub const msghdr = extern struct { |
| 503 | 523 | msg_name: ?*sockaddr, |
| 504 | 524 | msg_namelen: socklen_t, |
lib/std/os/bits/linux/arm64.zig+19| ... | ... | @@ -8,6 +8,7 @@ const iovec = linux.iovec; |
| 8 | 8 | const iovec_const = linux.iovec_const; |
| 9 | 9 | const uid_t = linux.uid_t; |
| 10 | 10 | const gid_t = linux.gid_t; |
| 11 | const pid_t = linux.pid_t; | |
| 11 | 12 | const stack_t = linux.stack_t; |
| 12 | 13 | const sigset_t = linux.sigset_t; |
| 13 | 14 | pub const SYS = extern enum(usize) { |
| ... | ... | @@ -344,6 +345,15 @@ pub const F_GETLK = 5; |
| 344 | 345 | pub const F_SETLK = 6; |
| 345 | 346 | pub const F_SETLKW = 7; |
| 346 | 347 | |
| 348 | pub const F_RDLCK = 0; | |
| 349 | pub const F_WRLCK = 1; | |
| 350 | pub const F_UNLCK = 2; | |
| 351 | ||
| 352 | pub const LOCK_SH = 1; | |
| 353 | pub const LOCK_EX = 2; | |
| 354 | pub const LOCK_UN = 8; | |
| 355 | pub const LOCK_NB = 4; | |
| 356 | ||
| 347 | 357 | pub const F_SETOWN_EX = 15; |
| 348 | 358 | pub const F_GETOWN_EX = 16; |
| 349 | 359 | |
| ... | ... | @@ -367,6 +377,15 @@ pub const MAP_NORESERVE = 0x4000; |
| 367 | 377 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; |
| 368 | 378 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; |
| 369 | 379 | |
| 380 | pub const Flock = extern struct { | |
| 381 | l_type: i16, | |
| 382 | l_whence: i16, | |
| 383 | l_start: off_t, | |
| 384 | l_len: off_t, | |
| 385 | l_pid: pid_t, | |
| 386 | __unused: [4]u8, | |
| 387 | }; | |
| 388 | ||
| 370 | 389 | pub const msghdr = extern struct { |
| 371 | 390 | msg_name: ?*sockaddr, |
| 372 | 391 | msg_namelen: socklen_t, |
lib/std/os/bits/linux/i386.zig+18| ... | ... | @@ -8,6 +8,7 @@ const iovec = linux.iovec; |
| 8 | 8 | const iovec_const = linux.iovec_const; |
| 9 | 9 | const uid_t = linux.uid_t; |
| 10 | 10 | const gid_t = linux.gid_t; |
| 11 | const pid_t = linux.pid_t; | |
| 11 | 12 | const stack_t = linux.stack_t; |
| 12 | 13 | const sigset_t = linux.sigset_t; |
| 13 | 14 | |
| ... | ... | @@ -477,6 +478,15 @@ pub const F_GETLK = 12; |
| 477 | 478 | pub const F_SETLK = 13; |
| 478 | 479 | pub const F_SETLKW = 14; |
| 479 | 480 | |
| 481 | pub const F_RDLCK = 0; | |
| 482 | pub const F_WRLCK = 1; | |
| 483 | pub const F_UNLCK = 2; | |
| 484 | ||
| 485 | pub const LOCK_SH = 1; | |
| 486 | pub const LOCK_EX = 2; | |
| 487 | pub const LOCK_UN = 8; | |
| 488 | pub const LOCK_NB = 4; | |
| 489 | ||
| 480 | 490 | pub const F_SETOWN_EX = 15; |
| 481 | 491 | pub const F_GETOWN_EX = 16; |
| 482 | 492 | |
| ... | ... | @@ -494,6 +504,14 @@ pub const MMAP2_UNIT = 4096; |
| 494 | 504 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; |
| 495 | 505 | pub const VDSO_CGT_VER = "LINUX_2.6"; |
| 496 | 506 | |
| 507 | pub const Flock = extern struct { | |
| 508 | l_type: i16, | |
| 509 | l_whence: i16, | |
| 510 | l_start: off_t, | |
| 511 | l_len: off_t, | |
| 512 | l_pid: pid_t, | |
| 513 | }; | |
| 514 | ||
| 497 | 515 | pub const msghdr = extern struct { |
| 498 | 516 | msg_name: ?*sockaddr, |
| 499 | 517 | msg_namelen: socklen_t, |
lib/std/os/bits/linux/mipsel.zig+20| ... | ... | @@ -5,6 +5,7 @@ const iovec = linux.iovec; |
| 5 | 5 | const iovec_const = linux.iovec_const; |
| 6 | 6 | const uid_t = linux.uid_t; |
| 7 | 7 | const gid_t = linux.gid_t; |
| 8 | const pid_t = linux.pid_t; | |
| 8 | 9 | |
| 9 | 10 | pub const SYS = extern enum(usize) { |
| 10 | 11 | pub const Linux = 4000; |
| ... | ... | @@ -419,6 +420,15 @@ pub const F_GETLK = 33; |
| 419 | 420 | pub const F_SETLK = 34; |
| 420 | 421 | pub const F_SETLKW = 35; |
| 421 | 422 | |
| 423 | pub const F_RDLCK = 0; | |
| 424 | pub const F_WRLCK = 1; | |
| 425 | pub const F_UNLCK = 2; | |
| 426 | ||
| 427 | pub const LOCK_SH = 1; | |
| 428 | pub const LOCK_EX = 2; | |
| 429 | pub const LOCK_UN = 8; | |
| 430 | pub const LOCK_NB = 4; | |
| 431 | ||
| 422 | 432 | pub const F_SETOWN_EX = 15; |
| 423 | 433 | pub const F_GETOWN_EX = 16; |
| 424 | 434 | |
| ... | ... | @@ -464,6 +474,16 @@ pub const SO_RCVBUFFORCE = 33; |
| 464 | 474 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; |
| 465 | 475 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; |
| 466 | 476 | |
| 477 | pub const Flock = extern struct { | |
| 478 | l_type: i16, | |
| 479 | l_whence: i16, | |
| 480 | __pad0: [4]u8, | |
| 481 | l_start: off_t, | |
| 482 | l_len: off_t, | |
| 483 | l_pid: pid_t, | |
| 484 | __unused: [4]u8, | |
| 485 | }; | |
| 486 | ||
| 467 | 487 | pub const blksize_t = i32; |
| 468 | 488 | pub const nlink_t = u32; |
| 469 | 489 | pub const time_t = isize; |
lib/std/os/bits/linux/riscv64.zig+19| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | const std = @import("../../../std.zig"); |
| 3 | 3 | const uid_t = std.os.linux.uid_t; |
| 4 | 4 | const gid_t = std.os.linux.gid_t; |
| 5 | const pid_t = std.os.linux.pid_t; | |
| 5 | 6 | |
| 6 | 7 | pub const SYS = extern enum(usize) { |
| 7 | 8 | io_setup = 0, |
| ... | ... | @@ -338,6 +339,15 @@ pub const F_GETOWN = 9; |
| 338 | 339 | pub const F_SETSIG = 10; |
| 339 | 340 | pub const F_GETSIG = 11; |
| 340 | 341 | |
| 342 | pub const F_RDLCK = 0; | |
| 343 | pub const F_WRLCK = 1; | |
| 344 | pub const F_UNLCK = 2; | |
| 345 | ||
| 346 | pub const LOCK_SH = 1; | |
| 347 | pub const LOCK_EX = 2; | |
| 348 | pub const LOCK_UN = 8; | |
| 349 | pub const LOCK_NB = 4; | |
| 350 | ||
| 341 | 351 | pub const F_SETOWN_EX = 15; |
| 342 | 352 | pub const F_GETOWN_EX = 16; |
| 343 | 353 | |
| ... | ... | @@ -356,6 +366,15 @@ pub const timespec = extern struct { |
| 356 | 366 | tv_nsec: isize, |
| 357 | 367 | }; |
| 358 | 368 | |
| 369 | pub const Flock = extern struct { | |
| 370 | l_type: i16, | |
| 371 | l_whence: i16, | |
| 372 | l_start: off_t, | |
| 373 | l_len: off_t, | |
| 374 | l_pid: pid_t, | |
| 375 | __unused: [4]u8, | |
| 376 | }; | |
| 377 | ||
| 359 | 378 | /// Renamed to Stat to not conflict with the stat function. |
| 360 | 379 | /// atime, mtime, and ctime have functions to return `timespec`, |
| 361 | 380 | /// because although this is a POSIX API, the layout and names of |
lib/std/os/bits/linux/x86_64.zig+17| ... | ... | @@ -462,6 +462,23 @@ pub const REG_TRAPNO = 20; |
| 462 | 462 | pub const REG_OLDMASK = 21; |
| 463 | 463 | pub const REG_CR2 = 22; |
| 464 | 464 | |
| 465 | pub const LOCK_SH = 1; | |
| 466 | pub const LOCK_EX = 2; | |
| 467 | pub const LOCK_UN = 8; | |
| 468 | pub const LOCK_NB = 4; | |
| 469 | ||
| 470 | pub const F_RDLCK = 0; | |
| 471 | pub const F_WRLCK = 1; | |
| 472 | pub const F_UNLCK = 2; | |
| 473 | ||
| 474 | pub const Flock = extern struct { | |
| 475 | l_type: i16, | |
| 476 | l_whence: i16, | |
| 477 | l_start: off_t, | |
| 478 | l_len: off_t, | |
| 479 | l_pid: pid_t, | |
| 480 | }; | |
| 481 | ||
| 465 | 482 | pub const msghdr = extern struct { |
| 466 | 483 | msg_name: ?*sockaddr, |
| 467 | 484 | msg_namelen: socklen_t, |
lib/std/os/bits/netbsd.zig+17| ... | ... | @@ -35,6 +35,14 @@ pub const dl_phdr_info = extern struct { |
| 35 | 35 | dlpi_phnum: u16, |
| 36 | 36 | }; |
| 37 | 37 | |
| 38 | pub const Flock = extern struct { | |
| 39 | l_start: off_t, | |
| 40 | l_len: off_t, | |
| 41 | l_pid: pid_t, | |
| 42 | l_type: i16, | |
| 43 | l_whence: i16, | |
| 44 | }; | |
| 45 | ||
| 38 | 46 | pub const addrinfo = extern struct { |
| 39 | 47 | flags: i32, |
| 40 | 48 | family: i32, |
| ... | ... | @@ -435,6 +443,15 @@ pub const F_GETLK = 7; |
| 435 | 443 | pub const F_SETLK = 8; |
| 436 | 444 | pub const F_SETLKW = 9; |
| 437 | 445 | |
| 446 | pub const F_RDLCK = 1; | |
| 447 | pub const F_WRLCK = 3; | |
| 448 | pub const F_UNLCK = 2; | |
| 449 | ||
| 450 | pub const LOCK_SH = 1; | |
| 451 | pub const LOCK_EX = 2; | |
| 452 | pub const LOCK_UN = 8; | |
| 453 | pub const LOCK_NB = 4; | |
| 454 | ||
| 438 | 455 | pub const FD_CLOEXEC = 1; |
| 439 | 456 | |
| 440 | 457 | pub const SEEK_SET = 0; |
lib/std/os/linux.zig+4| ... | ... | @@ -592,6 +592,10 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize { |
| 592 | 592 | return syscall3(.fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), arg); |
| 593 | 593 | } |
| 594 | 594 | |
| 595 | pub fn flock(fd: fd_t, operation: i32) usize { | |
| 596 | return syscall2(.flock, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, operation))); | |
| 597 | } | |
| 598 | ||
| 595 | 599 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); |
| 596 | 600 | |
| 597 | 601 | // We must follow the C calling convention when we call into the VDSO |
lib/std/os/windows.zig+43-26| ... | ... | @@ -98,6 +98,7 @@ pub const OpenError = error{ |
| 98 | 98 | PathAlreadyExists, |
| 99 | 99 | Unexpected, |
| 100 | 100 | NameTooLong, |
| 101 | WouldBlock, | |
| 101 | 102 | }; |
| 102 | 103 | |
| 103 | 104 | /// TODO rename to CreateFileW |
| ... | ... | @@ -107,6 +108,8 @@ pub fn OpenFileW( |
| 107 | 108 | sub_path_w: [*:0]const u16, |
| 108 | 109 | sa: ?*SECURITY_ATTRIBUTES, |
| 109 | 110 | access_mask: ACCESS_MASK, |
| 111 | share_access_opt: ?ULONG, | |
| 112 | share_access_nonblocking: bool, | |
| 110 | 113 | creation: ULONG, |
| 111 | 114 | ) OpenError!HANDLE { |
| 112 | 115 | if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { |
| ... | ... | @@ -135,32 +138,46 @@ pub fn OpenFileW( |
| 135 | 138 | .SecurityQualityOfService = null, |
| 136 | 139 | }; |
| 137 | 140 | var io: IO_STATUS_BLOCK = undefined; |
| 138 | const rc = ntdll.NtCreateFile( | |
| 139 | &result, | |
| 140 | access_mask, | |
| 141 | &attr, | |
| 142 | &io, | |
| 143 | null, | |
| 144 | FILE_ATTRIBUTE_NORMAL, | |
| 145 | FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, | |
| 146 | creation, | |
| 147 | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, | |
| 148 | null, | |
| 149 | 0, | |
| 150 | ); | |
| 151 | switch (rc) { | |
| 152 | .SUCCESS => return result, | |
| 153 | .OBJECT_NAME_INVALID => unreachable, | |
| 154 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | |
| 155 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, | |
| 156 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, | |
| 157 | .INVALID_PARAMETER => unreachable, | |
| 158 | .SHARING_VIOLATION => return error.SharingViolation, | |
| 159 | .ACCESS_DENIED => return error.AccessDenied, | |
| 160 | .PIPE_BUSY => return error.PipeBusy, | |
| 161 | .OBJECT_PATH_SYNTAX_BAD => unreachable, | |
| 162 | .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, | |
| 163 | else => return unexpectedStatus(rc), | |
| 141 | const share_access = share_access_opt orelse (FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE); | |
| 142 | ||
| 143 | var delay: usize = 1; | |
| 144 | while (true) { | |
| 145 | const rc = ntdll.NtCreateFile( | |
| 146 | &result, | |
| 147 | access_mask, | |
| 148 | &attr, | |
| 149 | &io, | |
| 150 | null, | |
| 151 | FILE_ATTRIBUTE_NORMAL, | |
| 152 | share_access, | |
| 153 | creation, | |
| 154 | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, | |
| 155 | null, | |
| 156 | 0, | |
| 157 | ); | |
| 158 | switch (rc) { | |
| 159 | .SUCCESS => return result, | |
| 160 | .OBJECT_NAME_INVALID => unreachable, | |
| 161 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | |
| 162 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, | |
| 163 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, | |
| 164 | .INVALID_PARAMETER => unreachable, | |
| 165 | .SHARING_VIOLATION => { | |
| 166 | if (share_access_nonblocking) { | |
| 167 | return error.WouldBlock; | |
| 168 | } | |
| 169 | std.time.sleep(delay); | |
| 170 | if (delay < 1 * std.time.ns_per_s) { | |
| 171 | delay *= 2; | |
| 172 | } | |
| 173 | continue; // TODO: don't loop for async | |
| 174 | }, | |
| 175 | .ACCESS_DENIED => return error.AccessDenied, | |
| 176 | .PIPE_BUSY => return error.PipeBusy, | |
| 177 | .OBJECT_PATH_SYNTAX_BAD => unreachable, | |
| 178 | .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, | |
| 179 | else => return unexpectedStatus(rc), | |
| 180 | } | |
| 164 | 181 | } |
| 165 | 182 | } |
| 166 | 183 |
lib/std/zig/system.zig+2| ... | ... | @@ -468,6 +468,8 @@ pub const NativeTargetInfo = struct { |
| 468 | 468 | error.InvalidUtf8 => unreachable, |
| 469 | 469 | error.BadPathName => unreachable, |
| 470 | 470 | error.PipeBusy => unreachable, |
| 471 | error.FileLocksNotSupported => unreachable, | |
| 472 | error.WouldBlock => unreachable, | |
| 471 | 473 | |
| 472 | 474 | error.IsDir, |
| 473 | 475 | error.NotDir, |
src-self-hosted/stage2.zig+3| ... | ... | @@ -116,6 +116,8 @@ const Error = extern enum { |
| 116 | 116 | UnknownClangOption, |
| 117 | 117 | NestedResponseFile, |
| 118 | 118 | ZigIsTheCCompiler, |
| 119 | FileBusy, | |
| 120 | Locked, | |
| 119 | 121 | }; |
| 120 | 122 | |
| 121 | 123 | const FILE = std.c.FILE; |
| ... | ... | @@ -847,6 +849,7 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ |
| 847 | 849 | error.NoDevice => return .NoDevice, |
| 848 | 850 | error.NotDir => return .NotDir, |
| 849 | 851 | error.DeviceBusy => return .DeviceBusy, |
| 852 | error.FileLocksNotSupported => unreachable, | |
| 850 | 853 | }; |
| 851 | 854 | stage1_libc.initFromStage2(libc); |
| 852 | 855 | return .None; |
src/error.cpp+2| ... | ... | @@ -86,6 +86,8 @@ const char *err_str(Error err) { |
| 86 | 86 | case ErrorUnknownClangOption: return "unknown Clang option"; |
| 87 | 87 | case ErrorNestedResponseFile: return "nested response file"; |
| 88 | 88 | case ErrorZigIsTheCCompiler: return "Zig was not provided with libc installation information, and so it does not know where the libc paths are on the system. Zig attempted to use the system C compiler to find out where the libc paths are, but discovered that Zig is being used as the system C compiler."; |
| 89 | case ErrorFileBusy: return "file is busy"; | |
| 90 | case ErrorLocked: return "file is locked by another process"; | |
| 89 | 91 | } |
| 90 | 92 | return "(invalid error)"; |
| 91 | 93 | } |
src/stage2.h+2| ... | ... | @@ -108,6 +108,8 @@ enum Error { |
| 108 | 108 | ErrorUnknownClangOption, |
| 109 | 109 | ErrorNestedResponseFile, |
| 110 | 110 | ErrorZigIsTheCCompiler, |
| 111 | ErrorFileBusy, | |
| 112 | ErrorLocked, | |
| 111 | 113 | }; |
| 112 | 114 | |
| 113 | 115 | // ABI warning |