zig/std/os/windows/util.zig

191 lines
6.3 KiB
Zig
Raw Normal View History

2017-10-15 04:59:43 +08:00
const std = @import("../../index.zig");
const builtin = @import("builtin");
const os = std.os;
2017-10-15 04:59:43 +08:00
const windows = std.os.windows;
const assert = std.debug.assert;
const mem = std.mem;
const BufMap = std.BufMap;
const cstr = std.cstr;
2017-10-15 04:59:43 +08:00
2018-02-09 13:24:23 +08:00
pub const WaitError = error {
WaitAbandoned,
WaitTimeOut,
Unexpected,
};
pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
2017-10-15 04:59:43 +08:00
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),
};
2017-10-15 04:59:43 +08:00
},
else => error.Unexpected,
};
}
pub fn windowsClose(handle: windows.HANDLE) void {
assert(windows.CloseHandle(handle) != 0);
2017-10-15 04:59:43 +08:00
}
pub const WriteError = error {
SystemResources,
OperationAborted,
IoPending,
BrokenPipe,
Unexpected,
};
pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
windows.ERROR.IO_PENDING => WriteError.IoPending,
windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
else => os.unexpectedErrorWindows(err),
2017-10-15 04:59:43 +08:00
};
}
}
pub fn windowsIsTty(handle: windows.HANDLE) bool {
2017-10-15 04:59:43 +08:00
if (windowsIsCygwinPty(handle))
return true;
var out: windows.DWORD = undefined;
return windows.GetConsoleMode(handle, &out) != 0;
2017-10-15 04:59:43 +08:00
}
pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
2017-10-15 04:59:43 +08:00
const size = @sizeOf(windows.FILE_NAME_INFO);
var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
if (windows.GetFileInformationByHandleEx(handle, windows.FileNameInfo,
@ptrCast(&c_void, &name_info_bytes[0]), u32(name_info_bytes.len)) == 0)
2017-10-15 04:59:43 +08:00
{
return true;
}
const name_info = @ptrCast(&const windows.FILE_NAME_INFO, &name_info_bytes[0]);
const name_bytes = name_info_bytes[size..size + usize(name_info.FileNameLength)];
const name_wide = ([]u16)(name_bytes);
return mem.indexOf(u16, name_wide, []u16{'m','s','y','s','-'}) != null or
mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;
}
pub const OpenError = error {
SharingViolation,
PathAlreadyExists,
FileNotFound,
AccessDenied,
PipeBusy,
Unexpected,
2018-02-08 15:08:45 +08:00
OutOfMemory,
NameTooLong,
};
2017-10-15 04:59:43 +08:00
/// `file_path` may need to be copied in memory to add a null terminating byte. In this case
/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,
creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator)
OpenError!windows.HANDLE
2017-10-15 04:59:43 +08:00
{
var stack_buf: [os.max_noalloc_path_len]u8 = undefined;
2017-10-15 04:59:43 +08:00
var path0: []u8 = undefined;
var need_free = false;
defer if (need_free) (??allocator).free(path0);
if (file_path.len < stack_buf.len) {
path0 = stack_buf[0..file_path.len + 1];
} else if (allocator) |a| {
path0 = try a.alloc(u8, file_path.len + 1);
2017-10-15 04:59:43 +08:00
need_free = true;
} else {
return error.NameTooLong;
}
mem.copy(u8, path0, file_path);
path0[file_path.len] = 0;
const result = windows.CreateFileA(path0.ptr, desired_access, share_mode, null, creation_disposition,
flags_and_attrs, null);
if (result == windows.INVALID_HANDLE_VALUE) {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation,
windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists,
windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound,
windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied,
windows.ERROR.PIPE_BUSY => OpenError.PipeBusy,
else => os.unexpectedErrorWindows(err),
2017-10-15 04:59:43 +08:00
};
}
return result;
}
/// Caller must free result.
2018-02-01 11:48:40 +08:00
pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) ![]u8 {
// count bytes needed
const bytes_needed = x: {
var bytes_needed: usize = 1; // 1 for the final null byte
var it = env_map.iterator();
while (it.next()) |pair| {
// +1 for '='
// +1 for null byte
bytes_needed += pair.key.len + pair.value.len + 2;
}
break :x bytes_needed;
};
const result = try allocator.alloc(u8, bytes_needed);
errdefer allocator.free(result);
var it = env_map.iterator();
var i: usize = 0;
while (it.next()) |pair| {
mem.copy(u8, result[i..], pair.key);
i += pair.key.len;
result[i] = '=';
i += 1;
mem.copy(u8, result[i..], pair.value);
i += pair.value.len;
result[i] = 0;
i += 1;
}
result[i] = 0;
return result;
}
2018-02-01 11:48:40 +08:00
pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) !windows.HMODULE {
const padded_buff = try cstr.addNullByte(allocator, dll_path);
defer allocator.free(padded_buff);
return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
}
pub fn windowsUnloadDll(hModule: windows.HMODULE) void {
assert(windows.FreeLibrary(hModule)!= 0);
}
test "InvalidDll" {
if (builtin.os != builtin.Os.windows) return;
const DllName = "asdf.dll";
const allocator = std.debug.global_allocator;
const handle = os.windowsLoadDll(allocator, DllName) catch |err| {
assert(err == error.DllNotFound);
return;
};
}