| ... | @@ -39,11 +39,14 @@ pub const File = @import("file.zig").File; | ... | @@ -39,11 +39,14 @@ pub const File = @import("file.zig").File; |
| 39 | pub const time = @import("time.zig"); | 39 | pub const time = @import("time.zig"); |
| 40 | | 40 | |
| 41 | pub const page_size = 4 * 1024; | 41 | pub const page_size = 4 * 1024; |
| 42 | pub const PATH_MAX = switch (builtin.os) { | 42 | pub const MAX_PATH_BYTES = switch (builtin.os) { |
| 43 | Os.linux => linux.PATH_MAX, | 43 | Os.linux, Os.macosx, Os.ios => posix.PATH_MAX, |
| 44 | Os.macosx, Os.ios => darwin.PATH_MAX, | 44 | // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. |
| | 45 | // If it would require 4 UTF-8 bytes, then there would be a surrogate |
| | 46 | // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. |
| | 47 | // +1 for the null byte at the end, which can be encoded in 1 byte. |
| | 48 | Os.windows => 32767 * 3 + 1, |
| 45 | else => @compileError("Unsupported OS"), | 49 | else => @compileError("Unsupported OS"), |
| 46 | // https://msdn.microsoft.com/en-us/library/930f87yf.aspx | | |
| 47 | }; | 50 | }; |
| 48 | | 51 | |
| 49 | pub const UserInfo = @import("get_user_id.zig").UserInfo; | 52 | pub const UserInfo = @import("get_user_id.zig").UserInfo; |
| ... | @@ -423,7 +426,6 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off | ... | @@ -423,7 +426,6 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off |
| 423 | } | 426 | } |
| 424 | | 427 | |
| 425 | pub const PosixOpenError = error{ | 428 | pub const PosixOpenError = error{ |
| 426 | OutOfMemory, | | |
| 427 | AccessDenied, | 429 | AccessDenied, |
| 428 | FileTooBig, | 430 | FileTooBig, |
| 429 | IsDir, | 431 | IsDir, |
| ... | @@ -444,12 +446,10 @@ pub const PosixOpenError = error{ | ... | @@ -444,12 +446,10 @@ pub const PosixOpenError = error{ |
| 444 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates | 446 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates |
| 445 | /// the return value into zig errors. | 447 | /// the return value into zig errors. |
| 446 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 { | 448 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 { |
| 447 | var path_with_null: [PATH_MAX]u8 = undefined; | 449 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| 448 | if (file_path.len > PATH_MAX - 1) | 450 | if (file_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| 449 | return error.NameTooLong; | 451 | mem.copy(u8, path_with_null[0..], file_path); |
| 450 | mem.copy(u8, path_with_null[0..PATH_MAX - 1], file_path); | 452 | path_with_null[file_path.len] = 0; |
| 451 | path_with_null[file_path.len] = '\x00'; | | |
| 452 | | | |
| 453 | return posixOpenC(&path_with_null, flags, perm); | 453 | return posixOpenC(&path_with_null, flags, perm); |
| 454 | } | 454 | } |
| 455 | | 455 | |
| ... | @@ -728,43 +728,35 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned | ... | @@ -728,43 +728,35 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 728 | } | 728 | } |
| 729 | | 729 | |
| 730 | /// Caller must free the returned memory. | 730 | /// Caller must free the returned memory. |
| 731 | pub fn getCwd(allocator: *Allocator) ![]u8 { | 731 | pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { |
| 732 | switch (builtin.os) { | 732 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 733 | Os.windows => { | 733 | return mem.dupe(allocator, u8, try getCwd(&buf)); |
| 734 | var buf = try allocator.alloc(u8, 256); | 734 | } |
| 735 | errdefer allocator.free(buf); | | |
| 736 | | | |
| 737 | while (true) { | | |
| 738 | const result = windows.GetCurrentDirectoryA(@intCast(windows.WORD, buf.len), buf.ptr); | | |
| 739 | | 735 | |
| 740 | if (result == 0) { | 736 | pub const GetCwdError = error{Unexpected}; |
| 741 | const err = windows.GetLastError(); | | |
| 742 | return switch (err) { | | |
| 743 | else => unexpectedErrorWindows(err), | | |
| 744 | }; | | |
| 745 | } | | |
| 746 | | 737 | |
| 747 | if (result > buf.len) { | 738 | /// The result is a slice of out_buffer. |
| 748 | buf = try allocator.realloc(u8, buf, result); | 739 | pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 { |
| 749 | continue; | 740 | switch (builtin.os) { |
| | 741 | Os.windows => { |
| | 742 | var utf16le_buf: [windows_util.PATH_MAX_UTF16]u16 = undefined; |
| | 743 | const result = windows.GetCurrentDirectoryW(utf16le_buf.len, &utf16le_buf); |
| | 744 | if (result == 0) { |
| | 745 | const err = windows.GetLastError(); |
| | 746 | switch (err) { |
| | 747 | else => return unexpectedErrorWindows(err), |
| 750 | } | 748 | } |
| 751 | | | |
| 752 | return allocator.shrink(u8, buf, result); | | |
| 753 | } | 749 | } |
| | 750 | assert(result <= buf.len); |
| | 751 | const utf16le_slice = utf16le_buf[0..result]; |
| | 752 | return std.unicode.utf16leToUtf8(out_buffer, utf16le_buf); |
| 754 | }, | 753 | }, |
| 755 | else => { | 754 | else => { |
| 756 | var buf = try allocator.alloc(u8, 1024); | 755 | const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len)); |
| 757 | errdefer allocator.free(buf); | 756 | switch (err) { |
| 758 | while (true) { | 757 | 0 => return cstr.toSlice(out_buffer), |
| 759 | const err = posix.getErrno(posix.getcwd(buf.ptr, buf.len)); | 758 | posix.ERANGE => unreachable, |
| 760 | if (err == posix.ERANGE) { | 759 | else => return unexpectedErrorPosix(err), |
| 761 | buf = try allocator.realloc(u8, buf, buf.len * 2); | | |
| 762 | continue; | | |
| 763 | } else if (err > 0) { | | |
| 764 | return unexpectedErrorPosix(err); | | |
| 765 | } | | |
| 766 | | | |
| 767 | return allocator.shrink(u8, buf, cstr.len(buf.ptr)); | | |
| 768 | } | 760 | } |
| 769 | }, | 761 | }, |
| 770 | } | 762 | } |
| ... | @@ -899,56 +891,45 @@ pub const DeleteFileError = error{ | ... | @@ -899,56 +891,45 @@ pub const DeleteFileError = error{ |
| 899 | Unexpected, | 891 | Unexpected, |
| 900 | }; | 892 | }; |
| 901 | | 893 | |
| 902 | pub fn deleteFile(allocator: *Allocator, file_path: []const u8) DeleteFileError!void { | 894 | pub fn deleteFile(file_path: []const u8) DeleteFileError!void { |
| 903 | if (builtin.os == Os.windows) { | 895 | if (builtin.os == Os.windows) { |
| 904 | return deleteFileWindows(allocator, file_path); | 896 | return deleteFileWindows(file_path); |
| 905 | } else { | 897 | } else { |
| 906 | return deleteFilePosix(allocator, file_path); | 898 | return deleteFilePosix(file_path); |
| 907 | } | 899 | } |
| 908 | } | 900 | } |
| 909 | | 901 | |
| 910 | pub fn deleteFileWindows(allocator: *Allocator, file_path: []const u8) !void { | 902 | pub fn deleteFileWindows(file_path: []const u8) !void { |
| 911 | const buf = try allocator.alloc(u8, file_path.len + 1); | 903 | @compileError("TODO rewrite with DeleteFileW and no allocator"); |
| 912 | defer allocator.free(buf); | 904 | } |
| 913 | | | |
| 914 | mem.copy(u8, buf, file_path); | | |
| 915 | buf[file_path.len] = 0; | | |
| 916 | | 905 | |
| 917 | if (windows.DeleteFileA(buf.ptr) == 0) { | 906 | pub fn deleteFilePosixC(file_path: [*]const u8) !void { |
| 918 | const err = windows.GetLastError(); | 907 | const err = posix.getErrno(posix.unlink(file_path)); |
| 919 | return switch (err) { | 908 | switch (err) { |
| 920 | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, | 909 | 0 => return, |
| 921 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, | 910 | posix.EACCES => return error.AccessDenied, |
| 922 | windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong, | 911 | posix.EPERM => return error.AccessDenied, |
| 923 | else => unexpectedErrorWindows(err), | 912 | posix.EBUSY => return error.FileBusy, |
| 924 | }; | 913 | posix.EFAULT => unreachable, |
| | 914 | posix.EINVAL => unreachable, |
| | 915 | posix.EIO => return error.FileSystem, |
| | 916 | posix.EISDIR => return error.IsDir, |
| | 917 | posix.ELOOP => return error.SymLinkLoop, |
| | 918 | posix.ENAMETOOLONG => return error.NameTooLong, |
| | 919 | posix.ENOENT => return error.FileNotFound, |
| | 920 | posix.ENOTDIR => return error.NotDir, |
| | 921 | posix.ENOMEM => return error.SystemResources, |
| | 922 | posix.EROFS => return error.ReadOnlyFileSystem, |
| | 923 | else => return unexpectedErrorPosix(err), |
| 925 | } | 924 | } |
| 926 | } | 925 | } |
| 927 | | 926 | |
| 928 | pub fn deleteFilePosix(allocator: *Allocator, file_path: []const u8) !void { | 927 | pub fn deleteFilePosix(file_path: []const u8) !void { |
| 929 | const buf = try allocator.alloc(u8, file_path.len + 1); | 928 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| 930 | defer allocator.free(buf); | 929 | if (file_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| 931 | | 930 | mem.copy(u8, path_with_null[0..], file_path); |
| 932 | mem.copy(u8, buf, file_path); | 931 | path_with_null[file_path.len] = 0; |
| 933 | buf[file_path.len] = 0; | 932 | return deleteFilePosixC(&path_with_null); |
| 934 | | | |
| 935 | const err = posix.getErrno(posix.unlink(buf.ptr)); | | |
| 936 | if (err > 0) { | | |
| 937 | return switch (err) { | | |
| 938 | posix.EACCES, posix.EPERM => error.AccessDenied, | | |
| 939 | posix.EBUSY => error.FileBusy, | | |
| 940 | posix.EFAULT, posix.EINVAL => unreachable, | | |
| 941 | posix.EIO => error.FileSystem, | | |
| 942 | posix.EISDIR => error.IsDir, | | |
| 943 | posix.ELOOP => error.SymLinkLoop, | | |
| 944 | posix.ENAMETOOLONG => error.NameTooLong, | | |
| 945 | posix.ENOENT => error.FileNotFound, | | |
| 946 | posix.ENOTDIR => error.NotDir, | | |
| 947 | posix.ENOMEM => error.SystemResources, | | |
| 948 | posix.EROFS => error.ReadOnlyFileSystem, | | |
| 949 | else => unexpectedErrorPosix(err), | | |
| 950 | }; | | |
| 951 | } | | |
| 952 | } | 933 | } |
| 953 | | 934 | |
| 954 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is | 935 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is |
| ... | @@ -956,6 +937,7 @@ pub fn deleteFilePosix(allocator: *Allocator, file_path: []const u8) !void { | ... | @@ -956,6 +937,7 @@ pub fn deleteFilePosix(allocator: *Allocator, file_path: []const u8) !void { |
| 956 | /// there is a possibility of power loss or application termination leaving temporary files present | 937 | /// there is a possibility of power loss or application termination leaving temporary files present |
| 957 | /// in the same directory as dest_path. | 938 | /// in the same directory as dest_path. |
| 958 | /// Destination file will have the same mode as the source file. | 939 | /// Destination file will have the same mode as the source file. |
| | 940 | /// TODO investigate if this can work with no allocator |
| 959 | pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []const u8) !void { | 941 | pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []const u8) !void { |
| 960 | var in_file = try os.File.openRead(source_path); | 942 | var in_file = try os.File.openRead(source_path); |
| 961 | defer in_file.close(); | 943 | defer in_file.close(); |
| ... | @@ -978,6 +960,7 @@ pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []con | ... | @@ -978,6 +960,7 @@ pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []con |
| 978 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is | 960 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is |
| 979 | /// merged and readily available, | 961 | /// merged and readily available, |
| 980 | /// there is a possibility of power loss or application termination leaving temporary files present | 962 | /// there is a possibility of power loss or application termination leaving temporary files present |
| | 963 | /// TODO investigate if this can work with no allocator |
| 981 | pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { | 964 | pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { |
| 982 | var in_file = try os.File.openRead(source_path); | 965 | var in_file = try os.File.openRead(source_path); |
| 983 | defer in_file.close(); | 966 | defer in_file.close(); |
| ... | @@ -996,6 +979,7 @@ pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: [ | ... | @@ -996,6 +979,7 @@ pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: [ |
| 996 | } | 979 | } |
| 997 | | 980 | |
| 998 | pub const AtomicFile = struct { | 981 | pub const AtomicFile = struct { |
| | 982 | /// TODO investigate if we can make this work with no allocator |
| 999 | allocator: *Allocator, | 983 | allocator: *Allocator, |
| 1000 | file: os.File, | 984 | file: os.File, |
| 1001 | tmp_path: []u8, | 985 | tmp_path: []u8, |
| ... | @@ -1023,7 +1007,7 @@ pub const AtomicFile = struct { | ... | @@ -1023,7 +1007,7 @@ pub const AtomicFile = struct { |
| 1023 | try getRandomBytes(rand_buf[0..]); | 1007 | try getRandomBytes(rand_buf[0..]); |
| 1024 | b64_fs_encoder.encode(tmp_path[dirname_component_len..], rand_buf); | 1008 | b64_fs_encoder.encode(tmp_path[dirname_component_len..], rand_buf); |
| 1025 | | 1009 | |
| 1026 | const file = os.File.openWriteNoClobber(allocator, tmp_path, mode) catch |err| switch (err) { | 1010 | const file = os.File.openWriteNoClobber(tmp_path, mode) catch |err| switch (err) { |
| 1027 | error.PathAlreadyExists => continue, | 1011 | error.PathAlreadyExists => continue, |
| 1028 | // TODO zig should figure out that this error set does not include PathAlreadyExists since | 1012 | // TODO zig should figure out that this error set does not include PathAlreadyExists since |
| 1029 | // it is handled in the above switch | 1013 | // it is handled in the above switch |
| ... | @@ -1059,56 +1043,59 @@ pub const AtomicFile = struct { | ... | @@ -1059,56 +1043,59 @@ pub const AtomicFile = struct { |
| 1059 | } | 1043 | } |
| 1060 | }; | 1044 | }; |
| 1061 | | 1045 | |
| 1062 | pub fn rename(allocator: *Allocator, old_path: []const u8, new_path: []const u8) !void { | 1046 | pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void { |
| 1063 | const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2); | | |
| 1064 | defer allocator.free(full_buf); | | |
| 1065 | | | |
| 1066 | const old_buf = full_buf; | | |
| 1067 | mem.copy(u8, old_buf, old_path); | | |
| 1068 | old_buf[old_path.len] = 0; | | |
| 1069 | | | |
| 1070 | const new_buf = full_buf[old_path.len + 1 ..]; | | |
| 1071 | mem.copy(u8, new_buf, new_path); | | |
| 1072 | new_buf[new_path.len] = 0; | | |
| 1073 | | | |
| 1074 | if (is_windows) { | 1047 | if (is_windows) { |
| 1075 | const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; | 1048 | @compileError("TODO implement for windows"); |
| 1076 | if (windows.MoveFileExA(old_buf.ptr, new_buf.ptr, flags) == 0) { | | |
| 1077 | const err = windows.GetLastError(); | | |
| 1078 | return switch (err) { | | |
| 1079 | else => unexpectedErrorWindows(err), | | |
| 1080 | }; | | |
| 1081 | } | | |
| 1082 | } else { | 1049 | } else { |
| 1083 | const err = posix.getErrno(posix.rename(old_buf.ptr, new_buf.ptr)); | 1050 | const err = posix.getErrno(posix.rename(old_path, new_path)); |
| 1084 | if (err > 0) { | 1051 | switch (err) { |
| 1085 | return switch (err) { | 1052 | 0 => return, |
| 1086 | posix.EACCES, posix.EPERM => error.AccessDenied, | 1053 | posix.EACCES => return error.AccessDenied, |
| 1087 | posix.EBUSY => error.FileBusy, | 1054 | posix.EPERM => return error.AccessDenied, |
| 1088 | posix.EDQUOT => error.DiskQuota, | 1055 | posix.EBUSY => return error.FileBusy, |
| 1089 | posix.EFAULT, posix.EINVAL => unreachable, | 1056 | posix.EDQUOT => return error.DiskQuota, |
| 1090 | posix.EISDIR => error.IsDir, | 1057 | posix.EFAULT => unreachable, |
| 1091 | posix.ELOOP => error.SymLinkLoop, | 1058 | posix.EINVAL => unreachable, |
| 1092 | posix.EMLINK => error.LinkQuotaExceeded, | 1059 | posix.EISDIR => return error.IsDir, |
| 1093 | posix.ENAMETOOLONG => error.NameTooLong, | 1060 | posix.ELOOP => return error.SymLinkLoop, |
| 1094 | posix.ENOENT => error.FileNotFound, | 1061 | posix.EMLINK => return error.LinkQuotaExceeded, |
| 1095 | posix.ENOTDIR => error.NotDir, | 1062 | posix.ENAMETOOLONG => return error.NameTooLong, |
| 1096 | posix.ENOMEM => error.SystemResources, | 1063 | posix.ENOENT => return error.FileNotFound, |
| 1097 | posix.ENOSPC => error.NoSpaceLeft, | 1064 | posix.ENOTDIR => return error.NotDir, |
| 1098 | posix.EEXIST, posix.ENOTEMPTY => error.PathAlreadyExists, | 1065 | posix.ENOMEM => return error.SystemResources, |
| 1099 | posix.EROFS => error.ReadOnlyFileSystem, | 1066 | posix.ENOSPC => return error.NoSpaceLeft, |
| 1100 | posix.EXDEV => error.RenameAcrossMountPoints, | 1067 | posix.EEXIST => return error.PathAlreadyExists, |
| 1101 | else => unexpectedErrorPosix(err), | 1068 | posix.ENOTEMPTY => return error.PathAlreadyExists, |
| 1102 | }; | 1069 | posix.EROFS => return error.ReadOnlyFileSystem, |
| | 1070 | posix.EXDEV => return error.RenameAcrossMountPoints, |
| | 1071 | else => return unexpectedErrorPosix(err), |
| 1103 | } | 1072 | } |
| 1104 | } | 1073 | } |
| 1105 | } | 1074 | } |
| 1106 | | 1075 | |
| 1107 | pub fn makeDir(allocator: *Allocator, dir_path: []const u8) !void { | 1076 | pub fn rename(old_path: []const u8, new_path: []const u8) !void { |
| | 1077 | if (is_windows) { |
| | 1078 | @compileError("TODO rewrite with MoveFileExW and no allocator"); |
| | 1079 | } else { |
| | 1080 | var old_path_with_null: [posix.PATH_MAX]u8 = undefined; |
| | 1081 | if (old_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| | 1082 | mem.copy(u8, old_path_with_null[0..], old_path); |
| | 1083 | old_path_with_null[old_path.len] = 0; |
| | 1084 | |
| | 1085 | var new_path_with_null: [posix.PATH_MAX]u8 = undefined; |
| | 1086 | if (new_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| | 1087 | mem.copy(u8, new_path_with_null[0..], new_path); |
| | 1088 | new_path_with_null[new_path.len] = 0; |
| | 1089 | |
| | 1090 | return renameC(&old_path_with_null, &new_path_with_null); |
| | 1091 | } |
| | 1092 | } |
| | 1093 | |
| | 1094 | pub fn makeDir(dir_path: []const u8) !void { |
| 1108 | if (is_windows) { | 1095 | if (is_windows) { |
| 1109 | return makeDirWindows(allocator, dir_path); | 1096 | return makeDirWindows(dir_path); |
| 1110 | } else { | 1097 | } else { |
| 1111 | return makeDirPosix(allocator, dir_path); | 1098 | return makeDirPosix(dir_path); |
| 1112 | } | 1099 | } |
| 1113 | } | 1100 | } |
| 1114 | | 1101 | |
| ... | @@ -1126,30 +1113,35 @@ pub fn makeDirWindows(allocator: *Allocator, dir_path: []const u8) !void { | ... | @@ -1126,30 +1113,35 @@ pub fn makeDirWindows(allocator: *Allocator, dir_path: []const u8) !void { |
| 1126 | } | 1113 | } |
| 1127 | } | 1114 | } |
| 1128 | | 1115 | |
| 1129 | pub fn makeDirPosix(allocator: *Allocator, dir_path: []const u8) !void { | 1116 | pub fn makeDirPosixC(dir_path: [*]const u8) !void { |
| 1130 | const path_buf = try cstr.addNullByte(allocator, dir_path); | | |
| 1131 | defer allocator.free(path_buf); | | |
| 1132 | | | |
| 1133 | const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755)); | 1117 | const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755)); |
| 1134 | if (err > 0) { | 1118 | switch (err) { |
| 1135 | return switch (err) { | 1119 | 0 => return, |
| 1136 | posix.EACCES, posix.EPERM => error.AccessDenied, | 1120 | posix.EACCES => return error.AccessDenied, |
| 1137 | posix.EDQUOT => error.DiskQuota, | 1121 | posix.EPERM => return error.AccessDenied, |
| 1138 | posix.EEXIST => error.PathAlreadyExists, | 1122 | posix.EDQUOT => return error.DiskQuota, |
| 1139 | posix.EFAULT => unreachable, | 1123 | posix.EEXIST => return error.PathAlreadyExists, |
| 1140 | posix.ELOOP => error.SymLinkLoop, | 1124 | posix.EFAULT => unreachable, |
| 1141 | posix.EMLINK => error.LinkQuotaExceeded, | 1125 | posix.ELOOP => return error.SymLinkLoop, |
| 1142 | posix.ENAMETOOLONG => error.NameTooLong, | 1126 | posix.EMLINK => return error.LinkQuotaExceeded, |
| 1143 | posix.ENOENT => error.FileNotFound, | 1127 | posix.ENAMETOOLONG => return error.NameTooLong, |
| 1144 | posix.ENOMEM => error.SystemResources, | 1128 | posix.ENOENT => return error.FileNotFound, |
| 1145 | posix.ENOSPC => error.NoSpaceLeft, | 1129 | posix.ENOMEM => return error.SystemResources, |
| 1146 | posix.ENOTDIR => error.NotDir, | 1130 | posix.ENOSPC => return error.NoSpaceLeft, |
| 1147 | posix.EROFS => error.ReadOnlyFileSystem, | 1131 | posix.ENOTDIR => return error.NotDir, |
| 1148 | else => unexpectedErrorPosix(err), | 1132 | posix.EROFS => return error.ReadOnlyFileSystem, |
| 1149 | }; | 1133 | else => return unexpectedErrorPosix(err), |
| 1150 | } | 1134 | } |
| 1151 | } | 1135 | } |
| 1152 | | 1136 | |
| | 1137 | pub fn makeDirPosix(dir_path: []const u8) !void { |
| | 1138 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| | 1139 | if (dir_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| | 1140 | mem.copy(u8, path_with_null[0..], dir_path); |
| | 1141 | path_with_null[dir_path.len] = 0; |
| | 1142 | return makeDirPosixC(&path_with_null); |
| | 1143 | } |
| | 1144 | |
| 1153 | /// Calls makeDir recursively to make an entire path. Returns success if the path | 1145 | /// Calls makeDir recursively to make an entire path. Returns success if the path |
| 1154 | /// already exists and is a directory. | 1146 | /// already exists and is a directory. |
| 1155 | pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { | 1147 | pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { |
| ... | @@ -1409,6 +1401,7 @@ pub const Dir = struct { | ... | @@ -1409,6 +1401,7 @@ pub const Dir = struct { |
| 1409 | }, | 1401 | }, |
| 1410 | Os.macosx, Os.ios => Handle{ | 1402 | Os.macosx, Os.ios => Handle{ |
| 1411 | .fd = try posixOpen( | 1403 | .fd = try posixOpen( |
| | 1404 | allocator, |
| 1412 | dir_path, | 1405 | dir_path, |
| 1413 | posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, | 1406 | posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, |
| 1414 | 0, | 1407 | 0, |
| ... | @@ -1420,6 +1413,7 @@ pub const Dir = struct { | ... | @@ -1420,6 +1413,7 @@ pub const Dir = struct { |
| 1420 | }, | 1413 | }, |
| 1421 | Os.linux => Handle{ | 1414 | Os.linux => Handle{ |
| 1422 | .fd = try posixOpen( | 1415 | .fd = try posixOpen( |
| | 1416 | allocator, |
| 1423 | dir_path, | 1417 | dir_path, |
| 1424 | posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, | 1418 | posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, |
| 1425 | 0, | 1419 | 0, |
| ... | @@ -1616,39 +1610,35 @@ pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void { | ... | @@ -1616,39 +1610,35 @@ pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void { |
| 1616 | } | 1610 | } |
| 1617 | | 1611 | |
| 1618 | /// Read value of a symbolic link. | 1612 | /// Read value of a symbolic link. |
| 1619 | pub fn readLink(allocator: *Allocator, file_path: []const u8) ![]u8 { | 1613 | /// The return value is a slice of out_buffer. |
| 1620 | var path_with_null: [PATH_MAX]u8 = undefined; | 1614 | pub fn readLinkC(pathname: [*]const u8, out_buffer: *[posix.PATH_MAX]u8) ![]u8 { |
| 1621 | if (file_path.len > PATH_MAX - 1) | 1615 | const rc = posix.readlink(pathname, out_buffer, out_buffer.len); |
| 1622 | return error.NameTooLong; | 1616 | const err = posix.getErrno(rc); |
| 1623 | mem.copy(u8, path_with_null[0..PATH_MAX - 1], file_path); | 1617 | switch (err) { |
| 1624 | path_with_null[file_path.len] = '\x00'; | 1618 | 0 => return out_buffer[0..rc], |
| 1625 | | 1619 | posix.EACCES => error.AccessDenied, |
| 1626 | var result_buf = try allocator.alloc(u8, 1024); | 1620 | posix.EFAULT => unreachable, |
| 1627 | errdefer allocator.free(result_buf); | 1621 | posix.EINVAL => unreachable, |
| 1628 | while (true) { | 1622 | posix.EIO => return error.FileSystem, |
| 1629 | const ret_val = posix.readlink(&path_with_null, result_buf.ptr, result_buf.len); | 1623 | posix.ELOOP => return error.SymLinkLoop, |
| 1630 | const err = posix.getErrno(ret_val); | 1624 | posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX |
| 1631 | if (err > 0) { | 1625 | posix.ENOENT => return error.FileNotFound, |
| 1632 | return switch (err) { | 1626 | posix.ENOMEM => return error.SystemResources, |
| 1633 | posix.EACCES => error.AccessDenied, | 1627 | posix.ENOTDIR => return error.NotDir, |
| 1634 | posix.EFAULT, posix.EINVAL => unreachable, | 1628 | else => return unexpectedErrorPosix(err), |
| 1635 | posix.EIO => error.FileSystem, | | |
| 1636 | posix.ELOOP => error.SymLinkLoop, | | |
| 1637 | posix.ENAMETOOLONG => error.NameTooLong, | | |
| 1638 | posix.ENOENT => error.FileNotFound, | | |
| 1639 | posix.ENOMEM => error.SystemResources, | | |
| 1640 | posix.ENOTDIR => error.NotDir, | | |
| 1641 | else => unexpectedErrorPosix(err), | | |
| 1642 | }; | | |
| 1643 | } | | |
| 1644 | if (ret_val == result_buf.len) { | | |
| 1645 | result_buf = try allocator.realloc(u8, result_buf, result_buf.len * 2); | | |
| 1646 | continue; | | |
| 1647 | } | | |
| 1648 | return allocator.shrink(u8, result_buf, ret_val); | | |
| 1649 | } | 1629 | } |
| 1650 | } | 1630 | } |
| 1651 | | 1631 | |
| | 1632 | /// Read value of a symbolic link. |
| | 1633 | /// The return value is a slice of out_buffer. |
| | 1634 | pub fn readLink(file_path: []const u8, out_buffer: *[posix.PATH_MAX]u8) ![]u8 { |
| | 1635 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| | 1636 | if (file_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| | 1637 | mem.copy(u8, path_with_null[0..], file_path); |
| | 1638 | path_with_null[file_path.len] = 0; |
| | 1639 | return readLinkC(&path_with_null, out_buffer); |
| | 1640 | } |
| | 1641 | |
| 1652 | pub fn posix_setuid(uid: u32) !void { | 1642 | pub fn posix_setuid(uid: u32) !void { |
| 1653 | const err = posix.getErrno(posix.setuid(uid)); | 1643 | const err = posix.getErrno(posix.setuid(uid)); |
| 1654 | if (err == 0) return; | 1644 | if (err == 0) return; |
| ... | @@ -2035,13 +2025,13 @@ pub fn openSelfExe() !os.File { | ... | @@ -2035,13 +2025,13 @@ pub fn openSelfExe() !os.File { |
| 2035 | const proc_file_path = "/proc/self/exe"; | 2025 | const proc_file_path = "/proc/self/exe"; |
| 2036 | var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined; | 2026 | var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined; |
| 2037 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 2027 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 2038 | return os.File.openRead(proc_file_path); | 2028 | return os.File.openRead(&fixed_allocator.allocator, proc_file_path); |
| 2039 | }, | 2029 | }, |
| 2040 | Os.macosx, Os.ios => { | 2030 | Os.macosx, Os.ios => { |
| 2041 | var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined; | 2031 | var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined; |
| 2042 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 2032 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 2043 | const self_exe_path = try selfExePath(&fixed_allocator.allocator); | 2033 | const self_exe_path = try selfExePath(&fixed_allocator.allocator); |
| 2044 | return os.File.openRead(self_exe_path); | 2034 | return os.File.openRead(&fixed_allocator.allocator, self_exe_path); |
| 2045 | }, | 2035 | }, |
| 2046 | else => @compileError("Unsupported OS"), | 2036 | else => @compileError("Unsupported OS"), |
| 2047 | } | 2037 | } |