authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-25 23:46:59-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-25 23:46:59-05:00
log76f21852f6553fc22612bb82df19184fdb28719e
tree9d7c3d78805cd1f207ba85a28a66c2d4199fdbc2
parentf96d818770fa8264b7b87e55ef7e01ff5df44c77
parentec569ff26a325f359649bc1cc3515799ceccb62f

Merge branch 'gereeter-o_path'

closes #3743

6 files changed, 102 insertions(+), 29 deletions(-)

lib/std/fs.zig+79-22
...@@ -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;
352352
353 var dir = try Dir.open(dirname);353 var dir = try Dir.cwd().openDirList(dirname);
354 defer dir.close();354 defer dir.close();
355355
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 }
659659
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;
685685
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 }
690690
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 }
695695
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 }
777777
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 }
784798
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 }
788802
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 }
795838
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 directories841 error.FileTooBig => unreachable, // can't happen for directories
799 error.IsDir => unreachable, // we're providing O_DIRECTORY842 error.IsDir => unreachable, // we're providing O_DIRECTORY
800 error.NoSpaceLeft => unreachable, // not providing O_CREAT843 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 }
806849
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;
811868
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 }
10801137
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.name1230 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 {
1207pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {1264pub 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));
12091266
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();
12121269
1213 var name_buffer = try std.Buffer.init(allocator, dir_path);1270 var name_buffer = try std.Buffer.init(allocator, dir_path);
lib/std/os/test.zig+1-1
...@@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" {...@@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" {
20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
22 try fs.deleteTree("os_test_tmp");22 try fs.deleteTree("os_test_tmp");
23 if (fs.Dir.open("os_test_tmp")) |dir| {23 if (fs.Dir.cwd().openDirTraverse("os_test_tmp")) |dir| {
24 @panic("expected error");24 @panic("expected error");
25 } else |err| {25 } else |err| {
26 expect(err == error.FileNotFound);26 expect(err == error.FileNotFound);
lib/std/os/windows/bits.zig+19-3
...@@ -412,7 +412,10 @@ pub const READ_CONTROL = 0x00020000;...@@ -412,7 +412,10 @@ pub const READ_CONTROL = 0x00020000;
412pub const WRITE_DAC = 0x00040000;412pub const WRITE_DAC = 0x00040000;
413pub const WRITE_OWNER = 0x00080000;413pub const WRITE_OWNER = 0x00080000;
414pub const SYNCHRONIZE = 0x00100000;414pub const SYNCHRONIZE = 0x00100000;
415pub const STANDARD_RIGHTS_REQUIRED = 0x000f0000;415pub const STANDARD_RIGHTS_READ = READ_CONTROL;
416pub const STANDARD_RIGHTS_WRITE = READ_CONTROL;
417pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
418pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;
416419
417// disposition for NtCreateFile420// disposition for NtCreateFile
418pub const FILE_SUPERSEDE = 0;421pub const FILE_SUPERSEDE = 0;
...@@ -424,6 +427,21 @@ pub const FILE_OVERWRITE_IF = 5;...@@ -424,6 +427,21 @@ pub const FILE_OVERWRITE_IF = 5;
424pub const FILE_MAXIMUM_DISPOSITION = 5;427pub const FILE_MAXIMUM_DISPOSITION = 5;
425428
426// flags for NtCreateFile and NtOpenFile429// flags for NtCreateFile and NtOpenFile
430pub const FILE_READ_DATA = 0x00000001;
431pub const FILE_LIST_DIRECTORY = 0x00000001;
432pub const FILE_WRITE_DATA = 0x00000002;
433pub const FILE_ADD_FILE = 0x00000002;
434pub const FILE_APPEND_DATA = 0x00000004;
435pub const FILE_ADD_SUBDIRECTORY = 0x00000004;
436pub const FILE_CREATE_PIPE_INSTANCE = 0x00000004;
437pub const FILE_READ_EA = 0x00000008;
438pub const FILE_WRITE_EA = 0x00000010;
439pub const FILE_EXECUTE = 0x00000020;
440pub const FILE_TRAVERSE = 0x00000020;
441pub const FILE_DELETE_CHILD = 0x00000040;
442pub const FILE_READ_ATTRIBUTES = 0x00000080;
443pub const FILE_WRITE_ATTRIBUTES = 0x00000100;
444
427pub const FILE_DIRECTORY_FILE = 0x00000001;445pub const FILE_DIRECTORY_FILE = 0x00000001;
428pub const FILE_WRITE_THROUGH = 0x00000002;446pub const FILE_WRITE_THROUGH = 0x00000002;
429pub const FILE_SEQUENTIAL_ONLY = 0x00000004;447pub const FILE_SEQUENTIAL_ONLY = 0x00000004;
...@@ -755,8 +773,6 @@ pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;...@@ -755,8 +773,6 @@ pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
755773
756pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;774pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
757775
758pub const FILE_LIST_DIRECTORY = 1;
759
760pub const FILE_NOTIFY_CHANGE_CREATION = 64;776pub const FILE_NOTIFY_CHANGE_CREATION = 64;
761pub const FILE_NOTIFY_CHANGE_SIZE = 8;777pub const FILE_NOTIFY_CHANGE_SIZE = 8;
762pub const FILE_NOTIFY_CHANGE_SECURITY = 256;778pub const FILE_NOTIFY_CHANGE_SECURITY = 256;
src-self-hosted/main.zig+1-1
...@@ -715,7 +715,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -715,7 +715,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
715 // ) catch |err| switch (err) {715 // ) catch |err| switch (err) {
716 // error.IsDir, error.AccessDenied => {716 // error.IsDir, error.AccessDenied => {
717 // // TODO make event based (and dir.next())717 // // TODO make event based (and dir.next())
718 // var dir = try fs.Dir.open(file_path);718 // var dir = try fs.Dir.cwd().openDirList(file_path);
719 // defer dir.close();719 // defer dir.close();
720720
721 // var group = event.Group(FmtError!void).init(fmt.allocator);721 // var group = event.Group(FmtError!void).init(fmt.allocator);
src-self-hosted/stage1.zig+1-1
...@@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void...@@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
279 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {279 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
280 error.IsDir, error.AccessDenied => {280 error.IsDir, error.AccessDenied => {
281 // TODO make event based (and dir.next())281 // TODO make event based (and dir.next())
282 var dir = try fs.Dir.open(file_path);282 var dir = try fs.Dir.cwd().openDirList(file_path);
283 defer dir.close();283 defer dir.close();
284284
285 var dir_it = dir.iterate();285 var dir_it = dir.iterate();
tools/process_headers.zig+1-1
...@@ -340,7 +340,7 @@ pub fn main() !void {...@@ -340,7 +340,7 @@ pub fn main() !void {
340 try dir_stack.append(target_include_dir);340 try dir_stack.append(target_include_dir);
341341
342 while (dir_stack.popOrNull()) |full_dir_name| {342 while (dir_stack.popOrNull()) |full_dir_name| {
343 var dir = std.fs.Dir.open(full_dir_name) catch |err| switch (err) {343 var dir = std.fs.Dir.cwd().openDirList(full_dir_name) catch |err| switch (err) {
344 error.FileNotFound => continue :search,344 error.FileNotFound => continue :search,
345 error.AccessDenied => continue :search,345 error.AccessDenied => continue :search,
346 else => return err,346 else => return err,