@@ -1264,12 +1264,14 @@ public sealed class stat_result : PythonTuple {
12641264 internal stat_result ( int mode ) : this ( new object [ 10 ] { mode , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } , null ) { }
12651265
12661266 internal stat_result ( Mono . Unix . Native . Stat stat )
1267- : 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 ) ,
1267+ : 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 ) ,
1268+ ToInt ( stat . st_atime ) , ToInt ( stat . st_mtime ) , ToInt ( stat . st_ctime ) ,
12681269 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 ,
12691270 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 ) { }
12701271
12711272 internal stat_result ( int mode , ulong fileidx , long size , long st_atime_ns , long st_mtime_ns , long st_ctime_ns )
1272- : 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 ) ,
1273+ : this ( new object [ 16 ] { mode , ToInt ( fileidx ) , 0 , 0 , 0 , 0 , ToInt ( size ) ,
1274+ ToInt ( st_atime_ns / nanosecondsPerSeconds ) , ToInt ( st_mtime_ns / nanosecondsPerSeconds ) , ToInt ( st_ctime_ns / nanosecondsPerSeconds ) ,
12731275 st_atime_ns / ( double ) nanosecondsPerSeconds , st_mtime_ns / ( double ) nanosecondsPerSeconds , st_ctime_ns / ( double ) nanosecondsPerSeconds ,
12741276 ToInt ( st_atime_ns ) , ToInt ( st_mtime_ns ) , ToInt ( st_ctime_ns ) } , null ) { }
12751277
@@ -1519,54 +1521,30 @@ public static object stat(CodeContext context, int fd)
15191521 => fstat ( context , fd ) ;
15201522
15211523 public static string strerror ( int code ) {
1522- switch ( code ) {
1523- case 0 : return "No error" ;
1524- case PythonErrorNumber . E2BIG : return "Arg list too long" ;
1525- case PythonErrorNumber . EACCES : return "Permission denied" ;
1526- case PythonErrorNumber . EAGAIN : return "Resource temporarily unavailable" ;
1527- case PythonErrorNumber . EBADF : return "Bad file descriptor" ;
1528- case PythonErrorNumber . EBUSY : return "Resource device" ;
1529- case PythonErrorNumber . ECHILD : return "No child processes" ;
1530- case PythonErrorNumber . EDEADLK : return "Resource deadlock avoided" ;
1531- case PythonErrorNumber . EDOM : return "Domain error" ;
1532- case PythonErrorNumber . EDQUOT : return "Unknown error" ;
1533- case PythonErrorNumber . EEXIST : return "File exists" ;
1534- case PythonErrorNumber . EFAULT : return "Bad address" ;
1535- case PythonErrorNumber . EFBIG : return "File too large" ;
1536- case PythonErrorNumber . EILSEQ : return "Illegal byte sequence" ;
1537- case PythonErrorNumber . EINTR : return "Interrupted function call" ;
1538- case PythonErrorNumber . EINVAL : return "Invalid argument" ;
1539- case PythonErrorNumber . EIO : return "Input/output error" ;
1540- case PythonErrorNumber . EISCONN : return "Unknown error" ;
1541- case PythonErrorNumber . EISDIR : return "Is a directory" ;
1542- case PythonErrorNumber . EMFILE : return "Too many open files" ;
1543- case PythonErrorNumber . EMLINK : return "Too many links" ;
1544- case PythonErrorNumber . ENAMETOOLONG : return "Filename too long" ;
1545- case PythonErrorNumber . ENFILE : return "Too many open files in system" ;
1546- case PythonErrorNumber . ENODEV : return "No such device" ;
1547- case PythonErrorNumber . ENOENT : return "No such file or directory" ;
1548- case PythonErrorNumber . ENOEXEC : return "Exec format error" ;
1549- case PythonErrorNumber . ENOLCK : return "No locks available" ;
1550- case PythonErrorNumber . ENOMEM : return "Not enough space" ;
1551- case PythonErrorNumber . ENOSPC : return "No space left on device" ;
1552- case PythonErrorNumber . ENOSYS : return "Function not implemented" ;
1553- case PythonErrorNumber . ENOTDIR : return "Not a directory" ;
1554- case PythonErrorNumber . ENOTEMPTY : return "Directory not empty" ;
1555- case PythonErrorNumber . ENOTSOCK : return "Unknown error" ;
1556- case PythonErrorNumber . ENOTTY : return "Inappropriate I/O control operation" ;
1557- case PythonErrorNumber . ENXIO : return "No such device or address" ;
1558- case PythonErrorNumber . EPERM : return "Operation not permitted" ;
1559- case PythonErrorNumber . EPIPE : return "Broken pipe" ;
1560- case PythonErrorNumber . ERANGE : return "Result too large" ;
1561- case PythonErrorNumber . EROFS : return "Read-only file system" ;
1562- case PythonErrorNumber . ESPIPE : return "Invalid seek" ;
1563- case PythonErrorNumber . ESRCH : return "No such process" ;
1564- case PythonErrorNumber . EXDEV : return "Improper link" ;
1565- default :
1566- return "Unknown error " + code ;
1524+ #if FEATURE_NATIVE
1525+ const int bufsize = 0x1FF ;
1526+ var buffer = new StringBuilder ( bufsize ) ;
1527+
1528+ int result = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ?
1529+ Interop . Ucrtbase . strerror ( code , buffer ) :
1530+ strerror_r ( code , buffer ) ;
1531+
1532+ if ( result == 0 ) {
1533+ var msg = buffer . ToString ( ) ;
1534+ if ( msg . Length > 0 ) {
1535+ return msg ;
1536+ }
15671537 }
1538+ #endif
1539+ return "Unknown error " + code ;
15681540 }
15691541
1542+ #if FEATURE_NATIVE
1543+ // Isolate Mono.Unix from the rest of the method so that we don't try to load the Mono.Unix assembly on Windows.
1544+ private static int strerror_r ( int code , StringBuilder buffer )
1545+ => Mono . Unix . Native . Syscall . strerror_r ( Mono . Unix . Native . NativeConvert . ToErrno ( code ) , buffer ) ;
1546+ #endif
1547+
15701548#if FEATURE_PROCESS
15711549 [ Documentation ( "system(command) -> int\n Execute the command (a string) in a subshell." ) ]
15721550 public static int system ( [ NotNone ] string command ) {
@@ -1854,7 +1832,7 @@ public static PythonTuple waitpid(int pid, int options) {
18541832 Process ? process ;
18551833 lock ( _processToIdMapping ) {
18561834 if ( ! _processToIdMapping . TryGetValue ( pid , out process ) ) {
1857- throw PythonOps . OSError ( PythonErrorNumber . ECHILD , "No child processes" ) ;
1835+ throw GetOsError ( PythonErrorNumber . ECHILD ) ;
18581836 }
18591837 }
18601838
@@ -2238,15 +2216,13 @@ private static Exception DirectoryExists() {
22382216#if FEATURE_NATIVE
22392217
22402218 private static Exception GetLastUnixError ( string ? filename = null , string ? filename2 = null )
2241- => GetUnixError ( ( int ) Mono . Unix . Native . Syscall . GetLastError ( ) , filename , filename2 ) ;
2242-
2243- private static Exception GetUnixError ( int error , string ? filename = null , string ? filename2 = null ) {
2244- var msg = Mono . Unix . Native . Stdlib . strerror ( ( Mono . Unix . Native . Errno ) error ) ;
2245- return PythonOps . OSError ( error , msg , filename , null , filename2 ) ;
2246- }
2219+ => GetOsError ( Mono . Unix . Native . NativeConvert . FromErrno ( Mono . Unix . Native . Syscall . GetLastError ( ) ) , filename , filename2 ) ;
22472220
22482221#endif
22492222
2223+ private static Exception GetOsError ( int error , string ? filename = null , string ? filename2 = null )
2224+ => PythonOps . OSError ( error , strerror ( error ) , filename , null , filename2 ) ;
2225+
22502226#if FEATURE_NATIVE || FEATURE_CTYPES
22512227
22522228 // Gets an error message for a Win32 error code.
0 commit comments