implement os.faccessat for Windows
parent
4b02a39aa9
commit
8173fbfb66
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue