| author | |
| committer | |
| log | a9297f22671dff800821ff940395411f2adb8582 |
| tree | 5e1ed7fb4538dc0195bb7caa9dfe3c0c0a79c41c |
| parent | 5dd3c8eed65c020a5c5672ee595b16120b3dc431 |
| parent | de53537f10e22cc003cfbc77468349b758470f24 |
| signature |
Introduce std.fs.file.setEndPos9 files changed, 167 insertions(+), 4 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 left unchanged. | |
| 106 | pub fn setEndPos(self: File, length: u64) SetEndPosError!void { | |
| 107 | try os.ftruncate(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+25-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("../std.zig"); | |
| 1 | const std = @import("std"); | |
| 2 | const builtin = std.builtin; | |
| 3 | 3 | const io = std.io; |
| 4 | 4 | const meta = std.meta; |
| 5 | 5 | const trait = std.trait; |
| ... | ... | @@ -125,6 +125,29 @@ 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 | // Verify that the file size changes and the file offset is not moved | |
| 137 | std.testing.expect((try file.getEndPos()) == 0); | |
| 138 | std.testing.expect((try file.getPos()) == 0); | |
| 139 | try file.setEndPos(8192); | |
| 140 | std.testing.expect((try file.getEndPos()) == 8192); | |
| 141 | std.testing.expect((try file.getPos()) == 0); | |
| 142 | try file.seekTo(100); | |
| 143 | try file.setEndPos(4096); | |
| 144 | std.testing.expect((try file.getEndPos()) == 4096); | |
| 145 | std.testing.expect((try file.getPos()) == 100); | |
| 146 | try file.setEndPos(0); | |
| 147 | std.testing.expect((try file.getEndPos()) == 0); | |
| 148 | std.testing.expect((try file.getPos()) == 100); | |
| 149 | } | |
| 150 | ||
| 128 | 151 | test "updateTimes" { |
| 129 | 152 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 130 | 153 | var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true }); |
lib/std/os.zig+55| ... | ... | @@ -438,6 +438,61 @@ 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 | FileTooBig, | |
| 443 | InputOutput, | |
| 444 | CannotTruncate, | |
| 445 | FileBusy, | |
| 446 | } || UnexpectedError; | |
| 447 | ||
| 448 | pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { | |
| 449 | if (std.Target.current.os.tag == .windows) { | |
| 450 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | |
| 451 | var eof_info = windows.FILE_END_OF_FILE_INFORMATION{ | |
| 452 | .EndOfFile = @bitCast(windows.LARGE_INTEGER, length), | |
| 453 | }; | |
| 454 | ||
| 455 | const rc = windows.ntdll.NtSetInformationFile( | |
| 456 | fd, | |
| 457 | &io_status_block, | |
| 458 | &eof_info, | |
| 459 | @sizeOf(windows.FILE_END_OF_FILE_INFORMATION), | |
| 460 | .FileEndOfFileInformation, | |
| 461 | ); | |
| 462 | ||
| 463 | switch (rc) { | |
| 464 | .SUCCESS => {}, | |
| 465 | .INVALID_HANDLE => unreachable, // Handle not open for writing | |
| 466 | .ACCESS_DENIED => return error.CannotTruncate, | |
| 467 | else => return windows.unexpectedStatus(rc), | |
| 468 | } | |
| 469 | ||
| 470 | return; | |
| 471 | } | |
| 472 | ||
| 473 | while (true) { | |
| 474 | const rc = if (builtin.link_libc) | |
| 475 | if (std.Target.current.os.tag == .linux) | |
| 476 | system.ftruncate64(fd, @bitCast(off_t, length)) | |
| 477 | else | |
| 478 | system.ftruncate(fd, @bitCast(off_t, length)) | |
| 479 | else | |
| 480 | system.ftruncate(fd, length); | |
| 481 | ||
| 482 | switch (errno(rc)) { | |
| 483 | 0 => return, | |
| 484 | EINTR => continue, | |
| 485 | EFBIG => return error.FileTooBig, | |
| 486 | EIO => return error.InputOutput, | |
| 487 | EPERM => return error.CannotTruncate, | |
| 488 | ETXTBSY => return error.FileBusy, | |
| 489 | EBADF => unreachable, // Handle not open for writing | |
| 490 | EINVAL => unreachable, // Handle not open for writing | |
| 491 | else => |err| return unexpectedErrno(err), | |
| 492 | } | |
| 493 | } | |
| 494 | } | |
| 495 | ||
| 441 | 496 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. |
| 442 | 497 | /// |
| 443 | 498 | /// Retries when interrupted by a signal. |
lib/std/os/linux.zig+64-2| ... | ... | @@ -350,7 +350,13 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize { |
| 350 | 350 | ); |
| 351 | 351 | } |
| 352 | 352 | } else { |
| 353 | return syscall4(SYS_pread, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset); | |
| 353 | return syscall4( | |
| 354 | SYS_pread, | |
| 355 | @bitCast(usize, @as(isize, fd)), | |
| 356 | @ptrToInt(buf), | |
| 357 | count, | |
| 358 | offset, | |
| 359 | ); | |
| 354 | 360 | } |
| 355 | 361 | } |
| 356 | 362 | |
| ... | ... | @@ -384,8 +390,64 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { |
| 384 | 390 | return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count); |
| 385 | 391 | } |
| 386 | 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 | ||
| 387 | 420 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { |
| 388 | return syscall4(SYS_pwrite, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset); | |
| 421 | if (@hasDecl(@This(), "SYS_pwrite64")) { | |
| 422 | if (require_aligned_register_pair) { | |
| 423 | return syscall6( | |
| 424 | SYS_pwrite64, | |
| 425 | @bitCast(usize, @as(isize, fd)), | |
| 426 | @ptrToInt(buf), | |
| 427 | count, | |
| 428 | 0, | |
| 429 | @truncate(usize, offset), | |
| 430 | @truncate(usize, offset >> 32), | |
| 431 | ); | |
| 432 | } else { | |
| 433 | return syscall5( | |
| 434 | SYS_pwrite64, | |
| 435 | @bitCast(usize, @as(isize, fd)), | |
| 436 | @ptrToInt(buf), | |
| 437 | count, | |
| 438 | @truncate(usize, offset), | |
| 439 | @truncate(usize, offset >> 32), | |
| 440 | ); | |
| 441 | } | |
| 442 | } else { | |
| 443 | return syscall4( | |
| 444 | SYS_pwrite, | |
| 445 | @bitCast(usize, @as(isize, fd)), | |
| 446 | @ptrToInt(buf), | |
| 447 | count, | |
| 448 | offset, | |
| 449 | ); | |
| 450 | } | |
| 389 | 451 | } |
| 390 | 452 | |
| 391 | 453 | pub fn rename(old: [*:0]const u8, new: [*:0]const u8) usize { |
lib/std/os/windows/bits.zig+4| ... | ... | @@ -225,6 +225,10 @@ pub const FILE_POSITION_INFORMATION = extern struct { |
| 225 | 225 | CurrentByteOffset: LARGE_INTEGER, |
| 226 | 226 | }; |
| 227 | 227 | |
| 228 | pub const FILE_END_OF_FILE_INFORMATION = extern struct { | |
| 229 | EndOfFile: LARGE_INTEGER, | |
| 230 | }; | |
| 231 | ||
| 228 | 232 | pub const FILE_MODE_INFORMATION = extern struct { |
| 229 | 233 | Mode: ULONG, |
| 230 | 234 | }; |
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, |
lib/std/os/windows/ntdll.zig+7| ... | ... | @@ -16,6 +16,13 @@ pub extern "NtDll" fn NtQueryInformationFile( |
| 16 | 16 | Length: ULONG, |
| 17 | 17 | FileInformationClass: FILE_INFORMATION_CLASS, |
| 18 | 18 | ) callconv(.Stdcall) NTSTATUS; |
| 19 | pub extern "NtDll" fn NtSetInformationFile( | |
| 20 | FileHandle: HANDLE, | |
| 21 | IoStatusBlock: *IO_STATUS_BLOCK, | |
| 22 | FileInformation: PVOID, | |
| 23 | Length: ULONG, | |
| 24 | FileInformationClass: FILE_INFORMATION_CLASS, | |
| 25 | ) callconv(.Stdcall) NTSTATUS; | |
| 19 | 26 | |
| 20 | 27 | pub extern "NtDll" fn NtQueryAttributesFile( |
| 21 | 28 | ObjectAttributes: *OBJECT_ATTRIBUTES, |