| ... | @@ -350,7 +350,7 @@ pub fn deleteTree(full_path: []const u8) !void { | ... | @@ -350,7 +350,7 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 350 | CannotDeleteRootDirectory, | 350 | CannotDeleteRootDirectory, |
| 351 | }.CannotDeleteRootDirectory; | 351 | }.CannotDeleteRootDirectory; |
| 352 | | 352 | |
| 353 | var dir = try Dir.open(dirname); | 353 | var dir = try Dir.cwd().openDirList(dirname); |
| 354 | defer dir.close(); | 354 | defer dir.close(); |
| 355 | | 355 | |
| 356 | return dir.deleteTree(path.basename(full_path)); | 356 | return dir.deleteTree(path.basename(full_path)); |
| ... | @@ -657,8 +657,8 @@ pub const Dir = struct { | ... | @@ -657,8 +657,8 @@ pub const Dir = struct { |
| 657 | } | 657 | } |
| 658 | } | 658 | } |
| 659 | | 659 | |
| 660 | /// Returns an open handle to the current working directory. | 660 | /// Returns an handle to the current working directory that is open for traversal. |
| 661 | /// Closing the returned `Dir` is checked illegal behavior. | 661 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. |
| 662 | /// On POSIX targets, this function is comptime-callable. | 662 | /// On POSIX targets, this function is comptime-callable. |
| 663 | pub fn cwd() Dir { | 663 | pub fn cwd() Dir { |
| 664 | if (builtin.os == .windows) { | 664 | if (builtin.os == .windows) { |
| ... | @@ -683,14 +683,14 @@ pub const Dir = struct { | ... | @@ -683,14 +683,14 @@ pub const Dir = struct { |
| 683 | DeviceBusy, | 683 | DeviceBusy, |
| 684 | } || os.UnexpectedError; | 684 | } || os.UnexpectedError; |
| 685 | | 685 | |
| 686 | /// Call `close` to free the directory handle. | 686 | /// Deprecated; call `Dir.cwd().openDirList` directly. |
| 687 | pub fn open(dir_path: []const u8) OpenError!Dir { | 687 | pub fn open(dir_path: []const u8) OpenError!Dir { |
| 688 | return cwd().openDir(dir_path); | 688 | return cwd().openDirList(dir_path); |
| 689 | } | 689 | } |
| 690 | | 690 | |
| 691 | /// Same as `open` except the parameter is null-terminated. | 691 | /// Deprecated; call `Dir.cwd().openDirListC` directly. |
| 692 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { | 692 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { |
| 693 | return cwd().openDirC(dir_path_c); | 693 | return cwd().openDirListC(dir_path_c); |
| 694 | } | 694 | } |
| 695 | | 695 | |
| 696 | pub fn close(self: *Dir) void { | 696 | pub fn close(self: *Dir) void { |
| ... | @@ -775,26 +775,69 @@ pub const Dir = struct { | ... | @@ -775,26 +775,69 @@ pub const Dir = struct { |
| 775 | } | 775 | } |
| 776 | } | 776 | } |
| 777 | | 777 | |
| 778 | /// Call `close` on the result when done. | 778 | /// Deprecated; call `openDirList` directly. |
| 779 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { | 779 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { |
| | 780 | return self.openDirList(sub_path); |
| | 781 | } |
| | 782 | |
| | 783 | /// Deprecated; call `openDirListC` directly. |
| | 784 | pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { |
| | 785 | return self.openDirListC(sub_path_c); |
| | 786 | } |
| | 787 | |
| | 788 | /// Opens a directory at the given path with the ability to access subpaths |
| | 789 | /// of the result. Calling `iterate` on the result is illegal behavior; to |
| | 790 | /// list the contents of a directory, open it with `openDirList`. |
| | 791 | /// |
| | 792 | /// Call `close` on the result when done. |
| | 793 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 780 | if (builtin.os == .windows) { | 794 | if (builtin.os == .windows) { |
| 781 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 795 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 782 | return self.openDirW(&sub_path_w); | 796 | return self.openDirTraverseW(&sub_path_w); |
| 783 | } | 797 | } |
| 784 | | 798 | |
| 785 | const sub_path_c = try os.toPosixPath(sub_path); | 799 | const sub_path_c = try os.toPosixPath(sub_path); |
| 786 | return self.openDirC(&sub_path_c); | 800 | return self.openDirTraverseC(&sub_path_c); |
| 787 | } | 801 | } |
| 788 | | 802 | |
| 789 | /// Same as `openDir` except the parameter is null-terminated. | 803 | /// Opens a directory at the given path with the ability to access subpaths and list contents |
| 790 | pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | 804 | /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the |
| | 805 | /// same and may be more efficient. |
| | 806 | /// |
| | 807 | /// Call `close` on the result when done. |
| | 808 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { |
| | 809 | if (builtin.os == .windows) { |
| | 810 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| | 811 | return self.openDirListW(&sub_path_w); |
| | 812 | } |
| | 813 | |
| | 814 | const sub_path_c = try os.toPosixPath(sub_path); |
| | 815 | return self.openDirListC(&sub_path_c); |
| | 816 | } |
| | 817 | |
| | 818 | /// Same as `openDirTraverse` except the parameter is null-terminated. |
| | 819 | pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { |
| | 820 | if (builtin.os == .windows) { |
| | 821 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| | 822 | return self.openDirTraverseW(&sub_path_w); |
| | 823 | } else { |
| | 824 | const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; |
| | 825 | return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC | O_PATH); |
| | 826 | } |
| | 827 | } |
| | 828 | |
| | 829 | /// Same as `openDirList` except the parameter is null-terminated. |
| | 830 | pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { |
| 791 | if (builtin.os == .windows) { | 831 | if (builtin.os == .windows) { |
| 792 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | 832 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 793 | return self.openDirW(&sub_path_w); | 833 | return self.openDirListW(&sub_path_w); |
| | 834 | } else { |
| | 835 | return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC); |
| 794 | } | 836 | } |
| | 837 | } |
| 795 | | 838 | |
| 796 | const flags = os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC; | 839 | fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { |
| 797 | const fd = os.openatC(self.fd, sub_path_c, flags, 0) catch |err| switch (err) { | 840 | const fd = os.openatC(self.fd, sub_path_c, flags | os.O_DIRECTORY, 0) catch |err| switch (err) { |
| 798 | error.FileTooBig => unreachable, // can't happen for directories | 841 | error.FileTooBig => unreachable, // can't happen for directories |
| 799 | error.IsDir => unreachable, // we're providing O_DIRECTORY | 842 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| 800 | error.NoSpaceLeft => unreachable, // not providing O_CREAT | 843 | error.NoSpaceLeft => unreachable, // not providing O_CREAT |
| ... | @@ -804,9 +847,23 @@ pub const Dir = struct { | ... | @@ -804,9 +847,23 @@ pub const Dir = struct { |
| 804 | return Dir{ .fd = fd }; | 847 | return Dir{ .fd = fd }; |
| 805 | } | 848 | } |
| 806 | | 849 | |
| 807 | /// Same as `openDir` except the path parameter is UTF16LE, NT-prefixed. | 850 | /// Same as `openDirTraverse` except the path parameter is UTF16LE, NT-prefixed. |
| 808 | /// This function is Windows-only. | 851 | /// This function is Windows-only. |
| 809 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { | 852 | pub fn openDirTraverseW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { |
| | 853 | const w = os.windows; |
| | 854 | |
| | 855 | return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE); |
| | 856 | } |
| | 857 | |
| | 858 | /// Same as `openDirList` except the path parameter is UTF16LE, NT-prefixed. |
| | 859 | /// This function is Windows-only. |
| | 860 | pub fn openDirListW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { |
| | 861 | const w = os.windows; |
| | 862 | |
| | 863 | return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY); |
| | 864 | } |
| | 865 | |
| | 866 | fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { |
| 810 | const w = os.windows; | 867 | const w = os.windows; |
| 811 | | 868 | |
| 812 | var result = Dir{ | 869 | var result = Dir{ |
| ... | @@ -839,7 +896,7 @@ pub const Dir = struct { | ... | @@ -839,7 +896,7 @@ pub const Dir = struct { |
| 839 | var io: w.IO_STATUS_BLOCK = undefined; | 896 | var io: w.IO_STATUS_BLOCK = undefined; |
| 840 | const rc = w.ntdll.NtCreateFile( | 897 | const rc = w.ntdll.NtCreateFile( |
| 841 | &result.fd, | 898 | &result.fd, |
| 842 | w.GENERIC_READ | w.SYNCHRONIZE, | 899 | access_mask, |
| 843 | &attr, | 900 | &attr, |
| 844 | &io, | 901 | &io, |
| 845 | null, | 902 | null, |
| ... | @@ -1013,7 +1070,7 @@ pub const Dir = struct { | ... | @@ -1013,7 +1070,7 @@ pub const Dir = struct { |
| 1013 | error.Unexpected, | 1070 | error.Unexpected, |
| 1014 | => |e| return e, | 1071 | => |e| return e, |
| 1015 | } | 1072 | } |
| 1016 | var dir = self.openDir(sub_path) catch |err| switch (err) { | 1073 | var dir = self.openDirList(sub_path) catch |err| switch (err) { |
| 1017 | error.NotDir => { | 1074 | error.NotDir => { |
| 1018 | if (got_access_denied) { | 1075 | if (got_access_denied) { |
| 1019 | return error.AccessDenied; | 1076 | return error.AccessDenied; |
| ... | @@ -1078,7 +1135,7 @@ pub const Dir = struct { | ... | @@ -1078,7 +1135,7 @@ pub const Dir = struct { |
| 1078 | => |e| return e, | 1135 | => |e| return e, |
| 1079 | } | 1136 | } |
| 1080 | | 1137 | |
| 1081 | const new_dir = dir.openDir(entry.name) catch |err| switch (err) { | 1138 | const new_dir = dir.openDirList(entry.name) catch |err| switch (err) { |
| 1082 | error.NotDir => { | 1139 | error.NotDir => { |
| 1083 | if (got_access_denied) { | 1140 | if (got_access_denied) { |
| 1084 | return error.AccessDenied; | 1141 | return error.AccessDenied; |
| ... | @@ -1169,7 +1226,7 @@ pub const Walker = struct { | ... | @@ -1169,7 +1226,7 @@ pub const Walker = struct { |
| 1169 | try self.name_buffer.appendByte(path.sep); | 1226 | try self.name_buffer.appendByte(path.sep); |
| 1170 | try self.name_buffer.append(base.name); | 1227 | try self.name_buffer.append(base.name); |
| 1171 | if (base.kind == .Directory) { | 1228 | if (base.kind == .Directory) { |
| 1172 | var new_dir = top.dir_it.dir.openDir(base.name) catch |err| switch (err) { | 1229 | var new_dir = top.dir_it.dir.openDirList(base.name) catch |err| switch (err) { |
| 1173 | error.NameTooLong => unreachable, // no path sep in base.name | 1230 | error.NameTooLong => unreachable, // no path sep in base.name |
| 1174 | else => |e| return e, | 1231 | else => |e| return e, |
| 1175 | }; | 1232 | }; |
| ... | @@ -1207,7 +1264,7 @@ pub const Walker = struct { | ... | @@ -1207,7 +1264,7 @@ pub const Walker = struct { |
| 1207 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | 1264 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1208 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); | 1265 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1209 | | 1266 | |
| 1210 | var dir = try Dir.open(dir_path); | 1267 | var dir = try Dir.cwd().openDirList(dir_path); |
| 1211 | errdefer dir.close(); | 1268 | errdefer dir.close(); |
| 1212 | | 1269 | |
| 1213 | var name_buffer = try std.Buffer.init(allocator, dir_path); | 1270 | var name_buffer = try std.Buffer.init(allocator, dir_path); |