| author | |
| committer | |
| log | 413f9a5cfc9e867e3bc69b47b38c62b52a52d5e9 |
| tree | 527b612cd0b7de432ed0738cf8c181a8f37dfb93 |
| parent | d039fed831cfc219821b58f1d819d79ad49dc652 |
| signature |
update to non-deprecated std.fs APIs throughout the codebase
Related: #381115 files changed, 224 insertions(+), 88 deletions(-)
lib/std/build.zig+1-1| ... | @@ -2416,7 +2416,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { | ... | @@ -2416,7 +2416,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { |
| 2416 | const path_file = try fs.path.join(allocator, [_][]const u8{ appdata_path, "vcpkg.path.txt" }); | 2416 | const path_file = try fs.path.join(allocator, [_][]const u8{ appdata_path, "vcpkg.path.txt" }); |
| 2417 | defer allocator.free(path_file); | 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 | defer file.close(); | 2420 | defer file.close(); |
| 2421 | 2421 | ||
| 2422 | const size = @intCast(usize, try file.getEndPos()); | 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,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1131 | } | 1131 | } |
| 1132 | 1132 | ||
| 1133 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { | 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 | defer f.close(); | 1135 | defer f.close(); |
| 1136 | // TODO fstat and make sure that the file has the correct size | 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,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 2089 | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); | 2089 | const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); |
| 2090 | 2090 | ||
| 2091 | gop.kv.value = MachOFile{ | 2091 | gop.kv.value = MachOFile{ |
| 2092 | .bytes = try std.fs.Dir.cwd().readFileAllocAligned( | 2092 | .bytes = try std.fs.cwd().readFileAllocAligned( |
| 2093 | di.ofiles.allocator, | 2093 | di.ofiles.allocator, |
| 2094 | ofile_path, | 2094 | ofile_path, |
| 2095 | maxInt(usize), | 2095 | maxInt(usize), |
lib/std/fs.zig+137-35| ... | @@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File; | ... | @@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File; |
| 13 | 13 | ||
| 14 | pub const symLink = os.symlink; | 14 | pub const symLink = os.symlink; |
| 15 | pub const symLinkC = os.symlinkC; | 15 | pub const symLinkC = os.symlinkC; |
| 16 | pub const deleteFile = os.unlink; | ||
| 17 | pub const deleteFileC = os.unlinkC; | ||
| 18 | pub const rename = os.rename; | 16 | pub const rename = os.rename; |
| 19 | pub const renameC = os.renameC; | 17 | pub const renameC = os.renameC; |
| 20 | pub const renameW = os.renameW; | 18 | pub const renameW = os.renameW; |
| ... | @@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { | ... | @@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { |
| 88 | /// If any of the directories do not exist for dest_path, they are created. | 86 | /// If any of the directories do not exist for dest_path, they are created. |
| 89 | /// TODO https://github.com/ziglang/zig/issues/2885 | 87 | /// TODO https://github.com/ziglang/zig/issues/2885 |
| 90 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { | 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 | defer src_file.close(); | 92 | defer src_file.close(); |
| 93 | 93 | ||
| 94 | const src_stat = try src_file.stat(); | 94 | const src_stat = try src_file.stat(); |
| 95 | check_dest_stat: { | 95 | check_dest_stat: { |
| 96 | const dest_stat = blk: { | 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 | error.FileNotFound => break :check_dest_stat, | 98 | error.FileNotFound => break :check_dest_stat, |
| 99 | else => |e| return e, | 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,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil |
| 157 | /// in the same directory as dest_path. | 157 | /// in the same directory as dest_path. |
| 158 | /// Destination file will have the same mode as the source file. | 158 | /// Destination file will have the same mode as the source file. |
| 159 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | 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 | defer in_file.close(); | 161 | defer in_file.close(); |
| 162 | 162 | ||
| 163 | const mode = try in_file.mode(); | 163 | const mode = try in_file.mode(); |
| ... | @@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | ... | @@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { |
| 180 | /// merged and readily available, | 180 | /// merged and readily available, |
| 181 | /// there is a possibility of power loss or application termination leaving temporary files present | 181 | /// there is a possibility of power loss or application termination leaving temporary files present |
| 182 | pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { | 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 | defer in_file.close(); | 184 | defer in_file.close(); |
| 185 | 185 | ||
| 186 | var atomic_file = try AtomicFile.init(dest_path, mode); | 186 | var atomic_file = try AtomicFile.init(dest_path, mode); |
| ... | @@ -206,8 +206,6 @@ pub const AtomicFile = struct { | ... | @@ -206,8 +206,6 @@ pub const AtomicFile = struct { |
| 206 | 206 | ||
| 207 | /// dest_path must remain valid for the lifetime of AtomicFile | 207 | /// dest_path must remain valid for the lifetime of AtomicFile |
| 208 | /// call finish to atomically replace dest_path with contents | 208 | /// call finish to atomically replace dest_path with contents |
| 209 | /// TODO once we have null terminated pointers, use the | ||
| 210 | /// openWriteNoClobberN function | ||
| 211 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { | 209 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { |
| 212 | const dirname = path.dirname(dest_path); | 210 | const dirname = path.dirname(dest_path); |
| 213 | var rand_buf: [12]u8 = undefined; | 211 | var rand_buf: [12]u8 = undefined; |
| ... | @@ -224,15 +222,19 @@ pub const AtomicFile = struct { | ... | @@ -224,15 +222,19 @@ pub const AtomicFile = struct { |
| 224 | 222 | ||
| 225 | tmp_path_buf[tmp_path_len] = 0; | 223 | tmp_path_buf[tmp_path_len] = 0; |
| 226 | 224 | ||
| 225 | const my_cwd = cwd(); | ||
| 226 | |||
| 227 | while (true) { | 227 | while (true) { |
| 228 | try crypto.randomBytes(rand_buf[0..]); | 228 | try crypto.randomBytes(rand_buf[0..]); |
| 229 | b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf); | 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 | error.PathAlreadyExists => continue, | 236 | error.PathAlreadyExists => continue, |
| 233 | // TODO zig should figure out that this error set does not include PathAlreadyExists since | 237 | else => |e| return e, |
| 234 | // it is handled in the above switch | ||
| 235 | else => return err, | ||
| 236 | }; | 238 | }; |
| 237 | 239 | ||
| 238 | return AtomicFile{ | 240 | return AtomicFile{ |
| ... | @@ -248,7 +250,7 @@ pub const AtomicFile = struct { | ... | @@ -248,7 +250,7 @@ pub const AtomicFile = struct { |
| 248 | pub fn deinit(self: *AtomicFile) void { | 250 | pub fn deinit(self: *AtomicFile) void { |
| 249 | if (!self.finished) { | 251 | if (!self.finished) { |
| 250 | self.file.close(); | 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 | self.finished = true; | 254 | self.finished = true; |
| 253 | } | 255 | } |
| 254 | } | 256 | } |
| ... | @@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void { | ... | @@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void { |
| 350 | CannotDeleteRootDirectory, | 352 | CannotDeleteRootDirectory, |
| 351 | }.CannotDeleteRootDirectory; | 353 | }.CannotDeleteRootDirectory; |
| 352 | 354 | ||
| 353 | var dir = try Dir.cwd().openDirList(dirname); | 355 | var dir = try cwd().openDirList(dirname); |
| 354 | defer dir.close(); | 356 | defer dir.close(); |
| 355 | 357 | ||
| 356 | return dir.deleteTree(path.basename(full_path)); | 358 | return dir.deleteTree(path.basename(full_path)); |
| 357 | } else { | 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,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 | pub const OpenError = error{ | 662 | pub const OpenError = error{ |
| 672 | FileNotFound, | 663 | FileNotFound, |
| 673 | NotDir, | 664 | NotDir, |
| ... | @@ -683,12 +674,12 @@ pub const Dir = struct { | ... | @@ -683,12 +674,12 @@ pub const Dir = struct { |
| 683 | DeviceBusy, | 674 | DeviceBusy, |
| 684 | } || os.UnexpectedError; | 675 | } || os.UnexpectedError; |
| 685 | 676 | ||
| 686 | /// Deprecated; call `Dir.cwd().openDirList` directly. | 677 | /// Deprecated; call `cwd().openDirList` directly. |
| 687 | pub fn open(dir_path: []const u8) OpenError!Dir { | 678 | pub fn open(dir_path: []const u8) OpenError!Dir { |
| 688 | return cwd().openDirList(dir_path); | 679 | return cwd().openDirList(dir_path); |
| 689 | } | 680 | } |
| 690 | 681 | ||
| 691 | /// Deprecated; call `Dir.cwd().openDirListC` directly. | 682 | /// Deprecated; call `cwd().openDirListC` directly. |
| 692 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { | 683 | pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { |
| 693 | return cwd().openDirListC(dir_path_c); | 684 | return cwd().openDirListC(dir_path_c); |
| 694 | } | 685 | } |
| ... | @@ -700,7 +691,9 @@ pub const Dir = struct { | ... | @@ -700,7 +691,9 @@ pub const Dir = struct { |
| 700 | 691 | ||
| 701 | /// Opens a file for reading or writing, without attempting to create a new file. | 692 | /// Opens a file for reading or writing, without attempting to create a new file. |
| 702 | /// Call `File.close` to release the resource. | 693 | /// Call `File.close` to release the resource. |
| 694 | /// Asserts that the path parameter has no null bytes. | ||
| 703 | pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | 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); | ||
| 704 | if (builtin.os == .windows) { | 697 | if (builtin.os == .windows) { |
| 705 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 698 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 706 | return self.openFileW(&path_w, flags); | 699 | return self.openFileW(&path_w, flags); |
| ... | @@ -737,7 +730,9 @@ pub const Dir = struct { | ... | @@ -737,7 +730,9 @@ pub const Dir = struct { |
| 737 | 730 | ||
| 738 | /// Creates, opens, or overwrites a file with write access. | 731 | /// Creates, opens, or overwrites a file with write access. |
| 739 | /// Call `File.close` on the result when done. | 732 | /// Call `File.close` on the result when done. |
| 733 | /// Asserts that the path parameter has no null bytes. | ||
| 740 | pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | 734 | pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { |
| 735 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 741 | if (builtin.os == .windows) { | 736 | if (builtin.os == .windows) { |
| 742 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 737 | const path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 743 | return self.createFileW(&path_w, flags); | 738 | return self.createFileW(&path_w, flags); |
| ... | @@ -865,7 +860,10 @@ pub const Dir = struct { | ... | @@ -865,7 +860,10 @@ pub const Dir = struct { |
| 865 | /// list the contents of a directory, open it with `openDirList`. | 860 | /// list the contents of a directory, open it with `openDirList`. |
| 866 | /// | 861 | /// |
| 867 | /// Call `close` on the result when done. | 862 | /// Call `close` on the result when done. |
| 863 | /// | ||
| 864 | /// Asserts that the path parameter has no null bytes. | ||
| 868 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { | 865 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 866 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 869 | if (builtin.os == .windows) { | 867 | if (builtin.os == .windows) { |
| 870 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 868 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 871 | return self.openDirTraverseW(&sub_path_w); | 869 | return self.openDirTraverseW(&sub_path_w); |
| ... | @@ -880,7 +878,10 @@ pub const Dir = struct { | ... | @@ -880,7 +878,10 @@ pub const Dir = struct { |
| 880 | /// same and may be more efficient. | 878 | /// same and may be more efficient. |
| 881 | /// | 879 | /// |
| 882 | /// Call `close` on the result when done. | 880 | /// Call `close` on the result when done. |
| 881 | /// | ||
| 882 | /// Asserts that the path parameter has no null bytes. | ||
| 883 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { | 883 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { |
| 884 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 884 | if (builtin.os == .windows) { | 885 | if (builtin.os == .windows) { |
| 885 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 886 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 886 | return self.openDirListW(&sub_path_w); | 887 | return self.openDirListW(&sub_path_w); |
| ... | @@ -995,9 +996,12 @@ pub const Dir = struct { | ... | @@ -995,9 +996,12 @@ pub const Dir = struct { |
| 995 | pub const DeleteFileError = os.UnlinkError; | 996 | pub const DeleteFileError = os.UnlinkError; |
| 996 | 997 | ||
| 997 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 998 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 999 | /// Asserts that the path parameter has no null bytes. | ||
| 998 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { | 1000 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { |
| 999 | const sub_path_c = try os.toPosixPath(sub_path); | 1001 | os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) { |
| 1000 | return self.deleteFileC(&sub_path_c); | 1002 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR |
| 1003 | else => |e| return e, | ||
| 1004 | }; | ||
| 1001 | } | 1005 | } |
| 1002 | 1006 | ||
| 1003 | /// Same as `deleteFile` except the parameter is null-terminated. | 1007 | /// Same as `deleteFile` except the parameter is null-terminated. |
| ... | @@ -1008,6 +1012,14 @@ pub const Dir = struct { | ... | @@ -1008,6 +1012,14 @@ pub const Dir = struct { |
| 1008 | }; | 1012 | }; |
| 1009 | } | 1013 | } |
| 1010 | 1014 | ||
| 1015 | /// Same as `deleteFile` except the parameter is WTF-16 encoded. | ||
| 1016 | pub fn deleteFileW(self: Dir, sub_path_w: [*:0]const u16) DeleteFileError!void { | ||
| 1017 | os.unlinkatW(self.fd, sub_path_w, 0) catch |err| switch (err) { | ||
| 1018 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | ||
| 1019 | else => |e| return e, | ||
| 1020 | }; | ||
| 1021 | } | ||
| 1022 | |||
| 1011 | pub const DeleteDirError = error{ | 1023 | pub const DeleteDirError = error{ |
| 1012 | DirNotEmpty, | 1024 | DirNotEmpty, |
| 1013 | FileNotFound, | 1025 | FileNotFound, |
| ... | @@ -1026,7 +1038,9 @@ pub const Dir = struct { | ... | @@ -1026,7 +1038,9 @@ pub const Dir = struct { |
| 1026 | 1038 | ||
| 1027 | /// Returns `error.DirNotEmpty` if the directory is not empty. | 1039 | /// Returns `error.DirNotEmpty` if the directory is not empty. |
| 1028 | /// To delete a directory recursively, see `deleteTree`. | 1040 | /// To delete a directory recursively, see `deleteTree`. |
| 1041 | /// Asserts that the path parameter has no null bytes. | ||
| 1029 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { | 1042 | pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { |
| 1043 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 1030 | if (builtin.os == .windows) { | 1044 | if (builtin.os == .windows) { |
| 1031 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 1045 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 1032 | return self.deleteDirW(&sub_path_w); | 1046 | return self.deleteDirW(&sub_path_w); |
| ... | @@ -1054,7 +1068,9 @@ pub const Dir = struct { | ... | @@ -1054,7 +1068,9 @@ pub const Dir = struct { |
| 1054 | 1068 | ||
| 1055 | /// Read value of a symbolic link. | 1069 | /// Read value of a symbolic link. |
| 1056 | /// The return value is a slice of `buffer`, from index `0`. | 1070 | /// The return value is a slice of `buffer`, from index `0`. |
| 1071 | /// Asserts that the path parameter has no null bytes. | ||
| 1057 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1072 | pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1073 | if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0); | ||
| 1058 | const sub_path_c = try os.toPosixPath(sub_path); | 1074 | const sub_path_c = try os.toPosixPath(sub_path); |
| 1059 | return self.readLinkC(&sub_path_c, buffer); | 1075 | return self.readLinkC(&sub_path_c, buffer); |
| 1060 | } | 1076 | } |
| ... | @@ -1265,8 +1281,94 @@ pub const Dir = struct { | ... | @@ -1265,8 +1281,94 @@ pub const Dir = struct { |
| 1265 | } | 1281 | } |
| 1266 | } | 1282 | } |
| 1267 | } | 1283 | } |
| 1284 | |||
| 1285 | /// Writes content to the file system, creating a new file if it does not exist, truncating | ||
| 1286 | /// if it already exists. | ||
| 1287 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { | ||
| 1288 | var file = try self.createFile(sub_path, .{}); | ||
| 1289 | defer file.close(); | ||
| 1290 | try file.write(data); | ||
| 1291 | } | ||
| 1268 | }; | 1292 | }; |
| 1269 | 1293 | ||
| 1294 | /// Returns an handle to the current working directory that is open for traversal. | ||
| 1295 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. | ||
| 1296 | /// On POSIX targets, this function is comptime-callable. | ||
| 1297 | pub fn cwd() Dir { | ||
| 1298 | if (builtin.os == .windows) { | ||
| 1299 | return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; | ||
| 1300 | } else { | ||
| 1301 | return Dir{ .fd = os.AT_FDCWD }; | ||
| 1302 | } | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | /// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path. | ||
| 1306 | /// Call `File.close` to release the resource. | ||
| 1307 | /// Asserts that the path is absolute. See `Dir.openFile` for a function that | ||
| 1308 | /// operates on both absolute and relative paths. | ||
| 1309 | /// Asserts that the path parameter has no null bytes. See `openFileAbsoluteC` for a function | ||
| 1310 | /// that accepts a null-terminated path. | ||
| 1311 | pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 1312 | assert(path.isAbsolute(absolute_path)); | ||
| 1313 | return cwd().openFile(absolute_path, flags); | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | /// Same as `openFileAbsolute` but the path parameter is null-terminated. | ||
| 1317 | pub fn openFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 1318 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1319 | return cwd().openFileC(absolute_path_c, flags); | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | /// Same as `openFileAbsolute` but the path parameter is WTF-16 encoded. | ||
| 1323 | pub fn openFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File { | ||
| 1324 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1325 | return cwd().openFileW(absolute_path_w, flags); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | /// Creates, opens, or overwrites a file with write access, based on an absolute path. | ||
| 1329 | /// Call `File.close` to release the resource. | ||
| 1330 | /// Asserts that the path is absolute. See `Dir.createFile` for a function that | ||
| 1331 | /// operates on both absolute and relative paths. | ||
| 1332 | /// Asserts that the path parameter has no null bytes. See `createFileAbsoluteC` for a function | ||
| 1333 | /// that accepts a null-terminated path. | ||
| 1334 | pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 1335 | assert(path.isAbsolute(absolute_path)); | ||
| 1336 | return cwd().createFile(absolute_path, flags); | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | /// Same as `createFileAbsolute` but the path parameter is null-terminated. | ||
| 1340 | pub fn createFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 1341 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1342 | return cwd().createFileC(absolute_path_c, flags); | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | /// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded. | ||
| 1346 | pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | ||
| 1347 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1348 | return cwd().createFileW(absolute_path_w, flags); | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | /// Delete a file name and possibly the file it refers to, based on an absolute path. | ||
| 1352 | /// Asserts that the path is absolute. See `Dir.deleteFile` for a function that | ||
| 1353 | /// operates on both absolute and relative paths. | ||
| 1354 | /// Asserts that the path parameter has no null bytes. | ||
| 1355 | pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void { | ||
| 1356 | assert(path.isAbsolute(absolute_path)); | ||
| 1357 | return cwd().deleteFile(absolute_path); | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | /// Same as `deleteFileAbsolute` except the parameter is null-terminated. | ||
| 1361 | pub fn deleteFileAbsoluteC(absolute_path_c: [*:0]const u8) DeleteFileError!void { | ||
| 1362 | assert(path.isAbsoluteC(absolute_path_c)); | ||
| 1363 | return cwd().deleteFileC(absolute_path_c); | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. | ||
| 1367 | pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void { | ||
| 1368 | assert(path.isAbsoluteW(absolute_path_w)); | ||
| 1369 | return cwd().deleteFileW(absolute_path_w); | ||
| 1370 | } | ||
| 1371 | |||
| 1270 | pub const Walker = struct { | 1372 | pub const Walker = struct { |
| 1271 | stack: std.ArrayList(StackItem), | 1373 | stack: std.ArrayList(StackItem), |
| 1272 | name_buffer: std.Buffer, | 1374 | name_buffer: std.Buffer, |
| ... | @@ -1339,7 +1441,7 @@ pub const Walker = struct { | ... | @@ -1339,7 +1441,7 @@ pub const Walker = struct { |
| 1339 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | 1441 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1340 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); | 1442 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1341 | 1443 | ||
| 1342 | var dir = try Dir.cwd().openDirList(dir_path); | 1444 | var dir = try cwd().openDirList(dir_path); |
| 1343 | errdefer dir.close(); | 1445 | errdefer dir.close(); |
| 1344 | 1446 | ||
| 1345 | var name_buffer = try std.Buffer.init(allocator, dir_path); | 1447 | var name_buffer = try std.Buffer.init(allocator, dir_path); |
| ... | @@ -1373,18 +1475,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE | ... | @@ -1373,18 +1475,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE |
| 1373 | 1475 | ||
| 1374 | pub fn openSelfExe() OpenSelfExeError!File { | 1476 | pub fn openSelfExe() OpenSelfExeError!File { |
| 1375 | if (builtin.os == .linux) { | 1477 | if (builtin.os == .linux) { |
| 1376 | return File.openReadC("/proc/self/exe"); | 1478 | return openFileAbsoluteC("/proc/self/exe", .{}); |
| 1377 | } | 1479 | } |
| 1378 | if (builtin.os == .windows) { | 1480 | if (builtin.os == .windows) { |
| 1379 | const wide_slice = selfExePathW(); | 1481 | const wide_slice = selfExePathW(); |
| 1380 | const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); | 1482 | const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); |
| 1381 | return Dir.cwd().openReadW(&prefixed_path_w); | 1483 | return cwd().openReadW(&prefixed_path_w); |
| 1382 | } | 1484 | } |
| 1383 | var buf: [MAX_PATH_BYTES]u8 = undefined; | 1485 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1384 | const self_exe_path = try selfExePath(&buf); | 1486 | const self_exe_path = try selfExePath(&buf); |
| 1385 | buf[self_exe_path.len] = 0; | 1487 | buf[self_exe_path.len] = 0; |
| 1386 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 | 1488 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 |
| 1387 | return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr)); | 1489 | return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{}); |
| 1388 | } | 1490 | } |
| 1389 | 1491 | ||
| 1390 | test "openSelfExe" { | 1492 | test "openSelfExe" { |
lib/std/fs/file.zig+10-10| ... | @@ -51,42 +51,42 @@ pub const File = struct { | ... | @@ -51,42 +51,42 @@ pub const File = struct { |
| 51 | 51 | ||
| 52 | /// Deprecated; call `std.fs.Dir.openFile` directly. | 52 | /// Deprecated; call `std.fs.Dir.openFile` directly. |
| 53 | pub fn openRead(path: []const u8) OpenError!File { | 53 | pub fn openRead(path: []const u8) OpenError!File { |
| 54 | return std.fs.Dir.cwd().openFile(path, .{}); | 54 | return std.fs.cwd().openFile(path, .{}); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | /// Deprecated; call `std.fs.Dir.openFileC` directly. | 57 | /// Deprecated; call `std.fs.Dir.openFileC` directly. |
| 58 | pub fn openReadC(path_c: [*:0]const u8) OpenError!File { | 58 | pub fn openReadC(path_c: [*:0]const u8) OpenError!File { |
| 59 | return std.fs.Dir.cwd().openFileC(path_c, .{}); | 59 | return std.fs.cwd().openFileC(path_c, .{}); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | /// Deprecated; call `std.fs.Dir.openFileW` directly. | 62 | /// Deprecated; call `std.fs.Dir.openFileW` directly. |
| 63 | pub fn openReadW(path_w: [*]const u16) OpenError!File { | 63 | pub fn openReadW(path_w: [*]const u16) OpenError!File { |
| 64 | return std.fs.Dir.cwd().openFileW(path_w, .{}); | 64 | return std.fs.cwd().openFileW(path_w, .{}); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | /// Deprecated; call `std.fs.Dir.createFile` directly. | 67 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 68 | pub fn openWrite(path: []const u8) OpenError!File { | 68 | pub fn openWrite(path: []const u8) OpenError!File { |
| 69 | return std.fs.Dir.cwd().createFile(path, .{}); | 69 | return std.fs.cwd().createFile(path, .{}); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | /// Deprecated; call `std.fs.Dir.createFile` directly. | 72 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 73 | pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { | 73 | pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { |
| 74 | return std.fs.Dir.cwd().createFile(path, .{ .mode = file_mode }); | 74 | return std.fs.cwd().createFile(path, .{ .mode = file_mode }); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /// Deprecated; call `std.fs.Dir.createFileC` directly. | 77 | /// Deprecated; call `std.fs.Dir.createFileC` directly. |
| 78 | pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { | 78 | pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { |
| 79 | return std.fs.Dir.cwd().createFileC(path_c, .{ .mode = file_mode }); | 79 | return std.fs.cwd().createFileC(path_c, .{ .mode = file_mode }); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /// Deprecated; call `std.fs.Dir.createFileW` directly. | 82 | /// Deprecated; call `std.fs.Dir.createFileW` directly. |
| 83 | pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { | 83 | pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 84 | return std.fs.Dir.cwd().createFileW(path_w, .{ .mode = file_mode }); | 84 | return std.fs.cwd().createFileW(path_w, .{ .mode = file_mode }); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /// Deprecated; call `std.fs.Dir.createFile` directly. | 87 | /// Deprecated; call `std.fs.Dir.createFile` directly. |
| 88 | pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { | 88 | pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { |
| 89 | return std.fs.Dir.cwd().createFile(path, .{ | 89 | return std.fs.cwd().createFile(path, .{ |
| 90 | .mode = file_mode, | 90 | .mode = file_mode, |
| 91 | .exclusive = true, | 91 | .exclusive = true, |
| 92 | }); | 92 | }); |
| ... | @@ -94,7 +94,7 @@ pub const File = struct { | ... | @@ -94,7 +94,7 @@ pub const File = struct { |
| 94 | 94 | ||
| 95 | /// Deprecated; call `std.fs.Dir.createFileC` directly. | 95 | /// Deprecated; call `std.fs.Dir.createFileC` directly. |
| 96 | pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { | 96 | pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File { |
| 97 | return std.fs.Dir.cwd().createFileC(path_c, .{ | 97 | return std.fs.cwd().createFileC(path_c, .{ |
| 98 | .mode = file_mode, | 98 | .mode = file_mode, |
| 99 | .exclusive = true, | 99 | .exclusive = true, |
| 100 | }); | 100 | }); |
| ... | @@ -102,7 +102,7 @@ pub const File = struct { | ... | @@ -102,7 +102,7 @@ pub const File = struct { |
| 102 | 102 | ||
| 103 | /// Deprecated; call `std.fs.Dir.createFileW` directly. | 103 | /// Deprecated; call `std.fs.Dir.createFileW` directly. |
| 104 | pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { | 104 | pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { |
| 105 | return std.fs.Dir.cwd().createFileW(path_w, .{ | 105 | return std.fs.cwd().createFileW(path_w, .{ |
| 106 | .mode = file_mode, | 106 | .mode = file_mode, |
| 107 | .exclusive = true, | 107 | .exclusive = true, |
| 108 | }); | 108 | }); |
lib/std/fs/path.zig+32-1| ... | @@ -128,6 +128,14 @@ test "join" { | ... | @@ -128,6 +128,14 @@ test "join" { |
| 128 | testJoinPosix([_][]const u8{ "a/", "/c" }, "a/c"); | 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 | pub fn isAbsolute(path: []const u8) bool { | 139 | pub fn isAbsolute(path: []const u8) bool { |
| 132 | if (builtin.os == .windows) { | 140 | if (builtin.os == .windows) { |
| 133 | return isAbsoluteWindows(path); | 141 | return isAbsoluteWindows(path); |
| ... | @@ -136,7 +144,7 @@ pub fn isAbsolute(path: []const u8) bool { | ... | @@ -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 | if (path_w[0] == '/') | 148 | if (path_w[0] == '/') |
| 141 | return true; | 149 | return true; |
| 142 | 150 | ||
| ... | @@ -174,10 +182,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool { | ... | @@ -174,10 +182,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool { |
| 174 | return false; | 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 | pub fn isAbsolutePosix(path: []const u8) bool { | 204 | pub fn isAbsolutePosix(path: []const u8) bool { |
| 178 | return path[0] == sep_posix; | 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 | test "isAbsoluteWindows" { | 212 | test "isAbsoluteWindows" { |
| 182 | testIsAbsoluteWindows("/", true); | 213 | testIsAbsoluteWindows("/", true); |
| 183 | testIsAbsoluteWindows("//", true); | 214 | testIsAbsoluteWindows("//", true); |
lib/std/io.zig+4-7| ... | @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream; | ... | @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream; |
| 61 | pub const InStream = @import("io/in_stream.zig").InStream; | 61 | pub const InStream = @import("io/in_stream.zig").InStream; |
| 62 | pub const OutStream = @import("io/out_stream.zig").OutStream; | 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 | pub fn writeFile(path: []const u8, data: []const u8) !void { | 65 | pub fn writeFile(path: []const u8, data: []const u8) !void { |
| 66 | var file = try File.openWrite(path); | 66 | return fs.cwd().writeFile(path, data); |
| 67 | defer file.close(); | ||
| 68 | try file.write(data); | ||
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | /// On success, caller owns returned buffer. | 69 | /// Deprecated; use `std.fs.Dir.readFileAlloc`. |
| 72 | /// This function is deprecated; use `std.fs.Dir.readFileAlloc`. | ||
| 73 | pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 { | 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 | pub fn BufferedInStream(comptime Error: type) type { | 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,12 +14,14 @@ test "write a file, read it, then delete it" { |
| 14 | var raw_bytes: [200 * 1024]u8 = undefined; | 14 | var raw_bytes: [200 * 1024]u8 = undefined; |
| 15 | var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator; | 15 | var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator; |
| 16 | 16 | ||
| 17 | const cwd = fs.cwd(); | ||
| 18 | |||
| 17 | var data: [1024]u8 = undefined; | 19 | var data: [1024]u8 = undefined; |
| 18 | var prng = DefaultPrng.init(1234); | 20 | var prng = DefaultPrng.init(1234); |
| 19 | prng.random.bytes(data[0..]); | 21 | prng.random.bytes(data[0..]); |
| 20 | const tmp_file_name = "temp_test_file.txt"; | 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 | defer file.close(); | 25 | defer file.close(); |
| 24 | 26 | ||
| 25 | var file_out_stream = file.outStream(); | 27 | var file_out_stream = file.outStream(); |
| ... | @@ -32,8 +34,8 @@ test "write a file, read it, then delete it" { | ... | @@ -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 | 37 | // Make sure the exclusive flag is honored. |
| 36 | if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| { | 38 | if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| { |
| 37 | unreachable; | 39 | unreachable; |
| 38 | } else |err| { | 40 | } else |err| { |
| 39 | std.debug.assert(err == File.OpenError.PathAlreadyExists); | 41 | std.debug.assert(err == File.OpenError.PathAlreadyExists); |
| ... | @@ -41,7 +43,7 @@ test "write a file, read it, then delete it" { | ... | @@ -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 | defer file.close(); | 47 | defer file.close(); |
| 46 | 48 | ||
| 47 | const file_size = try file.getEndPos(); | 49 | const file_size = try file.getEndPos(); |
| ... | @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" { | ... | @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" { |
| 58 | expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); | 60 | expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); |
| 59 | expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); | 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 | test "BufferOutStream" { | 66 | test "BufferOutStream" { |
| ... | @@ -274,7 +276,7 @@ test "BitOutStream" { | ... | @@ -274,7 +276,7 @@ test "BitOutStream" { |
| 274 | test "BitStreams with File Stream" { | 276 | test "BitStreams with File Stream" { |
| 275 | const tmp_file_name = "temp_test_file.txt"; | 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 | defer file.close(); | 280 | defer file.close(); |
| 279 | 281 | ||
| 280 | var file_out = file.outStream(); | 282 | var file_out = file.outStream(); |
| ... | @@ -291,7 +293,7 @@ test "BitStreams with File Stream" { | ... | @@ -291,7 +293,7 @@ test "BitStreams with File Stream" { |
| 291 | try bit_stream.flushBits(); | 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 | defer file.close(); | 297 | defer file.close(); |
| 296 | 298 | ||
| 297 | var file_in = file.inStream(); | 299 | var file_in = file.inStream(); |
| ... | @@ -316,7 +318,7 @@ test "BitStreams with File Stream" { | ... | @@ -316,7 +318,7 @@ test "BitStreams with File Stream" { |
| 316 | 318 | ||
| 317 | expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); | 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 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { | 324 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { |
| ... | @@ -599,7 +601,7 @@ test "c out stream" { | ... | @@ -599,7 +601,7 @@ test "c out stream" { |
| 599 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | 601 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; |
| 600 | defer { | 602 | defer { |
| 601 | _ = std.c.fclose(out_file); | 603 | _ = std.c.fclose(out_file); |
| 602 | fs.deleteFileC(filename) catch {}; | 604 | fs.cwd().deleteFileC(filename) catch {}; |
| 603 | } | 605 | } |
| 604 | 606 | ||
| 605 | const out_stream = &io.COutStream.init(out_file).stream; | 607 | const out_stream = &io.COutStream.init(out_file).stream; |
| ... | @@ -608,10 +610,10 @@ test "c out stream" { | ... | @@ -608,10 +610,10 @@ test "c out stream" { |
| 608 | 610 | ||
| 609 | test "File seek ops" { | 611 | test "File seek ops" { |
| 610 | const tmp_file_name = "temp_test_file.txt"; | 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 | defer { | 614 | defer { |
| 613 | file.close(); | 615 | file.close(); |
| 614 | fs.deleteFile(tmp_file_name) catch {}; | 616 | fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 615 | } | 617 | } |
| 616 | 618 | ||
| 617 | try file.write([_]u8{0x55} ** 8192); | 619 | try file.write([_]u8{0x55} ** 8192); |
| ... | @@ -632,10 +634,10 @@ test "File seek ops" { | ... | @@ -632,10 +634,10 @@ test "File seek ops" { |
| 632 | 634 | ||
| 633 | test "updateTimes" { | 635 | test "updateTimes" { |
| 634 | const tmp_file_name = "just_a_temporary_file.txt"; | 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, .{}); |
| 636 | defer { | 638 | defer { |
| 637 | file.close(); | 639 | file.close(); |
| 638 | std.fs.deleteFile(tmp_file_name) catch {}; | 640 | std.fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 639 | } | 641 | } |
| 640 | var stat_old = try file.stat(); | 642 | var stat_old = try file.stat(); |
| 641 | // Set atime and mtime to 5s before | 643 | // Set atime and mtime to 5s before |
lib/std/net.zig+2-2| ... | @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( | ... | @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( |
| 812 | family: os.sa_family_t, | 812 | family: os.sa_family_t, |
| 813 | port: u16, | 813 | port: u16, |
| 814 | ) !void { | 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 | error.FileNotFound, | 816 | error.FileNotFound, |
| 817 | error.NotDir, | 817 | error.NotDir, |
| 818 | error.AccessDenied, | 818 | error.AccessDenied, |
| ... | @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { | ... | @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1006 | }; | 1006 | }; |
| 1007 | errdefer rc.deinit(); | 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 | error.FileNotFound, | 1010 | error.FileNotFound, |
| 1011 | error.NotDir, | 1011 | error.NotDir, |
| 1012 | error.AccessDenied, | 1012 | error.AccessDenied, |
lib/std/os.zig+7-5| ... | @@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e | ... | @@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 798 | path_buf[search_path.len] = '/'; | 798 | path_buf[search_path.len] = '/'; |
| 799 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); | 799 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); |
| 800 | path_buf[search_path.len + file_slice.len + 1] = 0; | 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 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); | 802 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); |
| 803 | switch (err) { | 803 | switch (err) { |
| 804 | error.AccessDenied => seen_eacces = true, | 804 | error.AccessDenied => seen_eacces = true, |
| ... | @@ -834,7 +834,7 @@ pub fn execvpe( | ... | @@ -834,7 +834,7 @@ pub fn execvpe( |
| 834 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); | 834 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); |
| 835 | arg_buf[arg.len] = 0; | 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 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); | 838 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); |
| 839 | } | 839 | } |
| 840 | argv_buf[argv_slice.len] = null; | 840 | argv_buf[argv_slice.len] = null; |
| ... | @@ -842,7 +842,7 @@ pub fn execvpe( | ... | @@ -842,7 +842,7 @@ pub fn execvpe( |
| 842 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); | 842 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); |
| 843 | defer freeNullDelimitedEnvMap(allocator, envp_buf); | 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 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); | 846 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); |
| 847 | 847 | ||
| 848 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); | 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,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 863 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); | 863 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); |
| 864 | env_buf[env_buf.len - 1] = 0; | 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 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); | 867 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); |
| 868 | } | 868 | } |
| 869 | assert(i == envp_count); | 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 | assert(envp_buf[envp_count] == null); | 872 | assert(envp_buf[envp_count] == null); |
| 873 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; | 873 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; |
| 874 | } | 874 | } |
| ... | @@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{ | ... | @@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{ |
| 1087 | }; | 1087 | }; |
| 1088 | 1088 | ||
| 1089 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 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 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { | 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 | if (builtin.os == .windows) { | 1093 | if (builtin.os == .windows) { |
| 1092 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); | 1094 | const file_path_w = try windows.sliceToPrefixedFileW(file_path); |
| 1093 | return unlinkatW(dirfd, &file_path_w, flags); | 1095 | return unlinkatW(dirfd, &file_path_w, flags); |
lib/std/os/linux/test.zig+3-4| ... | @@ -4,6 +4,7 @@ const linux = std.os.linux; | ... | @@ -4,6 +4,7 @@ const linux = std.os.linux; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const elf = std.elf; | 5 | const elf = std.elf; |
| 6 | const expect = std.testing.expect; | 6 | const expect = std.testing.expect; |
| 7 | const fs = std.fs; | ||
| 7 | 8 | ||
| 8 | test "getpid" { | 9 | test "getpid" { |
| 9 | expect(linux.getpid() != 0); | 10 | expect(linux.getpid() != 0); |
| ... | @@ -45,14 +46,12 @@ test "timer" { | ... | @@ -45,14 +46,12 @@ test "timer" { |
| 45 | err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1); | 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 | test "statx" { | 49 | test "statx" { |
| 51 | const tmp_file_name = "just_a_temporary_file.txt"; | 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 | defer { | 52 | defer { |
| 54 | file.close(); | 53 | file.close(); |
| 55 | std.fs.deleteFile(tmp_file_name) catch {}; | 54 | fs.cwd().deleteFile(tmp_file_name) catch {}; |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | var statx_buf: linux.Statx = undefined; | 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,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.cwd().openDirTraverse("os_test_tmp")) |dir| { | 23 | if (fs.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); |
| ... | @@ -111,7 +111,7 @@ test "AtomicFile" { | ... | @@ -111,7 +111,7 @@ test "AtomicFile" { |
| 111 | const content = try io.readFileAlloc(allocator, test_out_file); | 111 | const content = try io.readFileAlloc(allocator, test_out_file); |
| 112 | expect(mem.eql(u8, content, test_content)); | 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 | test "thread local storage" { | 117 | test "thread local storage" { |
lib/std/pdb.zig+2-1| ... | @@ -6,6 +6,7 @@ const mem = std.mem; | ... | @@ -6,6 +6,7 @@ const mem = std.mem; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | const coff = std.coff; | 8 | const coff = std.coff; |
| 9 | const fs = std.fs; | ||
| 9 | const File = std.fs.File; | 10 | const File = std.fs.File; |
| 10 | 11 | ||
| 11 | const ArrayList = std.ArrayList; | 12 | const ArrayList = std.ArrayList; |
| ... | @@ -469,7 +470,7 @@ pub const Pdb = struct { | ... | @@ -469,7 +470,7 @@ pub const Pdb = struct { |
| 469 | msf: Msf, | 470 | msf: Msf, |
| 470 | 471 | ||
| 471 | pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void { | 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 | self.allocator = coff_ptr.allocator; | 474 | self.allocator = coff_ptr.allocator; |
| 474 | self.coff = coff_ptr; | 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,7 +702,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 702 | max_src_size, | 702 | max_src_size, |
| 703 | ) catch |err| switch (err) { | 703 | ) catch |err| switch (err) { |
| 704 | error.IsDir, error.AccessDenied => { | 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 | defer dir.close(); | 706 | defer dir.close(); |
| 707 | 707 | ||
| 708 | var group = event.Group(FmtError!void).init(fmt.allocator); | 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,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.cwd().openDirList(file_path); | 282 | var dir = try fs.cwd().openDirList(file_path); |
| 283 | defer dir.close(); | 283 | defer dir.close(); |
| 284 | 284 | ||
| 285 | var dir_it = dir.iterate(); | 285 | var dir_it = dir.iterate(); |
test/standalone/cat/main.zig+5-3| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const io = std.io; | 2 | const io = std.io; |
| 3 | const process = std.process; | 3 | const process = std.process; |
| 4 | const File = std.fs.File; | 4 | const fs = std.fs; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const warn = std.debug.warn; | 6 | const warn = std.debug.warn; |
| 7 | const allocator = std.debug.global_allocator; | 7 | const allocator = std.debug.global_allocator; |
| ... | @@ -12,6 +12,8 @@ pub fn main() !void { | ... | @@ -12,6 +12,8 @@ pub fn main() !void { |
| 12 | var catted_anything = false; | 12 | var catted_anything = false; |
| 13 | const stdout_file = io.getStdOut(); | 13 | const stdout_file = io.getStdOut(); |
| 14 | 14 | ||
| 15 | const cwd = fs.cwd(); | ||
| 16 | |||
| 15 | while (args_it.next(allocator)) |arg_or_err| { | 17 | while (args_it.next(allocator)) |arg_or_err| { |
| 16 | const arg = try unwrapArg(arg_or_err); | 18 | const arg = try unwrapArg(arg_or_err); |
| 17 | if (mem.eql(u8, arg, "-")) { | 19 | if (mem.eql(u8, arg, "-")) { |
| ... | @@ -20,7 +22,7 @@ pub fn main() !void { | ... | @@ -20,7 +22,7 @@ pub fn main() !void { |
| 20 | } else if (arg[0] == '-') { | 22 | } else if (arg[0] == '-') { |
| 21 | return usage(exe); | 23 | return usage(exe); |
| 22 | } else { | 24 | } else { |
| 23 | const file = File.openRead(arg) catch |err| { | 25 | const file = cwd.openFile(arg, .{}) catch |err| { |
| 24 | warn("Unable to open file: {}\n", @errorName(err)); | 26 | warn("Unable to open file: {}\n", @errorName(err)); |
| 25 | return err; | 27 | return err; |
| 26 | }; | 28 | }; |
| ... | @@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void { | ... | @@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void { |
| 40 | return error.Invalid; | 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 | var buf: [1024 * 4]u8 = undefined; | 46 | var buf: [1024 * 4]u8 = undefined; |
| 45 | 47 | ||
| 46 | while (true) { | 48 | while (true) { |