fs.Dir.openDir: use empty object name for "." on Windows

master
Andrew Kelley 2019-10-21 19:17:33 -04:00
parent ef67c49785
commit 87f632b08a
6 changed files with 40 additions and 7 deletions

View File

@ -630,5 +630,8 @@ set_target_properties(zig PROPERTIES
LINK_FLAGS ${EXE_LDFLAGS} LINK_FLAGS ${EXE_LDFLAGS}
) )
target_link_libraries(zig compiler "${LIBUSERLAND}") target_link_libraries(zig compiler "${LIBUSERLAND}")
if(MSVC)
target_link_libraries(zig ntdll.lib)
endif()
add_dependencies(zig zig_build_libuserland) add_dependencies(zig zig_build_libuserland)
install(TARGETS zig DESTINATION bin) install(TARGETS zig DESTINATION bin)

View File

@ -590,6 +590,7 @@ pub const Dir = struct {
self.end_index = io.Information; self.end_index = io.Information;
switch (rc) { switch (rc) {
w.STATUS.SUCCESS => {}, w.STATUS.SUCCESS => {},
w.STATUS.ACCESS_DENIED => return error.AccessDenied,
else => return w.unexpectedStatus(rc), else => return w.unexpectedStatus(rc),
} }
} }
@ -708,7 +709,7 @@ pub const Dir = struct {
/// Call `close` on the result when done. /// Call `close` on the result when done.
pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir {
std.debug.warn("openDir {}\n", sub_path); // std.debug.warn("openDir {}\n", sub_path);
if (os.windows.is_the_target) { if (os.windows.is_the_target) {
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
return self.openDirW(&sub_path_w); return self.openDirW(&sub_path_w);
@ -740,9 +741,26 @@ pub const Dir = struct {
/// This function is Windows-only. /// This function is Windows-only.
pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir { pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir {
const w = os.windows; const w = os.windows;
var result = Dir{ var result = Dir{
.fd = undefined, .fd = undefined,
}; };
const desired_access = w.GENERIC_READ | w.SYNCHRONIZE;
// if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
// // Windows gives me STATUS_OBJECT_NAME_INVALID with "." as the object name.
// if (w.kernel32.DuplicateHandle(w.self_process_handle, self.fd, w.self_process_handle, &result.fd, desired_access, w.TRUE, 0) == 0) {
// switch (w.kernel32.GetLastError()) {
// else => |err| return w.unexpectedError(err),
// }
// @panic("handle DuplicateHandle error");
// }
// return result;
// }
//var mask: ?[*]const u16 = undefined; //var mask: ?[*]const u16 = undefined;
//var nt_name: w.UNICODE_STRING = undefined; //var nt_name: w.UNICODE_STRING = undefined;
//if (w.ntdll.RtlDosPathNameToNtPathName_U(sub_path_w, &nt_name, null, null) == 0) { //if (w.ntdll.RtlDosPathNameToNtPathName_U(sub_path_w, &nt_name, null, null) == 0) {
@ -760,7 +778,7 @@ pub const Dir = struct {
//} //}
const path_len_bytes = @intCast(u16, mem.toSliceConst(u16, sub_path_w).len * 2); const path_len_bytes = @intCast(u16, mem.toSliceConst(u16, sub_path_w).len * 2);
std.debug.warn("path_len_bytes = {}\n", path_len_bytes); // std.debug.warn("path_len_bytes = {}\n", path_len_bytes);
var nt_name = w.UNICODE_STRING{ var nt_name = w.UNICODE_STRING{
.Length = path_len_bytes, .Length = path_len_bytes,
.MaximumLength = path_len_bytes, .MaximumLength = path_len_bytes,
@ -774,7 +792,11 @@ pub const Dir = struct {
.SecurityDescriptor = null, .SecurityDescriptor = null,
.SecurityQualityOfService = null, .SecurityQualityOfService = null,
}; };
std.debug.warn("RootDirectory = {}\n", attr.RootDirectory); if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
// Windows does not recognize this, but it does work with empty string.
nt_name.Length = 0;
}
// std.debug.warn("RootDirectory = {}\n", attr.RootDirectory);
var io: w.IO_STATUS_BLOCK = undefined; var io: w.IO_STATUS_BLOCK = undefined;
const wide_slice = nt_name.Buffer[0 .. nt_name.Length / 2]; const wide_slice = nt_name.Buffer[0 .. nt_name.Length / 2];
//const wide_slice2 = std.mem.toSliceConst(u16, mask.?); //const wide_slice2 = std.mem.toSliceConst(u16, mask.?);
@ -782,11 +804,11 @@ pub const Dir = struct {
//var buf2: [200]u8 = undefined; //var buf2: [200]u8 = undefined;
const len = std.unicode.utf16leToUtf8(&buf, wide_slice) catch unreachable; const len = std.unicode.utf16leToUtf8(&buf, wide_slice) catch unreachable;
//const len2 = std.unicode.utf16leToUtf8(&buf2, wide_slice2) catch unreachable; //const len2 = std.unicode.utf16leToUtf8(&buf2, wide_slice2) catch unreachable;
std.debug.warn("path: {}\n", buf[0..len]); // std.debug.warn("path: {}\n", buf[0..len]);
//std.debug.warn("path: {}\nmask: {}\n", buf[0..len], buf2[0..len2]); //std.debug.warn("path: {}\nmask: {}\n", buf[0..len], buf2[0..len2]);
const rc = w.ntdll.NtCreateFile( const rc = w.ntdll.NtCreateFile(
&result.fd, &result.fd,
w.GENERIC_READ | w.SYNCHRONIZE, desired_access,
&attr, &attr,
&io, &io,
null, null,
@ -797,11 +819,12 @@ pub const Dir = struct {
null, null,
0, 0,
); );
std.debug.warn("result.fd = {}\n", result.fd); // std.debug.warn("result.fd = {}\n", result.fd);
switch (rc) { switch (rc) {
w.STATUS.SUCCESS => return result, w.STATUS.SUCCESS => return result,
w.STATUS.OBJECT_NAME_INVALID => @panic("openDirW invalid object name"), w.STATUS.OBJECT_NAME_INVALID => @panic("openDirW invalid object name"),
w.STATUS.OBJECT_NAME_NOT_FOUND => return error.FileNotFound, w.STATUS.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
w.STATUS.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
w.STATUS.INVALID_PARAMETER => { w.STATUS.INVALID_PARAMETER => {
@panic("invalid parameter"); @panic("invalid parameter");
}, },

View File

@ -20,6 +20,8 @@ pub const shell32 = @import("windows/shell32.zig");
pub usingnamespace @import("windows/bits.zig"); pub usingnamespace @import("windows/bits.zig");
pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));
/// `builtin` is missing `subsystem` when the subsystem is automatically detected, /// `builtin` is missing `subsystem` when the subsystem is automatically detected,
/// so Zig standard library has the subsystem detection logic here. This should generally be /// so Zig standard library has the subsystem detection logic here. This should generally be
/// used rather than `builtin.subsystem`. /// used rather than `builtin.subsystem`.
@ -898,7 +900,7 @@ pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
/// and you get an unexpected status. /// and you get an unexpected status.
pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError { pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
if (std.os.unexpected_error_tracing) { if (std.os.unexpected_error_tracing) {
std.debug.warn("error.Unexpected NTSTATUS={}\n", status); std.debug.warn("error.Unexpected NTSTATUS=0x{x}\n", status);
std.debug.dumpCurrentStackTrace(null); std.debug.dumpCurrentStackTrace(null);
} }
return error.Unexpected; return error.Unexpected;

View File

@ -872,3 +872,5 @@ pub const CURDIR = extern struct {
DosPath: UNICODE_STRING, DosPath: UNICODE_STRING,
Handle: HANDLE, Handle: HANDLE,
}; };
pub const DUPLICATE_SAME_ACCESS = 2;

View File

@ -47,6 +47,8 @@ pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_
pub extern "kernel32" stdcallcc fn DeleteFileW(lpFileName: [*]const u16) BOOL; pub extern "kernel32" stdcallcc fn DeleteFileW(lpFileName: [*]const u16) BOOL;
pub extern "kernel32" stdcallcc fn DuplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, lpTargetHandle: *HANDLE, dwDesiredAccess: DWORD, bInheritHandle: BOOL, dwOptions: DWORD) BOOL;
pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn; pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFindFileData: *WIN32_FIND_DATAW) HANDLE; pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFindFileData: *WIN32_FIND_DATAW) HANDLE;

View File

@ -8,4 +8,5 @@ pub const INVALID_PARAMETER = 0xC000000D;
pub const ACCESS_DENIED = 0xC0000022; pub const ACCESS_DENIED = 0xC0000022;
pub const OBJECT_NAME_INVALID = 0xC0000033; pub const OBJECT_NAME_INVALID = 0xC0000033;
pub const OBJECT_NAME_NOT_FOUND = 0xC0000034; pub const OBJECT_NAME_NOT_FOUND = 0xC0000034;
pub const OBJECT_PATH_NOT_FOUND = 0xC000003A;
pub const OBJECT_PATH_SYNTAX_BAD = 0xC000003B; pub const OBJECT_PATH_SYNTAX_BAD = 0xC000003B;