@@ -1248,12 +1248,14 @@ public sealed class stat_result : PythonTuple {
12481248 internal stat_result ( int mode ) : this ( new object [ 10 ] { mode , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } , null ) { }
12491249
12501250 internal stat_result ( Mono . Unix . Native . Stat stat )
1251- : this ( new object [ 16 ] { ( int ) stat . st_mode , ToInt ( stat . st_ino ) , ToInt ( stat . st_dev ) , ToInt ( stat . st_nlink ) , ToInt ( stat . st_uid ) , ToInt ( stat . st_gid ) , ToInt ( stat . st_size ) , ToInt ( stat . st_atime ) , ToInt ( stat . st_mtime ) , ToInt ( stat . st_ctime ) ,
1251+ : this ( new object [ 16 ] { Mono . Unix . Native . NativeConvert . FromFilePermissions ( stat . st_mode ) , ToInt ( stat . st_ino ) , ToInt ( stat . st_dev ) , ToInt ( stat . st_nlink ) , ToInt ( stat . st_uid ) , ToInt ( stat . st_gid ) , ToInt ( stat . st_size ) ,
1252+ ToInt ( stat . st_atime ) , ToInt ( stat . st_mtime ) , ToInt ( stat . st_ctime ) ,
12521253 stat . st_atime + stat . st_atime_nsec / ( double ) nanosecondsPerSeconds , stat . st_mtime + stat . st_mtime_nsec / ( double ) nanosecondsPerSeconds , stat . st_ctime + stat . st_ctime_nsec / ( double ) nanosecondsPerSeconds ,
12531254 ToInt ( stat . st_atime * nanosecondsPerSeconds + stat . st_atime_nsec ) , ToInt ( stat . st_mtime * nanosecondsPerSeconds + stat . st_mtime_nsec ) , ToInt ( stat . st_ctime * nanosecondsPerSeconds + stat . st_ctime_nsec ) } , null ) { }
12541255
12551256 internal stat_result ( int mode , ulong fileidx , long size , long st_atime_ns , long st_mtime_ns , long st_ctime_ns )
1256- : this ( new object [ 16 ] { mode , ToInt ( fileidx ) , 0 , 0 , 0 , 0 , ToInt ( size ) , ToInt ( st_atime_ns / nanosecondsPerSeconds ) , ToInt ( st_mtime_ns / nanosecondsPerSeconds ) , ToInt ( st_ctime_ns / nanosecondsPerSeconds ) ,
1257+ : this ( new object [ 16 ] { mode , ToInt ( fileidx ) , 0 , 0 , 0 , 0 , ToInt ( size ) ,
1258+ ToInt ( st_atime_ns / nanosecondsPerSeconds ) , ToInt ( st_mtime_ns / nanosecondsPerSeconds ) , ToInt ( st_ctime_ns / nanosecondsPerSeconds ) ,
12571259 st_atime_ns / ( double ) nanosecondsPerSeconds , st_mtime_ns / ( double ) nanosecondsPerSeconds , st_ctime_ns / ( double ) nanosecondsPerSeconds ,
12581260 ToInt ( st_atime_ns ) , ToInt ( st_mtime_ns ) , ToInt ( st_ctime_ns ) } , null ) { }
12591261
@@ -1495,54 +1497,30 @@ public static object stat(CodeContext context, int fd)
14951497 => fstat ( context , fd ) ;
14961498
14971499 public static string strerror ( int code ) {
1498- switch ( code ) {
1499- case 0 : return "No error" ;
1500- case PythonErrorNumber . E2BIG : return "Arg list too long" ;
1501- case PythonErrorNumber . EACCES : return "Permission denied" ;
1502- case PythonErrorNumber . EAGAIN : return "Resource temporarily unavailable" ;
1503- case PythonErrorNumber . EBADF : return "Bad file descriptor" ;
1504- case PythonErrorNumber . EBUSY : return "Resource device" ;
1505- case PythonErrorNumber . ECHILD : return "No child processes" ;
1506- case PythonErrorNumber . EDEADLK : return "Resource deadlock avoided" ;
1507- case PythonErrorNumber . EDOM : return "Domain error" ;
1508- case PythonErrorNumber . EDQUOT : return "Unknown error" ;
1509- case PythonErrorNumber . EEXIST : return "File exists" ;
1510- case PythonErrorNumber . EFAULT : return "Bad address" ;
1511- case PythonErrorNumber . EFBIG : return "File too large" ;
1512- case PythonErrorNumber . EILSEQ : return "Illegal byte sequence" ;
1513- case PythonErrorNumber . EINTR : return "Interrupted function call" ;
1514- case PythonErrorNumber . EINVAL : return "Invalid argument" ;
1515- case PythonErrorNumber . EIO : return "Input/output error" ;
1516- case PythonErrorNumber . EISCONN : return "Unknown error" ;
1517- case PythonErrorNumber . EISDIR : return "Is a directory" ;
1518- case PythonErrorNumber . EMFILE : return "Too many open files" ;
1519- case PythonErrorNumber . EMLINK : return "Too many links" ;
1520- case PythonErrorNumber . ENAMETOOLONG : return "Filename too long" ;
1521- case PythonErrorNumber . ENFILE : return "Too many open files in system" ;
1522- case PythonErrorNumber . ENODEV : return "No such device" ;
1523- case PythonErrorNumber . ENOENT : return "No such file or directory" ;
1524- case PythonErrorNumber . ENOEXEC : return "Exec format error" ;
1525- case PythonErrorNumber . ENOLCK : return "No locks available" ;
1526- case PythonErrorNumber . ENOMEM : return "Not enough space" ;
1527- case PythonErrorNumber . ENOSPC : return "No space left on device" ;
1528- case PythonErrorNumber . ENOSYS : return "Function not implemented" ;
1529- case PythonErrorNumber . ENOTDIR : return "Not a directory" ;
1530- case PythonErrorNumber . ENOTEMPTY : return "Directory not empty" ;
1531- case PythonErrorNumber . ENOTSOCK : return "Unknown error" ;
1532- case PythonErrorNumber . ENOTTY : return "Inappropriate I/O control operation" ;
1533- case PythonErrorNumber . ENXIO : return "No such device or address" ;
1534- case PythonErrorNumber . EPERM : return "Operation not permitted" ;
1535- case PythonErrorNumber . EPIPE : return "Broken pipe" ;
1536- case PythonErrorNumber . ERANGE : return "Result too large" ;
1537- case PythonErrorNumber . EROFS : return "Read-only file system" ;
1538- case PythonErrorNumber . ESPIPE : return "Invalid seek" ;
1539- case PythonErrorNumber . ESRCH : return "No such process" ;
1540- case PythonErrorNumber . EXDEV : return "Improper link" ;
1541- default :
1542- return "Unknown error " + code ;
1500+ #if FEATURE_NATIVE
1501+ const int bufsize = 0x1FF ;
1502+ var buffer = new StringBuilder ( bufsize ) ;
1503+
1504+ int result = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ?
1505+ Interop . Ucrtbase . strerror ( code , buffer ) :
1506+ strerror_r ( code , buffer ) ;
1507+
1508+ if ( result == 0 ) {
1509+ var msg = buffer . ToString ( ) ;
1510+ if ( msg . Length > 0 ) {
1511+ return msg ;
1512+ }
15431513 }
1514+ #endif
1515+ return "Unknown error " + code ;
15441516 }
15451517
1518+ #if FEATURE_NATIVE
1519+ // Isolate Mono.Unix from the rest of the method so that we don't try to load the Mono.Unix assembly on Windows.
1520+ private static int strerror_r ( int code , StringBuilder buffer )
1521+ => Mono . Unix . Native . Syscall . strerror_r ( Mono . Unix . Native . NativeConvert . ToErrno ( code ) , buffer ) ;
1522+ #endif
1523+
15461524#if FEATURE_PROCESS
15471525 [ Documentation ( "system(command) -> int\n Execute the command (a string) in a subshell." ) ]
15481526 public static int system ( [ NotNone ] string command ) {
@@ -1823,7 +1801,7 @@ public static PythonTuple waitpid(int pid, int options) {
18231801 Process ? process ;
18241802 lock ( _processToIdMapping ) {
18251803 if ( ! _processToIdMapping . TryGetValue ( pid , out process ) ) {
1826- throw PythonOps . OSError ( PythonErrorNumber . ECHILD , "No child processes" ) ;
1804+ throw GetOsError ( PythonErrorNumber . ECHILD ) ;
18271805 }
18281806 }
18291807
@@ -2207,15 +2185,13 @@ private static Exception DirectoryExists() {
22072185#if FEATURE_NATIVE
22082186
22092187 private static Exception GetLastUnixError ( string ? filename = null , string ? filename2 = null )
2210- => GetUnixError ( ( int ) Mono . Unix . Native . Syscall . GetLastError ( ) , filename , filename2 ) ;
2211-
2212- private static Exception GetUnixError ( int error , string ? filename = null , string ? filename2 = null ) {
2213- var msg = Mono . Unix . Native . Stdlib . strerror ( ( Mono . Unix . Native . Errno ) error ) ;
2214- return PythonOps . OSError ( error , msg , filename , null , filename2 ) ;
2215- }
2188+ => GetOsError ( Mono . Unix . Native . NativeConvert . FromErrno ( Mono . Unix . Native . Syscall . GetLastError ( ) ) , filename , filename2 ) ;
22162189
22172190#endif
22182191
2192+ private static Exception GetOsError ( int error , string ? filename = null , string ? filename2 = null )
2193+ => PythonOps . OSError ( error , strerror ( error ) , filename , null , filename2 ) ;
2194+
22192195#if FEATURE_NATIVE || FEATURE_CTYPES
22202196
22212197 // Gets an error message for a Win32 error code.
0 commit comments