Add NtDll-based ftruncate implementation

This commit is contained in:
LemonBoy 2020-03-12 22:46:12 +01:00
parent bd0b51477a
commit de53537f10
5 changed files with 40 additions and 7 deletions

View File

@ -102,7 +102,7 @@ pub const File = struct {
pub const SetEndPosError = os.TruncateError;
/// Shrinks or expands the file.
/// The file offset after this call is undefined.
/// The file offset after this call is left unchanged.
pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
try os.ftruncate(self.handle, length);
}

View File

@ -1,5 +1,5 @@
const builtin = @import("builtin");
const std = @import("../std.zig");
const std = @import("std");
const builtin = std.builtin;
const io = std.io;
const meta = std.meta;
const trait = std.trait;
@ -133,13 +133,19 @@ test "setEndPos" {
fs.cwd().deleteFile(tmp_file_name) catch {};
}
// Verify that the file size changes and the file offset is not moved
std.testing.expect((try file.getEndPos()) == 0);
std.testing.expect((try file.getPos()) == 0);
try file.setEndPos(8192);
std.testing.expect((try file.getEndPos()) == 8192);
std.testing.expect((try file.getPos()) == 0);
try file.seekTo(100);
try file.setEndPos(4096);
std.testing.expect((try file.getEndPos()) == 4096);
std.testing.expect((try file.getPos()) == 100);
try file.setEndPos(0);
std.testing.expect((try file.getEndPos()) == 0);
std.testing.expect((try file.getPos()) == 100);
}
test "updateTimes" {

View File

@ -447,10 +447,25 @@ pub const TruncateError = error{
pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
if (std.Target.current.os.tag == .windows) {
try windows.SetFilePointerEx_BEGIN(fd, length);
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
var eof_info = windows.FILE_END_OF_FILE_INFORMATION{
.EndOfFile = @bitCast(windows.LARGE_INTEGER, length),
};
if (windows.kernel32.SetEndOfFile(fd) == 0)
return TruncateError.Unexpected;
const rc = windows.ntdll.NtSetInformationFile(
fd,
&io_status_block,
&eof_info,
@sizeOf(windows.FILE_END_OF_FILE_INFORMATION),
.FileEndOfFileInformation,
);
switch (rc) {
.SUCCESS => {},
.INVALID_HANDLE => unreachable, // Handle not open for writing
.ACCESS_DENIED => return error.CannotTruncate,
else => return windows.unexpectedStatus(rc),
}
return;
}
@ -471,7 +486,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
EIO => return error.InputOutput,
EPERM => return error.CannotTruncate,
ETXTBSY => return error.FileBusy,
EBADF, EINVAL => unreachable,
EBADF => unreachable, // Handle not open for writing
EINVAL => unreachable, // Handle not open for writing
else => |err| return unexpectedErrno(err),
}
}

View File

@ -225,6 +225,10 @@ pub const FILE_POSITION_INFORMATION = extern struct {
CurrentByteOffset: LARGE_INTEGER,
};
pub const FILE_END_OF_FILE_INFORMATION = extern struct {
EndOfFile: LARGE_INTEGER,
};
pub const FILE_MODE_INFORMATION = extern struct {
Mode: ULONG,
};

View File

@ -16,6 +16,13 @@ pub extern "NtDll" fn NtQueryInformationFile(
Length: ULONG,
FileInformationClass: FILE_INFORMATION_CLASS,
) callconv(.Stdcall) NTSTATUS;
pub extern "NtDll" fn NtSetInformationFile(
FileHandle: HANDLE,
IoStatusBlock: *IO_STATUS_BLOCK,
FileInformation: PVOID,
Length: ULONG,
FileInformationClass: FILE_INFORMATION_CLASS,
) callconv(.Stdcall) NTSTATUS;
pub extern "NtDll" fn NtQueryAttributesFile(
ObjectAttributes: *OBJECT_ATTRIBUTES,