| author | |
| committer | |
| log | 2823fcabd1974550b889a56e8ada0eb52f3d2080 |
| tree | 151f1c813c7027271ef9b38872e9d88786c55678 |
| parent | fc3142aa9a54f014c07aac6ac2aab75f57c5a75f |
| parent | b7066b6024521f077d645c297879cce5f1ed563c |
| signature |
wasi: fixes IterableDir.nextWasi for large directory2 files changed, 47 insertions(+), 1 deletions(-)
lib/std/fs.zig+10-1| ... | ... | @@ -809,7 +809,11 @@ pub const IterableDir = struct { |
| 809 | 809 | // and we avoid the code complexity here. |
| 810 | 810 | const w = os.wasi; |
| 811 | 811 | start_over: while (true) { |
| 812 | if (self.index >= self.end_index) { | |
| 812 | // TODO https://github.com/ziglang/zig/issues/12498 | |
| 813 | _ = @sizeOf(w.dirent_t) + 1; | |
| 814 | // According to the WASI spec, the last entry might be truncated, | |
| 815 | // so we need to check if the left buffer contains the whole dirent. | |
| 816 | if (self.end_index - self.index < @sizeOf(w.dirent_t)) { | |
| 813 | 817 | var bufused: usize = undefined; |
| 814 | 818 | switch (w.fd_readdir(self.dir.fd, &self.buf, self.buf.len, self.cookie, &bufused)) { |
| 815 | 819 | .SUCCESS => {}, |
| ... | ... | @@ -828,6 +832,11 @@ pub const IterableDir = struct { |
| 828 | 832 | const entry = @ptrCast(*align(1) w.dirent_t, &self.buf[self.index]); |
| 829 | 833 | const entry_size = @sizeOf(w.dirent_t); |
| 830 | 834 | const name_index = self.index + entry_size; |
| 835 | if (name_index + entry.d_namlen > self.end_index) { | |
| 836 | // This case, the name is truncated, so we need to call readdir to store the entire name. | |
| 837 | self.end_index = self.index; // Force fd_readdir in the next loop. | |
| 838 | continue :start_over; | |
| 839 | } | |
| 831 | 840 | const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]); |
| 832 | 841 | |
| 833 | 842 | const next_index = name_index + entry.d_namlen; |
lib/std/fs/test.zig+37| ... | ... | @@ -186,6 +186,43 @@ test "Dir.Iterator" { |
| 186 | 186 | try testing.expect(contains(&entries, .{ .name = "some_dir", .kind = .Directory })); |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | test "Dir.Iterator many entries" { | |
| 190 | if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); | |
| 191 | ||
| 192 | var tmp_dir = tmpIterableDir(.{}); | |
| 193 | defer tmp_dir.cleanup(); | |
| 194 | ||
| 195 | const num = 1024; | |
| 196 | var i: usize = 0; | |
| 197 | var buf: [4]u8 = undefined; // Enough to store "1024". | |
| 198 | while (i < num) : (i += 1) { | |
| 199 | const name = try std.fmt.bufPrint(&buf, "{}", .{i}); | |
| 200 | const file = try tmp_dir.iterable_dir.dir.createFile(name, .{}); | |
| 201 | file.close(); | |
| 202 | } | |
| 203 | ||
| 204 | var arena = ArenaAllocator.init(testing.allocator); | |
| 205 | defer arena.deinit(); | |
| 206 | const allocator = arena.allocator(); | |
| 207 | ||
| 208 | var entries = std.ArrayList(IterableDir.Entry).init(allocator); | |
| 209 | ||
| 210 | // Create iterator. | |
| 211 | var iter = tmp_dir.iterable_dir.iterate(); | |
| 212 | while (try iter.next()) |entry| { | |
| 213 | // We cannot just store `entry` as on Windows, we're re-using the name buffer | |
| 214 | // which means we'll actually share the `name` pointer between entries! | |
| 215 | const name = try allocator.dupe(u8, entry.name); | |
| 216 | try entries.append(.{ .name = name, .kind = entry.kind }); | |
| 217 | } | |
| 218 | ||
| 219 | i = 0; | |
| 220 | while (i < num) : (i += 1) { | |
| 221 | const name = try std.fmt.bufPrint(&buf, "{}", .{i}); | |
| 222 | try testing.expect(contains(&entries, .{ .name = name, .kind = .File })); | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 189 | 226 | test "Dir.Iterator twice" { |
| 190 | 227 | var tmp_dir = tmpIterableDir(.{}); |
| 191 | 228 | defer tmp_dir.cleanup(); |