diff --git a/Dir.zig b/Dir.zig index ae3885325f38bf5943dc9d068577e34d8fbe4d2d..4495daa269cdd6256c4cab14bc2b7e813af1c64f 100644 --- a/Dir.zig +++ b/Dir.zig @@ -33,3 +33,10 @@ pub const OpenDirFlags = packed struct { pub fn to_std(self: Dir) std.fs.Dir { return .{ .fd = @intFromEnum(self.fd) }; } + +pub fn readFileAlloc(self: Dir, allocator: std.mem.Allocator, file_path: [:0]const u8, max_bytes: usize) ![:0]u8 { + var file = try self.openFile(file_path, .{}); + defer file.close(); + const stat_size = std.math.cast(usize, try file.getEndPos()) orelse return error.FileTooBig; + return file.readToEndAlloc(allocator, max_bytes, stat_size); +} diff --git a/File.zig b/File.zig index f649db5f887c64b60a61b2ff786729b49035321b..09f9be0d7cf99f4754bdaf82407d254ffda68572 100644 --- a/File.zig +++ b/File.zig @@ -52,6 +52,43 @@ pub fn stat(self: File) !Stat { }; } +pub fn getEndPos(self: File) !u64 { + return (try self.stat()).size; +} + +pub fn readToEndAlloc(self: File, allocator: std.mem.Allocator, max_bytes: usize, size_hint: ?usize) ![:0]u8 { + var array_list = try std.ArrayList(u8).initCapacity(allocator, @min(size_hint orelse 1023, max_bytes) + 1); + defer array_list.deinit(); + self.readAllArrayList(&array_list, max_bytes) catch |err| switch (err) { + error.StreamTooLong => return error.FileTooBig, + else => |e| return e, + }; + return try array_list.toOwnedSliceSentinel(0); +} + +pub fn readAllArrayList(self: File, array_list: *std.ArrayList(u8), max_append_size: usize) anyerror!void { + try array_list.ensureTotalCapacity(@min(max_append_size, 4096)); + const original_len = array_list.items.len; + var start_index: usize = original_len; + while (true) { + array_list.expandToCapacity(); + const dest_slice = array_list.items[start_index..]; + const bytes_read = try self.readAll(dest_slice); + start_index += bytes_read; + + if (start_index - original_len > max_append_size) { + array_list.shrinkAndFree(original_len + max_append_size); + return error.StreamTooLong; + } + if (bytes_read != dest_slice.len) { + array_list.shrinkAndFree(start_index); + return; + } + // This will trigger ArrayList to expand superlinearly at whatever its growth rate is. + try array_list.ensureTotalCapacity(start_index + 1); + } +} + pub const Stat = struct { inode: INode, size: u64,