| ... | ... | @@ -389,7 +389,26 @@ pub fn stat(self: File) StatError!Stat { |
| 389 | 389 | .inode = info.InternalInformation.IndexNumber, |
| 390 | 390 | .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)), |
| 391 | 391 | .mode = 0, |
| 392 | | .kind = if (info.StandardInformation.Directory == 0) .file else .directory, |
| 392 | .kind = if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) reparse_point: { |
| 393 | var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined; |
| 394 | const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation); |
| 395 | switch (tag_rc) { |
| 396 | .SUCCESS => {}, |
| 397 | // INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors |
| 398 | // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e |
| 399 | .INFO_LENGTH_MISMATCH => unreachable, |
| 400 | .ACCESS_DENIED => return error.AccessDenied, |
| 401 | else => return windows.unexpectedStatus(rc), |
| 402 | } |
| 403 | if (tag_info.ReparseTag & windows.reparse_tag_name_surrogate_bit != 0) { |
| 404 | break :reparse_point .sym_link; |
| 405 | } |
| 406 | // Unknown reparse point |
| 407 | break :reparse_point .unknown; |
| 408 | } else if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) |
| 409 | .directory |
| 410 | else |
| 411 | .file, |
| 393 | 412 | .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime), |
| 394 | 413 | .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime), |
| 395 | 414 | .ctime = windows.fromSysTime(info.BasicInformation.CreationTime), |
| ... | ... | @@ -791,7 +810,7 @@ pub const MetadataWindows = struct { |
| 791 | 810 | /// Can only return: `.file`, `.directory`, `.sym_link` or `.unknown` |
| 792 | 811 | pub fn kind(self: Self) Kind { |
| 793 | 812 | if (self.attributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { |
| 794 | | if (self.reparse_tag & 0x20000000 != 0) { |
| 813 | if (self.reparse_tag & windows.reparse_tag_name_surrogate_bit != 0) { |
| 795 | 814 | return .sym_link; |
| 796 | 815 | } |
| 797 | 816 | } else if (self.attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) { |
| ... | ... | @@ -842,10 +861,17 @@ pub fn metadata(self: File) MetadataError!Metadata { |
| 842 | 861 | |
| 843 | 862 | const reparse_tag: windows.DWORD = reparse_blk: { |
| 844 | 863 | if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { |
| 845 | | var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined; |
| 846 | | try windows.DeviceIoControl(self.handle, windows.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]); |
| 847 | | const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf[0])); |
| 848 | | break :reparse_blk reparse_struct.ReparseTag; |
| 864 | var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined; |
| 865 | const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation); |
| 866 | switch (tag_rc) { |
| 867 | .SUCCESS => {}, |
| 868 | // INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors |
| 869 | // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e |
| 870 | .INFO_LENGTH_MISMATCH => unreachable, |
| 871 | .ACCESS_DENIED => return error.AccessDenied, |
| 872 | else => return windows.unexpectedStatus(rc), |
| 873 | } |
| 874 | break :reparse_blk tag_info.ReparseTag; |
| 849 | 875 | } |
| 850 | 876 | break :reparse_blk 0; |
| 851 | 877 | }; |