| 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,6 +79,7 @@ pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, fla |
| 79 | pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t; | 79 | pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t; |
| 80 | pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int; | 80 | pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int; |
| 81 | pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int; | 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 | pub extern "c" fn raise(sig: c_int) c_int; | 83 | pub extern "c" fn raise(sig: c_int) c_int; |
| 83 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; | 84 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; |
| 84 | pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize; | 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,6 +82,8 @@ pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; |
| 82 | 82 | ||
| 83 | pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int; | 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 | pub extern "c" fn sendfile( | 87 | pub extern "c" fn sendfile( |
| 86 | out_fd: fd_t, | 88 | out_fd: fd_t, |
| 87 | in_fd: fd_t, | 89 | in_fd: fd_t, |
lib/std/fs/file.zig+8| ... | @@ -99,6 +99,14 @@ pub const File = struct { | ... | @@ -99,6 +99,14 @@ pub const File = struct { |
| 99 | return false; | 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 | pub const SeekError = os.SeekError; | 110 | pub const SeekError = os.SeekError; |
| 103 | 111 | ||
| 104 | /// Repositions read/write file offset relative to the current offset. | 112 | /// Repositions read/write file offset relative to the current offset. |
lib/std/io/test.zig+25-2| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const std = @import("std"); |
| 2 | const std = @import("../std.zig"); | 2 | const builtin = std.builtin; |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const meta = std.meta; | 4 | const meta = std.meta; |
| 5 | const trait = std.trait; | 5 | const trait = std.trait; |
| ... | @@ -125,6 +125,29 @@ test "File seek ops" { | ... | @@ -125,6 +125,29 @@ test "File seek ops" { |
| 125 | expect((try file.getPos()) == 1234); | 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 | test "updateTimes" { | 151 | test "updateTimes" { |
| 129 | const tmp_file_name = "just_a_temporary_file.txt"; | 152 | const tmp_file_name = "just_a_temporary_file.txt"; |
| 130 | var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true }); | 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,6 +438,61 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 438 | return index; | 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 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. | 496 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. |
| 442 | /// | 497 | /// |
| 443 | /// Retries when interrupted by a signal. | 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,7 +350,13 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize { |
| 350 | ); | 350 | ); |
| 351 | } | 351 | } |
| 352 | } else { | 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,8 +390,64 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { |
| 384 | return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count); | 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 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { | 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 | pub fn rename(old: [*:0]const u8, new: [*:0]const u8) usize { | 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,6 +225,10 @@ pub const FILE_POSITION_INFORMATION = extern struct { |
| 225 | CurrentByteOffset: LARGE_INTEGER, | 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 | pub const FILE_MODE_INFORMATION = extern struct { | 232 | pub const FILE_MODE_INFORMATION = extern struct { |
| 229 | Mode: ULONG, | 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,6 +8,7 @@ pub extern "kernel32" fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) c |
| 8 | pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL; | 8 | pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL; |
| 9 | 9 | ||
| 10 | pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) callconv(.Stdcall) BOOL; | 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 | pub extern "kernel32" fn CreateEventExW( | 13 | pub extern "kernel32" fn CreateEventExW( |
| 13 | lpEventAttributes: ?*SECURITY_ATTRIBUTES, | 14 | lpEventAttributes: ?*SECURITY_ATTRIBUTES, |
lib/std/os/windows/ntdll.zig+7| ... | @@ -16,6 +16,13 @@ pub extern "NtDll" fn NtQueryInformationFile( | ... | @@ -16,6 +16,13 @@ pub extern "NtDll" fn NtQueryInformationFile( |
| 16 | Length: ULONG, | 16 | Length: ULONG, |
| 17 | FileInformationClass: FILE_INFORMATION_CLASS, | 17 | FileInformationClass: FILE_INFORMATION_CLASS, |
| 18 | ) callconv(.Stdcall) NTSTATUS; | 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 | pub extern "NtDll" fn NtQueryAttributesFile( | 27 | pub extern "NtDll" fn NtQueryAttributesFile( |
| 21 | ObjectAttributes: *OBJECT_ATTRIBUTES, | 28 | ObjectAttributes: *OBJECT_ATTRIBUTES, |