mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
400 lines
17 KiB
C++
400 lines
17 KiB
C++
// ======================================================================
|
|
// \title Os/FileSystem.hpp
|
|
// \brief Os::FileSystem interface definition
|
|
// ======================================================================
|
|
|
|
#ifndef _OS_FILESYSTEM_HPP_
|
|
#define _OS_FILESYSTEM_HPP_
|
|
|
|
#include <Fw/FPrimeBasicTypes.hpp>
|
|
#include <Os/Directory.hpp>
|
|
#include <Os/File.hpp>
|
|
#include <Os/Os.hpp>
|
|
|
|
namespace Os {
|
|
|
|
struct FileSystemHandle {};
|
|
|
|
class FileSystemInterface {
|
|
public:
|
|
// Size of file chunks to use for file system operations (e.g. copyFile)
|
|
static constexpr FwSizeType FILE_SYSTEM_FILE_CHUNK_SIZE = FW_FILE_CHUNK_SIZE; //!< Size of file system chunk
|
|
|
|
enum Status {
|
|
OP_OK, //!< Operation was successful
|
|
ALREADY_EXISTS, //!< File already exists
|
|
NO_SPACE, //!< No space left
|
|
NO_PERMISSION, //!< No permission to write
|
|
NOT_DIR, //!< Path is not a directory
|
|
IS_DIR, //!< Path is a directory
|
|
NOT_EMPTY, //!< directory is not empty
|
|
INVALID_PATH, //!< Path is too long, too many sym links, etc.
|
|
DOESNT_EXIST, //!< Path doesn't exist
|
|
FILE_LIMIT, //!< Too many files or links
|
|
BUSY, //!< Operand is in use by the system or by a process
|
|
NO_MORE_FILES, //!< Directory stream has no more files
|
|
BUFFER_TOO_SMALL, //!< Buffer size is too small to hold full path (for getWorkingDirectory)
|
|
EXDEV_ERROR, // Operation not supported across devices (e.g. rename)
|
|
OVERFLOW_ERROR, // Operation failed due to overflow in calculation of the result
|
|
NOT_SUPPORTED, //!< Operation is not supported by the current implementation
|
|
OTHER_ERROR, //!< other OS-specific error
|
|
};
|
|
|
|
enum PathType {
|
|
FILE, //!< Path is a file
|
|
DIRECTORY, //!< Path is a directory
|
|
OTHER, //!< Path is not a file or directory, e.g. a socket
|
|
NOT_EXIST, //!< Path does not exist
|
|
};
|
|
|
|
//! \brief default constructor
|
|
FileSystemInterface() = default;
|
|
|
|
//! \brief default virtual destructor
|
|
virtual ~FileSystemInterface() = default;
|
|
|
|
//! \brief copy constructor is forbidden
|
|
FileSystemInterface(const FileSystemInterface& other) = delete;
|
|
|
|
//! \brief assignment operator is forbidden
|
|
FileSystemInterface& operator=(const FileSystemInterface& other) = delete;
|
|
|
|
//! \brief return the underlying FileSystem handle (implementation specific)
|
|
//! \return internal FileSystem handle representation
|
|
virtual FileSystemHandle* getHandle() = 0;
|
|
|
|
//! \brief provide a pointer to a FileSystem delegate object
|
|
static FileSystemInterface* getDelegate(FileSystemHandleStorage& aligned_new_memory);
|
|
|
|
// ------------------------------------------------------------------
|
|
// FileSystem operations to be implemented by an OSAL implementation
|
|
// ------------------------------------------------------------------
|
|
// These functions are to be overridden in each OS implementation
|
|
// See an example in in Os/Posix/FileSystem.hpp
|
|
|
|
//! \brief Remove a directory at the specified path
|
|
//! \param path The path of the directory to remove
|
|
//! \return Status of the operation
|
|
virtual Status _removeDirectory(const char* path) = 0;
|
|
|
|
//! \brief Remove a file at the specified path
|
|
//! \param path The path of the file to remove
|
|
//! \return Status of the operation
|
|
virtual Status _removeFile(const char* path) = 0;
|
|
|
|
//! \brief Rename (or move) a file from source to destination
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \return Status of the operation
|
|
virtual Status _rename(const char* sourcePath, const char* destPath) = 0;
|
|
|
|
//! \brief Get filesystem free and total space in bytes on the filesystem containing the specified path
|
|
//! \param path The path on the filesystem to query
|
|
//! \param totalBytes Reference to store the total bytes on the filesystem
|
|
//! \param freeBytes Reference to store the free bytes on the filesystem
|
|
//! \return Status of the operation
|
|
virtual Status _getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) = 0;
|
|
|
|
//! \brief Get the type of the path (file, directory, etc.)
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path to check
|
|
//! \param pathType Reference to store the path type
|
|
//! \return Status of the operation
|
|
virtual Status _getPathType(const char* path, PathType& pathType) = 0;
|
|
|
|
//! \brief Get the current working directory
|
|
//! \param path Buffer to store the current working directory path
|
|
//! \param bufferSize Size of the buffer
|
|
//! \return Status of the operation
|
|
virtual Status _getWorkingDirectory(char* path, FwSizeType bufferSize) = 0;
|
|
|
|
//! \brief Change the current working directory to the specified path
|
|
//! \param path The path of the new working directory
|
|
//! \return Status of the operation
|
|
virtual Status _changeWorkingDirectory(const char* path) = 0;
|
|
};
|
|
|
|
//! \brief FileSystem class
|
|
//!
|
|
//! This class provides a common interface for file system operations.
|
|
//! This class uses the singleton pattern and should be accessed through
|
|
//! its static functions, for example using `Os::FileSystem::removeFile(path)`.
|
|
class FileSystem final : public FileSystemInterface {
|
|
private:
|
|
FileSystem(); //!< Constructor (private because singleton pattern)
|
|
public:
|
|
~FileSystem() final; //!< Destructor
|
|
|
|
//! \brief return the underlying FileSystem handle (implementation specific)
|
|
//! \return internal FileSystem handle representation
|
|
FileSystemHandle* getHandle() override;
|
|
|
|
// ------------------------------------------------------------
|
|
// Implementation-specific FileSystem member functions
|
|
// ------------------------------------------------------------
|
|
|
|
//! \brief Remove a directory at the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the directory to remove
|
|
//! \return Status of the operation
|
|
Status _removeDirectory(const char* path) override;
|
|
|
|
//! \brief Remove a file at the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the file to remove
|
|
//! \return Status of the operation
|
|
Status _removeFile(const char* path) override;
|
|
|
|
//! \brief Rename a file from source to destination
|
|
//!
|
|
//! If the rename fails due to a cross-device operation, this function should return EXDEV_ERROR
|
|
//! and moveFile can be used instead to force a copy-and-remove.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as sourcePath or destPath.
|
|
//!
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \return Status of the operation
|
|
Status _rename(const char* sourcePath, const char* destPath) override;
|
|
|
|
//! \brief Get filesystem free and total space in bytes on the filesystem containing the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path on the filesystem to query
|
|
//! \param totalBytes Reference to store the total bytes on the filesystem
|
|
//! \param freeBytes Reference to store the free bytes on the filesystem
|
|
//! \return Status of the operation
|
|
Status _getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) override;
|
|
|
|
//! \brief Get the current working directory
|
|
//!
|
|
//! Writes the current working directory path to the provided buffer of size bufferSize.
|
|
//! If the buffer is too small to hold the full path, the function will return BUFFER_TOO_SMALL.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//! It is invalid to pass a bufferSize of 0.
|
|
//!
|
|
//! \param path Buffer to store the current working directory path
|
|
//! \param bufferSize Size of the buffer
|
|
//! \return Status of the operation
|
|
Status _getWorkingDirectory(char* path, FwSizeType bufferSize) override;
|
|
|
|
//! \brief Change the current working directory to the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the new working directory
|
|
//! \return Status of the operation
|
|
Status _changeWorkingDirectory(const char* path) override;
|
|
|
|
//! \brief Get the type of the path (file, directory, etc.)
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path to check
|
|
//! \param pathType Reference to store the path type
|
|
//! \return Status of the operation
|
|
Status _getPathType(const char* path, PathType& pathType) override;
|
|
|
|
// ------------------------------------------------------------
|
|
// Implementation-specific FileSystem static functions
|
|
// ------------------------------------------------------------
|
|
// These are static variants that are exposed to the user, and call the above member functions
|
|
|
|
//! \brief Remove a directory at the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the directory to remove
|
|
//! \return Status of the operation
|
|
static Status removeDirectory(const char* path);
|
|
|
|
//! \brief Remove a file at the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the file to remove
|
|
//! \return Status of the operation
|
|
static Status removeFile(const char* path);
|
|
|
|
//! \brief Rename a file from source to destination
|
|
//!
|
|
//! If the rename fails due to a cross-device operation, this function should return EXDEV_ERROR
|
|
//! and moveFile can be used instead to force a copy-and-remove.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as sourcePath or destPath.
|
|
//!
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \return Status of the operation
|
|
static Status rename(const char* sourcePath, const char* destPath);
|
|
|
|
//! \brief Get filesystem free and total space in bytes on the filesystem containing the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path on the filesystem to query
|
|
//! \param totalBytes Reference to store the total bytes on the filesystem
|
|
//! \param freeBytes Reference to store the free bytes on the filesystem
|
|
//! \return Status of the operation
|
|
static Status getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes);
|
|
|
|
//! \brief Get the current working directory
|
|
//!
|
|
//! Writes the current working directory path to the provided buffer of size bufferSize.
|
|
//! If the buffer is too small to hold the full path, the function will return BUFFER_TOO_SMALL.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//! It is invalid to pass a bufferSize of 0.
|
|
//!
|
|
//! \param path Buffer to store the current working directory path
|
|
//! \param bufferSize Size of the buffer
|
|
//! \return Status of the operation
|
|
static Status getWorkingDirectory(char* path, FwSizeType bufferSize);
|
|
|
|
//! \brief Change the current working directory to the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the new working directory
|
|
//! \return Status of the operation
|
|
static Status changeWorkingDirectory(const char* path);
|
|
|
|
// ------------------------------------------------------------
|
|
// Additional functions built on top of OS-specific operations
|
|
// ------------------------------------------------------------
|
|
|
|
//! \brief Return true if the path exists, false otherwise
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path to check for existence
|
|
//! \return True if the path exists, false otherwise
|
|
static bool exists(const char* path);
|
|
|
|
//! \brief Return the type of the path (file, directory, or doesn't exist)
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path to check for existence
|
|
//! \return PathType enum representing the type of the path (FILE, DIRECTORY, NOT_EXIST)
|
|
static PathType getPathType(const char* path);
|
|
|
|
//! \brief Touch a file at the specified path, creating it if it doesn't exist
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the file to touch
|
|
//! \return Status of the operation
|
|
static Status touch(const char* path);
|
|
|
|
//! \brief Create a new directory at the specified path.
|
|
//!
|
|
//! The optional errorIfAlreadyExists (default=false) parameter can be set to true
|
|
//! to return an error status if the directory already exists.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path where the new directory will be created
|
|
//! \param errorIfAlreadyExists If true, returns an error if the directory already exists
|
|
//! \return Status of the operation
|
|
static Status createDirectory(const char* path, bool errorIfAlreadyExists = false);
|
|
|
|
//! \brief Append the source file to the destination file
|
|
//!
|
|
//! This function opens both files, and iteratively reads the source by chunks and writes
|
|
//! chunks to the destination.
|
|
//! If the destination file does not exist and createMissingDest is true, a new file is created.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as either the source or destination path.
|
|
//!
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \param createMissingDest If true, creates a new file if the destination doesn't exist
|
|
//! \return Status of the operation
|
|
static Status appendFile(const char* sourcePath, const char* destPath, bool createMissingDest = false);
|
|
|
|
//! \brief Copy a file from the source path to the destination path
|
|
//!
|
|
//! This function opens both files, and iteratively reads the source by chunks and writes
|
|
//! chunks to the destination.
|
|
//!
|
|
//! It is invalid to pass `nullptr` as either the source or destination path.
|
|
//!
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \return Status of the operation
|
|
static Status copyFile(const char* sourcePath, const char* destPath);
|
|
|
|
//! \brief Move a file from sourcePath to destPath
|
|
//!
|
|
//! This is done by first trying to rename, and if renaming fails,
|
|
//! copy it and then remove the original
|
|
//!
|
|
//! It is invalid to pass `nullptr` as either the source or destination path.
|
|
//!
|
|
//! \param sourcePath The path of the source file
|
|
//! \param destPath The path of the destination file
|
|
//! \return Status of the operation
|
|
static Status moveFile(const char* sourcePath, const char* destPath);
|
|
|
|
//! \brief Get the size of the file (in bytes) at the specified path
|
|
//!
|
|
//! It is invalid to pass `nullptr` as the path.
|
|
//!
|
|
//! \param path The path of the file
|
|
//! \param size Reference to store the size of the file
|
|
//! \return Status of the operation
|
|
static Status getFileSize(const char* path, FwSizeType& size);
|
|
|
|
public:
|
|
//! \brief initialize singleton
|
|
static void init();
|
|
|
|
//! \brief get a reference to singleton
|
|
//! \return reference to singleton
|
|
static FileSystem& getSingleton();
|
|
|
|
private:
|
|
// ------------------------------------------------------------
|
|
// Internal helper functions
|
|
// ------------------------------------------------------------
|
|
|
|
//! \brief Convert a File::Status to a FileSystem::Status
|
|
static Status handleFileError(File::Status fileStatus);
|
|
|
|
//! \brief Convert a Directory::Status to a FileSystem::Status
|
|
static Status handleDirectoryError(Directory::Status dirStatus);
|
|
|
|
//! \brief A helper function that writes all the file information in the source
|
|
//! file to the destination file (replaces/appends to end/etc. depending
|
|
//! on destination file mode).
|
|
//!
|
|
//! Files must already be open and will remain open after this function
|
|
//! completes.
|
|
//!
|
|
//! @param source File to copy data from
|
|
//! @param destination File to copy data to
|
|
//! @param size The number of bytes to copy
|
|
static Status copyFileData(File& source, File& destination, FwSizeType size);
|
|
|
|
private:
|
|
// This section is used to store the implementation-defined FileSystem handle. To Os::FileSystem and fprime, this
|
|
// type is opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle
|
|
// in the byte-array here and set `handle` to that address for storage.
|
|
|
|
alignas(FW_HANDLE_ALIGNMENT) FileSystemHandleStorage m_handle_storage; //!< FileSystem handle storage
|
|
FileSystemInterface& m_delegate;
|
|
};
|
|
|
|
} // namespace Os
|
|
|
|
#endif
|