From e4d75c41635d567299564e8fb5f2c588fd7188f9 Mon Sep 17 00:00:00 2001 From: AMS21 Date: Wed, 29 Nov 2023 03:33:40 +0100 Subject: [PATCH] Generalize bug fix from #1512 (#1523) --- src/Common/PlatformLinux.inl | 28 +++++++++++++++++++++++++++- src/Common/PlatformWindows.inl | 2 ++ src/xrCore/FS.cpp | 18 ++---------------- src/xrCore/LocatorAPI.cpp | 6 +++--- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/Common/PlatformLinux.inl b/src/Common/PlatformLinux.inl index 0fbd663b165..4693ea525d1 100644 --- a/src/Common/PlatformLinux.inl +++ b/src/Common/PlatformLinux.inl @@ -429,7 +429,7 @@ inline int _rmdir(const char *path) } #define _write write #define _strupr strupr -#define _read read +#define _read xr_read #define _set_new_handler std::set_new_handler #define _finite isfinite inline int _mkdir(const char *dir) { return mkdir(dir, S_IRWXU); } @@ -1108,3 +1108,29 @@ inline tm* localtime_safe(const time_t *time, struct tm* result){ return localti #define xr_strerror(errno, buffer, bufferSize) strerror_r(errno, buffer, sizeof(buffer)) using xrpid_t = pid_t; + +// This is a drop-in replacement for calls to linux 'read' function. We use this because unlike other OSes +// Linux 'read' function can return less then the requested number of bytes and might need to be called multiple times. +// Apart from this, it behaves exactly as you would expect and matches the other OSes implementation. +// See also: https://www.man7.org/linux/man-pages/man2/read.2.html +inline ssize_t xr_read(int file_handle, void *buffer, size_t count) +{ + ssize_t total_r_bytes = 0; + do + { + const ssize_t r_bytes = + read(file_handle, reinterpret_cast(buffer) + total_r_bytes, count - total_r_bytes); + + // Check for error + if (r_bytes == -1) + return -1; + + // Check for EOF otherwise we would loop indefinitely + if (r_bytes == 0) + return total_r_bytes; + + total_r_bytes += r_bytes; + } while (static_cast(total_r_bytes) < count); + + return total_r_bytes; +} diff --git a/src/Common/PlatformWindows.inl b/src/Common/PlatformWindows.inl index f23fac4c2a9..fdebbd48f95 100644 --- a/src/Common/PlatformWindows.inl +++ b/src/Common/PlatformWindows.inl @@ -64,3 +64,5 @@ inline tm* localtime_safe(const time_t *time, struct tm* result){ return localti #define xr_strerror(errno, buffer, bufferSize) strerror_s(buffer, sizeof(buffer), errno) using xrpid_t = DWORD; + +using ssize_t = SSIZE_T; diff --git a/src/xrCore/FS.cpp b/src/xrCore/FS.cpp index b253123831c..f9fc17e07c0 100644 --- a/src/xrCore/FS.cpp +++ b/src/xrCore/FS.cpp @@ -134,22 +134,8 @@ void* FileDownload(pcstr file_name, const int& file_handle, size_t& file_size) VERIFY(file_size != 0); void* buffer = xr_malloc(file_size); -#ifdef XR_PLATFORM_LINUX - size_t total_r_bytes = 0; - do - { - const ssize_t r_bytes = - _read(file_handle, reinterpret_cast(buffer) + total_r_bytes, file_size - total_r_bytes); - R_ASSERT3(r_bytes > 0, "Can't read from file : ", file_name); - - total_r_bytes += r_bytes; - } while (total_r_bytes < file_size); -#elif defined(XR_PLATFORM_WINDOWS) || defined(XR_PLATFORM_BSD) || defined(XR_PLATFORM_APPLE) - int total_r_bytes = _read(file_handle, buffer, file_size); -#else -# error Select or add implementation for your platform -#endif - R_ASSERT3(total_r_bytes == file_size, "Can't read from file : ", file_name); + const ssize_t r_bytes = _read(file_handle, buffer, file_size); + R_ASSERT3(r_bytes > 0 && static_cast(r_bytes) == file_size, "Can't read from file : ", file_name); // file_size = r_bytes; diff --git a/src/xrCore/LocatorAPI.cpp b/src/xrCore/LocatorAPI.cpp index 3a1258a3c59..73a08a99367 100644 --- a/src/xrCore/LocatorAPI.cpp +++ b/src/xrCore/LocatorAPI.cpp @@ -339,14 +339,14 @@ IReader* open_chunk(int fd, u32 ID, pcstr archiveName, size_t archiveSize, bool while (true) { - read_byte = ::read(fd, &dwType, 4); + read_byte = _read(fd, &dwType, 4); if (read_byte == -1) return nullptr; else if (read_byte == 0) return nullptr; u32 tempSize = 0; - read_byte = ::read(fd, &tempSize, 4); + read_byte = _read(fd, &tempSize, 4); dwSize = tempSize; if (read_byte == -1) return nullptr; @@ -356,7 +356,7 @@ IReader* open_chunk(int fd, u32 ID, pcstr archiveName, size_t archiveSize, bool if ((dwType & ~CFS_CompressMark) == ID) { u8* src_data = xr_alloc(dwSize); - read_byte = ::read(fd, src_data, dwSize); + read_byte = _read(fd, src_data, dwSize); VERIFY(read_byte == dwSize); if (dwType & CFS_CompressMark)