#include "FileSystemHandler.h" #include "bsp_q7s/core/CoreController.h" #include "fsfw/tasks/TaskFactory.h" #include "fsfw/memory/GenericFileSystemMessage.h" #include "fsfw/ipc/QueueFactory.h" #include #include #include FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler): SystemObject(fileSystemHandler) { mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE); } 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 = HasReturnvaluesIF::RETURN_OK; while(true) { if(opCounter % 5 == 0) { if(coreCtrl->sdInitFinished()) { fileSystemCheckup(); } } result = mq->receiveMessage(&filemsg); if(result == MessageQueueIF::EMPTY) { break; } else if(result != HasReturnvaluesIF::RETURN_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->getSdCardActiveStatus(statusPair); sd::SdCard preferredSdCard; sdcMan->getPreferredSdCard(preferredSdCard); 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 != HasReturnvaluesIF::RETURN_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; ReturnValue_t result = sdcMan->getPreferredSdCard(preferredSdCard); if(result != HasReturnvaluesIF::RETURN_OK) { return result; } 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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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); }