67726e36b0
See #2380
150 lines
5.2 KiB
Zig
150 lines
5.2 KiB
Zig
const std = @import("../../std.zig");
|
|
const builtin = @import("builtin");
|
|
const os = std.os;
|
|
const unicode = std.unicode;
|
|
const windows = std.os.windows;
|
|
const assert = std.debug.assert;
|
|
const mem = std.mem;
|
|
const BufMap = std.BufMap;
|
|
const cstr = std.cstr;
|
|
|
|
pub const WaitError = error{
|
|
WaitAbandoned,
|
|
WaitTimeOut,
|
|
|
|
/// See https://github.com/ziglang/zig/issues/1396
|
|
Unexpected,
|
|
};
|
|
|
|
pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
|
|
const result = windows.WaitForSingleObject(handle, milliseconds);
|
|
return switch (result) {
|
|
windows.WAIT_ABANDONED => error.WaitAbandoned,
|
|
windows.WAIT_OBJECT_0 => {},
|
|
windows.WAIT_TIMEOUT => error.WaitTimeOut,
|
|
windows.WAIT_FAILED => x: {
|
|
const err = windows.GetLastError();
|
|
break :x switch (err) {
|
|
else => os.unexpectedErrorWindows(err),
|
|
};
|
|
},
|
|
else => error.Unexpected,
|
|
};
|
|
}
|
|
|
|
/// Caller must free result.
|
|
pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
|
|
// count bytes needed
|
|
const max_chars_needed = x: {
|
|
var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
|
|
var it = env_map.iterator();
|
|
while (it.next()) |pair| {
|
|
// +1 for '='
|
|
// +1 for null byte
|
|
max_chars_needed += pair.key.len + pair.value.len + 2;
|
|
}
|
|
break :x max_chars_needed;
|
|
};
|
|
const result = try allocator.alloc(u16, max_chars_needed);
|
|
errdefer allocator.free(result);
|
|
|
|
var it = env_map.iterator();
|
|
var i: usize = 0;
|
|
while (it.next()) |pair| {
|
|
i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
|
|
result[i] = '=';
|
|
i += 1;
|
|
i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
|
|
result[i] = 0;
|
|
i += 1;
|
|
}
|
|
result[i] = 0;
|
|
i += 1;
|
|
result[i] = 0;
|
|
i += 1;
|
|
result[i] = 0;
|
|
i += 1;
|
|
result[i] = 0;
|
|
i += 1;
|
|
return allocator.shrink(result, i);
|
|
}
|
|
|
|
pub fn windowsFindFirstFile(
|
|
dir_path: []const u8,
|
|
find_file_data: *windows.WIN32_FIND_DATAW,
|
|
) !windows.HANDLE {
|
|
const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
|
|
const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
|
|
|
|
if (handle == windows.INVALID_HANDLE_VALUE) {
|
|
const err = windows.GetLastError();
|
|
switch (err) {
|
|
windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
|
|
windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
|
|
else => return os.unexpectedErrorWindows(err),
|
|
}
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
/// Returns `true` if there was another file, `false` otherwise.
|
|
pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool {
|
|
if (windows.FindNextFileW(handle, find_file_data) == 0) {
|
|
const err = windows.GetLastError();
|
|
return switch (err) {
|
|
windows.ERROR.NO_MORE_FILES => false,
|
|
else => os.unexpectedErrorWindows(err),
|
|
};
|
|
}
|
|
return true;
|
|
}
|
|
|
|
pub const WindowsCreateIoCompletionPortError = error{Unexpected};
|
|
|
|
pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE {
|
|
const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
|
|
const err = windows.GetLastError();
|
|
switch (err) {
|
|
windows.ERROR.INVALID_PARAMETER => unreachable,
|
|
else => return os.unexpectedErrorWindows(err),
|
|
}
|
|
};
|
|
return handle;
|
|
}
|
|
|
|
pub const WindowsPostQueuedCompletionStatusError = error{Unexpected};
|
|
|
|
pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void {
|
|
if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
|
|
const err = windows.GetLastError();
|
|
switch (err) {
|
|
else => return os.unexpectedErrorWindows(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub const WindowsWaitResult = enum {
|
|
Normal,
|
|
Aborted,
|
|
Cancelled,
|
|
EOF,
|
|
};
|
|
|
|
pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
|
|
if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) {
|
|
const err = windows.GetLastError();
|
|
switch (err) {
|
|
windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted,
|
|
windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled,
|
|
windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF,
|
|
else => {
|
|
if (std.debug.runtime_safety) {
|
|
std.debug.panic("unexpected error: {}\n", err);
|
|
}
|
|
},
|
|
}
|
|
}
|
|
return WindowsWaitResult.Normal;
|
|
}
|