| author | |
| committer | |
| log | 11b8d3ce9d7bc8e3ab16813fd5415c9d45dbb232 |
| tree | 879d454b8c77d8a9dfeb4044ab55f66e513e7810 |
| parent | 85e1e3b95f1f1699a842a5e889d8987692a829a4 |
| parent | 2e7350140d4fbf9335e48693ccc4cba77d229c84 |
| signature |
15 files changed, 368 insertions(+), 166 deletions(-)
lib/std/build.zig+1-1| ... | ... | @@ -2416,7 +2416,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { |
| 2416 | 2416 | const path_file = try fs.path.join(allocator, [_][]const u8{ appdata_path, "vcpkg.path.txt" }); |
| 2417 | 2417 | defer allocator.free(path_file); |
| 2418 | 2418 | |
| 2419 | const file = fs.File.openRead(path_file) catch return null; | |
| 2419 | const file = fs.cwd().openFile(path_file, .{}) catch return null; | |
| 2420 | 2420 | defer file.close(); |
| 2421 | 2421 | |
| 2422 | 2422 | const size = @intCast(usize, try file.getEndPos()); |
lib/std/debug.zig+2-2| ... | ... | @@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1131 | 1131 | } |
| 1132 | 1132 | |
| 1133 | 1133 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { |
| 1134 | var f = try File.openRead(line_info.file_name); | |
| 1134 | var f = try fs.cwd().openFile(line_info.file_name, .{}); | |
| 1135 | 1135 | defer f.close(); |
| 1136 | 1136 | // TODO fstat and make sure that the file has the correct size |
| 1137 | 1137 | |
| ... | ... | @@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 2089 | 2089 | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); |
| 2090 | 2090 | |
| 2091 | 2091 | gop.kv.value = MachOFile{ |
| 2092 | .bytes = try std.fs.Dir.cwd().readFileAllocAligned( | |
| 2092 | .bytes = try std.fs.cwd().readFileAllocAligned( | |
| 2093 | 2093 | di.ofiles.allocator, |
| 2094 | 2094 | ofile_path, |
| 2095 | 2095 | maxInt(usize), |
lib/std/fs.zig+229-49| ... | ... | @@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File; |
| 13 | 13 | |
| 14 | 14 | pub const symLink = os.symlink; |
| 15 | 15 | pub const symLinkC = os.symlinkC; |
| 16 | pub const deleteFile = os.unlink; | |
| 17 | pub const deleteFileC = os.unlinkC; | |
| 18 | 16 | pub const rename = os.rename; |
| 19 | 17 | pub const renameC = os.renameC; |
| 20 | 18 | pub const renameW = os.renameW; |
| ... | ... | @@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { |
| 88 | 86 | /// If any of the directories do not exist for dest_path, they are created. |
| 89 | 87 | /// TODO https://github.com/ziglang/zig/issues/2885 |
| 90 | 88 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { |
| 91 | var src_file = try File.openRead(source_path); | |
| 89 | const my_cwd = cwd(); | |
| 90 | ||
| 91 | var src_file = try my_cwd.openFile(source_path, .{}); | |
| 92 | 92 | defer src_file.close(); |
| 93 | 93 | |
| 94 | 94 | const src_stat = try src_file.stat(); |
| 95 | 95 | check_dest_stat: { |
| 96 | 96 | const dest_stat = blk: { |
| 97 | var dest_file = File.openRead(dest_path) catch |err| switch (err) { | |
| 97 | var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) { | |
| 98 | 98 | error.FileNotFound => break :check_dest_stat, |
| 99 | 99 | else => |e| return e, |
| 100 | 100 | }; |
| ... | ... | @@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil |
| 157 | 157 | /// in the same directory as dest_path. |
| 158 | 158 | /// Destination file will have the same mode as the source file. |
| 159 | 159 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { |
| 160 | var in_file = try File.openRead(source_path); | |
| 160 | var in_file = try cwd().openFile(source_path, .{}); | |
| 161 | 161 | defer in_file.close(); |
| 162 | 162 | |
| 163 | 163 | const mode = try in_file.mode(); |
| ... | ... | @@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { |
| 180 | 180 | /// merged and readily available, |
| 181 | 181 | /// there is a possibility of power loss or application termination leaving temporary files present |
| 182 | 182 | pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { |
| 183 | var in_file = try File.openRead(source_path); | |
| 183 | var in_file = try cwd().openFile(source_path, .{}); | |
| 184 | 184 | defer in_file.close(); |
| 185 | 185 | |
| 186 | 186 | var atomic_file = try AtomicFile.init(dest_path, mode); |
| ... | ... | @@ -206,8 +206,6 @@ pub const AtomicFile = struct { |
| 206 | 206 | |
| 207 | 207 | /// dest_path must remain valid for the lifetime of AtomicFile |
| 208 | 208 | /// call finish to atomically replace dest_path with contents |
| 209 | /// TODO once we have null terminated pointers, use the | |
| 210 | /// openWriteNoClobberN function | |
| 211 | 209 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { |
| 212 | 210 | const dirname = path.dirname(dest_path); |
| 213 | 211 | var rand_buf: [12]u8 = undefined; |
| ... | ... | @@ -224,15 +222,19 @@ pub const AtomicFile = struct { |
| 224 | 222 | |
| 225 | 223 | tmp_path_buf[tmp_path_len] = 0; |
| 226 | 224 | |
| 225 | const my_cwd = cwd(); | |
| 226 | ||
| 227 | 227 | while (true) { |
| 228 | 228 | try crypto.randomBytes(rand_buf[0..]); |
| 229 | 229 | b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf); |
| 230 | 230 | |
| 231 | const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) { | |
| 231 | // TODO https://github.com/ziglang/zig/issues/3770 to clean up this @ptrCast | |
| 232 | const file = my_cwd.createFileC( | |
| 233 | @ptrCast([*:0]u8, &tmp_path_buf), | |
| 234 | .{ .mode = mode, .exclusive = true }, | |
| 235 | ) catch |err| switch (err) { | |
| 232 | 236 | error.PathAlreadyExists => continue, |
| 233 | // TODO zig should figure out that this error set does not include PathAlreadyExists since | |
| 234 | // it is handled in the above switch | |
| 235 | else => return err, | |
| 237 | else => |e| return e, | |
| 236 | 238 | }; |
| 237 | 239 | |
| 238 | 240 | return AtomicFile{ |
| ... | ... | @@ -248,7 +250,7 @@ pub const AtomicFile = struct { |
| 248 | 250 | pub fn deinit(self: *AtomicFile) void { |
| 249 | 251 | if (!self.finished) { |
| 250 | 252 | self.file.close(); |
| 251 | deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; | |
| 253 | cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; | |
| 252 | 254 | self.finished = true; |
| 253 | 255 | } |
| 254 | 256 | } |
| ... | ... | @@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 350 | 352 | CannotDeleteRootDirectory, |
| 351 | 353 | }.CannotDeleteRootDirectory; |
| 352 | 354 | |
| 353 | var dir = try Dir.cwd().openDirList(dirname); | |
| 355 | var dir = try cwd().openDirList(dirname); | |
| 354 | 356 | defer dir.close(); |
| 355 | 357 | |
| 356 | 358 | return dir.deleteTree(path.basename(full_path)); |
| 357 | 359 | } else { |
| 358 | return Dir.cwd().deleteTree(full_path); | |
| 360 | return cwd().deleteTree(full_path); | |
| 359 | 361 | } |
| 360 | 362 | } |
| 361 | 363 | |
| ... | ... | @@ -657,17 +659,6 @@ pub const Dir = struct { |
| 657 | 659 | } |
| 658 | 660 | } |
| 659 | 661 | |
| 660 | /// Returns an handle to the current working directory that is open for traversal. | |
| 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. | |
| 663 | pub fn cwd() Dir { | |
| 664 | if (builtin.os == .windows) { | |
| 665 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; | |
| 666 | } else { | |
| 667 | return Dir{ .fd = os.AT_FDCWD }; | |
| 668 | } | |
| 669 | } | |
| 670 | ||
| 671 | 662 | pub const OpenError = error{ |
| 672 | 663 | FileNotFound, |
| 673 | 664 | NotDir, |
| ... | ... | @@ -683,12 +674,12 @@ pub const Dir = struct { |
| 683 | 674 | DeviceBusy, |
| 684 | 675 | } || os.UnexpectedError; |
| 685 | 676 | |
| 686 | /// Deprecated; call `Dir.cwd().openDirList` directly. | |
| 677 | /// Deprecated; call `cwd().openDirList` directly. | |
| 687 | 678 | pub fn open(dir_path: []const u8) OpenError!Dir { |
| 688 | 679 | return cwd().openDirList(dir_path); |
| 689 | 680 | } |
| 690 | 681 | |
| 691 | /// Deprecated; call `Dir.cwd().openDirListC` directly. | |
| 682 | /// Deprecated; call `cwd().openDirListC` directly. | |
| 692 | 683 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { |
| 693 | 684 | return cwd().openDirListC(dir_path_c); |
| 694 | 685 | } |
| ... | ... | @@ -698,29 +689,110 @@ pub const Dir = struct { |
| 698 | 689 | self.* = undefined; |
| 699 | 690 | } |
| 700 | 691 | |
| 701 | /// Call `File.close` on the result when done. | |
| 702 | pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File { | |
| 692 | /// Opens a file for reading or writing, without attempting to create a new file. | |
| 693 | /// Call `File.close` to release the resource. | |
| 694 | /// Asserts that the path parameter has no null bytes. | |
| 695 | pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | |
| 696 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 703 | 697 | if (builtin.os == .windows) { |
| 704 | 698 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 705 | return self.openReadW(&path_w); | |
| 699 | return self.openFileW(&path_w, flags); | |
| 706 | 700 | } |
| 707 | 701 | const path_c = try os.toPosixPath(sub_path); |
| 708 | return self.openReadC(&path_c); | |
| 702 | return self.openFileC(&path_c, flags); | |
| 709 | 703 | } |
| 710 | 704 | |
| 711 | /// Call `File.close` on the result when done. | |
| 712 | pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { | |
| 705 | /// Same as `openFile` but the path parameter is null-terminated. | |
| 706 | pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | |
| 713 | 707 | if (builtin.os == .windows) { |
| 714 | 708 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path); |
| 715 | return self.openReadW(&path_w); | |
| 709 | return self.openFileW(&path_w, flags); | |
| 716 | 710 | } |
| 717 | 711 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 718 | const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC; | |
| 719 | const fd = try os.openatC(self.fd, sub_path, flags, 0); | |
| 720 | return File.openHandle(fd); | |
| 712 | const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) | |
| 713 | @as(u32, os.O_RDWR) | |
| 714 | else if (flags.write) | |
| 715 | @as(u32, os.O_WRONLY) | |
| 716 | else | |
| 717 | @as(u32, os.O_RDONLY); | |
| 718 | const fd = try os.openatC(self.fd, sub_path, os_flags, 0); | |
| 719 | return File{ .handle = fd }; | |
| 720 | } | |
| 721 | ||
| 722 | /// Same as `openFile` but Windows-only and the path parameter is | |
| 723 | /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded. | |
| 724 | pub fn openFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | |
| 725 | const w = os.windows; | |
| 726 | const access_mask = w.SYNCHRONIZE | | |
| 727 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | | |
| 728 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); | |
| 729 | return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN); | |
| 721 | 730 | } |
| 722 | 731 | |
| 723 | pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File { | |
| 732 | /// Creates, opens, or overwrites a file with write access. | |
| 733 | /// Call `File.close` on the result when done. | |
| 734 | /// Asserts that the path parameter has no null bytes. | |
| 735 | pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | |
| 736 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 737 | if (builtin.os == .windows) { | |
| 738 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); | |
| 739 | return self.createFileW(&path_w, flags); | |
| 740 | } | |
| 741 | const path_c = try os.toPosixPath(sub_path); | |
| 742 | return self.createFileC(&path_c, flags); | |
| 743 | } | |
| 744 | ||
| 745 | /// Same as `createFile` but the path parameter is null-terminated. | |
| 746 | pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | |
| 747 | if (builtin.os == .windows) { | |
| 748 | const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | |
| 749 | return self.createFileW(&path_w, flags); | |
| 750 | } | |
| 751 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | |
| 752 | const os_flags = O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | |
| 753 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | | |
| 754 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | | |
| 755 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); | |
| 756 | const fd = try os.openatC(self.fd, sub_path_c, os_flags, flags.mode); | |
| 757 | return File{ .handle = fd }; | |
| 758 | } | |
| 759 | ||
| 760 | /// Same as `createFile` but Windows-only and the path parameter is | |
| 761 | /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded. | |
| 762 | pub fn createFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | |
| 763 | const w = os.windows; | |
| 764 | const access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | | |
| 765 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0); | |
| 766 | const creation = if (flags.exclusive) | |
| 767 | @as(u32, w.FILE_CREATE) | |
| 768 | else if (flags.truncate) | |
| 769 | @as(u32, w.FILE_OVERWRITE_IF) | |
| 770 | else | |
| 771 | @as(u32, w.FILE_OPEN_IF); | |
| 772 | return self.openFileWindows(sub_path_w, access_mask, creation); | |
| 773 | } | |
| 774 | ||
| 775 | /// Deprecated; call `openFile` directly. | |
| 776 | pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File { | |
| 777 | return self.openFile(sub_path, .{}); | |
| 778 | } | |
| 779 | ||
| 780 | /// Deprecated; call `openFileC` directly. | |
| 781 | pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { | |
| 782 | return self.openFileC(sub_path, .{}); | |
| 783 | } | |
| 784 | ||
| 785 | /// Deprecated; call `openFileW` directly. | |
| 786 | pub fn openReadW(self: Dir, sub_path: [*:0]const u16) File.OpenError!File { | |
| 787 | return self.openFileW(sub_path, .{}); | |
| 788 | } | |
| 789 | ||
| 790 | pub fn openFileWindows( | |
| 791 | self: Dir, | |
| 792 | sub_path_w: [*:0]const u16, | |
| 793 | access_mask: os.windows.ACCESS_MASK, | |
| 794 | creation: os.windows.ULONG, | |
| 795 | ) File.OpenError!File { | |
| 724 | 796 | const w = os.windows; |
| 725 | 797 | |
| 726 | 798 | var result = File{ .handle = undefined }; |
| ... | ... | @@ -750,13 +822,13 @@ pub const Dir = struct { |
| 750 | 822 | var io: w.IO_STATUS_BLOCK = undefined; |
| 751 | 823 | const rc = w.ntdll.NtCreateFile( |
| 752 | 824 | &result.handle, |
| 753 | w.GENERIC_READ | w.SYNCHRONIZE, | |
| 825 | access_mask, | |
| 754 | 826 | &attr, |
| 755 | 827 | &io, |
| 756 | 828 | null, |
| 757 | 829 | w.FILE_ATTRIBUTE_NORMAL, |
| 758 | w.FILE_SHARE_READ, | |
| 759 | w.FILE_OPEN, | |
| 830 | w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, | |
| 831 | creation, | |
| 760 | 832 | w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT, |
| 761 | 833 | null, |
| 762 | 834 | 0, |
| ... | ... | @@ -771,6 +843,7 @@ pub const Dir = struct { |
| 771 | 843 | w.STATUS.ACCESS_DENIED => return error.AccessDenied, |
| 772 | 844 | w.STATUS.PIPE_BUSY => return error.PipeBusy, |
| 773 | 845 | w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable, |
| 846 | w.STATUS.OBJECT_NAME_COLLISION => return error.PathAlreadyExists, | |
| 774 | 847 | else => return w.unexpectedStatus(rc), |
| 775 | 848 | } |
| 776 | 849 | } |
| ... | ... | @@ -790,7 +863,10 @@ pub const Dir = struct { |
| 790 | 863 | /// list the contents of a directory, open it with `openDirList`. |
| 791 | 864 | /// |
| 792 | 865 | /// Call `close` on the result when done. |
| 866 | /// | |
| 867 | /// Asserts that the path parameter has no null bytes. | |
| 793 | 868 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 869 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 794 | 870 | if (builtin.os == .windows) { |
| 795 | 871 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 796 | 872 | return self.openDirTraverseW(&sub_path_w); |
| ... | ... | @@ -805,7 +881,10 @@ pub const Dir = struct { |
| 805 | 881 | /// same and may be more efficient. |
| 806 | 882 | /// |
| 807 | 883 | /// Call `close` on the result when done. |
| 884 | /// | |
| 885 | /// Asserts that the path parameter has no null bytes. | |
| 808 | 886 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 887 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 809 | 888 | if (builtin.os == .windows) { |
| 810 | 889 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 811 | 890 | return self.openDirListW(&sub_path_w); |
| ... | ... | @@ -920,9 +999,12 @@ pub const Dir = struct { |
| 920 | 999 | pub const DeleteFileError = os.UnlinkError; |
| 921 | 1000 | |
| 922 | 1001 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 1002 | /// Asserts that the path parameter has no null bytes. | |
| 923 | 1003 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { |
| 924 | const sub_path_c = try os.toPosixPath(sub_path); | |
| 925 | return self.deleteFileC(&sub_path_c); | |
| 1004 | os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) { | |
| 1005 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | |
| 1006 | else => |e| return e, | |
| 1007 | }; | |
| 926 | 1008 | } |
| 927 | 1009 | |
| 928 | 1010 | /// Same as `deleteFile` except the parameter is null-terminated. |
| ... | ... | @@ -933,6 +1015,14 @@ pub const Dir = struct { |
| 933 | 1015 | }; |
| 934 | 1016 | } |
| 935 | 1017 | |
| 1018 | /// Same as `deleteFile` except the parameter is WTF-16 encoded. | |
| 1019 | pub fn deleteFileW(self: Dir, sub_path_w: [*:0]const u16) DeleteFileError!void { | |
| 1020 | os.unlinkatW(self.fd, sub_path_w, 0) catch |err| switch (err) { | |
| 1021 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | |
| 1022 | else => |e| return e, | |
| 1023 | }; | |
| 1024 | } | |
| 1025 | ||
| 936 | 1026 | pub const DeleteDirError = error{ |
| 937 | 1027 | DirNotEmpty, |
| 938 | 1028 | FileNotFound, |
| ... | ... | @@ -951,7 +1041,9 @@ pub const Dir = struct { |
| 951 | 1041 | |
| 952 | 1042 | /// Returns `error.DirNotEmpty` if the directory is not empty. |
| 953 | 1043 | /// To delete a directory recursively, see `deleteTree`. |
| 1044 | /// Asserts that the path parameter has no null bytes. | |
| 954 | 1045 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { |
| 1046 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 955 | 1047 | if (builtin.os == .windows) { |
| 956 | 1048 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 957 | 1049 | return self.deleteDirW(&sub_path_w); |
| ... | ... | @@ -979,7 +1071,9 @@ pub const Dir = struct { |
| 979 | 1071 | |
| 980 | 1072 | /// Read value of a symbolic link. |
| 981 | 1073 | /// The return value is a slice of `buffer`, from index `0`. |
| 1074 | /// Asserts that the path parameter has no null bytes. | |
| 982 | 1075 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1076 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | |
| 983 | 1077 | const sub_path_c = try os.toPosixPath(sub_path); |
| 984 | 1078 | return self.readLinkC(&sub_path_c, buffer); |
| 985 | 1079 | } |
| ... | ... | @@ -1190,8 +1284,94 @@ pub const Dir = struct { |
| 1190 | 1284 | } |
| 1191 | 1285 | } |
| 1192 | 1286 | } |
| 1287 | ||
| 1288 | /// Writes content to the file system, creating a new file if it does not exist, truncating | |
| 1289 | /// if it already exists. | |
| 1290 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { | |
| 1291 | var file = try self.createFile(sub_path, .{}); | |
| 1292 | defer file.close(); | |
| 1293 | try file.write(data); | |
| 1294 | } | |
| 1193 | 1295 | }; |
| 1194 | 1296 | |
| 1297 | /// Returns an handle to the current working directory that is open for traversal. | |
| 1298 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. | |
| 1299 | /// On POSIX targets, this function is comptime-callable. | |
| 1300 | pub fn cwd() Dir { | |
| 1301 | if (builtin.os == .windows) { | |
| 1302 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; | |
| 1303 | } else { | |
| 1304 | return Dir{ .fd = os.AT_FDCWD }; | |
| 1305 | } | |
| 1306 | } | |
| 1307 | ||
| 1308 | /// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path. | |
| 1309 | /// Call `File.close` to release the resource. | |
| 1310 | /// Asserts that the path is absolute. See `Dir.openFile` for a function that | |
| 1311 | /// operates on both absolute and relative paths. | |
| 1312 | /// Asserts that the path parameter has no null bytes. See `openFileAbsoluteC` for a function | |
| 1313 | /// that accepts a null-terminated path. | |
| 1314 | pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | |
| 1315 | assert(path.isAbsolute(absolute_path)); | |
| 1316 | return cwd().openFile(absolute_path, flags); | |
| 1317 | } | |
| 1318 | ||
| 1319 | /// Same as `openFileAbsolute` but the path parameter is null-terminated. | |
| 1320 | pub fn openFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | |
| 1321 | assert(path.isAbsoluteC(absolute_path_c)); | |
| 1322 | return cwd().openFileC(absolute_path_c, flags); | |
| 1323 | } | |
| 1324 | ||
| 1325 | /// Same as `openFileAbsolute` but the path parameter is WTF-16 encoded. | |
| 1326 | pub fn openFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | |
| 1327 | assert(path.isAbsoluteW(absolute_path_w)); | |
| 1328 | return cwd().openFileW(absolute_path_w, flags); | |
| 1329 | } | |
| 1330 | ||
| 1331 | /// Creates, opens, or overwrites a file with write access, based on an absolute path. | |
| 1332 | /// Call `File.close` to release the resource. | |
| 1333 | /// Asserts that the path is absolute. See `Dir.createFile` for a function that | |
| 1334 | /// operates on both absolute and relative paths. | |
| 1335 | /// Asserts that the path parameter has no null bytes. See `createFileAbsoluteC` for a function | |
| 1336 | /// that accepts a null-terminated path. | |
| 1337 | pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | |
| 1338 | assert(path.isAbsolute(absolute_path)); | |
| 1339 | return cwd().createFile(absolute_path, flags); | |
| 1340 | } | |
| 1341 | ||
| 1342 | /// Same as `createFileAbsolute` but the path parameter is null-terminated. | |
| 1343 | pub fn createFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | |
| 1344 | assert(path.isAbsoluteC(absolute_path_c)); | |
| 1345 | return cwd().createFileC(absolute_path_c, flags); | |
| 1346 | } | |
| 1347 | ||
| 1348 | /// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded. | |
| 1349 | pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | |
| 1350 | assert(path.isAbsoluteW(absolute_path_w)); | |
| 1351 | return cwd().createFileW(absolute_path_w, flags); | |
| 1352 | } | |
| 1353 | ||
| 1354 | /// Delete a file name and possibly the file it refers to, based on an absolute path. | |
| 1355 | /// Asserts that the path is absolute. See `Dir.deleteFile` for a function that | |
| 1356 | /// operates on both absolute and relative paths. | |
| 1357 | /// Asserts that the path parameter has no null bytes. | |
| 1358 | pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void { | |
| 1359 | assert(path.isAbsolute(absolute_path)); | |
| 1360 | return cwd().deleteFile(absolute_path); | |
| 1361 | } | |
| 1362 | ||
| 1363 | /// Same as `deleteFileAbsolute` except the parameter is null-terminated. | |
| 1364 | pub fn deleteFileAbsoluteC(absolute_path_c: [*:0]const u8) DeleteFileError!void { | |
| 1365 | assert(path.isAbsoluteC(absolute_path_c)); | |
| 1366 | return cwd().deleteFileC(absolute_path_c); | |
| 1367 | } | |
| 1368 | ||
| 1369 | /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. | |
| 1370 | pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void { | |
| 1371 | assert(path.isAbsoluteW(absolute_path_w)); | |
| 1372 | return cwd().deleteFileW(absolute_path_w); | |
| 1373 | } | |
| 1374 | ||
| 1195 | 1375 | pub const Walker = struct { |
| 1196 | 1376 | stack: std.ArrayList(StackItem), |
| 1197 | 1377 | name_buffer: std.Buffer, |
| ... | ... | @@ -1264,7 +1444,7 @@ pub const Walker = struct { |
| 1264 | 1444 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1265 | 1445 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1266 | 1446 | |
| 1267 | var dir = try Dir.cwd().openDirList(dir_path); | |
| 1447 | var dir = try cwd().openDirList(dir_path); | |
| 1268 | 1448 | errdefer dir.close(); |
| 1269 | 1449 | |
| 1270 | 1450 | var name_buffer = try std.Buffer.init(allocator, dir_path); |
| ... | ... | @@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE |
| 1298 | 1478 | |
| 1299 | 1479 | pub fn openSelfExe() OpenSelfExeError!File { |
| 1300 | 1480 | if (builtin.os == .linux) { |
| 1301 | return File.openReadC("/proc/self/exe"); | |
| 1481 | return openFileAbsoluteC("/proc/self/exe", .{}); | |
| 1302 | 1482 | } |
| 1303 | 1483 | if (builtin.os == .windows) { |
| 1304 | 1484 | const wide_slice = selfExePathW(); |
| 1305 | 1485 | const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); |
| 1306 | return Dir.cwd().openReadW(&prefixed_path_w); | |
| 1486 | return cwd().openReadW(&prefixed_path_w); | |
| 1307 | 1487 | } |
| 1308 | 1488 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1309 | 1489 | const self_exe_path = try selfExePath(&buf); |
| 1310 | 1490 | buf[self_exe_path.len] = 0; |
| 1311 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 1312 | return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr)); | |
| 1491 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 1492 | return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{}); | |
| 1313 | 1493 | } |
| 1314 | 1494 | |
| 1315 | 1495 | test "openSelfExe" { |
lib/std/fs/file.zig+56-73| ... | ... | @@ -25,105 +25,87 @@ pub const File = struct { |
| 25 | 25 | |
| 26 | 26 | pub const OpenError = windows.CreateFileError || os.OpenError; |
| 27 | 27 | |
| 28 | /// Deprecated; call `std.fs.Dir.openRead` directly. | |
| 28 | /// TODO https://github.com/ziglang/zig/issues/3802 | |
| 29 | pub const OpenFlags = struct { | |
| 30 | read: bool = true, | |
| 31 | write: bool = false, | |
| 32 | }; | |
| 33 | ||
| 34 | /// TODO https://github.com/ziglang/zig/issues/3802 | |
| 35 | pub const CreateFlags = struct { | |
| 36 | /// Whether the file will be created with read access. | |
| 37 | read: bool = false, | |
| 38 | ||
| 39 | /// If the file already exists, and is a regular file, and the access | |
| 40 | /// mode allows writing, it will be truncated to length 0. | |
| 41 | truncate: bool = true, | |
| 42 | ||
| 43 | /// Ensures that this open call creates the file, otherwise causes | |
| 44 | /// `error.FileAlreadyExists` to be returned. | |
| 45 | exclusive: bool = false, | |
| 46 | ||
| 47 | /// For POSIX systems this is the file system mode the file will | |
| 48 | /// be created with. | |
| 49 | mode: Mode = default_mode, | |
| 50 | }; | |
| 51 | ||
| 52 | /// Deprecated; call `std.fs.Dir.openFile` directly. | |
| 29 | 53 | pub fn openRead(path: []const u8) OpenError!File { |
| 30 | return std.fs.Dir.cwd().openRead(path); | |
| 54 | return std.fs.cwd().openFile(path, .{}); | |
| 31 | 55 | } |
| 32 | 56 | |
| 33 | /// Deprecated; call `std.fs.Dir.openReadC` directly. | |
| 57 | /// Deprecated; call `std.fs.Dir.openFileC` directly. | |
| 34 | 58 | pub fn openReadC(path_c: [*:0]const u8) OpenError!File { |
| 35 | return std.fs.Dir.cwd().openReadC(path_c); | |
| 59 | return std.fs.cwd().openFileC(path_c, .{}); | |
| 36 | 60 | } |
| 37 | 61 | |
| 38 | /// Deprecated; call `std.fs.Dir.openReadW` directly. | |
| 62 | /// Deprecated; call `std.fs.Dir.openFileW` directly. | |
| 39 | 63 | pub fn openReadW(path_w: [*]const u16) OpenError!File { |
| 40 | return std.fs.Dir.cwd().openReadW(path_w); | |
| 64 | return std.fs.cwd().openFileW(path_w, .{}); | |
| 41 | 65 | } |
| 42 | 66 | |
| 43 | /// Calls `openWriteMode` with `default_mode` for the mode. | |
| 44 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 67 | /// Deprecated; call `std.fs.Dir.createFile` directly. | |
| 45 | 68 | pub fn openWrite(path: []const u8) OpenError!File { |
| 46 | return openWriteMode(path, default_mode); | |
| 69 | return std.fs.cwd().createFile(path, .{}); | |
| 47 | 70 | } |
| 48 | 71 | |
| 49 | /// If the path does not exist it will be created. | |
| 50 | /// If a file already exists in the destination it will be truncated. | |
| 51 | /// Call close to clean up. | |
| 52 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 72 | /// Deprecated; call `std.fs.Dir.createFile` directly. | |
| 53 | 73 | pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { |
| 54 | if (builtin.os == .windows) { | |
| 55 | const path_w = try windows.sliceToPrefixedFileW(path); | |
| 56 | return openWriteModeW(&path_w, file_mode); | |
| 57 | } | |
| 58 | const path_c = try os.toPosixPath(path); | |
| 59 | return openWriteModeC(&path_c, file_mode); | |
| 74 | return std.fs.cwd().createFile(path, .{ .mode = file_mode }); | |
| 60 | 75 | } |
| 61 | 76 | |
| 62 | /// Same as `openWriteMode` except `path` is null-terminated. | |
| 63 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 64 | pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File { | |
| 65 | if (builtin.os == .windows) { | |
| 66 | const path_w = try windows.cStrToPrefixedFileW(path); | |
| 67 | return openWriteModeW(&path_w, file_mode); | |
| 68 | } | |
| 69 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | |
| 70 | const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC; | |
| 71 | const fd = try os.openC(path, flags, file_mode); | |
| 72 | return openHandle(fd); | |
| 77 | /// Deprecated; call `std.fs.Dir.createFileC` directly. | |
| 78 | pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { | |
| 79 | return std.fs.cwd().createFileC(path_c, .{ .mode = file_mode }); | |
| 73 | 80 | } |
| 74 | 81 | |
| 75 | /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded | |
| 76 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 82 | /// Deprecated; call `std.fs.Dir.createFileW` directly. | |
| 77 | 83 | pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 78 | const handle = try windows.CreateFileW( | |
| 79 | path_w, | |
| 80 | windows.GENERIC_WRITE, | |
| 81 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | |
| 82 | null, | |
| 83 | windows.CREATE_ALWAYS, | |
| 84 | windows.FILE_ATTRIBUTE_NORMAL, | |
| 85 | null, | |
| 86 | ); | |
| 87 | return openHandle(handle); | |
| 84 | return std.fs.cwd().createFileW(path_w, .{ .mode = file_mode }); | |
| 88 | 85 | } |
| 89 | 86 | |
| 90 | /// If the path does not exist it will be created. | |
| 91 | /// If a file already exists in the destination this returns OpenError.PathAlreadyExists | |
| 92 | /// Call close to clean up. | |
| 93 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 87 | /// Deprecated; call `std.fs.Dir.createFile` directly. | |
| 94 | 88 | pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { |
| 95 | if (builtin.os == .windows) { | |
| 96 | const path_w = try windows.sliceToPrefixedFileW(path); | |
| 97 | return openWriteNoClobberW(&path_w, file_mode); | |
| 98 | } | |
| 99 | const path_c = try os.toPosixPath(path); | |
| 100 | return openWriteNoClobberC(&path_c, file_mode); | |
| 89 | return std.fs.cwd().createFile(path, .{ | |
| 90 | .mode = file_mode, | |
| 91 | .exclusive = true, | |
| 92 | }); | |
| 101 | 93 | } |
| 102 | 94 | |
| 103 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 104 | pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File { | |
| 105 | if (builtin.os == .windows) { | |
| 106 | const path_w = try windows.cStrToPrefixedFileW(path); | |
| 107 | return openWriteNoClobberW(&path_w, file_mode); | |
| 108 | } | |
| 109 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | |
| 110 | const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL; | |
| 111 | const fd = try os.openC(path, flags, file_mode); | |
| 112 | return openHandle(fd); | |
| 95 | /// Deprecated; call `std.fs.Dir.createFileC` directly. | |
| 96 | pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { | |
| 97 | return std.fs.cwd().createFileC(path_c, .{ | |
| 98 | .mode = file_mode, | |
| 99 | .exclusive = true, | |
| 100 | }); | |
| 113 | 101 | } |
| 114 | 102 | |
| 115 | /// TODO: deprecate this and move it to `std.fs.Dir`. | |
| 103 | /// Deprecated; call `std.fs.Dir.createFileW` directly. | |
| 116 | 104 | pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 117 | const handle = try windows.CreateFileW( | |
| 118 | path_w, | |
| 119 | windows.GENERIC_WRITE, | |
| 120 | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE, | |
| 121 | null, | |
| 122 | windows.CREATE_NEW, | |
| 123 | windows.FILE_ATTRIBUTE_NORMAL, | |
| 124 | null, | |
| 125 | ); | |
| 126 | return openHandle(handle); | |
| 105 | return std.fs.cwd().createFileW(path_w, .{ | |
| 106 | .mode = file_mode, | |
| 107 | .exclusive = true, | |
| 108 | }); | |
| 127 | 109 | } |
| 128 | 110 | |
| 129 | 111 | pub fn openHandle(handle: os.fd_t) File { |
| ... | ... | @@ -246,6 +228,7 @@ pub const File = struct { |
| 246 | 228 | windows.STATUS.SUCCESS => {}, |
| 247 | 229 | windows.STATUS.BUFFER_OVERFLOW => {}, |
| 248 | 230 | windows.STATUS.INVALID_PARAMETER => unreachable, |
| 231 | windows.STATUS.ACCESS_DENIED => return error.AccessDenied, | |
| 249 | 232 | else => return windows.unexpectedStatus(rc), |
| 250 | 233 | } |
| 251 | 234 | return Stat{ |
lib/std/fs/path.zig+32-1| ... | ... | @@ -128,6 +128,14 @@ test "join" { |
| 128 | 128 | testJoinPosix([_][]const u8{ "a/", "/c" }, "a/c"); |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | pub fn isAbsoluteC(path_c: [*:0]const u8) bool { | |
| 132 | if (builtin.os == .windows) { | |
| 133 | return isAbsoluteWindowsC(path_c); | |
| 134 | } else { | |
| 135 | return isAbsolutePosixC(path_c); | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 131 | 139 | pub fn isAbsolute(path: []const u8) bool { |
| 132 | 140 | if (builtin.os == .windows) { |
| 133 | 141 | return isAbsoluteWindows(path); |
| ... | ... | @@ -136,7 +144,7 @@ pub fn isAbsolute(path: []const u8) bool { |
| 136 | 144 | } |
| 137 | 145 | } |
| 138 | 146 | |
| 139 | pub fn isAbsoluteW(path_w: [*]const u16) bool { | |
| 147 | pub fn isAbsoluteW(path_w: [*:0]const u16) bool { | |
| 140 | 148 | if (path_w[0] == '/') |
| 141 | 149 | return true; |
| 142 | 150 | |
| ... | ... | @@ -174,10 +182,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool { |
| 174 | 182 | return false; |
| 175 | 183 | } |
| 176 | 184 | |
| 185 | pub fn isAbsoluteWindowsC(path_c: [*:0]const u8) bool { | |
| 186 | if (path_c[0] == '/') | |
| 187 | return true; | |
| 188 | ||
| 189 | if (path_c[0] == '\\') { | |
| 190 | return true; | |
| 191 | } | |
| 192 | if (path_c[0] == 0 or path_c[1] == 0 or path_c[2] == 0) { | |
| 193 | return false; | |
| 194 | } | |
| 195 | if (path_c[1] == ':') { | |
| 196 | if (path_c[2] == '/') | |
| 197 | return true; | |
| 198 | if (path_c[2] == '\\') | |
| 199 | return true; | |
| 200 | } | |
| 201 | return false; | |
| 202 | } | |
| 203 | ||
| 177 | 204 | pub fn isAbsolutePosix(path: []const u8) bool { |
| 178 | 205 | return path[0] == sep_posix; |
| 179 | 206 | } |
| 180 | 207 | |
| 208 | pub fn isAbsolutePosixC(path_c: [*:0]const u8) bool { | |
| 209 | return path_c[0] == sep_posix; | |
| 210 | } | |
| 211 | ||
| 181 | 212 | test "isAbsoluteWindows" { |
| 182 | 213 | testIsAbsoluteWindows("/", true); |
| 183 | 214 | testIsAbsoluteWindows("//", true); |
lib/std/io.zig+4-7| ... | ... | @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream; |
| 61 | 61 | pub const InStream = @import("io/in_stream.zig").InStream; |
| 62 | 62 | pub const OutStream = @import("io/out_stream.zig").OutStream; |
| 63 | 63 | |
| 64 | /// TODO move this to `std.fs` and add a version to `std.fs.Dir`. | |
| 64 | /// Deprecated; use `std.fs.Dir.writeFile`. | |
| 65 | 65 | pub fn writeFile(path: []const u8, data: []const u8) !void { |
| 66 | var file = try File.openWrite(path); | |
| 67 | defer file.close(); | |
| 68 | try file.write(data); | |
| 66 | return fs.cwd().writeFile(path, data); | |
| 69 | 67 | } |
| 70 | 68 | |
| 71 | /// On success, caller owns returned buffer. | |
| 72 | /// This function is deprecated; use `std.fs.Dir.readFileAlloc`. | |
| 69 | /// Deprecated; use `std.fs.Dir.readFileAlloc`. | |
| 73 | 70 | pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 { |
| 74 | return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize)); | |
| 71 | return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize)); | |
| 75 | 72 | } |
| 76 | 73 | |
| 77 | 74 | pub fn BufferedInStream(comptime Error: type) type { |
lib/std/io/test.zig+15-13| ... | ... | @@ -14,12 +14,14 @@ test "write a file, read it, then delete it" { |
| 14 | 14 | var raw_bytes: [200 * 1024]u8 = undefined; |
| 15 | 15 | var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator; |
| 16 | 16 | |
| 17 | const cwd = fs.cwd(); | |
| 18 | ||
| 17 | 19 | var data: [1024]u8 = undefined; |
| 18 | 20 | var prng = DefaultPrng.init(1234); |
| 19 | 21 | prng.random.bytes(data[0..]); |
| 20 | 22 | const tmp_file_name = "temp_test_file.txt"; |
| 21 | 23 | { |
| 22 | var file = try File.openWrite(tmp_file_name); | |
| 24 | var file = try cwd.createFile(tmp_file_name, .{}); | |
| 23 | 25 | defer file.close(); |
| 24 | 26 | |
| 25 | 27 | var file_out_stream = file.outStream(); |
| ... | ... | @@ -32,8 +34,8 @@ test "write a file, read it, then delete it" { |
| 32 | 34 | } |
| 33 | 35 | |
| 34 | 36 | { |
| 35 | // make sure openWriteNoClobber doesn't harm the file | |
| 36 | if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| { | |
| 37 | // Make sure the exclusive flag is honored. | |
| 38 | if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| { | |
| 37 | 39 | unreachable; |
| 38 | 40 | } else |err| { |
| 39 | 41 | std.debug.assert(err == File.OpenError.PathAlreadyExists); |
| ... | ... | @@ -41,7 +43,7 @@ test "write a file, read it, then delete it" { |
| 41 | 43 | } |
| 42 | 44 | |
| 43 | 45 | { |
| 44 | var file = try File.openRead(tmp_file_name); | |
| 46 | var file = try cwd.openFile(tmp_file_name, .{}); | |
| 45 | 47 | defer file.close(); |
| 46 | 48 | |
| 47 | 49 | const file_size = try file.getEndPos(); |
| ... | ... | @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" { |
| 58 | 60 | expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); |
| 59 | 61 | expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); |
| 60 | 62 | } |
| 61 | try fs.deleteFile(tmp_file_name); | |
| 63 | try cwd.deleteFile(tmp_file_name); | |
| 62 | 64 | } |
| 63 | 65 | |
| 64 | 66 | test "BufferOutStream" { |
| ... | ... | @@ -274,7 +276,7 @@ test "BitOutStream" { |
| 274 | 276 | test "BitStreams with File Stream" { |
| 275 | 277 | const tmp_file_name = "temp_test_file.txt"; |
| 276 | 278 | { |
| 277 | var file = try File.openWrite(tmp_file_name); | |
| 279 | var file = try fs.cwd().createFile(tmp_file_name, .{}); | |
| 278 | 280 | defer file.close(); |
| 279 | 281 | |
| 280 | 282 | var file_out = file.outStream(); |
| ... | ... | @@ -291,7 +293,7 @@ test "BitStreams with File Stream" { |
| 291 | 293 | try bit_stream.flushBits(); |
| 292 | 294 | } |
| 293 | 295 | { |
| 294 | var file = try File.openRead(tmp_file_name); | |
| 296 | var file = try fs.cwd().openFile(tmp_file_name, .{}); | |
| 295 | 297 | defer file.close(); |
| 296 | 298 | |
| 297 | 299 | var file_in = file.inStream(); |
| ... | ... | @@ -316,7 +318,7 @@ test "BitStreams with File Stream" { |
| 316 | 318 | |
| 317 | 319 | expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); |
| 318 | 320 | } |
| 319 | try fs.deleteFile(tmp_file_name); | |
| 321 | try fs.cwd().deleteFile(tmp_file_name); | |
| 320 | 322 | } |
| 321 | 323 | |
| 322 | 324 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { |
| ... | ... | @@ -599,7 +601,7 @@ test "c out stream" { |
| 599 | 601 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; |
| 600 | 602 | defer { |
| 601 | 603 | _ = std.c.fclose(out_file); |
| 602 | fs.deleteFileC(filename) catch {}; | |
| 604 | fs.cwd().deleteFileC(filename) catch {}; | |
| 603 | 605 | } |
| 604 | 606 | |
| 605 | 607 | const out_stream = &io.COutStream.init(out_file).stream; |
| ... | ... | @@ -608,10 +610,10 @@ test "c out stream" { |
| 608 | 610 | |
| 609 | 611 | test "File seek ops" { |
| 610 | 612 | const tmp_file_name = "temp_test_file.txt"; |
| 611 | var file = try File.openWrite(tmp_file_name); | |
| 613 | var file = try fs.cwd().createFile(tmp_file_name, .{}); | |
| 612 | 614 | defer { |
| 613 | 615 | file.close(); |
| 614 | fs.deleteFile(tmp_file_name) catch {}; | |
| 616 | fs.cwd().deleteFile(tmp_file_name) catch {}; | |
| 615 | 617 | } |
| 616 | 618 | |
| 617 | 619 | try file.write([_]u8{0x55} ** 8192); |
| ... | ... | @@ -632,10 +634,10 @@ test "File seek ops" { |
| 632 | 634 | |
| 633 | 635 | test "updateTimes" { |
| 634 | 636 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 635 | var file = try File.openWrite(tmp_file_name); | |
| 637 | var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true }); | |
| 636 | 638 | defer { |
| 637 | 639 | file.close(); |
| 638 | std.fs.deleteFile(tmp_file_name) catch {}; | |
| 640 | std.fs.cwd().deleteFile(tmp_file_name) catch {}; | |
| 639 | 641 | } |
| 640 | 642 | var stat_old = try file.stat(); |
| 641 | 643 | // Set atime and mtime to 5s before |
lib/std/net.zig+2-2| ... | ... | @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( |
| 812 | 812 | family: os.sa_family_t, |
| 813 | 813 | port: u16, |
| 814 | 814 | ) !void { |
| 815 | const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) { | |
| 815 | const file = fs.openFileAbsoluteC("/etc/hosts", .{}) catch |err| switch (err) { | |
| 816 | 816 | error.FileNotFound, |
| 817 | 817 | error.NotDir, |
| 818 | 818 | error.AccessDenied, |
| ... | ... | @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1006 | 1006 | }; |
| 1007 | 1007 | errdefer rc.deinit(); |
| 1008 | 1008 | |
| 1009 | const file = fs.File.openReadC("/etc/resolv.conf") catch |err| switch (err) { | |
| 1009 | const file = fs.openFileAbsoluteC("/etc/resolv.conf", .{}) catch |err| switch (err) { | |
| 1010 | 1010 | error.FileNotFound, |
| 1011 | 1011 | error.NotDir, |
| 1012 | 1012 | error.AccessDenied, |
lib/std/os.zig+13-6| ... | ... | @@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 798 | 798 | path_buf[search_path.len] = '/'; |
| 799 | 799 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); |
| 800 | 800 | path_buf[search_path.len + file_slice.len + 1] = 0; |
| 801 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 801 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 802 | 802 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); |
| 803 | 803 | switch (err) { |
| 804 | 804 | error.AccessDenied => seen_eacces = true, |
| ... | ... | @@ -834,7 +834,7 @@ pub fn execvpe( |
| 834 | 834 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); |
| 835 | 835 | arg_buf[arg.len] = 0; |
| 836 | 836 | |
| 837 | // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 837 | // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 838 | 838 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); |
| 839 | 839 | } |
| 840 | 840 | argv_buf[argv_slice.len] = null; |
| ... | ... | @@ -842,7 +842,7 @@ pub fn execvpe( |
| 842 | 842 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); |
| 843 | 843 | defer freeNullDelimitedEnvMap(allocator, envp_buf); |
| 844 | 844 | |
| 845 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 845 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 846 | 846 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); |
| 847 | 847 | |
| 848 | 848 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); |
| ... | ... | @@ -863,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 863 | 863 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); |
| 864 | 864 | env_buf[env_buf.len - 1] = 0; |
| 865 | 865 | |
| 866 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 866 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 867 | 867 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); |
| 868 | 868 | } |
| 869 | 869 | assert(i == envp_count); |
| 870 | 870 | } |
| 871 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | |
| 871 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 872 | 872 | assert(envp_buf[envp_count] == null); |
| 873 | 873 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; |
| 874 | 874 | } |
| ... | ... | @@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{ |
| 1087 | 1087 | }; |
| 1088 | 1088 | |
| 1089 | 1089 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 1090 | /// Asserts that the path parameter has no null bytes. | |
| 1090 | 1091 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { |
| 1092 | if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0); | |
| 1091 | 1093 | if (builtin.os == .windows) { |
| 1092 | 1094 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); |
| 1093 | 1095 | return unlinkatW(dirfd, &file_path_w, flags); |
| ... | ... | @@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 { |
| 2026 | 2028 | } |
| 2027 | 2029 | } |
| 2028 | 2030 | |
| 2029 | pub const FStatError = error{SystemResources} || UnexpectedError; | |
| 2031 | pub const FStatError = error{ | |
| 2032 | SystemResources, | |
| 2033 | AccessDenied, | |
| 2034 | } || UnexpectedError; | |
| 2030 | 2035 | |
| 2031 | 2036 | pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2032 | 2037 | var stat: Stat = undefined; |
| ... | ... | @@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2036 | 2041 | EINVAL => unreachable, |
| 2037 | 2042 | EBADF => unreachable, // Always a race condition. |
| 2038 | 2043 | ENOMEM => return error.SystemResources, |
| 2044 | EACCES => return error.AccessDenied, | |
| 2039 | 2045 | else => |err| return unexpectedErrno(err), |
| 2040 | 2046 | } |
| 2041 | 2047 | } |
| ... | ... | @@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat { |
| 2045 | 2051 | EINVAL => unreachable, |
| 2046 | 2052 | EBADF => unreachable, // Always a race condition. |
| 2047 | 2053 | ENOMEM => return error.SystemResources, |
| 2054 | EACCES => return error.AccessDenied, | |
| 2048 | 2055 | else => |err| return unexpectedErrno(err), |
| 2049 | 2056 | } |
| 2050 | 2057 | } |
lib/std/os/linux/test.zig+3-4| ... | ... | @@ -4,6 +4,7 @@ const linux = std.os.linux; |
| 4 | 4 | const mem = std.mem; |
| 5 | 5 | const elf = std.elf; |
| 6 | 6 | const expect = std.testing.expect; |
| 7 | const fs = std.fs; | |
| 7 | 8 | |
| 8 | 9 | test "getpid" { |
| 9 | 10 | expect(linux.getpid() != 0); |
| ... | ... | @@ -45,14 +46,12 @@ test "timer" { |
| 45 | 46 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); |
| 46 | 47 | } |
| 47 | 48 | |
| 48 | const File = std.fs.File; | |
| 49 | ||
| 50 | 49 | test "statx" { |
| 51 | 50 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 52 | var file = try File.openWrite(tmp_file_name); | |
| 51 | var file = try fs.cwd().createFile(tmp_file_name, .{}); | |
| 53 | 52 | defer { |
| 54 | 53 | file.close(); |
| 55 | std.fs.deleteFile(tmp_file_name) catch {}; | |
| 54 | fs.cwd().deleteFile(tmp_file_name) catch {}; | |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | var statx_buf: linux.Statx = undefined; |
lib/std/os/test.zig+2-2| ... | ... | @@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" { |
| 20 | 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 | 21 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); |
| 22 | 22 | try fs.deleteTree("os_test_tmp"); |
| 23 | if (fs.Dir.cwd().openDirTraverse("os_test_tmp")) |dir| { | |
| 23 | if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { | |
| 24 | 24 | @panic("expected error"); |
| 25 | 25 | } else |err| { |
| 26 | 26 | expect(err == error.FileNotFound); |
| ... | ... | @@ -111,7 +111,7 @@ test "AtomicFile" { |
| 111 | 111 | const content = try io.readFileAlloc(allocator, test_out_file); |
| 112 | 112 | expect(mem.eql(u8, content, test_content)); |
| 113 | 113 | |
| 114 | try fs.deleteFile(test_out_file); | |
| 114 | try fs.cwd().deleteFile(test_out_file); | |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | 117 | test "thread local storage" { |
lib/std/pdb.zig+2-1| ... | ... | @@ -6,6 +6,7 @@ const mem = std.mem; |
| 6 | 6 | const os = std.os; |
| 7 | 7 | const warn = std.debug.warn; |
| 8 | 8 | const coff = std.coff; |
| 9 | const fs = std.fs; | |
| 9 | 10 | const File = std.fs.File; |
| 10 | 11 | |
| 11 | 12 | const ArrayList = std.ArrayList; |
| ... | ... | @@ -469,7 +470,7 @@ pub const Pdb = struct { |
| 469 | 470 | msf: Msf, |
| 470 | 471 | |
| 471 | 472 | pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void { |
| 472 | self.in_file = try File.openRead(file_name); | |
| 473 | self.in_file = try fs.cwd().openFile(file_name, .{}); | |
| 473 | 474 | self.allocator = coff_ptr.allocator; |
| 474 | 475 | self.coff = coff_ptr; |
| 475 | 476 |
src-self-hosted/main.zig+1-1| ... | ... | @@ -702,7 +702,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 702 | 702 | max_src_size, |
| 703 | 703 | ) catch |err| switch (err) { |
| 704 | 704 | error.IsDir, error.AccessDenied => { |
| 705 | var dir = try fs.Dir.cwd().openDirList(file_path); | |
| 705 | var dir = try fs.cwd().openDirList(file_path); | |
| 706 | 706 | defer dir.close(); |
| 707 | 707 | |
| 708 | 708 | 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 | 279 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { |
| 280 | 280 | error.IsDir, error.AccessDenied => { |
| 281 | 281 | // TODO make event based (and dir.next()) |
| 282 | var dir = try fs.Dir.cwd().openDirList(file_path); | |
| 282 | var dir = try fs.cwd().openDirList(file_path); | |
| 283 | 283 | defer dir.close(); |
| 284 | 284 | |
| 285 | 285 | var dir_it = dir.iterate(); |
test/standalone/cat/main.zig+5-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const io = std.io; |
| 3 | 3 | const process = std.process; |
| 4 | const File = std.fs.File; | |
| 4 | const fs = std.fs; | |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | const warn = std.debug.warn; |
| 7 | 7 | const allocator = std.debug.global_allocator; |
| ... | ... | @@ -12,6 +12,8 @@ pub fn main() !void { |
| 12 | 12 | var catted_anything = false; |
| 13 | 13 | const stdout_file = io.getStdOut(); |
| 14 | 14 | |
| 15 | const cwd = fs.cwd(); | |
| 16 | ||
| 15 | 17 | while (args_it.next(allocator)) |arg_or_err| { |
| 16 | 18 | const arg = try unwrapArg(arg_or_err); |
| 17 | 19 | if (mem.eql(u8, arg, "-")) { |
| ... | ... | @@ -20,7 +22,7 @@ pub fn main() !void { |
| 20 | 22 | } else if (arg[0] == '-') { |
| 21 | 23 | return usage(exe); |
| 22 | 24 | } else { |
| 23 | const file = File.openRead(arg) catch |err| { | |
| 25 | const file = cwd.openFile(arg, .{}) catch |err| { | |
| 24 | 26 | warn("Unable to open file: {}\n", @errorName(err)); |
| 25 | 27 | return err; |
| 26 | 28 | }; |
| ... | ... | @@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void { |
| 40 | 42 | return error.Invalid; |
| 41 | 43 | } |
| 42 | 44 | |
| 43 | fn cat_file(stdout: File, file: File) !void { | |
| 45 | fn cat_file(stdout: fs.File, file: fs.File) !void { | |
| 44 | 46 | var buf: [1024 * 4]u8 = undefined; |
| 45 | 47 | |
| 46 | 48 | while (true) { |