| ... | @@ -389,7 +389,26 @@ pub fn stat(self: File) StatError!Stat { | ... | @@ -389,7 +389,26 @@ pub fn stat(self: File) StatError!Stat { |
| 389 | .inode = info.InternalInformation.IndexNumber, | 389 | .inode = info.InternalInformation.IndexNumber, |
| 390 | .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)), | 390 | .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)), |
| 391 | .mode = 0, | 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 | .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime), | 412 | .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime), |
| 394 | .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime), | 413 | .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime), |
| 395 | .ctime = windows.fromSysTime(info.BasicInformation.CreationTime), | 414 | .ctime = windows.fromSysTime(info.BasicInformation.CreationTime), |
| ... | @@ -791,7 +810,7 @@ pub const MetadataWindows = struct { | ... | @@ -791,7 +810,7 @@ pub const MetadataWindows = struct { |
| 791 | /// Can only return: `.file`, `.directory`, `.sym_link` or `.unknown` | 810 | /// Can only return: `.file`, `.directory`, `.sym_link` or `.unknown` |
| 792 | pub fn kind(self: Self) Kind { | 811 | pub fn kind(self: Self) Kind { |
| 793 | if (self.attributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { | 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 | return .sym_link; | 814 | return .sym_link; |
| 796 | } | 815 | } |
| 797 | } else if (self.attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) { | 816 | } else if (self.attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) { |
| ... | @@ -842,10 +861,17 @@ pub fn metadata(self: File) MetadataError!Metadata { | ... | @@ -842,10 +861,17 @@ pub fn metadata(self: File) MetadataError!Metadata { |
| 842 | | 861 | |
| 843 | const reparse_tag: windows.DWORD = reparse_blk: { | 862 | const reparse_tag: windows.DWORD = reparse_blk: { |
| 844 | if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { | 863 | if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { |
| 845 | var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined; | 864 | var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined; |
| 846 | try windows.DeviceIoControl(self.handle, windows.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]); | 865 | const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation); |
| 847 | const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf[0])); | 866 | switch (tag_rc) { |
| 848 | break :reparse_blk reparse_struct.ReparseTag; | 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 | break :reparse_blk 0; | 876 | break :reparse_blk 0; |
| 851 | }; | 877 | }; |