| ... | @@ -4110,6 +4110,30 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | ... | @@ -4110,6 +4110,30 @@ fn fileStatLinux(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4110 | } | 4110 | } |
| 4111 | } | 4111 | } |
| 4112 | | 4112 | |
| | 4113 | fn windowsGetFileDevice(file: File) error{ Canceled, AccessDenied, Unexpected }!windows.CTL_CODE.FILE_DEVICE { |
| | 4114 | var io_status_block: windows.IO_STATUS_BLOCK = undefined; |
| | 4115 | var device_info: windows.FILE.FS_DEVICE_INFORMATION = undefined; |
| | 4116 | { |
| | 4117 | const syscall: Syscall = try .start(); |
| | 4118 | while (true) switch (windows.ntdll.NtQueryVolumeInformationFile( |
| | 4119 | file.handle, |
| | 4120 | &io_status_block, |
| | 4121 | &device_info, |
| | 4122 | @sizeOf(windows.FILE.FS_DEVICE_INFORMATION), |
| | 4123 | .Device, |
| | 4124 | )) { |
| | 4125 | .SUCCESS => break syscall.finish(), |
| | 4126 | .CANCELLED => { |
| | 4127 | try syscall.checkCancel(); |
| | 4128 | continue; |
| | 4129 | }, |
| | 4130 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| | 4131 | else => |s| return syscall.unexpectedNtstatus(s), |
| | 4132 | }; |
| | 4133 | } |
| | 4134 | return device_info.DeviceType.FileDevice; |
| | 4135 | } |
| | 4136 | |
| 4113 | fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | 4137 | fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4114 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 4138 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 4115 | | 4139 | |
| ... | @@ -4134,7 +4158,31 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { | ... | @@ -4134,7 +4158,31 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat { |
| 4134 | // size provided. This is treated as success because the type of variable-length information that this would be relevant for | 4158 | // size provided. This is treated as success because the type of variable-length information that this would be relevant for |
| 4135 | // (name, volume name, etc) we don't care about. | 4159 | // (name, volume name, etc) we don't care about. |
| 4136 | .BUFFER_OVERFLOW => break syscall.finish(), | 4160 | .BUFFER_OVERFLOW => break syscall.finish(), |
| 4137 | .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), | 4161 | .INVALID_PARAMETER, // SERIAL_PORT devices like AUX, COM1, etc |
| | 4162 | .INVALID_DEVICE_REQUEST, // CONSOLE, etc devices |
| | 4163 | .INVALID_INFO_CLASS, // NULL, etc devices |
| | 4164 | => { |
| | 4165 | syscall.finish(); |
| | 4166 | const device = try windowsGetFileDevice(file); |
| | 4167 | return .{ |
| | 4168 | .inode = @intCast(@intFromPtr(file.handle)), |
| | 4169 | .size = 0, |
| | 4170 | .permissions = .default_file, |
| | 4171 | .kind = switch (device) { |
| | 4172 | // These are classified as FILE_TYPE_CHAR by GetFileType |
| | 4173 | // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletype |
| | 4174 | // (GetFileType calls NtQueryVolumeInformationFile with FS_DEVICE_INFORMATION) |
| | 4175 | .CONSOLE, .NULL, .SERIAL_PORT => .character_device, |
| | 4176 | else => .unknown, |
| | 4177 | }, |
| | 4178 | // Match the times that NtQueryInformationFile returns for named pipes. |
| | 4179 | .atime = windows.fromSysTime(0), |
| | 4180 | .mtime = windows.fromSysTime(0), |
| | 4181 | .ctime = windows.fromSysTime(0), |
| | 4182 | .nlink = 1, |
| | 4183 | .block_size = block_size, |
| | 4184 | }; |
| | 4185 | }, |
| 4138 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), | 4186 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| 4139 | .CANCELLED => { | 4187 | .CANCELLED => { |
| 4140 | try syscall.checkCancel(); | 4188 | try syscall.checkCancel(); |