| author | |
| committer | |
| log | 1badb2a840c47d49b49fa685db7a1553c0a40ee7 |
| tree | 2c76cac07cb70044f199d3174deda145f3b4cc9d |
| parent | 305fd06756d0a90e330c957d85738f195b94bc10 |
8 files changed, 305 insertions(+), 132 deletions(-)
lib/std/Io/Dir.zig+3-3| ... | @@ -12,6 +12,8 @@ const Allocator = std.mem.Allocator; | ... | @@ -12,6 +12,8 @@ const Allocator = std.mem.Allocator; |
| 12 | 12 | ||
| 13 | handle: Handle, | 13 | handle: Handle, |
| 14 | 14 | ||
| 15 | pub const Handle = std.posix.fd_t; | ||
| 16 | |||
| 15 | pub const path = std.fs.path; | 17 | pub const path = std.fs.path; |
| 16 | 18 | ||
| 17 | /// The maximum length of a file path that the operating system will accept. | 19 | /// The maximum length of a file path that the operating system will accept. |
| ... | @@ -396,8 +398,6 @@ pub fn walk(dir: Dir, allocator: Allocator) Allocator.Error!Walker { | ... | @@ -396,8 +398,6 @@ pub fn walk(dir: Dir, allocator: Allocator) Allocator.Error!Walker { |
| 396 | return .{ .inner = try walkSelectively(dir, allocator) }; | 398 | return .{ .inner = try walkSelectively(dir, allocator) }; |
| 397 | } | 399 | } |
| 398 | 400 | ||
| 399 | pub const Handle = std.posix.fd_t; | ||
| 400 | |||
| 401 | pub const PathNameError = error{ | 401 | pub const PathNameError = error{ |
| 402 | /// Returned when an insufficient buffer is provided that cannot fit the | 402 | /// Returned when an insufficient buffer is provided that cannot fit the |
| 403 | /// path name. | 403 | /// path name. |
| ... | @@ -1698,7 +1698,7 @@ pub fn copyFile( | ... | @@ -1698,7 +1698,7 @@ pub fn copyFile( |
| 1698 | options: CopyFileOptions, | 1698 | options: CopyFileOptions, |
| 1699 | ) CopyFileError!void { | 1699 | ) CopyFileError!void { |
| 1700 | const file = try source_dir.openFile(io, source_path, .{}); | 1700 | const file = try source_dir.openFile(io, source_path, .{}); |
| 1701 | var file_reader: File.Reader = .init(.{ .handle = file.handle }, io, &.{}); | 1701 | var file_reader: File.Reader = .init(file, io, &.{}); |
| 1702 | defer file_reader.file.close(io); | 1702 | defer file_reader.file.close(io); |
| 1703 | 1703 | ||
| 1704 | const permissions = options.permissions orelse blk: { | 1704 | const permissions = options.permissions orelse blk: { |
lib/std/Io/File.zig+26-4| ... | @@ -11,13 +11,14 @@ const Dir = std.Io.Dir; | ... | @@ -11,13 +11,14 @@ const Dir = std.Io.Dir; |
| 11 | 11 | ||
| 12 | handle: Handle, | 12 | handle: Handle, |
| 13 | 13 | ||
| 14 | pub const Handle = std.posix.fd_t; | ||
| 15 | |||
| 14 | pub const Reader = @import("File/Reader.zig"); | 16 | pub const Reader = @import("File/Reader.zig"); |
| 15 | pub const Writer = @import("File/Writer.zig"); | 17 | pub const Writer = @import("File/Writer.zig"); |
| 16 | pub const Atomic = @import("File/Atomic.zig"); | 18 | pub const Atomic = @import("File/Atomic.zig"); |
| 17 | /// Memory intended to remain consistent with file contents. | 19 | /// Memory intended to remain consistent with file contents. |
| 18 | pub const MemoryMap = @import("File/MemoryMap.zig"); | 20 | pub const MemoryMap = @import("File/MemoryMap.zig"); |
| 19 | 21 | ||
| 20 | pub const Handle = std.posix.fd_t; | ||
| 21 | pub const INode = std.posix.ino_t; | 22 | pub const INode = std.posix.ino_t; |
| 22 | pub const NLink = std.posix.nlink_t; | 23 | pub const NLink = std.posix.nlink_t; |
| 23 | pub const Uid = std.posix.uid_t; | 24 | pub const Uid = std.posix.uid_t; |
| ... | @@ -73,15 +74,36 @@ pub const Stat = struct { | ... | @@ -73,15 +74,36 @@ pub const Stat = struct { |
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | pub fn stdout() File { | 76 | pub fn stdout() File { |
| 76 | return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdOutput else std.posix.STDOUT_FILENO }; | 77 | return switch (native_os) { |
| 78 | .windows => .{ | ||
| 79 | .handle = std.os.windows.peb().ProcessParameters.hStdOutput, | ||
| 80 | }, | ||
| 81 | else => .{ | ||
| 82 | .handle = std.posix.STDOUT_FILENO, | ||
| 83 | }, | ||
| 84 | }; | ||
| 77 | } | 85 | } |
| 78 | 86 | ||
| 79 | pub fn stderr() File { | 87 | pub fn stderr() File { |
| 80 | return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdError else std.posix.STDERR_FILENO }; | 88 | return switch (native_os) { |
| 89 | .windows => .{ | ||
| 90 | .handle = std.os.windows.peb().ProcessParameters.hStdError, | ||
| 91 | }, | ||
| 92 | else => .{ | ||
| 93 | .handle = std.posix.STDERR_FILENO, | ||
| 94 | }, | ||
| 95 | }; | ||
| 81 | } | 96 | } |
| 82 | 97 | ||
| 83 | pub fn stdin() File { | 98 | pub fn stdin() File { |
| 84 | return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO }; | 99 | return switch (native_os) { |
| 100 | .windows => .{ | ||
| 101 | .handle = std.os.windows.peb().ProcessParameters.hStdInput, | ||
| 102 | }, | ||
| 103 | else => .{ | ||
| 104 | .handle = std.posix.STDIN_FILENO, | ||
| 105 | }, | ||
| 106 | }; | ||
| 85 | } | 107 | } |
| 86 | 108 | ||
| 87 | pub const StatError = error{ | 109 | pub const StatError = error{ |
lib/std/Io/File/Writer.zig+1-1| ... | @@ -101,7 +101,7 @@ pub fn moveToReader(w: *Writer) File.Reader { | ... | @@ -101,7 +101,7 @@ pub fn moveToReader(w: *Writer) File.Reader { |
| 101 | defer w.* = undefined; | 101 | defer w.* = undefined; |
| 102 | return .{ | 102 | return .{ |
| 103 | .io = w.io, | 103 | .io = w.io, |
| 104 | .file = .{ .handle = w.file.handle }, | 104 | .file = w.file, |
| 105 | .mode = w.mode, | 105 | .mode = w.mode, |
| 106 | .pos = w.pos, | 106 | .pos = w.pos, |
| 107 | .interface = File.Reader.initInterface(w.interface.buffer), | 107 | .interface = File.Reader.initInterface(w.interface.buffer), |
lib/std/Io/Threaded.zig+153-76| ... | @@ -571,7 +571,7 @@ const Future = struct { | ... | @@ -571,7 +571,7 @@ const Future = struct { |
| 571 | num_completed: *std.atomic.Value(u32), | 571 | num_completed: *std.atomic.Value(u32), |
| 572 | thread: ?*Thread, | 572 | thread: ?*Thread, |
| 573 | ) void { | 573 | ) void { |
| 574 | var need_signal: bool = thread != null and thread.?.cancelAwaitable(.fromFuture(future)); | 574 | var need_signal: bool = if (thread) |th| th.cancelAwaitable(.fromFuture(future)) else false; |
| 575 | var timeout_ns: u64 = 1 << 10; | 575 | var timeout_ns: u64 = 1 << 10; |
| 576 | while (true) { | 576 | while (true) { |
| 577 | need_signal = need_signal and thread.?.signalCanceledSyscall(t, .fromFuture(future)); | 577 | need_signal = need_signal and thread.?.signalCanceledSyscall(t, .fromFuture(future)); |
| ... | @@ -628,7 +628,7 @@ const Thread = struct { | ... | @@ -628,7 +628,7 @@ const Thread = struct { |
| 628 | 628 | ||
| 629 | const Handle = Handle: { | 629 | const Handle = Handle: { |
| 630 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; | 630 | if (std.Thread.use_pthreads) break :Handle std.c.pthread_t; |
| 631 | if (builtin.target.os.tag == .windows) break :Handle windows.HANDLE; | 631 | if (is_windows) break :Handle windows.HANDLE; |
| 632 | break :Handle void; | 632 | break :Handle void; |
| 633 | }; | 633 | }; |
| 634 | 634 | ||
| ... | @@ -1364,7 +1364,7 @@ fn worker(t: *Threaded) void { | ... | @@ -1364,7 +1364,7 @@ fn worker(t: *Threaded) void { |
| 1364 | .id = std.Thread.getCurrentId(), | 1364 | .id = std.Thread.getCurrentId(), |
| 1365 | .handle = handle: { | 1365 | .handle = handle: { |
| 1366 | if (std.Thread.use_pthreads) break :handle std.c.pthread_self(); | 1366 | if (std.Thread.use_pthreads) break :handle std.c.pthread_self(); |
| 1367 | if (builtin.target.os.tag == .windows) break :handle undefined; // populated below | 1367 | if (is_windows) break :handle undefined; // populated below |
| 1368 | }, | 1368 | }, |
| 1369 | .status = .init(.{ | 1369 | .status = .init(.{ |
| 1370 | .cancelation = .none, | 1370 | .cancelation = .none, |
| ... | @@ -1376,7 +1376,7 @@ fn worker(t: *Threaded) void { | ... | @@ -1376,7 +1376,7 @@ fn worker(t: *Threaded) void { |
| 1376 | }; | 1376 | }; |
| 1377 | Thread.current = &thread; | 1377 | Thread.current = &thread; |
| 1378 | 1378 | ||
| 1379 | if (builtin.target.os.tag == .windows) { | 1379 | if (is_windows) { |
| 1380 | assert(windows.ntdll.NtOpenThread( | 1380 | assert(windows.ntdll.NtOpenThread( |
| 1381 | &thread.handle, | 1381 | &thread.handle, |
| 1382 | .{ | 1382 | .{ |
| ... | @@ -1397,7 +1397,7 @@ fn worker(t: *Threaded) void { | ... | @@ -1397,7 +1397,7 @@ fn worker(t: *Threaded) void { |
| 1397 | &windows.teb().ClientId, | 1397 | &windows.teb().ClientId, |
| 1398 | ) == .SUCCESS); | 1398 | ) == .SUCCESS); |
| 1399 | } | 1399 | } |
| 1400 | defer if (builtin.target.os.tag == .windows) { | 1400 | defer if (is_windows) { |
| 1401 | windows.CloseHandle(thread.handle); | 1401 | windows.CloseHandle(thread.handle); |
| 1402 | }; | 1402 | }; |
| 1403 | 1403 | ||
| ... | @@ -3430,53 +3430,133 @@ fn dirCreateFileWindows( | ... | @@ -3430,53 +3430,133 @@ fn dirCreateFileWindows( |
| 3430 | sub_path: []const u8, | 3430 | sub_path: []const u8, |
| 3431 | flags: File.CreateFlags, | 3431 | flags: File.CreateFlags, |
| 3432 | ) File.OpenError!File { | 3432 | ) File.OpenError!File { |
| 3433 | const w = windows; | ||
| 3434 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 3433 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3435 | _ = t; | 3434 | _ = t; |
| 3436 | 3435 | ||
| 3437 | const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path); | 3436 | if (std.mem.eql(u8, sub_path, ".")) return error.IsDir; |
| 3437 | if (std.mem.eql(u8, sub_path, "..")) return error.IsDir; | ||
| 3438 | |||
| 3439 | const sub_path_w_array = try windows.sliceToPrefixedFileW(dir.handle, sub_path); | ||
| 3438 | const sub_path_w = sub_path_w_array.span(); | 3440 | const sub_path_w = sub_path_w_array.span(); |
| 3441 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; | ||
| 3439 | 3442 | ||
| 3440 | const handle = handle: { | 3443 | var nt_name: windows.UNICODE_STRING = .{ |
| 3441 | const syscall: Syscall = try .start(); | 3444 | .Length = path_len_bytes, |
| 3442 | while (true) { | 3445 | .MaximumLength = path_len_bytes, |
| 3443 | if (w.OpenFile(sub_path_w, .{ | 3446 | .Buffer = @constCast(sub_path_w.ptr), |
| 3444 | .dir = dir.handle, | ||
| 3445 | .access_mask = .{ | ||
| 3446 | .STANDARD = .{ .SYNCHRONIZE = true }, | ||
| 3447 | .GENERIC = .{ | ||
| 3448 | .WRITE = true, | ||
| 3449 | .READ = flags.read, | ||
| 3450 | }, | ||
| 3451 | }, | ||
| 3452 | .creation = if (flags.exclusive) | ||
| 3453 | .CREATE | ||
| 3454 | else if (flags.truncate) | ||
| 3455 | .OVERWRITE_IF | ||
| 3456 | else | ||
| 3457 | .OPEN_IF, | ||
| 3458 | })) |handle| { | ||
| 3459 | syscall.finish(); | ||
| 3460 | break :handle handle; | ||
| 3461 | } else |err| switch (err) { | ||
| 3462 | error.OperationCanceled => { | ||
| 3463 | try syscall.checkCancel(); | ||
| 3464 | continue; | ||
| 3465 | }, | ||
| 3466 | else => |e| return syscall.fail(e), | ||
| 3467 | } | ||
| 3468 | } | ||
| 3469 | }; | 3447 | }; |
| 3470 | errdefer w.CloseHandle(handle); | 3448 | const attr: windows.OBJECT_ATTRIBUTES = .{ |
| 3449 | .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), | ||
| 3450 | .RootDirectory = if (Dir.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle, | ||
| 3451 | .Attributes = .{ | ||
| 3452 | .INHERIT = false, | ||
| 3453 | }, | ||
| 3454 | .ObjectName = &nt_name, | ||
| 3455 | .SecurityDescriptor = null, | ||
| 3456 | .SecurityQualityOfService = null, | ||
| 3457 | }; | ||
| 3458 | const create_disposition: windows.FILE.CREATE_DISPOSITION = if (flags.exclusive) | ||
| 3459 | .CREATE | ||
| 3460 | else if (flags.truncate) | ||
| 3461 | .OVERWRITE_IF | ||
| 3462 | else | ||
| 3463 | .OPEN_IF; | ||
| 3464 | |||
| 3465 | const access_mask: windows.ACCESS_MASK = .{ | ||
| 3466 | .STANDARD = .{ .SYNCHRONIZE = true }, | ||
| 3467 | .GENERIC = .{ | ||
| 3468 | .WRITE = true, | ||
| 3469 | .READ = flags.read, | ||
| 3470 | }, | ||
| 3471 | }; | ||
| 3472 | |||
| 3473 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; | ||
| 3474 | |||
| 3475 | // There are multiple kernel bugs being worked around with retries. | ||
| 3476 | const max_attempts = 13; | ||
| 3477 | var attempt: u5 = 0; | ||
| 3478 | |||
| 3479 | var handle: windows.HANDLE = undefined; | ||
| 3480 | var syscall: Syscall = try .start(); | ||
| 3481 | while (true) switch (windows.ntdll.NtCreateFile( | ||
| 3482 | &handle, | ||
| 3483 | access_mask, | ||
| 3484 | &attr, | ||
| 3485 | &io_status_block, | ||
| 3486 | null, | ||
| 3487 | .{ .NORMAL = true }, | ||
| 3488 | .VALID_FLAGS, // share access | ||
| 3489 | create_disposition, | ||
| 3490 | .{ | ||
| 3491 | .NON_DIRECTORY_FILE = true, | ||
| 3492 | .IO = .SYNCHRONOUS_NONALERT, | ||
| 3493 | }, | ||
| 3494 | null, | ||
| 3495 | 0, | ||
| 3496 | )) { | ||
| 3497 | .SUCCESS => { | ||
| 3498 | syscall.finish(); | ||
| 3499 | break; | ||
| 3500 | }, | ||
| 3501 | .CANCELLED => { | ||
| 3502 | try syscall.checkCancel(); | ||
| 3503 | continue; | ||
| 3504 | }, | ||
| 3505 | .SHARING_VIOLATION => { | ||
| 3506 | // This occurs if the file attempting to be opened is a running | ||
| 3507 | // executable. However, there's a kernel bug: the error may be | ||
| 3508 | // incorrectly returned for an indeterminate amount of time | ||
| 3509 | // after an executable file is closed. Here we work around the | ||
| 3510 | // kernel bug with retry attempts. | ||
| 3511 | syscall.finish(); | ||
| 3512 | if (max_attempts - attempt == 0) return error.SharingViolation; | ||
| 3513 | try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1); | ||
| 3514 | attempt += 1; | ||
| 3515 | syscall = try .start(); | ||
| 3516 | continue; | ||
| 3517 | }, | ||
| 3518 | .DELETE_PENDING => { | ||
| 3519 | // This error means that there *was* a file in this location on | ||
| 3520 | // the file system, but it was deleted. However, the OS is not | ||
| 3521 | // finished with the deletion operation, and so this CreateFile | ||
| 3522 | // call has failed. Here, we simulate the kernel bug being | ||
| 3523 | // fixed by sleeping and retrying until the error goes away. | ||
| 3524 | syscall.finish(); | ||
| 3525 | if (max_attempts - attempt == 0) return error.SharingViolation; | ||
| 3526 | try parking_sleep.windowsRetrySleep((@as(u32, 1) << attempt) >> 1); | ||
| 3527 | attempt += 1; | ||
| 3528 | syscall = try .start(); | ||
| 3529 | continue; | ||
| 3530 | }, | ||
| 3531 | .OBJECT_NAME_INVALID => return syscall.fail(error.BadPathName), | ||
| 3532 | .OBJECT_NAME_NOT_FOUND => return syscall.fail(error.FileNotFound), | ||
| 3533 | .OBJECT_PATH_NOT_FOUND => return syscall.fail(error.FileNotFound), | ||
| 3534 | .BAD_NETWORK_PATH => return syscall.fail(error.NetworkNotFound), // \\server was not found | ||
| 3535 | .BAD_NETWORK_NAME => return syscall.fail(error.NetworkNotFound), // \\server was found but \\server\share wasn't | ||
| 3536 | .NO_MEDIA_IN_DEVICE => return syscall.fail(error.NoDevice), | ||
| 3537 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | ||
| 3538 | .PIPE_BUSY => return syscall.fail(error.PipeBusy), | ||
| 3539 | .PIPE_NOT_AVAILABLE => return syscall.fail(error.NoDevice), | ||
| 3540 | .OBJECT_NAME_COLLISION => return syscall.fail(error.PathAlreadyExists), | ||
| 3541 | .FILE_IS_A_DIRECTORY => return syscall.fail(error.IsDir), | ||
| 3542 | .NOT_A_DIRECTORY => return syscall.fail(error.NotDir), | ||
| 3543 | .USER_MAPPED_FILE => return syscall.fail(error.AccessDenied), | ||
| 3544 | .VIRUS_INFECTED, .VIRUS_DELETED => return syscall.fail(error.AntivirusInterference), | ||
| 3545 | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), | ||
| 3546 | .OBJECT_PATH_SYNTAX_BAD => |err| return syscall.ntstatusBug(err), | ||
| 3547 | .INVALID_HANDLE => |err| return syscall.ntstatusBug(err), | ||
| 3548 | else => |err| return syscall.unexpectedNtstatus(err), | ||
| 3549 | }; | ||
| 3550 | errdefer windows.CloseHandle(handle); | ||
| 3471 | 3551 | ||
| 3472 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | ||
| 3473 | const exclusive = switch (flags.lock) { | 3552 | const exclusive = switch (flags.lock) { |
| 3474 | .none => return .{ .handle = handle }, | 3553 | .none => return .{ .handle = handle }, |
| 3475 | .shared => false, | 3554 | .shared => false, |
| 3476 | .exclusive => true, | 3555 | .exclusive => true, |
| 3477 | }; | 3556 | }; |
| 3478 | const syscall: Syscall = try .start(); | 3557 | |
| 3479 | while (true) switch (w.ntdll.NtLockFile( | 3558 | syscall = try .start(); |
| 3559 | while (true) switch (windows.ntdll.NtLockFile( | ||
| 3480 | handle, | 3560 | handle, |
| 3481 | null, | 3561 | null, |
| 3482 | null, | 3562 | null, |
| ... | @@ -3968,7 +4048,10 @@ pub fn dirOpenFileWtf16( | ... | @@ -3968,7 +4048,10 @@ pub fn dirOpenFileWtf16( |
| 3968 | var attr: w.OBJECT_ATTRIBUTES = .{ | 4048 | var attr: w.OBJECT_ATTRIBUTES = .{ |
| 3969 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), | 4049 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), |
| 3970 | .RootDirectory = dir_handle, | 4050 | .RootDirectory = dir_handle, |
| 3971 | .Attributes = .{}, | 4051 | .Attributes = .{ |
| 4052 | // TODO should we set INHERIT=false? | ||
| 4053 | //.INHERIT = false, | ||
| 4054 | }, | ||
| 3972 | .ObjectName = &nt_name, | 4055 | .ObjectName = &nt_name, |
| 3973 | .SecurityDescriptor = null, | 4056 | .SecurityDescriptor = null, |
| 3974 | .SecurityQualityOfService = null, | 4057 | .SecurityQualityOfService = null, |
| ... | @@ -7923,15 +8006,14 @@ fn fileClose(userdata: ?*anyopaque, files: []const File) void { | ... | @@ -7923,15 +8006,14 @@ fn fileClose(userdata: ?*anyopaque, files: []const File) void { |
| 7923 | for (files) |file| posix.close(file.handle); | 8006 | for (files) |file| posix.close(file.handle); |
| 7924 | } | 8007 | } |
| 7925 | 8008 | ||
| 7926 | const fileReadStreaming = switch (native_os) { | 8009 | fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize { |
| 7927 | .windows => fileReadStreamingWindows, | ||
| 7928 | else => fileReadStreamingPosix, | ||
| 7929 | }; | ||
| 7930 | |||
| 7931 | fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize { | ||
| 7932 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 8010 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 7933 | _ = t; | 8011 | _ = t; |
| 8012 | if (is_windows) return fileReadStreamingWindows(file, data); | ||
| 8013 | return fileReadStreamingPosix(file, data); | ||
| 8014 | } | ||
| 7934 | 8015 | ||
| 8016 | fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usize { | ||
| 7935 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; | 8017 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| 7936 | var i: usize = 0; | 8018 | var i: usize = 0; |
| 7937 | for (data) |buf| { | 8019 | for (data) |buf| { |
| ... | @@ -8013,10 +8095,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8) | ... | @@ -8013,10 +8095,7 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: File, data: []const []u8) |
| 8013 | } | 8095 | } |
| 8014 | } | 8096 | } |
| 8015 | 8097 | ||
| 8016 | fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize { | 8098 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { |
| 8017 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | ||
| 8018 | _ = t; | ||
| 8019 | |||
| 8020 | const DWORD = windows.DWORD; | 8099 | const DWORD = windows.DWORD; |
| 8021 | var index: usize = 0; | 8100 | var index: usize = 0; |
| 8022 | while (index < data.len and data[index].len == 0) index += 1; | 8101 | while (index < data.len and data[index].len == 0) index += 1; |
| ... | @@ -8059,10 +8138,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u | ... | @@ -8059,10 +8138,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: File, data: []const []u |
| 8059 | } | 8138 | } |
| 8060 | } | 8139 | } |
| 8061 | 8140 | ||
| 8062 | fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { | 8141 | fn fileReadPositionalPosix(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| 8063 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | ||
| 8064 | _ = t; | ||
| 8065 | |||
| 8066 | if (!have_preadv) @compileError("TODO implement fileReadPositionalPosix for cursed operating systems that don't support preadv (it's only Haiku)"); | 8142 | if (!have_preadv) @compileError("TODO implement fileReadPositionalPosix for cursed operating systems that don't support preadv (it's only Haiku)"); |
| 8067 | 8143 | ||
| 8068 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; | 8144 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| ... | @@ -8144,15 +8220,14 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8 | ... | @@ -8144,15 +8220,14 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: File, data: []const []u8 |
| 8144 | } | 8220 | } |
| 8145 | } | 8221 | } |
| 8146 | 8222 | ||
| 8147 | const fileReadPositional = switch (native_os) { | 8223 | fn fileReadPositional(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { |
| 8148 | .windows => fileReadPositionalWindows, | ||
| 8149 | else => fileReadPositionalPosix, | ||
| 8150 | }; | ||
| 8151 | |||
| 8152 | fn fileReadPositionalWindows(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { | ||
| 8153 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 8224 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8154 | _ = t; | 8225 | _ = t; |
| 8226 | if (is_windows) return fileReadPositionalWindows(file, data, offset); | ||
| 8227 | return fileReadPositionalPosix(file, data, offset); | ||
| 8228 | } | ||
| 8155 | 8229 | ||
| 8230 | fn fileReadPositionalWindows(file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize { | ||
| 8156 | var index: usize = 0; | 8231 | var index: usize = 0; |
| 8157 | while (index < data.len and data[index].len == 0) index += 1; | 8232 | while (index < data.len and data[index].len == 0) index += 1; |
| 8158 | if (index == data.len) return 0; | 8233 | if (index == data.len) return 0; |
| ... | @@ -8244,7 +8319,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi | ... | @@ -8244,7 +8319,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi |
| 8244 | } | 8319 | } |
| 8245 | } | 8320 | } |
| 8246 | 8321 | ||
| 8247 | if (native_os == .windows) { | 8322 | if (is_windows) { |
| 8248 | const syscall: Syscall = try .start(); | 8323 | const syscall: Syscall = try .start(); |
| 8249 | while (true) { | 8324 | while (true) { |
| 8250 | if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) { | 8325 | if (windows.kernel32.SetFilePointerEx(fd, offset, null, windows.FILE_CURRENT) != 0) { |
| ... | @@ -8329,7 +8404,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi | ... | @@ -8329,7 +8404,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 8329 | _ = t; | 8404 | _ = t; |
| 8330 | const fd = file.handle; | 8405 | const fd = file.handle; |
| 8331 | 8406 | ||
| 8332 | if (native_os == .windows) { | 8407 | if (is_windows) { |
| 8333 | // "The starting point is zero or the beginning of the file. If [FILE_BEGIN] | 8408 | // "The starting point is zero or the beginning of the file. If [FILE_BEGIN] |
| 8334 | // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value." | 8409 | // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value." |
| 8335 | // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex | 8410 | // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex |
| ... | @@ -11628,7 +11703,7 @@ fn netWriteWindows( | ... | @@ -11628,7 +11703,7 @@ fn netWriteWindows( |
| 11628 | splat: usize, | 11703 | splat: usize, |
| 11629 | ) net.Stream.Writer.Error!usize { | 11704 | ) net.Stream.Writer.Error!usize { |
| 11630 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 11705 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 11631 | comptime assert(native_os == .windows); | 11706 | comptime assert(is_windows); |
| 11632 | 11707 | ||
| 11633 | var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined; | 11708 | var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined; |
| 11634 | var len: u32 = 0; | 11709 | var len: u32 = 0; |
| ... | @@ -11896,7 +11971,7 @@ fn netInterfaceNameResolve( | ... | @@ -11896,7 +11971,7 @@ fn netInterfaceNameResolve( |
| 11896 | } | 11971 | } |
| 11897 | } | 11972 | } |
| 11898 | 11973 | ||
| 11899 | if (native_os == .windows) { | 11974 | if (is_windows) { |
| 11900 | try Thread.checkCancel(); | 11975 | try Thread.checkCancel(); |
| 11901 | @panic("TODO implement netInterfaceNameResolve for Windows"); | 11976 | @panic("TODO implement netInterfaceNameResolve for Windows"); |
| 11902 | } | 11977 | } |
| ... | @@ -11930,7 +12005,7 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa | ... | @@ -11930,7 +12005,7 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa |
| 11930 | @panic("TODO implement netInterfaceName for linux"); | 12005 | @panic("TODO implement netInterfaceName for linux"); |
| 11931 | } | 12006 | } |
| 11932 | 12007 | ||
| 11933 | if (native_os == .windows) { | 12008 | if (is_windows) { |
| 11934 | @panic("TODO implement netInterfaceName for windows"); | 12009 | @panic("TODO implement netInterfaceName for windows"); |
| 11935 | } | 12010 | } |
| 11936 | 12011 | ||
| ... | @@ -15247,11 +15322,13 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { | ... | @@ -15247,11 +15322,13 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File { |
| 15247 | 15322 | ||
| 15248 | const int = try t.environ.zig_progress_handle; | 15323 | const int = try t.environ.zig_progress_handle; |
| 15249 | 15324 | ||
| 15250 | return .{ .handle = switch (@typeInfo(Io.File.Handle)) { | 15325 | return .{ |
| 15251 | .int => int, | 15326 | .handle = switch (@typeInfo(Io.File.Handle)) { |
| 15252 | .pointer => @ptrFromInt(int), | 15327 | .int => int, |
| 15253 | else => return error.UnsupportedOperation, | 15328 | .pointer => @ptrFromInt(int), |
| 15254 | } }; | 15329 | else => return error.UnsupportedOperation, |
| 15330 | }, | ||
| 15331 | }; | ||
| 15255 | } | 15332 | } |
| 15256 | 15333 | ||
| 15257 | pub fn environString(t: *Threaded, comptime name: []const u8) ?[:0]const u8 { | 15334 | pub fn environString(t: *Threaded, comptime name: []const u8) ?[:0]const u8 { |
| ... | @@ -15562,13 +15639,13 @@ test { | ... | @@ -15562,13 +15639,13 @@ test { |
| 15562 | _ = @import("Threaded/test.zig"); | 15639 | _ = @import("Threaded/test.zig"); |
| 15563 | } | 15640 | } |
| 15564 | 15641 | ||
| 15565 | const use_parking_futex = switch (builtin.target.os.tag) { | 15642 | const use_parking_futex = switch (native_os) { |
| 15566 | .windows => true, // RtlWaitOnAddress is a userland implementation anyway | 15643 | .windows => true, // RtlWaitOnAddress is a userland implementation anyway |
| 15567 | .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now. | 15644 | .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now. |
| 15568 | .illumos => true, // Illumos has no futex mechanism | 15645 | .illumos => true, // Illumos has no futex mechanism |
| 15569 | else => false, | 15646 | else => false, |
| 15570 | }; | 15647 | }; |
| 15571 | const use_parking_sleep = switch (builtin.target.os.tag) { | 15648 | const use_parking_sleep = switch (native_os) { |
| 15572 | // On Windows, we can implement sleep either with `NtDelayExecution` (which is how `SleepEx` in | 15649 | // On Windows, we can implement sleep either with `NtDelayExecution` (which is how `SleepEx` in |
| 15573 | // kernel32 works) or `NtWaitForAlertByThreadId` (thread parking). We're already using the | 15650 | // kernel32 works) or `NtWaitForAlertByThreadId` (thread parking). We're already using the |
| 15574 | // latter for futex, so we may as well use it for sleeping too, to maximise code reuse. I'm | 15651 | // latter for futex, so we may as well use it for sleeping too, to maximise code reuse. I'm |
| ... | @@ -15926,7 +16003,7 @@ const parking_sleep = struct { | ... | @@ -15926,7 +16003,7 @@ const parking_sleep = struct { |
| 15926 | /// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation. | 16003 | /// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation. |
| 15927 | fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void { | 16004 | fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) error{Timeout}!void { |
| 15928 | comptime assert(use_parking_futex or use_parking_sleep); | 16005 | comptime assert(use_parking_futex or use_parking_sleep); |
| 15929 | switch (builtin.target.os.tag) { | 16006 | switch (native_os) { |
| 15930 | .windows => { | 16007 | .windows => { |
| 15931 | var timeout_buf: windows.LARGE_INTEGER = undefined; | 16008 | var timeout_buf: windows.LARGE_INTEGER = undefined; |
| 15932 | const raw_timeout: ?*windows.LARGE_INTEGER = if (opt_deadline) |deadline| timeout: { | 16009 | const raw_timeout: ?*windows.LARGE_INTEGER = if (opt_deadline) |deadline| timeout: { |
| ... | @@ -15980,7 +16057,7 @@ fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) err | ... | @@ -15980,7 +16057,7 @@ fn park(opt_deadline: ?std.Io.Clock.Timestamp, addr_hint: ?*const anyopaque) err |
| 15980 | } | 16057 | } |
| 15981 | } | 16058 | } |
| 15982 | 16059 | ||
| 15983 | const UnparkTid = switch (builtin.target.os.tag) { | 16060 | const UnparkTid = switch (native_os) { |
| 15984 | // `NtAlertMultipleThreadByThreadId` is weird and wants 64-bit thread handles? | 16061 | // `NtAlertMultipleThreadByThreadId` is weird and wants 64-bit thread handles? |
| 15985 | .windows => usize, | 16062 | .windows => usize, |
| 15986 | else => std.Thread.Id, | 16063 | else => std.Thread.Id, |
| ... | @@ -15988,7 +16065,7 @@ const UnparkTid = switch (builtin.target.os.tag) { | ... | @@ -15988,7 +16065,7 @@ const UnparkTid = switch (builtin.target.os.tag) { |
| 15988 | /// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation. | 16065 | /// `addr_hint` has no semantic effect, but may allow the OS to optimize this operation. |
| 15989 | fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void { | 16066 | fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void { |
| 15990 | comptime assert(use_parking_futex or use_parking_sleep); | 16067 | comptime assert(use_parking_futex or use_parking_sleep); |
| 15991 | switch (builtin.target.os.tag) { | 16068 | switch (native_os) { |
| 15992 | .windows => { | 16069 | .windows => { |
| 15993 | // TODO: this condition is currently disabled because mingw-w64 does not contain this | 16070 | // TODO: this condition is currently disabled because mingw-w64 does not contain this |
| 15994 | // symbol. Once it's added, enable this check to use the new bulk API where possible. | 16071 | // symbol. Once it's added, enable this check to use the new bulk API where possible. |
lib/std/Progress.zig+3-1| ... | @@ -977,7 +977,9 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff | ... | @@ -977,7 +977,9 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 977 | 0.., | 977 | 0.., |
| 978 | ) |main_parent, *main_storage, main_index| { | 978 | ) |main_parent, *main_storage, main_index| { |
| 979 | if (main_parent == .unused) continue; | 979 | if (main_parent == .unused) continue; |
| 980 | const file: Io.File = .{ .handle = main_storage.getIpcFd() orelse continue }; | 980 | const file: Io.File = .{ |
| 981 | .handle = main_storage.getIpcFd() orelse continue, | ||
| 982 | }; | ||
| 981 | const opt_saved_metadata = findOld(file.handle, old_ipc_metadata_fds, old_ipc_metadata); | 983 | const opt_saved_metadata = findOld(file.handle, old_ipc_metadata_fds, old_ipc_metadata); |
| 982 | var bytes_read: usize = 0; | 984 | var bytes_read: usize = 0; |
| 983 | while (true) { | 985 | while (true) { |
lib/std/os/windows.zig+93-41| ... | @@ -392,6 +392,8 @@ pub const FILE = struct { | ... | @@ -392,6 +392,8 @@ pub const FILE = struct { |
| 392 | Characteristics: ULONG, | 392 | Characteristics: ULONG, |
| 393 | }; | 393 | }; |
| 394 | 394 | ||
| 395 | pub const USE_FILE_POINTER_POSITION = -2; | ||
| 396 | |||
| 395 | // ref: um/WinBase.h | 397 | // ref: um/WinBase.h |
| 396 | 398 | ||
| 397 | pub const ATTRIBUTE_TAG_INFO = extern struct { | 399 | pub const ATTRIBUTE_TAG_INFO = extern struct { |
| ... | @@ -466,9 +468,11 @@ pub const FILE = struct { | ... | @@ -466,9 +468,11 @@ pub const FILE = struct { |
| 466 | pub const CREATE_DISPOSITION = enum(ULONG) { | 468 | pub const CREATE_DISPOSITION = enum(ULONG) { |
| 467 | /// If the file already exists, replace it with the given file. If it does not, create the given file. | 469 | /// If the file already exists, replace it with the given file. If it does not, create the given file. |
| 468 | SUPERSEDE = 0x00000000, | 470 | SUPERSEDE = 0x00000000, |
| 469 | /// If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file. | 471 | /// If the file already exists, open it instead of creating a new file. |
| 472 | /// If it does not, fail the request and do not create a new file. | ||
| 470 | OPEN = 0x00000001, | 473 | OPEN = 0x00000001, |
| 471 | /// If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file. | 474 | /// If the file already exists, fail the request and do not create or |
| 475 | /// open the given file. If it does not, create the given file. | ||
| 472 | CREATE = 0x00000002, | 476 | CREATE = 0x00000002, |
| 473 | /// If the file already exists, open it. If it does not, create the given file. | 477 | /// If the file already exists, open it. If it does not, create the given file. |
| 474 | OPEN_IF = 0x00000003, | 478 | OPEN_IF = 0x00000003, |
| ... | @@ -482,75 +486,122 @@ pub const FILE = struct { | ... | @@ -482,75 +486,122 @@ pub const FILE = struct { |
| 482 | 486 | ||
| 483 | /// Define the create/open option flags | 487 | /// Define the create/open option flags |
| 484 | pub const MODE = packed struct(ULONG) { | 488 | pub const MODE = packed struct(ULONG) { |
| 485 | /// The file being created or opened is a directory file. With this flag, the CreateDisposition parameter must be set to `.CREATE`, `.FILE_OPEN`, or `.OPEN_IF`. | 489 | /// The file being created or opened is a directory file. With this |
| 486 | /// With this flag, other compatible CreateOptions flags include only the following: `SYNCHRONOUS_IO`, `WRITE_THROUGH`, `OPEN_FOR_BACKUP_INTENT`, and `OPEN_BY_FILE_ID`. | 490 | /// flag, the CreateDisposition parameter must be set to `.CREATE`, |
| 491 | /// `.FILE_OPEN`, or `.OPEN_IF`. With this flag, other compatible | ||
| 492 | /// CreateOptions flags include only the following: `SYNCHRONOUS_IO`, | ||
| 493 | /// `WRITE_THROUGH`, `OPEN_FOR_BACKUP_INTENT`, and `OPEN_BY_FILE_ID`. | ||
| 487 | DIRECTORY_FILE: bool = false, | 494 | DIRECTORY_FILE: bool = false, |
| 488 | /// Applications that write data to the file must actually transfer the data into the file before any requested write operation is considered complete. | 495 | /// Applications that write data to the file must actually transfer the |
| 489 | /// This flag is automatically set if the CreateOptions flag `NO_INTERMEDIATE_BUFFERING` is set. | 496 | /// data into the file before any requested write operation is |
| 497 | /// considered complete. This flag is automatically set if the | ||
| 498 | /// CreateOptions flag `NO_INTERMEDIATE_BUFFERING` is set. | ||
| 490 | WRITE_THROUGH: bool = false, | 499 | WRITE_THROUGH: bool = false, |
| 491 | /// All accesses to the file are sequential. | 500 | /// All accesses to the file are sequential. |
| 492 | SEQUENTIAL_ONLY: bool = false, | 501 | SEQUENTIAL_ONLY: bool = false, |
| 493 | /// The file cannot be cached or buffered in a driver's internal buffers. This flag is incompatible with the DesiredAccess `FILE_APPEND_DATA` flag. | 502 | /// The file cannot be cached or buffered in a driver's internal |
| 503 | /// buffers. This flag is incompatible with the DesiredAccess | ||
| 504 | /// `FILE_APPEND_DATA` flag. | ||
| 494 | NO_INTERMEDIATE_BUFFERING: bool = false, | 505 | NO_INTERMEDIATE_BUFFERING: bool = false, |
| 495 | IO: enum(u2) { | 506 | IO: enum(u2) { |
| 496 | /// All operations on the file are performed asynchronously. | 507 | /// All operations on the file are performed asynchronously. |
| 497 | ASYNCHRONOUS = 0b00, | 508 | ASYNCHRONOUS = 0b00, |
| 498 | /// All operations on the file are performed synchronously. Any wait on behalf of the caller is subject to premature termination from alerts. | 509 | /// All operations on the file are performed synchronously. Any |
| 499 | /// This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess `SYNCHRONIZE` flag also must be set. | 510 | /// wait on behalf of the caller is subject to premature |
| 511 | /// termination from alerts. This flag also causes the I/O system | ||
| 512 | /// to maintain the file position context. If this flag is set, the | ||
| 513 | /// DesiredAccess `SYNCHRONIZE` flag also must be set. | ||
| 500 | SYNCHRONOUS_ALERT = 0b01, | 514 | SYNCHRONOUS_ALERT = 0b01, |
| 501 | /// All operations on the file are performed synchronously. Waits in the system to synchronize I/O queuing and completion are not subject to alerts. | 515 | /// All operations on the file are performed synchronously. Waits |
| 502 | /// This flag also causes the I/O system to maintain the file position context. If this flag is set, the DesiredAccess `SYNCHRONIZE` flag also must be set. | 516 | /// in the system to synchronize I/O queuing and completion are not |
| 517 | /// subject to alerts. This flag also causes the I/O system to | ||
| 518 | /// maintain the file position context. If this flag is set, the | ||
| 519 | /// DesiredAccess `SYNCHRONIZE` flag also must be set. | ||
| 503 | SYNCHRONOUS_NONALERT = 0b10, | 520 | SYNCHRONOUS_NONALERT = 0b10, |
| 504 | _, | 521 | _, |
| 505 | 522 | ||
| 506 | pub const VALID_FLAGS: @This() = @enumFromInt(0b11); | 523 | pub const VALID_FLAGS: @This() = @enumFromInt(0b11); |
| 507 | } = .ASYNCHRONOUS, | 524 | } = .ASYNCHRONOUS, |
| 508 | /// The file being opened must not be a directory file or this call fails. The file object being opened can represent a data file, a logical, virtual, or physical | 525 | /// The file being opened must not be a directory file or this call |
| 509 | /// device, or a volume. | 526 | /// fails. The file object being opened can represent a data file, a |
| 527 | /// logical, virtual, or physical device, or a volume. | ||
| 510 | NON_DIRECTORY_FILE: bool = false, | 528 | NON_DIRECTORY_FILE: bool = false, |
| 511 | /// Create a tree connection for this file in order to open it over the network. This flag is not used by device and intermediate drivers. | 529 | /// Create a tree connection for this file in order to open it over the |
| 530 | /// network. This flag is not used by device and intermediate drivers. | ||
| 512 | CREATE_TREE_CONNECTION: bool = false, | 531 | CREATE_TREE_CONNECTION: bool = false, |
| 513 | /// Complete this operation immediately with an alternate success code of `STATUS_OPLOCK_BREAK_IN_PROGRESS` if the target file is oplocked, rather than blocking | 532 | /// Complete this operation immediately with an alternate success code |
| 514 | /// the caller's thread. If the file is oplocked, another caller already has access to the file. This flag is not used by device and intermediate drivers. | 533 | /// of `STATUS_OPLOCK_BREAK_IN_PROGRESS` if the target file is |
| 534 | /// oplocked, rather than blocking the caller's thread. If the file is | ||
| 535 | /// oplocked, another caller already has access to the file. This flag | ||
| 536 | /// is not used by device and intermediate drivers. | ||
| 515 | COMPLETE_IF_OPLOCKED: bool = false, | 537 | COMPLETE_IF_OPLOCKED: bool = false, |
| 516 | /// If the extended attributes on an existing file being opened indicate that the caller must understand EAs to properly interpret the file, fail this request | 538 | /// If the extended attributes on an existing file being opened |
| 517 | /// because the caller does not understand how to deal with EAs. This flag is irrelevant for device and intermediate drivers. | 539 | /// indicate that the caller must understand EAs to properly interpret |
| 540 | /// the file, fail this request because the caller does not understand | ||
| 541 | /// how to deal with EAs. This flag is irrelevant for device and | ||
| 542 | /// intermediate drivers. | ||
| 518 | NO_EA_KNOWLEDGE: bool = false, | 543 | NO_EA_KNOWLEDGE: bool = false, |
| 519 | OPEN_REMOTE_INSTANCE: bool = false, | 544 | OPEN_REMOTE_INSTANCE: bool = false, |
| 520 | /// Accesses to the file can be random, so no sequential read-ahead operations should be performed on the file by FSDs or the system. | 545 | /// Accesses to the file can be random, so no sequential read-ahead |
| 546 | /// operations should be performed on the file by FSDs or the system. | ||
| 521 | RANDOM_ACCESS: bool = false, | 547 | RANDOM_ACCESS: bool = false, |
| 522 | /// Delete the file when the last handle to it is passed to `NtClose`. If this flag is set, the `DELETE` flag must be set in the DesiredAccess parameter. | 548 | /// Delete the file when the last handle to it is passed to `NtClose`. |
| 549 | /// If this flag is set, the `DELETE` flag must be set in the | ||
| 550 | /// DesiredAccess parameter. | ||
| 523 | DELETE_ON_CLOSE: bool = false, | 551 | DELETE_ON_CLOSE: bool = false, |
| 524 | /// The file name that is specified by the `ObjectAttributes` parameter includes the 8-byte file reference number for the file. This number is assigned by and | 552 | /// The file name that is specified by the `ObjectAttributes` parameter |
| 525 | /// specific to the particular file system. If the file is a reparse point, the file name will also include the name of a device. Note that the FAT file system | 553 | /// includes the 8-byte file reference number for the file. This number |
| 526 | /// does not support this flag. This flag is not used by device and intermediate drivers. | 554 | /// is assigned by and specific to the particular file system. If the |
| 555 | /// file is a reparse point, the file name will also include the name | ||
| 556 | /// of a device. Note that the FAT file system does not support this | ||
| 557 | /// flag. This flag is not used by device and intermediate drivers. | ||
| 527 | OPEN_BY_FILE_ID: bool = false, | 558 | OPEN_BY_FILE_ID: bool = false, |
| 528 | /// The file is being opened for backup intent. Therefore, the system should check for certain access rights and grant the caller the appropriate access to the | 559 | /// The file is being opened for backup intent. Therefore, the system |
| 529 | /// file before checking the DesiredAccess parameter against the file's security descriptor. This flag not used by device and intermediate drivers. | 560 | /// should check for certain access rights and grant the caller the |
| 561 | /// appropriate access to the file before checking the DesiredAccess | ||
| 562 | /// parameter against the file's security descriptor. This flag not | ||
| 563 | /// used by device and intermediate drivers. | ||
| 530 | OPEN_FOR_BACKUP_INTENT: bool = false, | 564 | OPEN_FOR_BACKUP_INTENT: bool = false, |
| 531 | /// Suppress inheritance of `FILE_ATTRIBUTE.COMPRESSED` from the parent directory. This allows creation of a non-compressed file in a directory that is marked | 565 | /// Suppress inheritance of `FILE_ATTRIBUTE.COMPRESSED` from the parent |
| 532 | /// compressed. | 566 | /// directory. This allows creation of a non-compressed file in a |
| 567 | /// directory that is marked compressed. | ||
| 533 | NO_COMPRESSION: bool = false, | 568 | NO_COMPRESSION: bool = false, |
| 534 | /// The file is being opened and an opportunistic lock on the file is being requested as a single atomic operation. The file system checks for oplocks before it | 569 | /// The file is being opened and an opportunistic lock on the file is |
| 535 | /// performs the create operation and will fail the create with a return code of STATUS_CANNOT_BREAK_OPLOCK if the result would be to break an existing oplock. | 570 | /// being requested as a single atomic operation. The file system |
| 536 | /// For more information, see the Remarks section. | 571 | /// checks for oplocks before it performs the create operation and will |
| 572 | /// fail the create with a return code of STATUS_CANNOT_BREAK_OPLOCK if | ||
| 573 | /// the result would be to break an existing oplock. For more | ||
| 574 | /// information, see the Remarks section. | ||
| 537 | /// | 575 | /// |
| 538 | /// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This flag is not supported. | 576 | /// Windows Server 2008, Windows Vista, Windows Server 2003 and Windows |
| 577 | /// XP: This flag is not supported. | ||
| 539 | /// | 578 | /// |
| 540 | /// This flag is supported on the following file systems: NTFS, FAT, and exFAT. | 579 | /// This flag is supported on the following file systems: NTFS, FAT, |
| 580 | /// and exFAT. | ||
| 541 | OPEN_REQUIRING_OPLOCK: bool = false, | 581 | OPEN_REQUIRING_OPLOCK: bool = false, |
| 542 | Reserved17: u3 = 0, | 582 | Reserved17: u3 = 0, |
| 543 | /// This flag allows an application to request a filter opportunistic lock to prevent other applications from getting share violations. If there are already open | 583 | /// This flag allows an application to request a filter opportunistic |
| 544 | /// handles, the create request will fail with STATUS_OPLOCK_NOT_GRANTED. For more information, see the Remarks section. | 584 | /// lock to prevent other applications from getting share violations. |
| 585 | /// If there are already open handles, the create request will fail | ||
| 586 | /// with STATUS_OPLOCK_NOT_GRANTED. For more information, see the | ||
| 587 | /// Remarks section. | ||
| 545 | RESERVE_OPFILTER: bool = false, | 588 | RESERVE_OPFILTER: bool = false, |
| 546 | /// Open a file with a reparse point and bypass normal reparse point processing for the file. For more information, see the Remarks section. | 589 | /// Open a file with a reparse point and bypass normal reparse point |
| 590 | /// processing for the file. For more information, see the Remarks | ||
| 591 | /// section. | ||
| 547 | OPEN_REPARSE_POINT: bool = false, | 592 | OPEN_REPARSE_POINT: bool = false, |
| 548 | /// Instructs any filters that perform offline storage or virtualization to not recall the contents of the file as a result of this open. | 593 | /// Instructs any filters that perform offline storage or |
| 594 | /// virtualization to not recall the contents of the file as a result | ||
| 595 | /// of this open. | ||
| 549 | OPEN_NO_RECALL: bool = false, | 596 | OPEN_NO_RECALL: bool = false, |
| 550 | /// This flag instructs the file system to capture the user associated with the calling thread. Any subsequent calls to `FltQueryVolumeInformation` or | 597 | /// This flag instructs the file system to capture the user associated |
| 551 | /// `ZwQueryVolumeInformationFile` using the returned handle will assume the captured user, rather than the calling user at the time, for purposes of computing | 598 | /// with the calling thread. Any subsequent calls to |
| 552 | /// the free space available to the caller. This applies to the following FsInformationClass values: `FileFsSizeInformation`, `FileFsFullSizeInformation`, and | 599 | /// `FltQueryVolumeInformation` or `ZwQueryVolumeInformationFile` using |
| 553 | /// `FileFsFullSizeInformationEx`. | 600 | /// the returned handle will assume the captured user, rather than the |
| 601 | /// calling user at the time, for purposes of computing the free space | ||
| 602 | /// available to the caller. This applies to the following | ||
| 603 | /// FsInformationClass values: `FileFsSizeInformation`, | ||
| 604 | /// `FileFsFullSizeInformation`, and `FileFsFullSizeInformationEx`. | ||
| 554 | OPEN_FOR_FREE_SPACE_QUERY: bool = false, | 605 | OPEN_FOR_FREE_SPACE_QUERY: bool = false, |
| 555 | Reserved24: u8 = 0, | 606 | Reserved24: u8 = 0, |
| 556 | 607 | ||
| ... | @@ -597,7 +648,8 @@ pub const FILE = struct { | ... | @@ -597,7 +648,8 @@ pub const FILE = struct { |
| 597 | // ref: km/ntifs.h | 648 | // ref: km/ntifs.h |
| 598 | 649 | ||
| 599 | pub const INFORMATION = extern struct { | 650 | pub const INFORMATION = extern struct { |
| 600 | /// The set of flags that specify the mode in which the file can be accessed. These flags are a subset of `MODE`. | 651 | /// The set of flags that specify the mode in which the file can be |
| 652 | /// accessed. These flags are a subset of `MODE`. | ||
| 601 | Mode: MODE, | 653 | Mode: MODE, |
| 602 | }; | 654 | }; |
| 603 | }; | 655 | }; |
lib/std/os/windows/ntdll.zig+15-3| ... | @@ -567,9 +567,8 @@ pub extern "ntdll" fn NtWaitForAlertByThreadId( | ... | @@ -567,9 +567,8 @@ pub extern "ntdll" fn NtWaitForAlertByThreadId( |
| 567 | Address: ?*const anyopaque, | 567 | Address: ?*const anyopaque, |
| 568 | Timeout: ?*const LARGE_INTEGER, | 568 | Timeout: ?*const LARGE_INTEGER, |
| 569 | ) callconv(.winapi) NTSTATUS; | 569 | ) callconv(.winapi) NTSTATUS; |
| 570 | pub extern "ntdll" fn NtAlertThreadByThreadId( | 570 | pub extern "ntdll" fn NtAlertThreadByThreadId(ThreadId: DWORD) callconv(.winapi) NTSTATUS; |
| 571 | ThreadId: DWORD, | 571 | pub extern "ntdll" fn NtAlertThread(ThreadHandle: HANDLE) callconv(.winapi) NTSTATUS; |
| 572 | ) callconv(.winapi) NTSTATUS; | ||
| 573 | pub extern "ntdll" fn NtAlertMultipleThreadByThreadId( | 572 | pub extern "ntdll" fn NtAlertMultipleThreadByThreadId( |
| 574 | ThreadIds: [*]const ULONG_PTR, | 573 | ThreadIds: [*]const ULONG_PTR, |
| 575 | ThreadCount: ULONG, | 574 | ThreadCount: ULONG, |
| ... | @@ -589,3 +588,16 @@ pub extern "ntdll" fn NtCancelSynchronousIoFile( | ... | @@ -589,3 +588,16 @@ pub extern "ntdll" fn NtCancelSynchronousIoFile( |
| 589 | RequestToCancel: ?*IO_STATUS_BLOCK, | 588 | RequestToCancel: ?*IO_STATUS_BLOCK, |
| 590 | IoStatusBlock: *IO_STATUS_BLOCK, | 589 | IoStatusBlock: *IO_STATUS_BLOCK, |
| 591 | ) callconv(.winapi) NTSTATUS; | 590 | ) callconv(.winapi) NTSTATUS; |
| 591 | |||
| 592 | pub extern "ntdll" fn NtDelayExecution( | ||
| 593 | Alertable: BOOLEAN, | ||
| 594 | DelayInterval: *const LARGE_INTEGER, | ||
| 595 | ) callconv(.winapi) NTSTATUS; | ||
| 596 | |||
| 597 | pub extern "ntdll" fn NtCancelIoFileEx( | ||
| 598 | FileHandle: HANDLE, | ||
| 599 | /// Documentation has this as IO_STATUS_BLOCK but it's actually the APC | ||
| 600 | /// context parameter. | ||
| 601 | IoRequestToCancel: ?*anyopaque, | ||
| 602 | IoStatusBlock: *IO_STATUS_BLOCK, | ||
| 603 | ) callconv(.winapi) NTSTATUS; |
src/link/Lld.zig+11-3| ... | @@ -278,7 +278,7 @@ pub fn flush( | ... | @@ -278,7 +278,7 @@ pub fn flush( |
| 278 | }; | 278 | }; |
| 279 | result catch |err| switch (err) { | 279 | result catch |err| switch (err) { |
| 280 | error.OutOfMemory, error.LinkFailure => |e| return e, | 280 | error.OutOfMemory, error.LinkFailure => |e| return e, |
| 281 | else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), | 281 | else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {t}", .{e}), |
| 282 | }; | 282 | }; |
| 283 | } | 283 | } |
| 284 | 284 | ||
| ... | @@ -1630,7 +1630,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi | ... | @@ -1630,7 +1630,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1630 | }) catch |err| break :term err; | 1630 | }) catch |err| break :term err; |
| 1631 | 1631 | ||
| 1632 | var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); | 1632 | var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); |
| 1633 | stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited); | 1633 | stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) { |
| 1634 | error.StreamTooLong => unreachable, // unlimited | ||
| 1635 | error.OutOfMemory => |e| return e, | ||
| 1636 | error.ReadFailed => return stderr_reader.err.?, | ||
| 1637 | }; | ||
| 1634 | break :term child.wait(io); | 1638 | break :term child.wait(io); |
| 1635 | }) catch |first_err| term: { | 1639 | }) catch |first_err| term: { |
| 1636 | const err = switch (first_err) { | 1640 | const err = switch (first_err) { |
| ... | @@ -1682,7 +1686,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi | ... | @@ -1682,7 +1686,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1682 | break :term rsp_child.wait(io) catch |err| break :err err; | 1686 | break :term rsp_child.wait(io) catch |err| break :err err; |
| 1683 | } else { | 1687 | } else { |
| 1684 | var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{}); | 1688 | var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{}); |
| 1685 | stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited); | 1689 | stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) { |
| 1690 | error.StreamTooLong => unreachable, // unlimited | ||
| 1691 | error.OutOfMemory => |e| return e, | ||
| 1692 | error.ReadFailed => return stderr_reader.err.?, | ||
| 1693 | }; | ||
| 1686 | break :term rsp_child.wait(io) catch |err| break :err err; | 1694 | break :term rsp_child.wait(io) catch |err| break :err err; |
| 1687 | } | 1695 | } |
| 1688 | }, | 1696 | }, |