Merge pull request #4716 from LemonBoy/sys-misc

Introduce std.fs.file.setEndPos
This commit is contained in:
Andrew Kelley 2020-03-13 11:18:08 -04:00 committed by GitHub
commit a9297f2267
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 167 additions and 4 deletions

View File

@ -79,6 +79,7 @@ pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, fla
pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t;
pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int;
pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;
pub extern "c" fn raise(sig: c_int) c_int;
pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize;

View File

@ -82,6 +82,8 @@ pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
pub extern "c" fn sendfile(
out_fd: fd_t,
in_fd: fd_t,

View File

@ -99,6 +99,14 @@ pub const File = struct {
return false;
}
pub const SetEndPosError = os.TruncateError;
/// Shrinks or expands the file.
/// The file offset after this call is left unchanged.
pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
try os.ftruncate(self.handle, length);
}
pub const SeekError = os.SeekError;
/// Repositions read/write file offset relative to the current offset.

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;
@ -125,6 +125,29 @@ test "File seek ops" {
expect((try file.getPos()) == 1234);
}
test "setEndPos" {
const tmp_file_name = "temp_test_file.txt";
var file = try fs.cwd().createFile(tmp_file_name, .{});
defer {
file.close();
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" {
const tmp_file_name = "just_a_temporary_file.txt";
var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true });

View File

@ -438,6 +438,61 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
return index;
}
pub const TruncateError = error{
FileTooBig,
InputOutput,
CannotTruncate,
FileBusy,
} || UnexpectedError;
pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
if (std.Target.current.os.tag == .windows) {
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
var eof_info = windows.FILE_END_OF_FILE_INFORMATION{
.EndOfFile = @bitCast(windows.LARGE_INTEGER, length),
};
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;
}
while (true) {
const rc = if (builtin.link_libc)
if (std.Target.current.os.tag == .linux)
system.ftruncate64(fd, @bitCast(off_t, length))
else
system.ftruncate(fd, @bitCast(off_t, length))
else
system.ftruncate(fd, length);
switch (errno(rc)) {
0 => return,
EINTR => continue,
EFBIG => return error.FileTooBig,
EIO => return error.InputOutput,
EPERM => return error.CannotTruncate,
ETXTBSY => return error.FileBusy,
EBADF => unreachable, // Handle not open for writing
EINVAL => unreachable, // Handle not open for writing
else => |err| return unexpectedErrno(err),
}
}
}
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
///
/// Retries when interrupted by a signal.

View File

@ -350,7 +350,13 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
);
}
} else {
return syscall4(SYS_pread, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
return syscall4(
SYS_pread,
@bitCast(usize, @as(isize, fd)),
@ptrToInt(buf),
count,
offset,
);
}
}
@ -384,8 +390,64 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
}
pub fn ftruncate(fd: i32, length: u64) usize {
if (@hasDecl(@This(), "SYS_ftruncate64")) {
if (require_aligned_register_pair) {
return syscall4(
SYS_ftruncate64,
@bitCast(usize, @as(isize, fd)),
0,
@truncate(usize, length),
@truncate(usize, length >> 32),
);
} else {
return syscall3(
SYS_ftruncate64,
@bitCast(usize, @as(isize, fd)),
@truncate(usize, length),
@truncate(usize, length >> 32),
);
}
} else {
return syscall2(
SYS_ftruncate,
@bitCast(usize, @as(isize, fd)),
@truncate(usize, length),
);
}
}
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
return syscall4(SYS_pwrite, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
if (@hasDecl(@This(), "SYS_pwrite64")) {
if (require_aligned_register_pair) {
return syscall6(
SYS_pwrite64,
@bitCast(usize, @as(isize, fd)),
@ptrToInt(buf),
count,
0,
@truncate(usize, offset),
@truncate(usize, offset >> 32),
);
} else {
return syscall5(
SYS_pwrite64,
@bitCast(usize, @as(isize, fd)),
@ptrToInt(buf),
count,
@truncate(usize, offset),
@truncate(usize, offset >> 32),
);
}
} else {
return syscall4(
SYS_pwrite,
@bitCast(usize, @as(isize, fd)),
@ptrToInt(buf),
count,
offset,
);
}
}
pub fn rename(old: [*:0]const u8, new: [*:0]const u8) usize {

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

@ -8,6 +8,7 @@ pub extern "kernel32" fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) c
pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn SetEndOfFile(hFile: HANDLE) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn CreateEventExW(
lpEventAttributes: ?*SECURITY_ATTRIBUTES,

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,