implement os.faccessat for Windows

master
Andrew Kelley 2020-02-16 17:10:43 -05:00
parent 4b02a39aa9
commit 8173fbfb66
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 65 additions and 14 deletions

View File

@ -109,13 +109,13 @@ pub fn Batch(
test "std.event.Batch" {
var count: usize = 0;
var batch = Batch(void, 2).init();
var batch = Batch(void, 2, .auto_async).init();
batch.add(&async sleepALittle(&count));
batch.add(&async increaseByTen(&count));
batch.wait();
testing.expect(count == 11);
var another = Batch(anyerror!void, 2).init();
var another = Batch(anyerror!void, 2, .auto_async).init();
another.add(&async somethingElse());
another.add(&async doSomethingThatFails());
testing.expectError(error.ItBroke, another.wait());

View File

@ -818,6 +818,13 @@ pub const Dir = struct {
) File.OpenError!File {
const w = os.windows;
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
return error.IsDir;
}
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
return error.IsDir;
}
var result = File{
.handle = undefined,
.io_mode = .blocking,
@ -839,12 +846,6 @@ pub const Dir = struct {
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
return error.IsDir;
}
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
return error.IsDir;
}
var io: w.IO_STATUS_BLOCK = undefined;
const rc = w.ntdll.NtCreateFile(
&result.handle,
@ -1332,12 +1333,20 @@ pub const Dir = struct {
/// For example, instead of testing if a file exists and then opening it, just
/// open it and handle the error for file not found.
pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
if (builtin.os == .windows) {
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
return self.accessW(&sub_path_w, flags);
}
const path_c = try os.toPosixPath(sub_path);
return self.accessZ(&path_c, flags);
}
/// Same as `access` except the path parameter is null-terminated.
pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
if (builtin.os == .windows) {
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
return self.accessW(&sub_path_w, flags);
}
const os_mode = if (flags.write and flags.read)
@as(u32, os.R_OK | os.W_OK)
else if (flags.write)
@ -1351,9 +1360,13 @@ pub const Dir = struct {
return result;
}
/// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
pub fn accessW(self: Dir, sub_path: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
return os.faccessatW(self.fd, sub_path, 0, 0);
/// Same as `access` except asserts the target OS is Windows and the path parameter is
/// * WTF-16 encoded
/// * null-terminated
/// * NtDll prefixed
/// TODO currently this ignores `flags`.
pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
return os.faccessatW(self.fd, sub_path_w, 0, 0);
}
};

View File

@ -2553,10 +2553,42 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces
}
/// Same as `faccessat` except asserts the target is Windows and the path parameter
/// is null-terminated WTF-16 encoded.
/// is NtDll-prefixed, null-terminated, WTF-16 encoded.
/// TODO currently this ignores `mode` and `flags`
pub fn faccessatW(dirfd: fd_t, path: [*:0]const u16, mode: u32, flags: u32) AccessError!void {
@compileError("TODO implement faccessatW on Windows");
pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void {
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
return;
}
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
return;
}
const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
error.Overflow => return error.NameTooLong,
};
var nt_name = windows.UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
};
var attr = windows.OBJECT_ATTRIBUTES{
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd,
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
.ObjectName = &nt_name,
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
var basic_info: windows.FILE_BASIC_INFORMATION = undefined;
switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) {
.SUCCESS => return,
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
.INVALID_PARAMETER => unreachable,
.ACCESS_DENIED => return error.PermissionDenied,
.OBJECT_PATH_SYNTAX_BAD => unreachable,
else => |rc| return windows.unexpectedStatus(rc),
}
}
pub const PipeError = error{

View File

@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile(
Length: ULONG,
FileInformationClass: FILE_INFORMATION_CLASS,
) callconv(.Stdcall) NTSTATUS;
pub extern "NtDll" fn NtQueryAttributesFile(
ObjectAttributes: *OBJECT_ATTRIBUTES,
FileAttributes: *FILE_BASIC_INFORMATION,
) callconv(.Stdcall) NTSTATUS;
pub extern "NtDll" fn NtCreateFile(
FileHandle: *HANDLE,
DesiredAccess: ACCESS_MASK,