| author | |
| committer | |
| log | 73a8c9beaa63c48b6ddaeec8d2a67b239f0dec92 |
| tree | 38e42ddabbcb8c6306d7f225154d26d3db1f58d9 |
| parent | 26140678a5c72604f2baac3cb9d1e5f7b37b6b8d |
Some files such as the ones in /proc report a st_size of zero, try to
read the file anyway if we hit that case.5 files changed, 28 insertions(+), 17 deletions(-)
lib/std/fs.zig+1-3| ... | @@ -1454,9 +1454,7 @@ pub const Dir = struct { | ... | @@ -1454,9 +1454,7 @@ pub const Dir = struct { |
| 1454 | var file = try self.openFile(file_path, .{}); | 1454 | var file = try self.openFile(file_path, .{}); |
| 1455 | defer file.close(); | 1455 | defer file.close(); |
| 1456 | 1456 | ||
| 1457 | const stat_size = try file.getEndPos(); | 1457 | return file.readAllAllocOptions(allocator, max_bytes, alignment, optional_sentinel); |
| 1458 | |||
| 1459 | return file.readAllAllocOptions(allocator, stat_size, max_bytes, alignment, optional_sentinel); | ||
| 1460 | } | 1458 | } |
| 1461 | 1459 | ||
| 1462 | pub const DeleteTreeError = error{ | 1460 | pub const DeleteTreeError = error{ |
lib/std/fs/file.zig+21-7| ... | @@ -365,8 +365,8 @@ pub const File = struct { | ... | @@ -365,8 +365,8 @@ pub const File = struct { |
| 365 | 365 | ||
| 366 | /// On success, caller owns returned buffer. | 366 | /// On success, caller owns returned buffer. |
| 367 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 367 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 368 | pub fn readAllAlloc(self: File, allocator: *mem.Allocator, stat_size: u64, max_bytes: usize) ![]u8 { | 368 | pub fn readAllAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 { |
| 369 | return self.readAllAllocOptions(allocator, stat_size, max_bytes, @alignOf(u8), null); | 369 | return self.readAllAllocOptions(allocator, max_bytes, @alignOf(u8), null); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | /// On success, caller owns returned buffer. | 372 | /// On success, caller owns returned buffer. |
| ... | @@ -375,19 +375,33 @@ pub const File = struct { | ... | @@ -375,19 +375,33 @@ pub const File = struct { |
| 375 | pub fn readAllAllocOptions( | 375 | pub fn readAllAllocOptions( |
| 376 | self: File, | 376 | self: File, |
| 377 | allocator: *mem.Allocator, | 377 | allocator: *mem.Allocator, |
| 378 | stat_size: u64, | ||
| 379 | max_bytes: usize, | 378 | max_bytes: usize, |
| 380 | comptime alignment: u29, | 379 | comptime alignment: u29, |
| 381 | comptime optional_sentinel: ?u8, | 380 | comptime optional_sentinel: ?u8, |
| 382 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | 381 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { |
| 382 | const stat_size = try self.getEndPos(); | ||
| 383 | const size = math.cast(usize, stat_size) catch math.maxInt(usize); | 383 | const size = math.cast(usize, stat_size) catch math.maxInt(usize); |
| 384 | if (size > max_bytes) return error.FileTooBig; | 384 | if (size > max_bytes) return error.FileTooBig; |
| 385 | 385 | ||
| 386 | const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel); | 386 | // The file size returned by stat is used as hint to set the buffer |
| 387 | errdefer allocator.free(buf); | 387 | // size. If the reported size is zero, as it happens on Linux for files |
| 388 | // in /proc, a small buffer is allocated instead. | ||
| 389 | const initial_cap = (if (size > 0) size else 1024) + @boolToInt(optional_sentinel != null); | ||
| 390 | var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap); | ||
| 391 | defer array_list.deinit(); | ||
| 388 | 392 | ||
| 389 | try self.reader().readNoEof(buf); | 393 | self.reader().readAllArrayList(&array_list, max_bytes) catch |err| switch (err) { |
| 390 | return buf; | 394 | error.StreamTooLong => return error.FileTooBig, |
| 395 | else => |e| return e, | ||
| 396 | }; | ||
| 397 | |||
| 398 | if (optional_sentinel) |sentinel| { | ||
| 399 | try array_list.append(sentinel); | ||
| 400 | const buf = array_list.toOwnedSlice(); | ||
| 401 | return buf[0 .. buf.len - 1 :sentinel]; | ||
| 402 | } else { | ||
| 403 | return array_list.toOwnedSlice(); | ||
| 404 | } | ||
| 391 | } | 405 | } |
| 392 | 406 | ||
| 393 | pub const ReadError = os.ReadError; | 407 | pub const ReadError = os.ReadError; |
lib/std/fs/test.zig+4-5| ... | @@ -188,30 +188,29 @@ test "readAllAlloc" { | ... | @@ -188,30 +188,29 @@ test "readAllAlloc" { |
| 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); | 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); |
| 189 | defer file.close(); | 189 | defer file.close(); |
| 190 | 190 | ||
| 191 | const buf1 = try file.readAllAlloc(testing.allocator, 0, 1024); | 191 | const buf1 = try file.readAllAlloc(testing.allocator, 1024); |
| 192 | defer testing.allocator.free(buf1); | 192 | defer testing.allocator.free(buf1); |
| 193 | testing.expect(buf1.len == 0); | 193 | testing.expect(buf1.len == 0); |
| 194 | 194 | ||
| 195 | const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n"; | 195 | const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n"; |
| 196 | try file.writeAll(write_buf); | 196 | try file.writeAll(write_buf); |
| 197 | try file.seekTo(0); | 197 | try file.seekTo(0); |
| 198 | const file_size = try file.getEndPos(); | ||
| 199 | 198 | ||
| 200 | // max_bytes > file_size | 199 | // max_bytes > file_size |
| 201 | const buf2 = try file.readAllAlloc(testing.allocator, file_size, 1024); | 200 | const buf2 = try file.readAllAlloc(testing.allocator, 1024); |
| 202 | defer testing.allocator.free(buf2); | 201 | defer testing.allocator.free(buf2); |
| 203 | testing.expectEqual(write_buf.len, buf2.len); | 202 | testing.expectEqual(write_buf.len, buf2.len); |
| 204 | testing.expect(std.mem.eql(u8, write_buf, buf2)); | 203 | testing.expect(std.mem.eql(u8, write_buf, buf2)); |
| 205 | try file.seekTo(0); | 204 | try file.seekTo(0); |
| 206 | 205 | ||
| 207 | // max_bytes == file_size | 206 | // max_bytes == file_size |
| 208 | const buf3 = try file.readAllAlloc(testing.allocator, file_size, write_buf.len); | 207 | const buf3 = try file.readAllAlloc(testing.allocator, write_buf.len); |
| 209 | defer testing.allocator.free(buf3); | 208 | defer testing.allocator.free(buf3); |
| 210 | testing.expectEqual(write_buf.len, buf3.len); | 209 | testing.expectEqual(write_buf.len, buf3.len); |
| 211 | testing.expect(std.mem.eql(u8, write_buf, buf3)); | 210 | testing.expect(std.mem.eql(u8, write_buf, buf3)); |
| 212 | 211 | ||
| 213 | // max_bytes < file_size | 212 | // max_bytes < file_size |
| 214 | testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, file_size, write_buf.len - 1)); | 213 | testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, write_buf.len - 1)); |
| 215 | } | 214 | } |
| 216 | 215 | ||
| 217 | test "directory operations on files" { | 216 | test "directory operations on files" { |
src-self-hosted/main.zig+2-1| ... | @@ -742,6 +742,7 @@ const FmtError = error{ | ... | @@ -742,6 +742,7 @@ const FmtError = error{ |
| 742 | LinkQuotaExceeded, | 742 | LinkQuotaExceeded, |
| 743 | FileBusy, | 743 | FileBusy, |
| 744 | EndOfStream, | 744 | EndOfStream, |
| 745 | Unseekable, | ||
| 745 | NotOpenForWriting, | 746 | NotOpenForWriting, |
| 746 | } || fs.File.OpenError; | 747 | } || fs.File.OpenError; |
| 747 | 748 | ||
| ... | @@ -805,7 +806,7 @@ fn fmtPathFile( | ... | @@ -805,7 +806,7 @@ fn fmtPathFile( |
| 805 | if (stat.kind == .Directory) | 806 | if (stat.kind == .Directory) |
| 806 | return error.IsDir; | 807 | return error.IsDir; |
| 807 | 808 | ||
| 808 | const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) { | 809 | const source_code = source_file.readAllAlloc(fmt.gpa, max_src_size) catch |err| switch (err) { |
| 809 | error.ConnectionResetByPeer => unreachable, | 810 | error.ConnectionResetByPeer => unreachable, |
| 810 | error.ConnectionTimedOut => unreachable, | 811 | error.ConnectionTimedOut => unreachable, |
| 811 | error.NotOpenForReading => unreachable, | 812 | error.NotOpenForReading => unreachable, |
src-self-hosted/stage2.zig-1| ... | @@ -615,7 +615,6 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ | ... | @@ -615,7 +615,6 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ |
| 615 | error.NotOpenForWriting => unreachable, | 615 | error.NotOpenForWriting => unreachable, |
| 616 | error.NotOpenForReading => unreachable, | 616 | error.NotOpenForReading => unreachable, |
| 617 | error.Unexpected => return .Unexpected, | 617 | error.Unexpected => return .Unexpected, |
| 618 | error.EndOfStream => return .EndOfFile, | ||
| 619 | error.IsDir => return .IsDir, | 618 | error.IsDir => return .IsDir, |
| 620 | error.ConnectionResetByPeer => unreachable, | 619 | error.ConnectionResetByPeer => unreachable, |
| 621 | error.ConnectionTimedOut => unreachable, | 620 | error.ConnectionTimedOut => unreachable, |