| ... | ... | @@ -4088,6 +4088,30 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4088 | 4088 | } |
| 4089 | 4089 | } |
| 4090 | 4090 | |
| 4091 | fn windowsGetFileDevice(file: File) error{ Canceled, AccessDenied, Unexpected }!windows.CTL_CODE.FILE_DEVICE { |
| 4092 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| 4093 | var device_info: windows.FILE.FS_DEVICE_INFORMATION = undefined; |
| 4094 | { |
| 4095 | const syscall: Syscall = try .start(); |
| 4096 | while (true) switch (windows.ntdll.NtQueryVolumeInformationFile( |
| 4097 | file.handle, |
| 4098 | &io_status_block, |
| 4099 | &device_info, |
| 4100 | @sizeOf(windows.FILE.FS_DEVICE_INFORMATION), |
| 4101 | .Device, |
| 4102 | )) { |
| 4103 | .SUCCESS => break syscall.finish(), |
| 4104 | .CANCELLED => { |
| 4105 | try syscall.checkCancel(); |
| 4106 | continue; |
| 4107 | }, |
| 4108 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 4109 | else => |s| return syscall.unexpectedNtstatus(s), |
| 4110 | }; |
| 4111 | } |
| 4112 | return device_info.DeviceType.FileDevice; |
| 4113 | } |
| 4114 | |
| 4091 | 4115 | fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4092 | 4116 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4093 | 4117 | |
| ... | ... | @@ -4112,7 +4136,31 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4112 | 4136 | // size provided. This is treated as success because the type of variable-length information that this would be relevant for |
| 4113 | 4137 | // (name, volume name, etc) we don't care about. |
| 4114 | 4138 | .BUFFER_OVERFLOW => break syscall.finish(), |
| 4115 | | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), |
| 4139 | .INVALID_PARAMETER, // SERIAL_PORT devices like AUX, COM1, etc |
| 4140 | .INVALID_DEVICE_REQUEST, // CONSOLE, etc devices |
| 4141 | .INVALID_INFO_CLASS, // NULL, etc devices |
| 4142 | => { |
| 4143 | syscall.finish(); |
| 4144 | const device = try windowsGetFileDevice(file); |
| 4145 | return .{ |
| 4146 | .inode = @intCast(@intFromPtr(file.handle)), |
| 4147 | .size = 0, |
| 4148 | .permissions = .default_file, |
| 4149 | .kind = switch (device) { |
| 4150 | // These are classified as FILE_TYPE_CHAR by GetFileType |
| 4151 | // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletype |
| 4152 | // (GetFileType calls NtQueryVolumeInformationFile with FS_DEVICE_INFORMATION) |
| 4153 | .CONSOLE, .NULL, .SERIAL_PORT => .character_device, |
| 4154 | else => .unknown, |
| 4155 | }, |
| 4156 | // Match the times that NtQueryInformationFile returns for named pipes. |
| 4157 | .atime = windows.fromSysTime(0), |
| 4158 | .mtime = windows.fromSysTime(0), |
| 4159 | .ctime = windows.fromSysTime(0), |
| 4160 | .nlink = 1, |
| 4161 | .block_size = block_size, |
| 4162 | }; |
| 4163 | }, |
| 4116 | 4164 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 4117 | 4165 | .CANCELLED => { |
| 4118 | 4166 | try syscall.checkCancel(); |
| ... | ... | @@ -4151,8 +4199,10 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4151 | 4199 | break :reparse_point .unknown; |
| 4152 | 4200 | } else if (info.BasicInformation.FileAttributes.DIRECTORY) |
| 4153 | 4201 | .directory |
| 4154 | | else |
| 4155 | | .file, |
| 4202 | else switch (try windowsGetFileDevice(file)) { |
| 4203 | .NAMED_PIPE => .named_pipe, |
| 4204 | else => .file, |
| 4205 | }, |
| 4156 | 4206 | .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime), |
| 4157 | 4207 | .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime), |
| 4158 | 4208 | .ctime = windows.fromSysTime(info.BasicInformation.ChangeTime), |
| ... | ... | @@ -17794,6 +17844,7 @@ pub fn windowsCreatePipe(t: *Threaded, options: CreatePipeOptions) ![2]windows.H |
| 17794 | 17844 | .READ_DATA = options.inbound, |
| 17795 | 17845 | .WRITE_DATA = options.outbound, |
| 17796 | 17846 | .WRITE_ATTRIBUTES = true, |
| 17847 | .READ_ATTRIBUTES = true, |
| 17797 | 17848 | } }, |
| 17798 | 17849 | .STANDARD = .{ .SYNCHRONIZE = true }, |
| 17799 | 17850 | }, |
| ... | ... | @@ -17836,6 +17887,7 @@ pub fn windowsCreatePipe(t: *Threaded, options: CreatePipeOptions) ![2]windows.H |
| 17836 | 17887 | .READ_DATA = options.outbound, |
| 17837 | 17888 | .WRITE_DATA = options.inbound, |
| 17838 | 17889 | .WRITE_ATTRIBUTES = true, |
| 17890 | .READ_ATTRIBUTES = true, |
| 17839 | 17891 | } }, |
| 17840 | 17892 | .STANDARD = .{ .SYNCHRONIZE = true }, |
| 17841 | 17893 | }, |