diff --git a/cpp/src/arrow/io/file_test.cc b/cpp/src/arrow/io/file_test.cc index 81ae716ef67..ac40c285e6d 100644 --- a/cpp/src/arrow/io/file_test.cc +++ b/cpp/src/arrow/io/file_test.cc @@ -1150,5 +1150,48 @@ TEST_F(TestStdio, ReadStdinReadAfterClose) { ASSERT_EQ(sizeof(buffer), input.Tell()); } +#ifdef _WIN32 +// Test Windows error code mapping in mman.h +// Note: We include mman.h here to test the __map_mman_error function directly +#include "arrow/io/mman.h" + +TEST(TestMmanErrorMapping, MapCommonErrors) { + // Test that common Windows error codes map correctly to POSIX errno values. + // This verifies __map_mman_error() matches Arrow's WinErrorToErrno conventions. + + // File/path not found errors + ASSERT_EQ(__map_mman_error(ERROR_FILE_NOT_FOUND, EPERM), ENOENT); + ASSERT_EQ(__map_mman_error(ERROR_PATH_NOT_FOUND, EPERM), ENOENT); + + // Access/permission errors + ASSERT_EQ(__map_mman_error(ERROR_ACCESS_DENIED, EPERM), EACCES); + ASSERT_EQ(__map_mman_error(ERROR_SHARING_VIOLATION, EPERM), EACCES); + ASSERT_EQ(__map_mman_error(ERROR_LOCK_VIOLATION, EPERM), EACCES); + + // Invalid handle errors + ASSERT_EQ(__map_mman_error(ERROR_INVALID_HANDLE, EPERM), EBADF); + ASSERT_EQ(__map_mman_error(ERROR_INVALID_TARGET_HANDLE, EPERM), EBADF); + + // Invalid parameter/function errors + ASSERT_EQ(__map_mman_error(ERROR_INVALID_PARAMETER, EPERM), EINVAL); + ASSERT_EQ(__map_mman_error(ERROR_INVALID_FUNCTION, EPERM), EINVAL); + + // Memory/resource errors + ASSERT_EQ(__map_mman_error(ERROR_ARENA_TRASHED, EPERM), ENOMEM); + ASSERT_EQ(__map_mman_error(ERROR_NOT_ENOUGH_MEMORY, EPERM), ENOMEM); + ASSERT_EQ(__map_mman_error(ERROR_INVALID_BLOCK, EPERM), ENOMEM); + + ASSERT_EQ(__map_mman_error(ERROR_TOO_MANY_OPEN_FILES, EPERM), EMFILE); + ASSERT_EQ(__map_mman_error(ERROR_DISK_FULL, EPERM), ENOSPC); + + // Zero error code + ASSERT_EQ(__map_mman_error(0, EPERM), 0); + + // Unknown/unmapped error codes should return the default (deferr) + ASSERT_EQ(__map_mman_error(99999, EPERM), EPERM); + ASSERT_EQ(__map_mman_error(12345, EINVAL), EINVAL); +} +#endif // _WIN32 + } // namespace io } // namespace arrow diff --git a/cpp/src/arrow/io/mman.h b/cpp/src/arrow/io/mman.h index 04d450cbff5..be4cb289009 100644 --- a/cpp/src/arrow/io/mman.h +++ b/cpp/src/arrow/io/mman.h @@ -39,10 +39,73 @@ # define FILE_MAP_EXECUTE 0x0020 #endif +// Map Windows error codes from GetLastError() to POSIX errno values. +// +// Parameters: +// err: Must be a DWORD value from GetLastError() (not HRESULT, not NTSTATUS). +// This function is called immediately after Windows API calls that set +// the last error via SetLastError() / GetLastError(). +// deferr: Default errno value to return for unmapped errors. Callers pass +// EPERM as the default to maintain behavioral compatibility. +// +// Returns: +// POSIX errno value for known errors, or deferr for unmapped errors. +// +// Note: This function mirrors the mapping from Arrow's WinErrorToErrno() function +// (in arrow/util/io_util.cc) for consistency. All mapped error codes return the +// same errno values as WinErrorToErrno(). We cannot call WinErrorToErrno() +// directly because it's in an anonymous namespace and not exported, and this +// header must remain lightweight without additional dependencies. +// +// Unlike WinErrorToErrno() which returns 0 for unmapped errors, this function +// returns the deferr parameter to maintain compatibility with callers that +// explicitly pass a default (typically EPERM). +// +// The mapping covers common errors from memory mapping operations: +// - File/handle errors (ERROR_FILE_NOT_FOUND, ERROR_ACCESS_DENIED, etc.) +// - Memory/resource errors (ERROR_NOT_ENOUGH_MEMORY, etc.) +// - Parameter errors (ERROR_INVALID_PARAMETER, etc.) static inline int __map_mman_error(const DWORD err, const int deferr) { if (err == 0) return 0; - // TODO: implement - return err; + + switch (err) { + // File/path not found errors - matches WinErrorToErrno + case ERROR_FILE_NOT_FOUND: // 2 + case ERROR_PATH_NOT_FOUND: // 3 + return ENOENT; + + // Access/permission errors - matches WinErrorToErrno + case ERROR_ACCESS_DENIED: // 5 + case ERROR_SHARING_VIOLATION: // 32 + case ERROR_LOCK_VIOLATION: // 33 + return EACCES; + + // Invalid handle errors - matches WinErrorToErrno + case ERROR_INVALID_HANDLE: // 6 + case ERROR_INVALID_TARGET_HANDLE: // 114 + return EBADF; + + // Invalid parameter/function errors - matches WinErrorToErrno + case ERROR_INVALID_PARAMETER: // 87 + case ERROR_INVALID_FUNCTION: // 1 + return EINVAL; + + // Memory/resource errors - matches WinErrorToErrno + case ERROR_ARENA_TRASHED: // 7 + case ERROR_NOT_ENOUGH_MEMORY: // 8 + case ERROR_INVALID_BLOCK: // 9 + return ENOMEM; + + case ERROR_TOO_MANY_OPEN_FILES: // 4 + return EMFILE; + + case ERROR_DISK_FULL: // 112 + return ENOSPC; + + // Default: return the provided default errno for unmapped errors + default: + return deferr; + } } static inline DWORD __map_mmap_prot_page(const int prot) {