1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
//! Code taken from 0.15.2 and `std.fs.file`. See README.md for license and
//! details.
const builtin = @import("builtin");
const std = @import("std");
const global = @import("../../global.zig");
pub const ReadToEndAllocError = error{FileTooBig} ||
std.Io.File.ReadStreamingError ||
std.mem.Allocator.Error;
/// Read the file from its current position through end-of-stream, returning
/// `error.FileTooBig` if the result exceeds `max_bytes`.
///
/// Caller owns the memory.
pub fn readToEndAlloc(file: std.Io.File, alloc: std.mem.Allocator, max_bytes: usize) ReadToEndAllocError![]u8 {
var read_buf: [4096]u8 = undefined;
var result: std.ArrayList(u8) = .empty;
defer result.deinit(alloc);
while (true) {
const n = file.readStreaming(global.io(), &.{&read_buf}) catch |err| switch (err) {
error.EndOfStream => break,
else => |e| return e,
};
if (n == 0) continue;
if (n > max_bytes - result.items.len) return error.FileTooBig;
try result.appendSlice(alloc, read_buf[0..n]);
}
return result.toOwnedSlice(alloc);
}
test "readToEndAlloc reads through EOF and permits exact limit" {
const testing = std.testing;
const contents = "hello, world";
var tmp_dir = testing.tmpDir(.{});
defer tmp_dir.cleanup();
try tmp_dir.dir.writeFile(testing.io, .{
.sub_path = "data",
.data = contents,
});
const file = try tmp_dir.dir.openFile(testing.io, "data", .{});
defer file.close(testing.io);
const result = try readToEndAlloc(file, testing.allocator, contents.len);
defer testing.allocator.free(result);
try testing.expectEqualStrings(contents, result);
const too_big_file = try tmp_dir.dir.openFile(testing.io, "data", .{});
defer too_big_file.close(testing.io);
try testing.expectError(
error.FileTooBig,
readToEndAlloc(too_big_file, testing.allocator, contents.len - 1),
);
}
|