#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2023 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_SUPPORT_SOURCE 1 #include "LinuxFileApi.h" #if defined(NUCLEX_SUPPORT_LINUX) #include "PosixApi.h" // Linux uses Posix error handling #include "PosixPathApi.h" // Path manipulation stuff for ::mk*temp() #include // for PATH_MAX #include // ::open() and flags #include // ::read(), ::write(), ::close(), etc. #include // To access ::errno directly #include // std::vector namespace { // ------------------------------------------------------------------------------------------- // #if 0 // If temporary file/directory methods are moved to this file /// Builds the template string that's passed to ::mkstemp()/::mkdtemp() /// Path vector the template will be stored in /// Prefix for the temporary filename, can be empty void buildTemplateForMkTemp(std::string &path, const std::string &prefix) { path.reserve(256); // PATH_MAX would be a bit too bloaty usually... // Obtain the system's temporary directory (usually /tmp, can be overridden) // path: "/tmp/" { Nuclex::Support::Platform::PosixPathApi::GetTemporaryDirectory(path); std::string::size_type length = path.size(); if(path[length - 1] != '/') { path.push_back('/'); } } // Append the user-specified prefix, if any // path: "/tmp/myapp" if(!prefix.empty()) { path.append(prefix); } // Append the mandatory placeholder characters // path: "/tmp/myappXXXXXX" { static const std::string placeholder(u8"XXXXXX", 6); path.append(placeholder); } } #endif // 0 // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Support { namespace Platform { // ------------------------------------------------------------------------------------------- // int LinuxFileApi::OpenFileForReading(const std::string &path) { int fileDescriptor = ::open(path.c_str(), O_RDONLY | O_LARGEFILE); if(unlikely(fileDescriptor < 0)) { int errorNumber = errno; std::string errorMessage(u8"Could not open file '"); errorMessage.append(path); errorMessage.append(u8"' for reading"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } return fileDescriptor; } // ------------------------------------------------------------------------------------------- // int LinuxFileApi::OpenFileForWriting(const std::string &path) { int fileDescriptor = ::open( path.c_str(), O_RDWR | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH ); if(unlikely(fileDescriptor < 0)) { int errorNumber = errno; std::string errorMessage(u8"Could not open file '"); errorMessage.append(path); errorMessage.append(u8"' for writing"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } return fileDescriptor; } // ------------------------------------------------------------------------------------------- // std::size_t LinuxFileApi::Seek(int fileDescriptor, ::off_t offset, int anchor) { ::off_t absolutePosition = ::lseek(fileDescriptor, offset, anchor); if(absolutePosition == -1) { int errorNumber = errno; std::string errorMessage(u8"Could not seek within file"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } return static_cast(absolutePosition); } // ------------------------------------------------------------------------------------------- // std::size_t LinuxFileApi::Read( int fileDescriptor, std::uint8_t *buffer, std::size_t count ) { ssize_t result = ::read(fileDescriptor, buffer, count); if(unlikely(result == static_cast(-1))) { int errorNumber = errno; std::string errorMessage(u8"Could not read data from file"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } return static_cast(result); } // ------------------------------------------------------------------------------------------- // std::size_t LinuxFileApi::Write( int fileDescriptor, const std::uint8_t *buffer, std::size_t count ) { ssize_t result = ::write(fileDescriptor, buffer, count); if(unlikely(result == static_cast(-1))) { int errorNumber = errno; std::string errorMessage(u8"Could not write data to file"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } return result; } // ------------------------------------------------------------------------------------------- // void LinuxFileApi::SetLength(int fileDescriptor, std::size_t byteCount) { int result = ::ftruncate(fileDescriptor, static_cast<::off_t>(byteCount)); if(result == -1) { int errorNumber = errno; std::string errorMessage(u8"Could not truncate/pad file to specified length"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } } // ------------------------------------------------------------------------------------------- // void LinuxFileApi::Flush(int fileDescriptor) { int result = ::fsync(fileDescriptor); if(unlikely(result == -1)) { int errorNumber = errno; std::string errorMessage(u8"Could not flush file buffers"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } } // ------------------------------------------------------------------------------------------- // void LinuxFileApi::Close(int fileDescriptor, bool throwOnError /* = true */) { int result = ::close(fileDescriptor); if(throwOnError && unlikely(result == -1)) { int errorNumber = errno; std::string errorMessage(u8"Could not close file"); Platform::PosixApi::ThrowExceptionForSystemError(errorMessage, errorNumber); } } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Support::Platform #endif // defined(NUCLEX_SUPPORT_LINUX)