From 49b6dfb7c839ae6d7aa6c66823dc87df601fec9a Mon Sep 17 00:00:00 2001 From: attila Date: Wed, 5 Feb 2025 12:01:23 +0100 Subject: [PATCH] Fix 0 file descriptor handling on POSIX systems --- .../juce_core/detail/juce_NativeFileHandle.h | 57 +++++++++++++++++++ .../juce_core/files/juce_FileInputStream.cpp | 2 +- .../juce_core/files/juce_FileInputStream.h | 2 +- .../juce_core/files/juce_FileOutputStream.h | 2 +- modules/juce_core/juce_core.h | 1 + .../juce_core/native/juce_Files_android.cpp | 4 +- .../juce_core/native/juce_SharedCode_posix.h | 37 ++++++------ 7 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 modules/juce_core/detail/juce_NativeFileHandle.h diff --git a/modules/juce_core/detail/juce_NativeFileHandle.h b/modules/juce_core/detail/juce_NativeFileHandle.h new file mode 100644 index 0000000000..30f665dc18 --- /dev/null +++ b/modules/juce_core/detail/juce_NativeFileHandle.h @@ -0,0 +1,57 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce::detail +{ + +#if JUCE_WINDOWS +using NativeFileHandle = void*; +#else +class NativeFileHandle +{ + static constexpr int invalidFd = -1; + +public: + int get() const noexcept { return fd; } + bool isValid() const noexcept { return 0 <= fd; } + + void set (int newFd) noexcept { fd = newFd; } + void invalidate() noexcept { fd = invalidFd; } + +private: + int fd = invalidFd; +}; +#endif + +} // namespace juce::detail diff --git a/modules/juce_core/files/juce_FileInputStream.cpp b/modules/juce_core/files/juce_FileInputStream.cpp index e719aca957..c5e10e4461 100644 --- a/modules/juce_core/files/juce_FileInputStream.cpp +++ b/modules/juce_core/files/juce_FileInputStream.cpp @@ -35,7 +35,7 @@ namespace juce { -int64 juce_fileSetPosition (void* handle, int64 pos); +int64 juce_fileSetPosition (detail::NativeFileHandle handle, int64 pos); //============================================================================== diff --git a/modules/juce_core/files/juce_FileInputStream.h b/modules/juce_core/files/juce_FileInputStream.h index 8779b5f227..0ae36624cd 100644 --- a/modules/juce_core/files/juce_FileInputStream.h +++ b/modules/juce_core/files/juce_FileInputStream.h @@ -89,7 +89,7 @@ public: private: //============================================================================== const File file; - void* fileHandle = nullptr; + detail::NativeFileHandle fileHandle{}; int64 currentPosition = 0; Result status { Result::ok() }; diff --git a/modules/juce_core/files/juce_FileOutputStream.h b/modules/juce_core/files/juce_FileOutputStream.h index b29c0f2baf..8e31928387 100644 --- a/modules/juce_core/files/juce_FileOutputStream.h +++ b/modules/juce_core/files/juce_FileOutputStream.h @@ -119,7 +119,7 @@ public: private: //============================================================================== File file; - void* fileHandle = nullptr; + detail::NativeFileHandle fileHandle{}; Result status { Result::ok() }; int64 currentPosition = 0; size_t bufferSize, bytesInBuffer = 0; diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index eac5e7986a..6af1f68f96 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -318,6 +318,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "files/juce_File.h" #include "files/juce_DirectoryIterator.h" #include "files/juce_RangedDirectoryIterator.h" +#include "detail/juce_NativeFileHandle.h" #include "files/juce_FileInputStream.h" #include "files/juce_FileOutputStream.h" #include "files/juce_FileSearchPath.h" diff --git a/modules/juce_core/native/juce_Files_android.cpp b/modules/juce_core/native/juce_Files_android.cpp index 70bec895fa..3941a79881 100644 --- a/modules/juce_core/native/juce_Files_android.cpp +++ b/modules/juce_core/native/juce_Files_android.cpp @@ -949,9 +949,9 @@ private: void FileOutputStream::flushInternal() { - if (fileHandle != nullptr) + if (fileHandle.isValid()) { - if (fsync (getFD (fileHandle)) == -1) + if (fsync (fileHandle.get()) == -1) status = getResultForErrno(); // This stuff tells the OS to asynchronously update the metadata diff --git a/modules/juce_core/native/juce_SharedCode_posix.h b/modules/juce_core/native/juce_SharedCode_posix.h index 3f505f09c0..2525344e09 100644 --- a/modules/juce_core/native/juce_SharedCode_posix.h +++ b/modules/juce_core/native/juce_SharedCode_posix.h @@ -241,9 +241,6 @@ namespace { return value == -1 ? getResultForErrno() : Result::ok(); } - - int getFD (void* handle) noexcept { return (int) (pointer_sized_int) handle; } - void* fdToVoidPointer (int fd) noexcept { return (void*) (pointer_sized_int) fd; } } bool File::isDirectory() const @@ -442,9 +439,9 @@ Result File::createDirectoryInternal (const String& fileName) const } //============================================================================== -int64 juce_fileSetPosition (void* handle, int64 pos) +int64 juce_fileSetPosition (detail::NativeFileHandle handle, int64 pos) { - if (handle != nullptr && lseek (getFD (handle), (off_t) pos, SEEK_SET) == pos) + if (handle.isValid() && lseek (handle.get(), (off_t) pos, SEEK_SET) == pos) return pos; return -1; @@ -455,24 +452,24 @@ void FileInputStream::openHandle() auto f = open (file.getFullPathName().toUTF8(), O_RDONLY); if (f != -1) - fileHandle = fdToVoidPointer (f); + fileHandle.set (f); else status = getResultForErrno(); } FileInputStream::~FileInputStream() { - if (fileHandle != nullptr) - close (getFD (fileHandle)); + if (fileHandle.isValid()) + close (fileHandle.get()); } size_t FileInputStream::readInternal (void* buffer, size_t numBytes) { ssize_t result = 0; - if (fileHandle != nullptr) + if (fileHandle.isValid()) { - result = ::read (getFD (fileHandle), buffer, numBytes); + result = ::read (fileHandle.get(), buffer, numBytes); if (result < 0) { @@ -497,7 +494,7 @@ void FileOutputStream::openHandle() if (currentPosition >= 0) { - fileHandle = fdToVoidPointer (f); + fileHandle.set (f); } else { @@ -515,7 +512,7 @@ void FileOutputStream::openHandle() auto f = open (file.getFullPathName().toUTF8(), O_RDWR | O_CREAT, 00644); if (f != -1) - fileHandle = fdToVoidPointer (f); + fileHandle.set (f); else status = getResultForErrno(); } @@ -523,19 +520,19 @@ void FileOutputStream::openHandle() void FileOutputStream::closeHandle() { - if (fileHandle != nullptr) + if (fileHandle.isValid()) { - close (getFD (fileHandle)); - fileHandle = nullptr; + close (fileHandle.get()); + fileHandle.invalidate(); } } ssize_t FileOutputStream::writeInternal (const void* data, size_t numBytes) { - if (fileHandle == nullptr) + if (! fileHandle.isValid()) return 0; - auto result = ::write (getFD (fileHandle), data, numBytes); + auto result = ::write (fileHandle.get(), data, numBytes); if (result == -1) status = getResultForErrno(); @@ -546,18 +543,18 @@ ssize_t FileOutputStream::writeInternal (const void* data, size_t numBytes) #ifndef JUCE_ANDROID void FileOutputStream::flushInternal() { - if (fileHandle != nullptr && fsync (getFD (fileHandle)) == -1) + if (fileHandle.isValid() && fsync (fileHandle.get()) == -1) status = getResultForErrno(); } #endif Result FileOutputStream::truncate() { - if (fileHandle == nullptr) + if (! fileHandle.isValid()) return status; flush(); - return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition)); + return getResultForReturnValue (ftruncate (fileHandle.get(), (off_t) currentPosition)); } //==============================================================================