| ... | ... | @@ -1055,10 +1055,11 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1055 | 1055 | return; |
| 1056 | 1056 | } else |err| switch (err) { |
| 1057 | 1057 | error.FileNotFound => return, |
| 1058 | |
| 1059 | error.AccessDenied, |
| 1058 | 1060 | error.IsDir => {}, |
| 1059 | 1061 | |
| 1060 | 1062 | error.OutOfMemory, |
| 1061 | | error.AccessDenied, |
| 1062 | 1063 | error.SymLinkLoop, |
| 1063 | 1064 | error.NameTooLong, |
| 1064 | 1065 | error.SystemResources, |
| ... | ... | @@ -1109,18 +1110,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError! |
| 1109 | 1110 | } |
| 1110 | 1111 | |
| 1111 | 1112 | pub const Dir = struct { |
| 1112 | | // See man getdents |
| 1113 | 1113 | fd: i32, |
| 1114 | darwin_seek: darwin_seek_t, |
| 1114 | 1115 | allocator: &Allocator, |
| 1115 | 1116 | buf: []u8, |
| 1116 | 1117 | index: usize, |
| 1117 | 1118 | end_index: usize, |
| 1118 | 1119 | |
| 1119 | | const LinuxEntry = extern struct { |
| 1120 | | d_ino: usize, |
| 1121 | | d_off: usize, |
| 1122 | | d_reclen: u16, |
| 1123 | | d_name: u8, // field address is the address of first byte of name |
| 1120 | const darwin_seek_t = switch (builtin.os) { |
| 1121 | Os.macosx, Os.ios => i64, |
| 1122 | else => void, |
| 1124 | 1123 | }; |
| 1125 | 1124 | |
| 1126 | 1125 | pub const Entry = struct { |
| ... | ... | @@ -1135,15 +1134,26 @@ pub const Dir = struct { |
| 1135 | 1134 | SymLink, |
| 1136 | 1135 | File, |
| 1137 | 1136 | UnixDomainSocket, |
| 1137 | Wht, // TODO wtf is this |
| 1138 | 1138 | Unknown, |
| 1139 | 1139 | }; |
| 1140 | 1140 | }; |
| 1141 | 1141 | |
| 1142 | 1142 | pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir { |
| 1143 | | const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0); |
| 1143 | const fd = switch (builtin.os) { |
| 1144 | Os.windows => @compileError("TODO support Dir.open for windows"), |
| 1145 | Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), |
| 1146 | Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0), |
| 1147 | else => @compileError("Dir.open is not supported for this platform"), |
| 1148 | }; |
| 1149 | const darwin_seek_init = switch (builtin.os) { |
| 1150 | Os.macosx, Os.ios => 0, |
| 1151 | else => {}, |
| 1152 | }; |
| 1144 | 1153 | return Dir { |
| 1145 | 1154 | .allocator = allocator, |
| 1146 | 1155 | .fd = fd, |
| 1156 | .darwin_seek = darwin_seek_init, |
| 1147 | 1157 | .index = 0, |
| 1148 | 1158 | .end_index = 0, |
| 1149 | 1159 | .buf = []u8{}, |
| ... | ... | @@ -1158,6 +1168,76 @@ pub const Dir = struct { |
| 1158 | 1168 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 1159 | 1169 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 1160 | 1170 | pub fn next(self: &Dir) !?Entry { |
| 1171 | switch (builtin.os) { |
| 1172 | Os.linux => return self.nextLinux(), |
| 1173 | Os.macosx, Os.ios => return self.nextDarwin(), |
| 1174 | Os.windows => return self.nextWindows(), |
| 1175 | else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)), |
| 1176 | } |
| 1177 | } |
| 1178 | |
| 1179 | fn nextDarwin(self: &Dir) !?Entry { |
| 1180 | start_over: while (true) { |
| 1181 | if (self.index >= self.end_index) { |
| 1182 | if (self.buf.len == 0) { |
| 1183 | self.buf = try self.allocator.alloc(u8, page_size); |
| 1184 | } |
| 1185 | |
| 1186 | while (true) { |
| 1187 | const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, |
| 1188 | &self.darwin_seek); |
| 1189 | const err = posix.getErrno(result); |
| 1190 | if (err > 0) { |
| 1191 | switch (err) { |
| 1192 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, |
| 1193 | posix.EINVAL => { |
| 1194 | self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2); |
| 1195 | continue; |
| 1196 | }, |
| 1197 | else => return unexpectedErrorPosix(err), |
| 1198 | } |
| 1199 | } |
| 1200 | if (result == 0) |
| 1201 | return null; |
| 1202 | self.index = 0; |
| 1203 | self.end_index = result; |
| 1204 | break; |
| 1205 | } |
| 1206 | } |
| 1207 | const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); |
| 1208 | const next_index = self.index + darwin_entry.d_reclen; |
| 1209 | self.index = next_index; |
| 1210 | |
| 1211 | const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen]; |
| 1212 | |
| 1213 | // skip . and .. entries |
| 1214 | if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { |
| 1215 | continue :start_over; |
| 1216 | } |
| 1217 | |
| 1218 | const entry_kind = switch (darwin_entry.d_type) { |
| 1219 | posix.DT_BLK => Entry.Kind.BlockDevice, |
| 1220 | posix.DT_CHR => Entry.Kind.CharacterDevice, |
| 1221 | posix.DT_DIR => Entry.Kind.Directory, |
| 1222 | posix.DT_FIFO => Entry.Kind.NamedPipe, |
| 1223 | posix.DT_LNK => Entry.Kind.SymLink, |
| 1224 | posix.DT_REG => Entry.Kind.File, |
| 1225 | posix.DT_SOCK => Entry.Kind.UnixDomainSocket, |
| 1226 | posix.DT_WHT => Entry.Kind.Wht, |
| 1227 | else => Entry.Kind.Unknown, |
| 1228 | }; |
| 1229 | return Entry { |
| 1230 | .name = name, |
| 1231 | .kind = entry_kind, |
| 1232 | }; |
| 1233 | } |
| 1234 | } |
| 1235 | |
| 1236 | fn nextWindows(self: &Dir) !?Entry { |
| 1237 | @compileError("TODO support Dir.next for windows"); |
| 1238 | } |
| 1239 | |
| 1240 | fn nextLinux(self: &Dir) !?Entry { |
| 1161 | 1241 | start_over: while (true) { |
| 1162 | 1242 | if (self.index >= self.end_index) { |
| 1163 | 1243 | if (self.buf.len == 0) { |
| ... | ... | @@ -1166,7 +1246,7 @@ pub const Dir = struct { |
| 1166 | 1246 | |
| 1167 | 1247 | while (true) { |
| 1168 | 1248 | const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); |
| 1169 | | const err = linux.getErrno(result); |
| 1249 | const err = posix.getErrno(result); |
| 1170 | 1250 | if (err > 0) { |
| 1171 | 1251 | switch (err) { |
| 1172 | 1252 | posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, |
| ... | ... | @@ -1184,7 +1264,7 @@ pub const Dir = struct { |
| 1184 | 1264 | break; |
| 1185 | 1265 | } |
| 1186 | 1266 | } |
| 1187 | | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); |
| 1267 | const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]); |
| 1188 | 1268 | const next_index = self.index + linux_entry.d_reclen; |
| 1189 | 1269 | self.index = next_index; |
| 1190 | 1270 | |
| ... | ... | @@ -1683,7 +1763,7 @@ test "std.os" { |
| 1683 | 1763 | |
| 1684 | 1764 | |
| 1685 | 1765 | // TODO make this a build variable that you can set |
| 1686 | | const unexpected_error_tracing = false; |
| 1766 | const unexpected_error_tracing = true; |
| 1687 | 1767 | |
| 1688 | 1768 | /// Call this when you made a syscall or something that sets errno |
| 1689 | 1769 | /// and you get an unexpected error. |