#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2021 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 #ifndef NUCLEX_STORAGE_FILESYSTEM_LINUX_LINUXFILE_H #define NUCLEX_STORAGE_FILESYSTEM_LINUX_LINUXFILE_H #include "Nuclex/Storage/Config.h" #if defined(NUCLEX_STORAGE_LINUX) #include "Nuclex/Storage/FileSystem/File.h" #include // for std::shared_ptr #include // for std::atomic #include // for std::shared_mutex namespace Nuclex { namespace Storage { namespace FileSystem { // ------------------------------------------------------------------------------------------- // class FileManagerBackend; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Storage::FileSystem namespace Nuclex { namespace Storage { namespace FileSystem { namespace Linux { // ------------------------------------------------------------------------------------------- // /// Accesses a real file on a mounted Linux file system class LinuxFile : public File { // use std::enable_shared_from_this? /// Initializes a new Windows file /// Backend in which the open file will be tracked /// Absolute path to the file /// Whether the file should be created right away /// /// If the file does not exist and is false, an exception /// is thrown. If is true, the file will be created right /// away to ensure it is reserved in the actual file system. /// public: LinuxFile( std::shared_ptr backend, const std::string &absolutePath, bool create = false ); /// Frees all resources owned by the instance public: virtual ~LinuxFile() override; /// Determines the size of the file /// The size of the file in bytes public: std::uint64_t GetSize() const override; /// Returns the name of the file /// The file's name public: const std::string &GetName() const override; /// Returns the path the file is stored at in the native format /// The file's absolute path in the native OS format public: virtual const std::string &GetNativePath() const override { return this->absolutePath; } /// Changes the name of the file /// New name the file will be known under public: void Rename(const std::string &name) override; /// Retrieves the time at which the file has been last modified /// The since since the last modification of the file took place public: std::time_t GetLastModificationTime() const override; /// Reads raw data from the file /// Absolute file position data will be read from /// Buffer into which data will be read /// Number of bytes that will be read public: void ReadAt( std::uint64_t location, void *buffer, std::size_t count ) const override; /// Writes raw data into the file /// Absolute file position data will be written to /// Buffer from which data will be taken /// Number of bytes that will be written public: void WriteAt( std::uint64_t location, const void *buffer, std::size_t count ) override; /// Ensures changes to the file have been written to disk public: void Flush() override; /// Opens the file descriptor with shared read access /// /// This is called by the ReadAt() method if it detects that the file descriptor /// is not valid (i.e. file not opened yet). It's moved into a separate method in /// order to keep the hot code path inside ReadAt() short. /// private: void openFileForReading() const; /// Opens the file descriptor with shared read access /// /// This is called by the WriteAt() method if it detects that the file descriptor /// is not valid (i.e. file not opened yet). It's moved into a separate method in /// order to keep the hot code path inside WriteAt() short. /// private: void openFileForWriting() const; /// Backend that's keeping track of opened files private: std::shared_ptr backend; /// Absolute path of the file in the file system private: std::string absolutePath; /// Name of the file private: std::string name; // TODO: Move the fields below into a structure that is created on-demand // to avoid having tons of mutexes around. Perhaps create this structure through // the file manager backend so that it can close the least recently used files // if too many are open? /// Reader/Writer lock mutex used for access + handle change /// /// Shared lock is used for accessing the file descriptor (including writes). /// Exclusive lock is used to change (close, open, re-open) the file descriptor. /// private: mutable std::shared_mutex readerWriterLock; /// Number of the opened file or -1 if not opened yet private: mutable std::atomic fileDescriptor; /// Whether the file has been opened for writing private: mutable std::atomic isOpenedWritable; /// Current position of the file cursor private: mutable std::atomic fileCursor; }; // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Storage::FileSystem::Linux #endif // defined(NUCLEX_STORAGE_LINUX) #endif // NUCLEX_STORAGE_FILESYSTEM_LINUX_LINUXFILE_H