authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-11 20:56:43+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-12 09:43:45+01:00
log11df0d0cf8c786d5b502c21a42d47631657a42f4
treeb860be3c40159ad2ea9c41f44c3873d1b29e33bb
parent89d7fc773d66609a8d93106f9a6d84d479771690

std: Add setEndPos to fs.file

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
7979pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t;
8080pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int;
8181pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
82pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;
8283pub extern "c" fn raise(sig: c_int) c_int;
8384pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
8485pub 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;
8282
8383pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
8484
85pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
86
8587pub extern "c" fn sendfile(
8688 out_fd: fd_t,
8789 in_fd: fd_t,
lib/std/fs/file.zig+8
......@@ -99,6 +99,14 @@ pub const File = struct {
9999 return false;
100100 }
101101
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
102110 pub const SeekError = os.SeekError;
103111
104112 /// Repositions read/write file offset relative to the current offset.
lib/std/io/test.zig+17
......@@ -125,6 +125,23 @@ test "File seek ops" {
125125 expect((try file.getPos()) == 1234);
126126}
127127
128test "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
128145test "updateTimes" {
129146 const tmp_file_name = "just_a_temporary_file.txt";
130147 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 {
438438 return index;
439439}
440440
441pub const TruncateError = error{
442 /// The file descriptor is not open for writing.
443 NotFile,
444} || UnexpectedError;
445
446pub 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
441474/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
442475///
443476/// 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 {
390390 return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
391391}
392392
393pub 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
393420pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
394421 if (@hasDecl(@This(), "SYS_pwrite64")) {
395422 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
88pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL;
99
1010pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) callconv(.Stdcall) BOOL;
11pub extern "kernel32" fn SetEndOfFile(hFile: HANDLE) callconv(.Stdcall) BOOL;
1112
1213pub extern "kernel32" fn CreateEventExW(
1314 lpEventAttributes: ?*SECURITY_ATTRIBUTES,