authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-13 11:18:08-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-03-13 11:18:08-04:00
loga9297f22671dff800821ff940395411f2adb8582
tree5e1ed7fb4538dc0195bb7caa9dfe3c0c0a79c41c
parent5dd3c8eed65c020a5c5672ee595b16120b3dc431
parentde53537f10e22cc003cfbc77468349b758470f24
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4716 from LemonBoy/sys-misc

Introduce std.fs.file.setEndPos

9 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
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 left unchanged.
106 pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
107 try os.ftruncate(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+25-2
......@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const std = @import("../std.zig");
1const std = @import("std");
2const builtin = std.builtin;
33const io = std.io;
44const meta = std.meta;
55const trait = std.trait;
......@@ -125,6 +125,29 @@ 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 // 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
128151test "updateTimes" {
129152 const tmp_file_name = "just_a_temporary_file.txt";
130153 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 {
438438 return index;
439439}
440440
441pub const TruncateError = error{
442 FileTooBig,
443 InputOutput,
444 CannotTruncate,
445 FileBusy,
446} || UnexpectedError;
447
448pub 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
441496/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
442497///
443498/// 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 {
350350 );
351351 }
352352 } 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 );
354360 }
355361}
356362
......@@ -384,8 +390,64 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
384390 return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
385391}
386392
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
387420pub 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 }
389451}
390452
391453pub 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 {
225225 CurrentByteOffset: LARGE_INTEGER,
226226};
227227
228pub const FILE_END_OF_FILE_INFORMATION = extern struct {
229 EndOfFile: LARGE_INTEGER,
230};
231
228232pub const FILE_MODE_INFORMATION = extern struct {
229233 Mode: ULONG,
230234};
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,
lib/std/os/windows/ntdll.zig+7
......@@ -16,6 +16,13 @@ pub extern "NtDll" fn NtQueryInformationFile(
1616 Length: ULONG,
1717 FileInformationClass: FILE_INFORMATION_CLASS,
1818) callconv(.Stdcall) NTSTATUS;
19pub 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;
1926
2027pub extern "NtDll" fn NtQueryAttributesFile(
2128 ObjectAttributes: *OBJECT_ATTRIBUTES,