Windows: Fix iterator name buffer size not handling all possible file name components

Each u16 within a file name component can be encoded as up to 3 UTF-8 bytes, so we need to use MAX_NAME_BYTES to account for all possible UTF-8 encoded names.

Fixes #8268
This commit is contained in:
Ryan Liptak 2022-10-13 21:21:16 -07:00
parent 33fdc43714
commit c6ff1a7160
2 changed files with 40 additions and 2 deletions

View File

@ -58,7 +58,7 @@ pub const MAX_NAME_BYTES = switch (builtin.os.tag) {
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
// If it would require 4 UTF-8 bytes, then there would be a surrogate
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
.windows => os.NAME_MAX * 3,
.windows => os.windows.NAME_MAX * 3,
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "NAME_MAX"))
root.os.NAME_MAX
else
@ -697,7 +697,7 @@ pub const IterableDir = struct {
index: usize,
end_index: usize,
first_iter: bool,
name_data: [256]u8,
name_data: [MAX_NAME_BYTES]u8,
const Self = @This();

View File

@ -703,6 +703,44 @@ test "makePath in a directory that no longer exists" {
try testing.expectError(error.FileNotFound, tmp.dir.makePath("sub-path"));
}
fn testFilenameLimits(iterable_dir: IterableDir, maxed_filename: []const u8) !void {
// setup, create a dir and a nested file both with maxed filenames, and walk the dir
{
var maxed_dir = try iterable_dir.dir.makeOpenPath(maxed_filename, .{});
defer maxed_dir.close();
try maxed_dir.writeFile(maxed_filename, "");
var walker = try iterable_dir.walk(testing.allocator);
defer walker.deinit();
var count: usize = 0;
while (try walker.next()) |entry| {
try testing.expectEqualStrings(maxed_filename, entry.basename);
count += 1;
}
try testing.expectEqual(@as(usize, 2), count);
}
// ensure that we can delete the tree
try iterable_dir.dir.deleteTree(maxed_filename);
}
test "filename limits" {
var tmp = tmpIterableDir(.{});
defer tmp.cleanup();
if (builtin.os.tag == .windows) {
// is the character with the largest codepoint that is encoded as a single u16 in UTF-16,
// so Windows allows for NAME_MAX of them
const maxed_windows_filename = ("".*) ** std.os.windows.NAME_MAX;
try testFilenameLimits(tmp.iterable_dir, &maxed_windows_filename);
} else {
const maxed_ascii_filename = [_]u8{'1'} ** std.fs.MAX_NAME_BYTES;
try testFilenameLimits(tmp.iterable_dir, &maxed_ascii_filename);
}
}
test "writev, readv" {
var tmp = tmpDir(.{});
defer tmp.cleanup();