| ... | ... | @@ -52,6 +52,43 @@ pub fn stat(self: File) !Stat { |
| 52 | 52 | }; |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | pub fn getEndPos(self: File) !u64 { |
| 56 | return (try self.stat()).size; |
| 57 | } |
| 58 | |
| 59 | pub fn readToEndAlloc(self: File, allocator: std.mem.Allocator, max_bytes: usize, size_hint: ?usize) ![:0]u8 { |
| 60 | var array_list = try std.ArrayList(u8).initCapacity(allocator, @min(size_hint orelse 1023, max_bytes) + 1); |
| 61 | defer array_list.deinit(); |
| 62 | self.readAllArrayList(&array_list, max_bytes) catch |err| switch (err) { |
| 63 | error.StreamTooLong => return error.FileTooBig, |
| 64 | else => |e| return e, |
| 65 | }; |
| 66 | return try array_list.toOwnedSliceSentinel(0); |
| 67 | } |
| 68 | |
| 69 | pub fn readAllArrayList(self: File, array_list: *std.ArrayList(u8), max_append_size: usize) anyerror!void { |
| 70 | try array_list.ensureTotalCapacity(@min(max_append_size, 4096)); |
| 71 | const original_len = array_list.items.len; |
| 72 | var start_index: usize = original_len; |
| 73 | while (true) { |
| 74 | array_list.expandToCapacity(); |
| 75 | const dest_slice = array_list.items[start_index..]; |
| 76 | const bytes_read = try self.readAll(dest_slice); |
| 77 | start_index += bytes_read; |
| 78 | |
| 79 | if (start_index - original_len > max_append_size) { |
| 80 | array_list.shrinkAndFree(original_len + max_append_size); |
| 81 | return error.StreamTooLong; |
| 82 | } |
| 83 | if (bytes_read != dest_slice.len) { |
| 84 | array_list.shrinkAndFree(start_index); |
| 85 | return; |
| 86 | } |
| 87 | // This will trigger ArrayList to expand superlinearly at whatever its growth rate is. |
| 88 | try array_list.ensureTotalCapacity(start_index + 1); |
| 89 | } |
| 90 | } |
| 91 | |
| 55 | 92 | pub const Stat = struct { |
| 56 | 93 | inode: INode, |
| 57 | 94 | size: u64, |