| ... | ... | @@ -39,11 +39,14 @@ pub const File = @import("file.zig").File; |
| 39 | 39 | pub const time = @import("time.zig"); |
| 40 | 40 | |
| 41 | 41 | pub const page_size = 4 * 1024; |
| 42 | | pub const PATH_MAX = switch (builtin.os) { |
| 43 | | Os.linux => linux.PATH_MAX, |
| 44 | | Os.macosx, Os.ios => darwin.PATH_MAX, |
| 42 | pub const MAX_PATH_BYTES = switch (builtin.os) { |
| 43 | Os.linux, Os.macosx, Os.ios => posix.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 | 49 | else => @compileError("Unsupported OS"), |
| 46 | | // https://msdn.microsoft.com/en-us/library/930f87yf.aspx |
| 47 | 50 | }; |
| 48 | 51 | |
| 49 | 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 | 426 | } |
| 424 | 427 | |
| 425 | 428 | pub const PosixOpenError = error{ |
| 426 | | OutOfMemory, |
| 427 | 429 | AccessDenied, |
| 428 | 430 | FileTooBig, |
| 429 | 431 | IsDir, |
| ... | ... | @@ -444,12 +446,10 @@ pub const PosixOpenError = error{ |
| 444 | 446 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates |
| 445 | 447 | /// the return value into zig errors. |
| 446 | 448 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 { |
| 447 | | var path_with_null: [PATH_MAX]u8 = undefined; |
| 448 | | if (file_path.len > PATH_MAX - 1) |
| 449 | | return error.NameTooLong; |
| 450 | | mem.copy(u8, path_with_null[0..PATH_MAX - 1], file_path); |
| 451 | | path_with_null[file_path.len] = '\x00'; |
| 452 | | |
| 449 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| 450 | if (file_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| 451 | mem.copy(u8, path_with_null[0..], file_path); |
| 452 | path_with_null[file_path.len] = 0; |
| 453 | 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 | 728 | } |
| 729 | 729 | |
| 730 | 730 | /// Caller must free the returned memory. |
| 731 | | pub fn getCwd(allocator: *Allocator) ![]u8 { |
| 732 | | switch (builtin.os) { |
| 733 | | Os.windows => { |
| 734 | | var buf = try allocator.alloc(u8, 256); |
| 735 | | errdefer allocator.free(buf); |
| 736 | | |
| 737 | | while (true) { |
| 738 | | const result = windows.GetCurrentDirectoryA(@intCast(windows.WORD, buf.len), buf.ptr); |
| 731 | pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { |
| 732 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 733 | return mem.dupe(allocator, u8, try getCwd(&buf)); |
| 734 | } |
| 739 | 735 | |
| 740 | | if (result == 0) { |
| 741 | | const err = windows.GetLastError(); |
| 742 | | return switch (err) { |
| 743 | | else => unexpectedErrorWindows(err), |
| 744 | | }; |
| 745 | | } |
| 736 | pub const GetCwdError = error{Unexpected}; |
| 746 | 737 | |
| 747 | | if (result > buf.len) { |
| 748 | | buf = try allocator.realloc(u8, buf, result); |
| 749 | | continue; |
| 738 | /// The result is a slice of out_buffer. |
| 739 | pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 { |
| 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 | 754 | else => { |
| 756 | | var buf = try allocator.alloc(u8, 1024); |
| 757 | | errdefer allocator.free(buf); |
| 758 | | while (true) { |
| 759 | | const err = posix.getErrno(posix.getcwd(buf.ptr, buf.len)); |
| 760 | | if (err == posix.ERANGE) { |
| 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)); |
| 755 | const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len)); |
| 756 | switch (err) { |
| 757 | 0 => return cstr.toSlice(out_buffer), |
| 758 | posix.ERANGE => unreachable, |
| 759 | else => return unexpectedErrorPosix(err), |
| 768 | 760 | } |
| 769 | 761 | }, |
| 770 | 762 | } |
| ... | ... | @@ -899,56 +891,45 @@ pub const DeleteFileError = error{ |
| 899 | 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 | 895 | if (builtin.os == Os.windows) { |
| 904 | | return deleteFileWindows(allocator, file_path); |
| 896 | return deleteFileWindows(file_path); |
| 905 | 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 { |
| 911 | | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 912 | | defer allocator.free(buf); |
| 913 | | |
| 914 | | mem.copy(u8, buf, file_path); |
| 915 | | buf[file_path.len] = 0; |
| 902 | pub fn deleteFileWindows(file_path: []const u8) !void { |
| 903 | @compileError("TODO rewrite with DeleteFileW and no allocator"); |
| 904 | } |
| 916 | 905 | |
| 917 | | if (windows.DeleteFileA(buf.ptr) == 0) { |
| 918 | | const err = windows.GetLastError(); |
| 919 | | return switch (err) { |
| 920 | | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, |
| 921 | | windows.ERROR.ACCESS_DENIED => error.AccessDenied, |
| 922 | | windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong, |
| 923 | | else => unexpectedErrorWindows(err), |
| 924 | | }; |
| 906 | pub fn deleteFilePosixC(file_path: [*]const u8) !void { |
| 907 | const err = posix.getErrno(posix.unlink(file_path)); |
| 908 | switch (err) { |
| 909 | 0 => return, |
| 910 | posix.EACCES => return error.AccessDenied, |
| 911 | posix.EPERM => return error.AccessDenied, |
| 912 | posix.EBUSY => return error.FileBusy, |
| 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 { |
| 929 | | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 930 | | defer allocator.free(buf); |
| 931 | | |
| 932 | | mem.copy(u8, buf, file_path); |
| 933 | | buf[file_path.len] = 0; |
| 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 | | } |
| 927 | pub fn deleteFilePosix(file_path: []const u8) !void { |
| 928 | var path_with_null: [posix.PATH_MAX]u8 = undefined; |
| 929 | if (file_path.len >= posix.PATH_MAX) return error.NameTooLong; |
| 930 | mem.copy(u8, path_with_null[0..], file_path); |
| 931 | path_with_null[file_path.len] = 0; |
| 932 | return deleteFilePosixC(&path_with_null); |
| 952 | 933 | } |
| 953 | 934 | |
| 954 | 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 | 937 | /// there is a possibility of power loss or application termination leaving temporary files present |
| 957 | 938 | /// in the same directory as dest_path. |
| 958 | 939 | /// Destination file will have the same mode as the source file. |
| 940 | /// TODO investigate if this can work with no allocator |
| 959 | 941 | pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []const u8) !void { |
| 960 | 942 | var in_file = try os.File.openRead(source_path); |
| 961 | 943 | defer in_file.close(); |
| ... | ... | @@ -978,6 +960,7 @@ pub fn copyFile(allocator: *Allocator, source_path: []const u8, dest_path: []con |
| 978 | 960 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is |
| 979 | 961 | /// merged and readily available, |
| 980 | 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 | 964 | pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { |
| 982 | 965 | var in_file = try os.File.openRead(source_path); |
| 983 | 966 | defer in_file.close(); |
| ... | ... | @@ -996,6 +979,7 @@ pub fn copyFileMode(allocator: *Allocator, source_path: []const u8, dest_path: [ |
| 996 | 979 | } |
| 997 | 980 | |
| 998 | 981 | pub const AtomicFile = struct { |
| 982 | /// TODO investigate if we can make this work with no allocator |
| 999 | 983 | allocator: *Allocator, |
| 1000 | 984 | file: os.File, |
| 1001 | 985 | tmp_path: []u8, |
| ... | ... | @@ -1023,7 +1007,7 @@ pub const AtomicFile = struct { |
| 1023 | 1007 | try getRandomBytes(rand_buf[0..]); |
| 1024 | 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 | 1011 | error.PathAlreadyExists => continue, |
| 1028 | 1012 | // TODO zig should figure out that this error set does not include PathAlreadyExists since |
| 1029 | 1013 | // it is handled in the above switch |
| ... | ... | @@ -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 { |
| 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 | | |
| 1046 | pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void { |
| 1074 | 1047 | if (is_windows) { |
| 1075 | | const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; |
| 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 | | } |
| 1048 | @compileError("TODO implement for windows"); |
| 1082 | 1049 | } else { |
| 1083 | | const err = posix.getErrno(posix.rename(old_buf.ptr, new_buf.ptr)); |
| 1084 | | if (err > 0) { |
| 1085 | | return switch (err) { |
| 1086 | | posix.EACCES, posix.EPERM => error.AccessDenied, |
| 1087 | | posix.EBUSY => error.FileBusy, |
| 1088 | | posix.EDQUOT => error.DiskQuota, |
| 1089 | | posix.EFAULT, posix.EINVAL => unreachable, |
| 1090 | | posix.EISDIR => error.IsDir, |
| 1091 | | posix.ELOOP => error.SymLinkLoop, |
| 1092 | | posix.EMLINK => error.LinkQuotaExceeded, |
| 1093 | | posix.ENAMETOOLONG => error.NameTooLong, |
| 1094 | | posix.ENOENT => error.FileNotFound, |
| 1095 | | posix.ENOTDIR => error.NotDir, |
| 1096 | | posix.ENOMEM => error.SystemResources, |
| 1097 | | posix.ENOSPC => error.NoSpaceLeft, |
| 1098 | | posix.EEXIST, posix.ENOTEMPTY => error.PathAlreadyExists, |
| 1099 | | posix.EROFS => error.ReadOnlyFileSystem, |
| 1100 | | posix.EXDEV => error.RenameAcrossMountPoints, |
| 1101 | | else => unexpectedErrorPosix(err), |
| 1102 | | }; |
| 1050 | const err = posix.getErrno(posix.rename(old_path, new_path)); |
| 1051 | switch (err) { |
| 1052 | 0 => return, |
| 1053 | posix.EACCES => return error.AccessDenied, |
| 1054 | posix.EPERM => return error.AccessDenied, |
| 1055 | posix.EBUSY => return error.FileBusy, |
| 1056 | posix.EDQUOT => return error.DiskQuota, |
| 1057 | posix.EFAULT => unreachable, |
| 1058 | posix.EINVAL => unreachable, |
| 1059 | posix.EISDIR => return error.IsDir, |
| 1060 | posix.ELOOP => return error.SymLinkLoop, |
| 1061 | posix.EMLINK => return error.LinkQuotaExceeded, |
| 1062 | posix.ENAMETOOLONG => return error.NameTooLong, |
| 1063 | posix.ENOENT => return error.FileNotFound, |
| 1064 | posix.ENOTDIR => return error.NotDir, |
| 1065 | posix.ENOMEM => return error.SystemResources, |
| 1066 | posix.ENOSPC => return error.NoSpaceLeft, |
| 1067 | posix.EEXIST => return error.PathAlreadyExists, |
| 1068 | posix.ENOTEMPTY => return error.PathAlreadyExists, |
| 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 | 1095 | if (is_windows) { |
| 1109 | | return makeDirWindows(allocator, dir_path); |
| 1096 | return makeDirWindows(dir_path); |
| 1110 | 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 | 1113 | } |
| 1127 | 1114 | } |
| 1128 | 1115 | |
| 1129 | | pub fn makeDirPosix(allocator: *Allocator, dir_path: []const u8) !void { |
| 1130 | | const path_buf = try cstr.addNullByte(allocator, dir_path); |
| 1131 | | defer allocator.free(path_buf); |
| 1132 | | |
| 1116 | pub fn makeDirPosixC(dir_path: [*]const u8) !void { |
| 1133 | 1117 | const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755)); |
| 1134 | | if (err > 0) { |
| 1135 | | return switch (err) { |
| 1136 | | posix.EACCES, posix.EPERM => error.AccessDenied, |
| 1137 | | posix.EDQUOT => error.DiskQuota, |
| 1138 | | posix.EEXIST => error.PathAlreadyExists, |
| 1139 | | posix.EFAULT => unreachable, |
| 1140 | | posix.ELOOP => error.SymLinkLoop, |
| 1141 | | posix.EMLINK => error.LinkQuotaExceeded, |
| 1142 | | posix.ENAMETOOLONG => error.NameTooLong, |
| 1143 | | posix.ENOENT => error.FileNotFound, |
| 1144 | | posix.ENOMEM => error.SystemResources, |
| 1145 | | posix.ENOSPC => error.NoSpaceLeft, |
| 1146 | | posix.ENOTDIR => error.NotDir, |
| 1147 | | posix.EROFS => error.ReadOnlyFileSystem, |
| 1148 | | else => unexpectedErrorPosix(err), |
| 1149 | | }; |
| 1118 | switch (err) { |
| 1119 | 0 => return, |
| 1120 | posix.EACCES => return error.AccessDenied, |
| 1121 | posix.EPERM => return error.AccessDenied, |
| 1122 | posix.EDQUOT => return error.DiskQuota, |
| 1123 | posix.EEXIST => return error.PathAlreadyExists, |
| 1124 | posix.EFAULT => unreachable, |
| 1125 | posix.ELOOP => return error.SymLinkLoop, |
| 1126 | posix.EMLINK => return error.LinkQuotaExceeded, |
| 1127 | posix.ENAMETOOLONG => return error.NameTooLong, |
| 1128 | posix.ENOENT => return error.FileNotFound, |
| 1129 | posix.ENOMEM => return error.SystemResources, |
| 1130 | posix.ENOSPC => return error.NoSpaceLeft, |
| 1131 | posix.ENOTDIR => return error.NotDir, |
| 1132 | posix.EROFS => return error.ReadOnlyFileSystem, |
| 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 | 1145 | /// Calls makeDir recursively to make an entire path. Returns success if the path |
| 1154 | 1146 | /// already exists and is a directory. |
| 1155 | 1147 | pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { |
| ... | ... | @@ -1409,6 +1401,7 @@ pub const Dir = struct { |
| 1409 | 1401 | }, |
| 1410 | 1402 | Os.macosx, Os.ios => Handle{ |
| 1411 | 1403 | .fd = try posixOpen( |
| 1404 | allocator, |
| 1412 | 1405 | dir_path, |
| 1413 | 1406 | posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, |
| 1414 | 1407 | 0, |
| ... | ... | @@ -1420,6 +1413,7 @@ pub const Dir = struct { |
| 1420 | 1413 | }, |
| 1421 | 1414 | Os.linux => Handle{ |
| 1422 | 1415 | .fd = try posixOpen( |
| 1416 | allocator, |
| 1423 | 1417 | dir_path, |
| 1424 | 1418 | posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, |
| 1425 | 1419 | 0, |
| ... | ... | @@ -1616,39 +1610,35 @@ pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void { |
| 1616 | 1610 | } |
| 1617 | 1611 | |
| 1618 | 1612 | /// Read value of a symbolic link. |
| 1619 | | pub fn readLink(allocator: *Allocator, file_path: []const u8) ![]u8 { |
| 1620 | | var path_with_null: [PATH_MAX]u8 = undefined; |
| 1621 | | if (file_path.len > PATH_MAX - 1) |
| 1622 | | return error.NameTooLong; |
| 1623 | | mem.copy(u8, path_with_null[0..PATH_MAX - 1], file_path); |
| 1624 | | path_with_null[file_path.len] = '\x00'; |
| 1625 | | |
| 1626 | | var result_buf = try allocator.alloc(u8, 1024); |
| 1627 | | errdefer allocator.free(result_buf); |
| 1628 | | while (true) { |
| 1629 | | const ret_val = posix.readlink(&path_with_null, result_buf.ptr, result_buf.len); |
| 1630 | | const err = posix.getErrno(ret_val); |
| 1631 | | if (err > 0) { |
| 1632 | | return switch (err) { |
| 1633 | | posix.EACCES => error.AccessDenied, |
| 1634 | | posix.EFAULT, posix.EINVAL => unreachable, |
| 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); |
| 1613 | /// The return value is a slice of out_buffer. |
| 1614 | pub fn readLinkC(pathname: [*]const u8, out_buffer: *[posix.PATH_MAX]u8) ![]u8 { |
| 1615 | const rc = posix.readlink(pathname, out_buffer, out_buffer.len); |
| 1616 | const err = posix.getErrno(rc); |
| 1617 | switch (err) { |
| 1618 | 0 => return out_buffer[0..rc], |
| 1619 | posix.EACCES => error.AccessDenied, |
| 1620 | posix.EFAULT => unreachable, |
| 1621 | posix.EINVAL => unreachable, |
| 1622 | posix.EIO => return error.FileSystem, |
| 1623 | posix.ELOOP => return error.SymLinkLoop, |
| 1624 | posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX |
| 1625 | posix.ENOENT => return error.FileNotFound, |
| 1626 | posix.ENOMEM => return error.SystemResources, |
| 1627 | posix.ENOTDIR => return error.NotDir, |
| 1628 | else => return unexpectedErrorPosix(err), |
| 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 | 1642 | pub fn posix_setuid(uid: u32) !void { |
| 1653 | 1643 | const err = posix.getErrno(posix.setuid(uid)); |
| 1654 | 1644 | if (err == 0) return; |
| ... | ... | @@ -2035,13 +2025,13 @@ pub fn openSelfExe() !os.File { |
| 2035 | 2025 | const proc_file_path = "/proc/self/exe"; |
| 2036 | 2026 | var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined; |
| 2037 | 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 | 2030 | Os.macosx, Os.ios => { |
| 2041 | 2031 | var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined; |
| 2042 | 2032 | var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 2043 | 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 | 2036 | else => @compileError("Unsupported OS"), |
| 2047 | 2037 | } |