@@ -1103,15 +1103,22 @@ typedef union {
11031103
11041104
11051105void
1106- _Py_attribute_data_to_stat (BY_HANDLE_FILE_INFORMATION * info , ULONG reparse_tag ,
1107- FILE_BASIC_INFO * basic_info , FILE_ID_INFO * id_info ,
1106+ _Py_attribute_data_to_stat (BY_HANDLE_FILE_INFORMATION * info , FILE_STANDARD_INFO * standard_info ,
1107+ ULONG reparse_tag , FILE_BASIC_INFO * basic_info , FILE_ID_INFO * id_info ,
11081108 struct _Py_stat_struct * result )
11091109{
11101110 memset (result , 0 , sizeof (* result ));
1111- result -> st_mode = attributes_to_mode (info -> dwFileAttributes );
1112- result -> st_size = (((__int64 )info -> nFileSizeHigh )<<32 ) + info -> nFileSizeLow ;
1113- result -> st_dev = id_info ? id_info -> VolumeSerialNumber : info -> dwVolumeSerialNumber ;
1114- result -> st_rdev = 0 ;
1111+
1112+ if (info ) {
1113+ result -> st_size = (((__int64 )info -> nFileSizeHigh ) << 32 ) + info -> nFileSizeLow ;
1114+ result -> st_nlink = info -> nNumberOfLinks ;
1115+ result -> st_dev = id_info ? id_info -> VolumeSerialNumber : info -> dwVolumeSerialNumber ;
1116+ }
1117+ if (standard_info && !info ) {
1118+ result -> st_size = standard_info -> EndOfFile .QuadPart ;
1119+ result -> st_nlink = standard_info -> NumberOfLinks ;
1120+ }
1121+
11151122 /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */
11161123 if (basic_info ) {
11171124 LARGE_INTEGER_to_time_t_nsec (& basic_info -> CreationTime , & result -> st_birthtime , & result -> st_birthtime_nsec );
@@ -1123,7 +1130,6 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
11231130 FILE_TIME_to_time_t_nsec (& info -> ftLastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
11241131 FILE_TIME_to_time_t_nsec (& info -> ftLastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
11251132 }
1126- result -> st_nlink = info -> nNumberOfLinks ;
11271133
11281134 if (id_info ) {
11291135 id_128_to_ino file_id ;
@@ -1134,49 +1140,31 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
11341140 if (!result -> st_ino && !result -> st_ino_high ) {
11351141 /* should only occur for DirEntry_from_find_data, in which case the
11361142 index is likely to be zero anyway. */
1137- result -> st_ino = (((uint64_t )info -> nFileIndexHigh ) << 32 ) + info -> nFileIndexLow ;
1143+ if (info )
1144+ result -> st_ino = (((uint64_t )info -> nFileIndexHigh ) << 32 ) + info -> nFileIndexLow ;
11381145 }
11391146
1140- /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will
1141- open other name surrogate reparse points without traversing them. To
1142- detect/handle these, check st_file_attributes and st_reparse_tag. */
1143- result -> st_reparse_tag = reparse_tag ;
1144- if (info -> dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
1145- reparse_tag == IO_REPARSE_TAG_SYMLINK ) {
1146- /* set the bits that make this a symlink */
1147- result -> st_mode = (result -> st_mode & ~S_IFMT ) | S_IFLNK ;
1148- }
1149- result -> st_file_attributes = info -> dwFileAttributes ;
1150- }
1147+ const DWORD fileAttributes = basic_info ? basic_info -> FileAttributes : info -> dwFileAttributes ;
11511148
1152- void
1153- _Py_attribute_data_to_stat_UWP (FILE_STANDARD_INFO * standard_info , ULONG reparse_tag ,
1154- FILE_BASIC_INFO * basic_info , struct _Py_stat_struct * result )
1155- {
1156- memset (result , 0 , sizeof (* result ));
1157- result -> st_mode = attributes_to_mode (basic_info -> FileAttributes );
1158- result -> st_size = standard_info -> EndOfFile .QuadPart ;
1159- result -> st_dev = 1 ;
1160-
1161- /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */
1162- LARGE_INTEGER_to_time_t_nsec (& basic_info -> CreationTime , & result -> st_birthtime , & result -> st_birthtime_nsec );
1163- LARGE_INTEGER_to_time_t_nsec (& basic_info -> ChangeTime , & result -> st_ctime , & result -> st_ctime_nsec );
1164- LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
1165- LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
1166-
1167- result -> st_nlink = standard_info -> NumberOfLinks ;
1168- result -> st_ino = basic_info -> CreationTime .QuadPart ;
1149+ result -> st_file_attributes = fileAttributes ;
1150+ result -> st_mode = attributes_to_mode (fileAttributes );
11691151
11701152 /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will
11711153 open other name surrogate reparse points without traversing them. To
11721154 detect/handle these, check st_file_attributes and st_reparse_tag. */
11731155 result -> st_reparse_tag = reparse_tag ;
1174- if (basic_info -> FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
1156+ if (result -> st_file_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
11751157 reparse_tag == IO_REPARSE_TAG_SYMLINK ) {
11761158 /* set the bits that make this a symlink */
11771159 result -> st_mode = (result -> st_mode & ~S_IFMT ) | S_IFLNK ;
11781160 }
1179- result -> st_file_attributes = basic_info -> FileAttributes ;
1161+
1162+ // For UWP compatibility since is not possible obtain the VolumeSerialNumber
1163+ // and FileId due security restriction and App isolation
1164+ #ifndef MS_WINDOWS_DESKTOP
1165+ result -> st_dev = 1 ;
1166+ basic_info -> CreationTime .QuadPart ;
1167+ #endif
11801168}
11811169
11821170void
@@ -1316,9 +1304,9 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status)
13161304 }
13171305
13181306#ifdef MS_WINDOWS_DESKTOP
1319- _Py_attribute_data_to_stat (& info , 0 , & basicInfo , pIdInfo , status );
1307+ _Py_attribute_data_to_stat (& info , NULL , 0 , & basicInfo , pIdInfo , status );
13201308#else
1321- _Py_attribute_data_to_stat_UWP ( & standardInfo , 0 , & basicInfo , status );
1309+ _Py_attribute_data_to_stat ( NULL , & standardInfo , 0 , & basicInfo , NULL , status );
13221310#endif
13231311 return 0 ;
13241312#else
0 commit comments