@@ -1103,29 +1103,26 @@ 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 ,
1108- struct _Py_stat_struct * result )
1106+ _Py_attribute_data_to_stat (FILE_BASIC_INFO * basic_info ,
1107+ FILE_STANDARD_INFO * standard_info ,
1108+ FILE_ID_INFO * id_info ,
1109+ ULONG reparse_tag ,
1110+ struct _Py_stat_struct * result )
11091111{
11101112 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 ;
1113+ result -> st_mode = attributes_to_mode (basic_info -> FileAttributes );
1114+ result -> st_size = standard_info -> EndOfFile .QuadPart ;
11141115 result -> st_rdev = 0 ;
1116+
11151117 /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */
1116- if (basic_info ) {
1117- LARGE_INTEGER_to_time_t_nsec (& basic_info -> CreationTime , & result -> st_birthtime , & result -> st_birthtime_nsec );
1118- LARGE_INTEGER_to_time_t_nsec (& basic_info -> ChangeTime , & result -> st_ctime , & result -> st_ctime_nsec );
1119- LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
1120- LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
1121- } else {
1122- FILE_TIME_to_time_t_nsec (& info -> ftCreationTime , & result -> st_birthtime , & result -> st_birthtime_nsec );
1123- FILE_TIME_to_time_t_nsec (& info -> ftLastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
1124- FILE_TIME_to_time_t_nsec (& info -> ftLastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
1125- }
1126- result -> st_nlink = info -> nNumberOfLinks ;
1118+ LARGE_INTEGER_to_time_t_nsec (& basic_info -> CreationTime , & result -> st_birthtime , & result -> st_birthtime_nsec );
1119+ LARGE_INTEGER_to_time_t_nsec (& basic_info -> ChangeTime , & result -> st_ctime , & result -> st_ctime_nsec );
1120+ LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
1121+ LARGE_INTEGER_to_time_t_nsec (& basic_info -> LastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
1122+ result -> st_nlink = standard_info -> NumberOfLinks ;
11271123
11281124 if (id_info ) {
1125+ result -> st_dev = id_info -> VolumeSerialNumber ;
11291126 id_128_to_ino file_id ;
11301127 file_id .id = id_info -> FileId ;
11311128 result -> st_ino = file_id .st_ino ;
@@ -1134,19 +1131,19 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
11341131 if (!result -> st_ino && !result -> st_ino_high ) {
11351132 /* should only occur for DirEntry_from_find_data, in which case the
11361133 index is likely to be zero anyway. */
1137- result -> st_ino = ((( uint64_t ) info -> nFileIndexHigh ) << 32 ) + info -> nFileIndexLow ;
1134+ result -> st_ino = basic_info -> CreationTime . QuadPart ;
11381135 }
11391136
11401137 /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will
11411138 open other name surrogate reparse points without traversing them. To
11421139 detect/handle these, check st_file_attributes and st_reparse_tag. */
11431140 result -> st_reparse_tag = reparse_tag ;
1144- if (info -> dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
1141+ if (basic_info -> FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
11451142 reparse_tag == IO_REPARSE_TAG_SYMLINK ) {
11461143 /* set the bits that make this a symlink */
11471144 result -> st_mode = (result -> st_mode & ~S_IFMT ) | S_IFLNK ;
11481145 }
1149- result -> st_file_attributes = info -> dwFileAttributes ;
1146+ result -> st_file_attributes = basic_info -> FileAttributes ;
11501147}
11511148
11521149void
@@ -1213,6 +1210,63 @@ _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info,
12131210 }
12141211}
12151212
1213+ void
1214+ _Py_find_data_to_stat (WIN32_FIND_DATAW * find_data , struct _Py_stat_struct * result )
1215+ {
1216+ memset (result , 0 , sizeof (* result ));
1217+ result -> st_mode = attributes_to_mode (find_data -> dwFileAttributes );
1218+ FILE_TIME_to_time_t_nsec (& find_data -> ftCreationTime , & result -> st_ctime , & result -> st_ctime_nsec );
1219+ FILE_TIME_to_time_t_nsec (& find_data -> ftLastWriteTime , & result -> st_mtime , & result -> st_mtime_nsec );
1220+ FILE_TIME_to_time_t_nsec (& find_data -> ftLastAccessTime , & result -> st_atime , & result -> st_atime_nsec );
1221+ result -> st_size = ((long long )find_data -> nFileSizeHigh ) << 32 > find_data -> nFileSizeLow ;
1222+
1223+ if (find_data -> dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
1224+ find_data -> dwReserved0 == IO_REPARSE_TAG_SYMLINK ) {
1225+ /* first clear the S_IFMT bits */
1226+ result -> st_mode ^= (result -> st_mode & S_IFMT );
1227+ /* now set the bits that make this a symlink */
1228+ result -> st_mode |= S_IFLNK ;
1229+ }
1230+ result -> st_file_attributes = find_data -> dwFileAttributes ;
1231+ }
1232+
1233+ int
1234+ _Py_stat_from_file_handle (HANDLE h , struct _Py_stat_struct * result , ULONG reparse_tag , BOOL set_ino )
1235+ {
1236+ FILE_BASIC_INFO basic_info = {0 };
1237+ FILE_STANDARD_INFO standard_info = {0 };
1238+ FILE_ID_INFO idInfo = {0 };
1239+ FILE_ID_INFO * pIdInfo = & idInfo ;
1240+ if (!GetFileInformationByHandleEx (h , FileBasicInfo , & basic_info , sizeof (basic_info )) ||
1241+ !GetFileInformationByHandleEx (h , FileStandardInfo , & standard_info , sizeof (standard_info ))) {
1242+ /* The Win32 error is already set, but we also set errno for
1243+ callers who expect it */
1244+ switch (GetLastError ()) {
1245+ case ERROR_INVALID_PARAMETER :
1246+ case ERROR_INVALID_FUNCTION :
1247+ case ERROR_NOT_SUPPORTED :
1248+ /* Volumes and physical disks are block devices, e.g.
1249+ \\.\C: and \\.\PhysicalDrive0. */
1250+ memset (result , 0 , sizeof (* result ));
1251+ result -> st_mode = 0x6000 ; /* S_IFBLK */
1252+ }
1253+ PyErr_SetFromWindowsErr (0 );
1254+ errno = winerror_to_errno (GetLastError ());
1255+ return -1 ;
1256+ }
1257+
1258+ if (!GetFileInformationByHandleEx (h , FileIdInfo , & idInfo , sizeof (idInfo ))) {
1259+ /* Failed to get FileIdInfo, so do not pass it along */
1260+ pIdInfo = NULL ;
1261+ }
1262+
1263+ _Py_attribute_data_to_stat (& basic_info , & standard_info , pIdInfo , reparse_tag , result );
1264+ /* specific to fstat() */
1265+ if (set_ino ) {
1266+ result -> st_ino = basic_info .CreationTime .QuadPart ;
1267+ }
1268+ return 0 ;
1269+ }
12161270#endif
12171271
12181272/* Return information about a file.
@@ -1231,10 +1285,6 @@ int
12311285_Py_fstat_noraise (int fd , struct _Py_stat_struct * status )
12321286{
12331287#ifdef MS_WINDOWS
1234- BY_HANDLE_FILE_INFORMATION info ;
1235- FILE_BASIC_INFO basicInfo ;
1236- FILE_ID_INFO idInfo ;
1237- FILE_ID_INFO * pIdInfo = & idInfo ;
12381288 HANDLE h ;
12391289 int type ;
12401290
@@ -1266,21 +1316,7 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status)
12661316 return 0 ;
12671317 }
12681318
1269- if (!GetFileInformationByHandle (h , & info ) ||
1270- !GetFileInformationByHandleEx (h , FileBasicInfo , & basicInfo , sizeof (basicInfo ))) {
1271- /* The Win32 error is already set, but we also set errno for
1272- callers who expect it */
1273- errno = winerror_to_errno (GetLastError ());
1274- return -1 ;
1275- }
1276-
1277- if (!GetFileInformationByHandleEx (h , FileIdInfo , & idInfo , sizeof (idInfo ))) {
1278- /* Failed to get FileIdInfo, so do not pass it along */
1279- pIdInfo = NULL ;
1280- }
1281-
1282- _Py_attribute_data_to_stat (& info , 0 , & basicInfo , pIdInfo , status );
1283- return 0 ;
1319+ return _Py_stat_from_file_handle (h , status , 0 , TRUE);
12841320#else
12851321 return fstat (fd , status );
12861322#endif
0 commit comments