authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-12 22:46:12+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-13 08:45:37+01:00
logde53537f10e22cc003cfbc77468349b758470f24
tree8d8685fa2ec6d44ea0b73be7a719da990a7f5663
parentbd0b51477a6cb0dc7ea7739f61a70110d39ba601

Add NtDll-based ftruncate implementation


5 files changed, 40 insertions(+), 7 deletions(-)

lib/std/fs/file.zig+1-1
...@@ -102,7 +102,7 @@ pub const File = struct {...@@ -102,7 +102,7 @@ pub const File = struct {
102 pub const SetEndPosError = os.TruncateError;102 pub const SetEndPosError = os.TruncateError;
103103
104 /// Shrinks or expands the file.104 /// Shrinks or expands the file.
105 /// The file offset after this call is undefined.105 /// The file offset after this call is left unchanged.
106 pub fn setEndPos(self: File, length: u64) SetEndPosError!void {106 pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
107 try os.ftruncate(self.handle, length);107 try os.ftruncate(self.handle, length);
108 }108 }
lib/std/io/test.zig+8-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const std = @import("std");
2const std = @import("../std.zig");2const builtin = std.builtin;
3const io = std.io;3const io = std.io;
4const meta = std.meta;4const meta = std.meta;
5const trait = std.trait;5const trait = std.trait;
...@@ -133,13 +133,19 @@ test "setEndPos" {...@@ -133,13 +133,19 @@ test "setEndPos" {
133 fs.cwd().deleteFile(tmp_file_name) catch {};133 fs.cwd().deleteFile(tmp_file_name) catch {};
134 }134 }
135135
136 // Verify that the file size changes and the file offset is not moved
136 std.testing.expect((try file.getEndPos()) == 0);137 std.testing.expect((try file.getEndPos()) == 0);
138 std.testing.expect((try file.getPos()) == 0);
137 try file.setEndPos(8192);139 try file.setEndPos(8192);
138 std.testing.expect((try file.getEndPos()) == 8192);140 std.testing.expect((try file.getEndPos()) == 8192);
141 std.testing.expect((try file.getPos()) == 0);
142 try file.seekTo(100);
139 try file.setEndPos(4096);143 try file.setEndPos(4096);
140 std.testing.expect((try file.getEndPos()) == 4096);144 std.testing.expect((try file.getEndPos()) == 4096);
145 std.testing.expect((try file.getPos()) == 100);
141 try file.setEndPos(0);146 try file.setEndPos(0);
142 std.testing.expect((try file.getEndPos()) == 0);147 std.testing.expect((try file.getEndPos()) == 0);
148 std.testing.expect((try file.getPos()) == 100);
143}149}
144150
145test "updateTimes" {151test "updateTimes" {
lib/std/os.zig+20-4
...@@ -447,10 +447,25 @@ pub const TruncateError = error{...@@ -447,10 +447,25 @@ pub const TruncateError = error{
447447
448pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {448pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
449 if (std.Target.current.os.tag == .windows) {449 if (std.Target.current.os.tag == .windows) {
450 try windows.SetFilePointerEx_BEGIN(fd, length);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 );
451462
452 if (windows.kernel32.SetEndOfFile(fd) == 0)463 switch (rc) {
453 return TruncateError.Unexpected;464 .SUCCESS => {},
465 .INVALID_HANDLE => unreachable, // Handle not open for writing
466 .ACCESS_DENIED => return error.CannotTruncate,
467 else => return windows.unexpectedStatus(rc),
468 }
454469
455 return;470 return;
456 }471 }
...@@ -471,7 +486,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -471,7 +486,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
471 EIO => return error.InputOutput,486 EIO => return error.InputOutput,
472 EPERM => return error.CannotTruncate,487 EPERM => return error.CannotTruncate,
473 ETXTBSY => return error.FileBusy,488 ETXTBSY => return error.FileBusy,
474 EBADF, EINVAL => unreachable,489 EBADF => unreachable, // Handle not open for writing
490 EINVAL => unreachable, // Handle not open for writing
475 else => |err| return unexpectedErrno(err),491 else => |err| return unexpectedErrno(err),
476 }492 }
477 }493 }
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};
227227
228pub const FILE_END_OF_FILE_INFORMATION = extern struct {
229 EndOfFile: LARGE_INTEGER,
230};
231
228pub const FILE_MODE_INFORMATION = extern struct {232pub const FILE_MODE_INFORMATION = extern struct {
229 Mode: ULONG,233 Mode: ULONG,
230};234};
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;
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
20pub extern "NtDll" fn NtQueryAttributesFile(27pub extern "NtDll" fn NtQueryAttributesFile(
21 ObjectAttributes: *OBJECT_ATTRIBUTES,28 ObjectAttributes: *OBJECT_ATTRIBUTES,