Skip to content

Commit 1cd8e71

Browse files
authored
Isolate POSIX-specific native calls in PythonNT into separate file (#1870)
* Isolate POSIX-specific native calls in PythonNT into separate file * Simplify error creation * Clean up some error usage in mmap * Normalize macos platform name * Fix some mmap errors on POSIX * Move more functions to posix.cs * Update after review
1 parent 9082851 commit 1cd8e71

File tree

7 files changed

+300
-201
lines changed

7 files changed

+300
-201
lines changed

Src/IronPython.Modules/_overlapped.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
using System;
66
using System.Numerics;
77
using System.Runtime.InteropServices;
8+
using System.Runtime.Versioning;
89

910
using IronPython.Runtime;
1011

1112
[assembly: PythonModule("_overlapped", typeof(IronPython.Modules.PythonOverlapped), PlatformsAttribute.PlatformFamily.Windows)]
1213
namespace IronPython.Modules {
14+
15+
[SupportedOSPlatform("windows")]
1316
public static class PythonOverlapped {
1417
public const int ERROR_NETNAME_DELETED = 64;
1518
public const int ERROR_SEM_TIMEOUT = 121;

Src/IronPython.Modules/_winapi.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
using System;
1010
using System.Numerics;
1111
using System.Runtime.InteropServices;
12+
using System.Runtime.Versioning;
1213
using System.Text;
1314

1415
using IronPython.Runtime;
1516
using IronPython.Runtime.Operations;
1617

1718
[assembly: PythonModule("_winapi", typeof(IronPython.Modules.PythonWinApi), PlatformsAttribute.PlatformFamily.Windows)]
1819
namespace IronPython.Modules {
20+
[SupportedOSPlatform("windows")]
1921
public static class PythonWinApi {
2022
#region Public API
2123

Src/IronPython.Modules/mmap.cs

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#if FEATURE_MMAP
66

77
using System;
8-
using System.ComponentModel;
98
using System.Diagnostics;
109
using System.Globalization;
1110
using 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

Comments
 (0)