55#if FEATURE_MMAP
66
77using System ;
8- using System . ComponentModel ;
98using System . Diagnostics ;
109using System . Globalization ;
1110using System . IO ;
@@ -205,12 +204,12 @@ public static class MmapModule {
205204
206205 public static readonly string __doc__ = null ;
207206
208- private static string FormatError ( int errorCode ) {
209- return new Win32Exception ( errorCode ) . Message ;
210- }
211-
212- private static Exception WindowsError ( int code ) {
213- return PythonExceptions . CreateThrowable ( PythonExceptions . OSError , code , FormatError ( code ) ) ;
207+ private static Exception WindowsError ( int winerror ) {
208+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
209+ return PythonNT . GetWin32Error ( winerror ) ;
210+ } else {
211+ return PythonNT . GetOsError ( PythonExceptions . _OSError . WinErrorToErrno ( winerror ) ) ;
212+ }
214213 }
215214
216215 public static PythonType error => PythonExceptions . OSError ;
@@ -234,7 +233,7 @@ public MmapUnix(CodeContext/*!*/ context, int fileno, long length, int flags = M
234233 private static MemoryMappedFileAccess ToMmapFileAccess ( int flags , int prot , int access ) {
235234 if ( access == ACCESS_DEFAULT ) {
236235 if ( ( flags & ( MAP_PRIVATE | MAP_SHARED ) ) == 0 ) {
237- throw PythonOps . OSError ( PythonErrno . EINVAL , "Invalid argument" ) ;
236+ throw PythonNT . GetOsError ( PythonErrno . EINVAL ) ;
238237 }
239238 if ( ( prot & PROT_WRITE ) != 0 ) {
240239 prot |= PROT_READ ;
@@ -339,13 +338,13 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
339338#if NET8_0_OR_GREATER
340339 // On .NET 8.0+ we can create a MemoryMappedFile directly from a file descriptor
341340 stream . Flush ( ) ;
342- CheckFileAccessAndSize ( stream ) ;
343- fileno = Dup ( fileno ) ;
341+ CheckFileAccessAndSize ( stream , isWindows : false ) ;
342+ fileno = PythonNT . dupUnix ( fileno , closeOnExec : true ) ;
344343 _handle = new SafeFileHandle ( ( IntPtr ) fileno , ownsHandle : true ) ;
345344 _file = MemoryMappedFile . CreateFromFile ( _handle , _mapName , stream . Length , _fileAccess , HandleInheritability . None , leaveOpen : true ) ;
346345#else
347346 // On .NET 6.0 on POSIX we need to create a FileStream from the file descriptor
348- fileno = Dup ( fileno ) ;
347+ fileno = PythonNT . dupUnix ( fileno , closeOnExec : true ) ;
349348 _handle = new SafeFileHandle ( ( IntPtr ) fileno , ownsHandle : true ) ;
350349 FileAccess fa = stream . CanWrite ? stream . CanRead ? FileAccess . ReadWrite : FileAccess . Write : FileAccess . Read ;
351350 // This FileStream constructor may or may not work on Mono, but on Mono streams.ReadStream is FileStream
@@ -356,7 +355,7 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
356355 }
357356 // otherwise leaves _file as null and _sourceStream as null
358357 } else {
359- throw PythonOps . OSError ( PythonExceptions . _OSError . ERROR_INVALID_BLOCK , "Bad file descriptor" ) ;
358+ throw PythonNT . GetOsError ( PythonErrno . EBADF ) ;
360359 }
361360
362361 if ( _file is null ) {
@@ -369,7 +368,7 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
369368 length = _sourceStream . Length - _offset ;
370369 }
371370
372- CheckFileAccessAndSize ( _sourceStream ) ;
371+ CheckFileAccessAndSize ( _sourceStream , RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) ;
373372
374373 long capacity = checked ( _offset + length ) ;
375374
@@ -402,7 +401,7 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
402401 }
403402 _position = 0L ;
404403
405- void CheckFileAccessAndSize ( Stream stream ) {
404+ void CheckFileAccessAndSize ( Stream stream , bool isWindows ) {
406405 bool isValid = _fileAccess switch {
407406 MemoryMappedFileAccess . Read => stream . CanRead ,
408407 MemoryMappedFileAccess . ReadWrite => stream . CanRead && stream . CanWrite ,
@@ -414,10 +413,10 @@ void CheckFileAccessAndSize(Stream stream) {
414413
415414 try {
416415 if ( ! isValid ) {
417- throw PythonOps . OSError ( PythonExceptions . _OSError . ERROR_ACCESS_DENIED , "Invalid access mode" ) ;
416+ throw WindowsError ( PythonExceptions . _OSError . ERROR_ACCESS_DENIED ) ;
418417 }
419418
420- if ( ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ) {
419+ if ( ! isWindows ) {
421420 // Unix map does not support increasing size on open
422421 if ( length != 0 && _offset + length > stream . Length ) {
423422 throw PythonOps . ValueError ( "mmap length is greater than file size" ) ;
@@ -437,29 +436,6 @@ void CheckFileAccessAndSize(Stream stream) {
437436 } // end of constructor
438437
439438
440- // TODO: Move to PythonNT - POSIX
441- private static int Dup ( int fd ) {
442- int fd2 = Mono . Unix . Native . Syscall . dup ( fd ) ;
443- if ( fd2 == - 1 ) throw PythonNT . GetLastUnixError ( ) ;
444-
445- try {
446- // set close-on-exec flag
447- int flags = Mono . Unix . Native . Syscall . fcntl ( fd2 , Mono . Unix . Native . FcntlCommand . F_GETFD ) ;
448- if ( flags == - 1 ) throw PythonNT . GetLastUnixError ( ) ;
449-
450- const int FD_CLOEXEC = 1 ; // TODO: Move to module fcntl
451- flags |= FD_CLOEXEC ;
452- flags = Mono . Unix . Native . Syscall . fcntl ( fd2 , Mono . Unix . Native . FcntlCommand . F_SETFD , flags ) ;
453- if ( flags == - 1 ) throw PythonNT . GetLastUnixError ( ) ;
454- } catch {
455- Mono . Unix . Native . Syscall . close ( fd2 ) ;
456- throw ;
457- }
458-
459- return fd2 ;
460- }
461-
462-
463439 public object __len__ ( ) {
464440 using ( new MmapLocker ( this ) ) {
465441 return ReturnLong ( _view . Capacity ) ;
@@ -825,12 +801,20 @@ public void resize(long newsize) {
825801 throw PythonOps . TypeError ( "mmap can't resize a readonly or copy-on-write memory map." ) ;
826802 }
827803
804+ if ( newsize < 0 ) {
805+ throw PythonOps . ValueError ( "new size out of range" ) ;
806+ }
807+
828808 if ( _handle is not null
829809 && ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) || RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ) ) {
830810 // resize on Posix platforms
831811 try {
832812 if ( _handle . IsInvalid ) {
833- throw PythonOps . OSError ( PythonErrno . EBADF , "Bad file descriptor" ) ;
813+ throw PythonNT . GetOsError ( PythonErrno . EBADF ) ;
814+ }
815+ if ( newsize == 0 ) {
816+ // resizing to an empty mapped region is not allowed
817+ throw PythonNT . GetOsError ( PythonErrno . EINVAL ) ;
834818 }
835819 _view . Flush ( ) ;
836820 _view . Dispose ( ) ;
@@ -1132,20 +1116,18 @@ internal Bytes GetSearchString() {
11321116 }
11331117 }
11341118
1135- [ SupportedOSPlatform ( "linux" ) , SupportedOSPlatform ( "macos" ) ]
1119+ [ SupportedOSPlatform ( "linux" ) ]
1120+ [ SupportedOSPlatform ( "macos" ) ]
11361121 private static long GetFileSizeUnix ( SafeFileHandle handle ) {
11371122 long size ;
11381123 if ( handle . IsInvalid ) {
1139- throw PythonOps . OSError ( PythonExceptions . _OSError . ERROR_INVALID_HANDLE , "Invalid file handle" ) ;
1124+ throw PythonNT . GetOsError ( PythonErrno . EBADF ) ;
11401125 }
11411126
11421127 if ( Mono . Unix . Native . Syscall . fstat ( ( int ) handle . DangerousGetHandle ( ) , out Mono . Unix . Native . Stat status ) == 0 ) {
11431128 size = status . st_size ;
11441129 } else {
1145- Mono . Unix . Native . Errno errno = Mono . Unix . Native . Stdlib . GetLastError ( ) ;
1146- string msg = Mono . Unix . UnixMarshal . GetErrorDescription ( errno ) ;
1147- int error = Mono . Unix . Native . NativeConvert . FromErrno ( errno ) ;
1148- throw PythonOps . OSError ( error , msg ) ;
1130+ throw PythonNT . GetLastUnixError ( ) ;
11491131 }
11501132
11511133 return size ;
0 commit comments