#include "FileSystemHandler.h" #include #include #include #include "bsp_q7s/core/CoreController.h" #include "fsfw/ipc/QueueFactory.h" #include "fsfw/memory/GenericFileSystemMessage.h" #include "fsfw/tasks/TaskFactory.h" FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler) : SystemObject(fileSystemHandler) { auto mqArgs = MqArgs(this->getObjectId()); mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } FileSystemHandler::~FileSystemHandler() { QueueFactory::instance()->deleteMessageQueue(mq); } ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) { while (true) { try { fileSystemHandlerLoop(); } catch (std::bad_alloc& e) { // Restart OBSW, hints at a memory leak sif::error << "Allocation error in FileSystemHandler::performOperation" << e.what() << std::endl; // Set up an error file or a special flag in the scratch buffer for these cases triggerEvent(CoreController::ALLOC_FAILURE, 0, 0); CoreController::incrementAllocationFailureCount(); } } } void FileSystemHandler::fileSystemHandlerLoop() { CommandMessage filemsg; ReturnValue_t result = returnvalue::OK; while (true) { if (opCounter % 5 == 0) { if (coreCtrl->sdInitFinished()) { fileSystemCheckup(); } } result = mq->receiveMessage(&filemsg); if (result == MessageQueueIF::EMPTY) { break; } else if (result != returnvalue::FAILED) { sif::warning << "FileSystemHandler::performOperation: Message reception failed!" << std::endl; break; } Command_t command = filemsg.getCommand(); switch (command) { case (GenericFileSystemMessage::CMD_CREATE_DIRECTORY): { break; } case (GenericFileSystemMessage::CMD_CREATE_FILE): { break; } } opCounter++; } // This task will have a low priority and will run permanently in the background // so we will just run in a permanent loop here and check file system // messages permanently opCounter++; TaskFactory::instance()->delayTask(1000); } void FileSystemHandler::fileSystemCheckup() { SdCardManager::SdStatePair statusPair; sdcMan->getSdCardsStatus(statusPair); sd::SdCard preferredSdCard = sdcMan->getPreferredSdCard(); if ((preferredSdCard == sd::SdCard::SLOT_0) and (statusPair.first == sd::SdState::MOUNTED)) { currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; } else if ((preferredSdCard == sd::SdCard::SLOT_1) and (statusPair.second == sd::SdState::MOUNTED)) { currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; } else { std::string sdString; if (preferredSdCard == sd::SdCard::SLOT_0) { sdString = "0"; } else { sdString = "1"; } sif::warning << "FileSystemHandler::performOperation: " "Inconsistent state detected" << std::endl; sif::warning << "Preferred SD card is " << sdString << " but does not appear to be mounted. Attempting fix.." << std::endl; // This function will appear to fix the inconsistent state ReturnValue_t result = sdcMan->sanitizeState(&statusPair, preferredSdCard); if (result != returnvalue::OK) { // Oh no. triggerEvent(SdCardManager::SANITIZATION_FAILED, 0, 0); sif::error << "FileSystemHandler::fileSystemCheckup: Sanitization failed" << std::endl; } } } MessageQueueId_t FileSystemHandler::getCommandQueue() const { return mq->getId(); } ReturnValue_t FileSystemHandler::initialize() { coreCtrl = ObjectManager::instance()->get(objects::CORE_CONTROLLER); if (coreCtrl == nullptr) { sif::error << "FileSystemHandler::initialize: Could not retrieve core controller handle" << std::endl; } sdcMan = SdCardManager::instance(); sd::SdCard preferredSdCard = sdcMan->getPreferredSdCard(); if (preferredSdCard == sd::SdCard::SLOT_0) { currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT; } else if (preferredSdCard == sd::SdCard::SLOT_1) { currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT; } return returnvalue::OK; } ReturnValue_t FileSystemHandler::appendToFile(const char* repositoryPath, const char* filename, const uint8_t* data, size_t size, uint16_t packetNumber, FileSystemArgsIF* args) { auto path = getInitPath(args) / repositoryPath / filename; if (not std::filesystem::exists(path)) { return FILE_DOES_NOT_EXIST; } std::ofstream file(path, std::ios_base::app | std::ios_base::out); file.write(reinterpret_cast(data), size); if (not file.good()) { return GENERIC_FILE_ERROR; } return returnvalue::OK; } ReturnValue_t FileSystemHandler::createFile(const char* repositoryPath, const char* filename, const uint8_t* data, size_t size, FileSystemArgsIF* args) { auto path = getInitPath(args) / filename; if (std::filesystem::exists(path)) { return FILE_ALREADY_EXISTS; } std::ofstream file(path); file.write(reinterpret_cast(data), size); if (not file.good()) { return GENERIC_FILE_ERROR; } return returnvalue::OK; } ReturnValue_t FileSystemHandler::removeFile(const char* repositoryPath, const char* filename, FileSystemArgsIF* args) { auto path = getInitPath(args) / repositoryPath / filename; if (not std::filesystem::exists(path)) { return FILE_DOES_NOT_EXIST; } int result = std::remove(path.c_str()); if (result != 0) { sif::warning << "FileSystemHandler::deleteFile: Failed with code " << result << std::endl; return GENERIC_FILE_ERROR; } return returnvalue::OK; } ReturnValue_t FileSystemHandler::createDirectory(const char* repositoryPath, const char* dirname, bool createParentDirs, FileSystemArgsIF* args) { auto path = getInitPath(args) / repositoryPath / dirname; if (std::filesystem::exists(path)) { return DIRECTORY_ALREADY_EXISTS; } if (std::filesystem::create_directory(path)) { return returnvalue::OK; } sif::warning << "Creating directory " << path << " failed" << std::endl; return GENERIC_FILE_ERROR; } ReturnValue_t FileSystemHandler::removeDirectory(const char* repositoryPath, const char* dirname, bool deleteRecurively, FileSystemArgsIF* args) { auto path = getInitPath(args) / repositoryPath / dirname; if (not std::filesystem::exists(path)) { return DIRECTORY_DOES_NOT_EXIST; } std::error_code err; if (not deleteRecurively) { if (std::filesystem::remove(path, err)) { return returnvalue::OK; } else { // Check error code. Most probably denied permissions because folder is not empty sif::warning << "FileSystemHandler::removeDirectory: Deleting directory failed with " "code " << err.value() << ": " << strerror(err.value()) << std::endl; if (err.value() == ENOTEMPTY) { return DIRECTORY_NOT_EMPTY; } else { return GENERIC_FILE_ERROR; } } } else { if (std::filesystem::remove_all(path, err)) { return returnvalue::OK; } else { sif::warning << "FileSystemHandler::removeDirectory: Deleting directory failed with " "code " << err.value() << ": " << strerror(err.value()) << std::endl; // Check error code if (err.value() == ENOTEMPTY) { return DIRECTORY_NOT_EMPTY; } else { return GENERIC_FILE_ERROR; } } } return returnvalue::OK; } ReturnValue_t FileSystemHandler::renameFile(const char* repositoryPath, const char* oldFilename, const char* newFilename, FileSystemArgsIF* args) { auto basepath = getInitPath(args) / repositoryPath; std::filesystem::rename(basepath / oldFilename, basepath / newFilename); return returnvalue::OK; } void FileSystemHandler::parseCfg(FsCommandCfg* cfg, bool& useMountPrefix) { if (cfg != nullptr) { useMountPrefix = cfg->useMountPrefix; } } std::filesystem::path FileSystemHandler::getInitPath(FileSystemArgsIF* args) { bool useMountPrefix = true; parseCfg(reinterpret_cast(args), useMountPrefix); std::string path; if (useMountPrefix) { path = currentMountPrefix; } return std::filesystem::path(path); }