Skip to content

Commit

Permalink
organize windows utility functions
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Oct 14, 2017
1 parent a68dc65 commit 0307dc0
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 109 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -581,6 +581,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_S
install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/error.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/index.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/util.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
Expand Down
117 changes: 8 additions & 109 deletions std/os/index.zig
Expand Up @@ -25,6 +25,14 @@ pub const page_size = 4 * 1024;
pub const UserInfo = @import("get_user_id.zig").UserInfo;
pub const getUserInfo = @import("get_user_id.zig").getUserInfo;

const windows_util = @import("windows/util.zig");
pub const windowsClose = windows_util.windowsClose;
pub const windowsWaitSingle = windows_util.windowsWaitSingle;
pub const windowsWrite = windows_util.windowsWrite;
pub const windowsIsTty = windows_util.windowsIsTty;
pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
pub const windowsOpen = windows_util.windowsOpen;

const debug = @import("../debug.zig");
const assert = debug.assert;

Expand Down Expand Up @@ -162,10 +170,6 @@ pub fn posixClose(fd: i32) {
}
}

pub fn windowsClose(handle: windows.HANDLE) {
assert(windows.CloseHandle(handle));
}

/// Calls POSIX read, and keeps trying if it gets interrupted.
pub fn posixRead(fd: i32, buf: []u8) -> %void {
var index: usize = 0;
Expand Down Expand Up @@ -223,50 +227,6 @@ pub fn posixWrite(fd: i32, bytes: []const u8) -> %void {
}
}

error SystemResources;
error OperationAborted;
error IoPending;
error BrokenPipe;

pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) -> %void {
if (!windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null)) {
return switch (windows.GetLastError()) {
windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,
windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,
windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,
windows.ERROR.IO_PENDING => error.IoPending,
windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
else => error.Unexpected,
};
}
}

pub fn windowsIsTty(handle: windows.HANDLE) -> bool {
if (windowsIsCygwinPty(handle))
return true;

var out: windows.DWORD = undefined;
return windows.GetConsoleMode(handle, &out);
}

pub fn windowsIsCygwinPty(handle: windows.HANDLE) -> bool {
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)))
{
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;
}

/// ::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.
Expand Down Expand Up @@ -322,51 +282,6 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
}
}


error SharingViolation;
error PipeBusy;

/// `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: ?&Allocator) -> %windows.HANDLE
{
var stack_buf: [max_noalloc_path_len]u8 = undefined;
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 = %return a.alloc(u8, file_path.len + 1);
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 => error.SharingViolation,
windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists,
windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
windows.ERROR.ACCESS_DENIED => error.AccessDenied,
windows.ERROR.PIPE_BUSY => error.PipeBusy,
else => error.Unexpected,
};
}

return result;
}

pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
while (true) {
const err = posix.getErrno(posix.dup2(old_fd, new_fd));
Expand Down Expand Up @@ -1394,22 +1309,6 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
assert(it.next(&debug.global_allocator) == null);
}

error WaitAbandoned;
error WaitTimeOut;

pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) -> %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 => switch (windows.GetLastError()) {
else => error.Unexpected,
},
else => error.Unexpected,
};
}

test "std.os" {
_ = @import("child_process.zig");
_ = @import("darwin_errno.zig");
Expand Down
112 changes: 112 additions & 0 deletions std/os/windows/util.zig
@@ -0,0 +1,112 @@
const std = @import("../../index.zig");
const windows = std.os.windows;
const assert = std.debug.assert;
const mem = std.mem;

error WaitAbandoned;
error WaitTimeOut;

pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) -> %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 => switch (windows.GetLastError()) {
else => error.Unexpected,
},
else => error.Unexpected,
};
}

pub fn windowsClose(handle: windows.HANDLE) {
assert(windows.CloseHandle(handle));
}

error SystemResources;
error OperationAborted;
error IoPending;
error BrokenPipe;

pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) -> %void {
if (!windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null)) {
return switch (windows.GetLastError()) {
windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,
windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,
windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,
windows.ERROR.IO_PENDING => error.IoPending,
windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
else => error.Unexpected,
};
}
}

pub fn windowsIsTty(handle: windows.HANDLE) -> bool {
if (windowsIsCygwinPty(handle))
return true;

var out: windows.DWORD = undefined;
return windows.GetConsoleMode(handle, &out);
}

pub fn windowsIsCygwinPty(handle: windows.HANDLE) -> bool {
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)))
{
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;
}

error SharingViolation;
error PipeBusy;

/// `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: ?&Allocator) -> %windows.HANDLE
{
var stack_buf: [max_noalloc_path_len]u8 = undefined;
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 = %return a.alloc(u8, file_path.len + 1);
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 => error.SharingViolation,
windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists,
windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
windows.ERROR.ACCESS_DENIED => error.AccessDenied,
windows.ERROR.PIPE_BUSY => error.PipeBusy,
else => error.Unexpected,
};
}

return result;
}

0 comments on commit 0307dc0

Please sign in to comment.