@@ -437,15 +437,25 @@ public static object fspath(CodeContext context, [AllowNull] object path)
437437 [ LightThrowing ]
438438 public static object fstat ( CodeContext /*!*/ context , int fd ) {
439439 PythonContext pythonContext = context . LanguageContext ;
440- if ( pythonContext . FileManager . TryGetFileFromId ( pythonContext , fd , out PythonIOModule . FileIO file ) ) {
440+ pythonContext . FileManager . TryGetObjectFromId ( pythonContext , fd , out object obj ) ;
441+ if ( obj is PythonIOModule . FileIO file ) {
441442 if ( file . IsConsole ) return new stat_result ( 8192 ) ;
442- if ( file . _readStream is PipeStream ) return new stat_result ( 4096 ) ;
443- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) || RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
444- if ( IsUnixStream ( file . _readStream ) ) return new stat_result ( 4096 ) ;
445- }
443+ if ( StatStream ( file . _readStream ) is not null and var res ) return res ;
446444 if ( file . name is string strName ) return lstat ( strName , new Dictionary < string , object > ( 1 ) ) ;
445+ } else if ( obj is Stream stream && StatStream ( stream ) is not null and var res ) {
446+ return res ;
447+ }
448+ return LightExceptions . Throw ( PythonOps . OSError ( 9 , "Bad file descriptor" ) ) ;
449+
450+ static stat_result ? StatStream ( Stream stream ) {
451+ if ( stream is PipeStream ) return new stat_result ( 4096 ) ;
452+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
453+ if ( ReferenceEquals ( stream , Stream . Null ) ) return new stat_result ( 8192 ) ;
454+ } else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) || RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) {
455+ if ( IsUnixStream ( stream ) ) return new stat_result ( 4096 ) ;
456+ }
457+ return null ;
447458 }
448- throw PythonOps . OSError ( 9 , "Bad file descriptor" ) ;
449459
450460 static bool IsUnixStream ( Stream stream ) {
451461 return stream is Mono . Unix . UnixStream ;
@@ -843,8 +853,7 @@ public static object open(CodeContext/*!*/ context, [NotNone] string path, int f
843853 FileAccess access = FileAccessFromFlags ( flags ) ;
844854 FileOptions options = FileOptionsFromFlags ( flags ) ;
845855 Stream fs ;
846- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) && string . Equals ( path , "nul" , StringComparison . OrdinalIgnoreCase )
847- || ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) || RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) && path == "/dev/null" ) {
856+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) && IsNulFile ( path ) ) {
848857 fs = Stream . Null ;
849858 } else if ( access == FileAccess . Read && ( fileMode == FileMode . CreateNew || fileMode == FileMode . Create || fileMode == FileMode . Append ) ) {
850859 // .NET doesn't allow Create/CreateNew w/ access == Read, so create the file, then close it, then
@@ -1427,7 +1436,9 @@ public static object stat([NotNone] string path, [ParamDictionary, NotNone] IDic
14271436 int mode = 0 ;
14281437 long size ;
14291438
1430- if ( Directory . Exists ( path ) ) {
1439+ if ( IsNulFile ( path ) ) {
1440+ return new stat_result ( 0x2000 ) ;
1441+ } else if ( Directory . Exists ( path ) ) {
14311442 size = 0 ;
14321443 mode = 0x4000 | S_IEXEC ;
14331444 } else if ( File . Exists ( path ) ) {
@@ -2337,6 +2348,13 @@ private static void VerifyPath(string path, string functionName, string argName)
23372348 if ( path . IndexOf ( ( char ) 0 ) != - 1 ) throw PythonOps . ValueError ( $ "{ functionName } : embedded null character in { argName } ") ;
23382349 }
23392350
2351+ [ SupportedOSPlatform ( "windows" ) ]
2352+ private static bool IsNulFile ( string path )
2353+ => path . StartsWith ( "nul" , StringComparison . OrdinalIgnoreCase )
2354+ && ( path . Length == 3
2355+ || path . Length == 4 && path [ 3 ] == ':'
2356+ || path . Length == 5 && path [ 3 ] == ':' && path [ 4 ] == ':' ) ;
2357+
23402358 #endregion
23412359 }
23422360}
0 commit comments