| author | |
| committer | |
| log | 11df0d0cf8c786d5b502c21a42d47631657a42f4 |
| tree | b860be3c40159ad2ea9c41f44c3873d1b29e33bb |
| parent | 89d7fc773d66609a8d93106f9a6d84d479771690 |
Allow the user to shrink/grow the file size as needed.7 files changed, 89 insertions(+), 0 deletions(-)
lib/std/c.zig+1| ... | ... | @@ -79,6 +79,7 @@ pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, fla |
| 79 | 79 | pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t; |
| 80 | 80 | pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int; |
| 81 | 81 | pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int; |
| 82 | pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int; | |
| 82 | 83 | pub extern "c" fn raise(sig: c_int) c_int; |
| 83 | 84 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; |
| 84 | 85 | pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize; |
lib/std/c/linux.zig+2| ... | ... | @@ -82,6 +82,8 @@ pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; |
| 82 | 82 | |
| 83 | 83 | pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int; |
| 84 | 84 | |
| 85 | pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int; | |
| 86 | ||
| 85 | 87 | pub extern "c" fn sendfile( |
| 86 | 88 | out_fd: fd_t, |
| 87 | 89 | in_fd: fd_t, |
lib/std/fs/file.zig+8| ... | ... | @@ -99,6 +99,14 @@ pub const File = struct { |
| 99 | 99 | return false; |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | pub const SetEndPosError = os.TruncateError; | |
| 103 | ||
| 104 | /// Shrinks or expands the file. | |
| 105 | /// The file offset after this call is undefined. | |
| 106 | pub fn setEndPos(self: File, length: u64) SetEndPosError!void { | |
| 107 | try os.truncate(self.handle, length); | |
| 108 | } | |
| 109 | ||
| 102 | 110 | pub const SeekError = os.SeekError; |
| 103 | 111 | |
| 104 | 112 | /// Repositions read/write file offset relative to the current offset. |
lib/std/io/test.zig+17| ... | ... | @@ -125,6 +125,23 @@ test "File seek ops" { |
| 125 | 125 | expect((try file.getPos()) == 1234); |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | test "setEndPos" { | |
| 129 | const tmp_file_name = "temp_test_file.txt"; | |
| 130 | var file = try fs.cwd().createFile(tmp_file_name, .{}); | |
| 131 | defer { | |
| 132 | file.close(); | |
| 133 | fs.cwd().deleteFile(tmp_file_name) catch {}; | |
| 134 | } | |
| 135 | ||
| 136 | std.testing.expect((try file.getEndPos()) == 0); | |
| 137 | try file.setEndPos(8192); | |
| 138 | std.testing.expect((try file.getEndPos()) == 8192); | |
| 139 | try file.setEndPos(4096); | |
| 140 | std.testing.expect((try file.getEndPos()) == 4096); | |
| 141 | try file.setEndPos(0); | |
| 142 | std.testing.expect((try file.getEndPos()) == 0); | |
| 143 | } | |
| 144 | ||
| 128 | 145 | test "updateTimes" { |
| 129 | 146 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 130 | 147 | var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true }); |
lib/std/os.zig+33| ... | ... | @@ -438,6 +438,39 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 438 | 438 | return index; |
| 439 | 439 | } |
| 440 | 440 | |
| 441 | pub const TruncateError = error{ | |
| 442 | /// The file descriptor is not open for writing. | |
| 443 | NotFile, | |
| 444 | } || UnexpectedError; | |
| 445 | ||
| 446 | pub fn truncate(fd: fd_t, length: u64) TruncateError!void { | |
| 447 | if (std.Target.current.os.tag == .windows) { | |
| 448 | try windows.SetFilePointerEx_BEGIN(fd, length); | |
| 449 | ||
| 450 | if (windows.kernel32.SetEndOfFile(fd) == 0) | |
| 451 | return TruncateError.Unexpected; | |
| 452 | ||
| 453 | return; | |
| 454 | } | |
| 455 | ||
| 456 | while (true) { | |
| 457 | const rc = if (builtin.link_libc) blk: { | |
| 458 | if (std.Target.current.os.tag == .linux) | |
| 459 | break :blk system.ftruncate64(fd, @bitCast(off_t, length)) | |
| 460 | else | |
| 461 | break :blk system.ftruncate(fd, @bitCast(off_t, length)); | |
| 462 | } else | |
| 463 | system.ftruncate(fd, length); | |
| 464 | ||
| 465 | switch (errno(rc)) { | |
| 466 | 0 => return, | |
| 467 | EINTR => continue, | |
| 468 | EBADF, EINVAL => return error.NotFile, | |
| 469 | else => |err| return unexpectedErrno(err), | |
| 470 | } | |
| 471 | } | |
| 472 | } | |
| 473 | ||
| 441 | 474 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. |
| 442 | 475 | /// |
| 443 | 476 | /// Retries when interrupted by a signal. |
lib/std/os/linux.zig+27| ... | ... | @@ -390,6 +390,33 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { |
| 390 | 390 | return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count); |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | pub fn ftruncate(fd: i32, length: u64) usize { | |
| 394 | if (@hasDecl(@This(), "SYS_ftruncate64")) { | |
| 395 | if (require_aligned_register_pair) { | |
| 396 | return syscall4( | |
| 397 | SYS_ftruncate64, | |
| 398 | @bitCast(usize, @as(isize, fd)), | |
| 399 | 0, | |
| 400 | @truncate(usize, length), | |
| 401 | @truncate(usize, length >> 32), | |
| 402 | ); | |
| 403 | } else { | |
| 404 | return syscall3( | |
| 405 | SYS_ftruncate64, | |
| 406 | @bitCast(usize, @as(isize, fd)), | |
| 407 | @truncate(usize, length), | |
| 408 | @truncate(usize, length >> 32), | |
| 409 | ); | |
| 410 | } | |
| 411 | } else { | |
| 412 | return syscall2( | |
| 413 | SYS_ftruncate, | |
| 414 | @bitCast(usize, @as(isize, fd)), | |
| 415 | @truncate(usize, length), | |
| 416 | ); | |
| 417 | } | |
| 418 | } | |
| 419 | ||
| 393 | 420 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { |
| 394 | 421 | if (@hasDecl(@This(), "SYS_pwrite64")) { |
| 395 | 422 | if (require_aligned_register_pair) { |
lib/std/os/windows/kernel32.zig+1| ... | ... | @@ -8,6 +8,7 @@ pub extern "kernel32" fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) c |
| 8 | 8 | pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL; |
| 9 | 9 | |
| 10 | 10 | pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) callconv(.Stdcall) BOOL; |
| 11 | pub extern "kernel32" fn SetEndOfFile(hFile: HANDLE) callconv(.Stdcall) BOOL; | |
| 11 | 12 | |
| 12 | 13 | pub extern "kernel32" fn CreateEventExW( |
| 13 | 14 | lpEventAttributes: ?*SECURITY_ATTRIBUTES, |