@@ -565,7 +565,8 @@ attributes_to_mode(DWORD attr)
565565}
566566
567567void
568- _Py_attribute_data_to_stat (BY_HANDLE_FILE_INFORMATION * info , ULONG reparse_tag , struct _Py_stat_struct * result )
568+ _Py_attribute_data_to_stat (BY_HANDLE_FILE_INFORMATION * info , ULONG reparse_tag ,
569+ struct _Py_stat_struct * result )
569570{
570571 memset (result , 0 , sizeof (* result ));
571572 result -> st_mode = attributes_to_mode (info -> dwFileAttributes );
@@ -595,9 +596,12 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag,
595596 files larger than 2 GB. fstat() may fail with EOVERFLOW on files larger
596597 than 2 GB because the file size type is an signed 32-bit integer: see issue
597598 #23152.
598- */
599+
600+ On Windows, set the last Windows error and return nonzero on error. On
601+ POSIX, set errno and return nonzero on error. Fill status and return 0 on
602+ success. */
599603int
600- _Py_fstat (int fd , struct _Py_stat_struct * result )
604+ _Py_fstat_noraise (int fd , struct _Py_stat_struct * status )
601605{
602606#ifdef MS_WINDOWS
603607 BY_HANDLE_FILE_INFORMATION info ;
@@ -619,38 +623,70 @@ _Py_fstat(int fd, struct _Py_stat_struct *result)
619623 SetLastError (ERROR_INVALID_HANDLE );
620624 return -1 ;
621625 }
622- memset (result , 0 , sizeof (* result ));
626+ memset (status , 0 , sizeof (* status ));
623627
624628 type = GetFileType (h );
625629 if (type == FILE_TYPE_UNKNOWN ) {
626630 DWORD error = GetLastError ();
627- if (error != 0 ) {
631+ if (error != 0 )
628632 return -1 ;
629- }
630633 /* else: valid but unknown file */
631634 }
632635
633636 if (type != FILE_TYPE_DISK ) {
634637 if (type == FILE_TYPE_CHAR )
635- result -> st_mode = _S_IFCHR ;
638+ status -> st_mode = _S_IFCHR ;
636639 else if (type == FILE_TYPE_PIPE )
637- result -> st_mode = _S_IFIFO ;
640+ status -> st_mode = _S_IFIFO ;
638641 return 0 ;
639642 }
640643
641644 if (!GetFileInformationByHandle (h , & info )) {
642645 return -1 ;
643646 }
644647
645- _Py_attribute_data_to_stat (& info , 0 , result );
648+ _Py_attribute_data_to_stat (& info , 0 , status );
646649 /* specific to fstat() */
647- result -> st_ino = (((__int64 )info .nFileIndexHigh )<<32 ) + info .nFileIndexLow ;
650+ status -> st_ino = (((__int64 )info .nFileIndexHigh )<<32 ) + info .nFileIndexLow ;
648651 return 0 ;
649652#else
650- return fstat (fd , result );
653+ return fstat (fd , status );
651654#endif
652655}
653656
657+ /* Return information about a file.
658+
659+ On POSIX, use fstat().
660+
661+ On Windows, use GetFileType() and GetFileInformationByHandle() which support
662+ files larger than 2 GB. fstat() may fail with EOVERFLOW on files larger
663+ than 2 GB because the file size type is an signed 32-bit integer: see issue
664+ #23152.
665+
666+ Raise an exception and return -1 on error. On Windows, set the last Windows
667+ error on error. On POSIX, set errno on error. Fill status and return 0 on
668+ success.
669+
670+ The GIL must be held. */
671+ int
672+ _Py_fstat (int fd , struct _Py_stat_struct * status )
673+ {
674+ int res ;
675+
676+ Py_BEGIN_ALLOW_THREADS
677+ res = _Py_fstat_noraise (fd , status );
678+ Py_END_ALLOW_THREADS
679+
680+ if (res != 0 ) {
681+ #ifdef MS_WINDOWS
682+ PyErr_SetFromWindowsErr (0 );
683+ #else
684+ PyErr_SetFromErrno (PyExc_OSError );
685+ #endif
686+ return -1 ;
687+ }
688+ return 0 ;
689+ }
654690
655691/* Call _wstat() on Windows, or encode the path to the filesystem encoding and
656692 call stat() otherwise. Only fill st_mode attribute on Windows.
0 commit comments