Function CreatePipe [src]

A Zig wrapper around NtCreateNamedPipeFile and NtCreateFile syscalls. It implements similar behavior to CreatePipe and is meant to serve as a direct substitute for that call.

Prototype

pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void

Parameters

rd: *HANDLEwr: *HANDLEsattr: *const SECURITY_ATTRIBUTES

Possible Errors

SystemResources
Unexpected

Source

pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { // Up to NT 5.2 (Windows XP/Server 2003), `CreatePipe` would generate a pipe similar to: // // \??\pipe\Win32Pipes.{pid}.{count} // // where `pid` is the process id and count is a incrementing counter. // The implementation was changed after NT 6.0 (Vista) to open a handle to the Named Pipe File System // and use that as the root directory for `NtCreateNamedPipeFile`. // This object is visible under the NPFS but has no filename attached to it. // // This implementation replicates how `CreatePipe` works in modern Windows versions. const opt_dev_handle = @atomicLoad(?HANDLE, &npfs, .seq_cst); const dev_handle = opt_dev_handle orelse blk: { const str = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\NamedPipe\\"); const len: u16 = @truncate(str.len * @sizeOf(u16)); const name = UNICODE_STRING{ .Length = len, .MaximumLength = len, .Buffer = @constCast(@ptrCast(str)), }; const attrs = OBJECT_ATTRIBUTES{ .ObjectName = @constCast(&name), .Length = @sizeOf(OBJECT_ATTRIBUTES), .RootDirectory = null, .Attributes = 0, .SecurityDescriptor = null, .SecurityQualityOfService = null, }; var iosb: IO_STATUS_BLOCK = undefined; var handle: HANDLE = undefined; switch (ntdll.NtCreateFile( &handle, GENERIC_READ | SYNCHRONIZE, @constCast(&attrs), &iosb, null, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, null, 0, )) { .SUCCESS => {}, // Judging from the ReactOS sources this is technically possible. .INSUFFICIENT_RESOURCES => return error.SystemResources, .INVALID_PARAMETER => unreachable, else => |e| return unexpectedStatus(e), } if (@cmpxchgStrong(?HANDLE, &npfs, null, handle, .seq_cst, .seq_cst)) |xchg| { CloseHandle(handle); break :blk xchg.?; } else break :blk handle; }; const name = UNICODE_STRING{ .Buffer = null, .Length = 0, .MaximumLength = 0 }; var attrs = OBJECT_ATTRIBUTES{ .ObjectName = @constCast(&name), .Length = @sizeOf(OBJECT_ATTRIBUTES), .RootDirectory = dev_handle, .Attributes = OBJ_CASE_INSENSITIVE, .SecurityDescriptor = sattr.lpSecurityDescriptor, .SecurityQualityOfService = null, }; if (sattr.bInheritHandle != 0) attrs.Attributes |= OBJ_INHERIT; // 120 second relative timeout in 100ns units. const default_timeout: LARGE_INTEGER = (-120 * std.time.ns_per_s) / 100; var iosb: IO_STATUS_BLOCK = undefined; var read: HANDLE = undefined; switch (ntdll.NtCreateNamedPipeFile( &read, GENERIC_READ | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attrs, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT, FILE_PIPE_BYTE_STREAM_TYPE, FILE_PIPE_BYTE_STREAM_MODE, FILE_PIPE_QUEUE_OPERATION, 1, 4096, 4096, @constCast(&default_timeout), )) { .SUCCESS => {}, .INVALID_PARAMETER => unreachable, .INSUFFICIENT_RESOURCES => return error.SystemResources, else => |e| return unexpectedStatus(e), } errdefer CloseHandle(read); attrs.RootDirectory = read; var write: HANDLE = undefined; switch (ntdll.NtCreateFile( &write, GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attrs, &iosb, null, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, null, 0, )) { .SUCCESS => {}, .INVALID_PARAMETER => unreachable, .INSUFFICIENT_RESOURCES => return error.SystemResources, else => |e| return unexpectedStatus(e), } rd.* = read; wr.* = write; }