#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) { // A double slash between repo and filename should not be an issue, so add it in any case std::string fullPath = currentMountPrefix + std::string(repositoryPath) + "/" + std::string(filename); if(not std::filesystem::exists(fullPath)) { return FILE_DOES_NOT_EXIST; } std::ofstream file(fullPath, 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) { std::string fullPath; bool useMountPrefix = true; parseCfg(reinterpret_cast(args), useMountPrefix); if(useMountPrefix) { fullPath += currentMountPrefix; } // A double slash between repo and filename should not be an issue, so add it in any case fullPath += std::string(repositoryPath) + "/" + std::string(filename); if(std::filesystem::exists(fullPath)) { return FILE_ALREADY_EXISTS; } std::ofstream file(fullPath); 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) { std::string fullPath; bool useMountPrefix = true; parseCfg(reinterpret_cast(args), useMountPrefix); if(useMountPrefix) { fullPath += currentMountPrefix; } // A double slash between repo and filename should not be an issue, so add it in any case fullPath += std::string(repositoryPath) + "/" + std::string(filename); if(not std::filesystem::exists(fullPath)) { return FILE_DOES_NOT_EXIST; } int result = std::remove(fullPath.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) { std::string fullPath; bool useMountPrefix = true; parseCfg(reinterpret_cast(args), useMountPrefix); if(useMountPrefix) { fullPath += currentMountPrefix; } fullPath += std::string(repositoryPath); fullPath += "/" + std::string(dirname); if(std::filesystem::exists(fullPath)) { return DIRECTORY_ALREADY_EXISTS; } if(std::filesystem::create_directory(fullPath)) { return HasReturnvaluesIF::RETURN_OK; } sif::warning << "Creating directory " << fullPath << " failed" << std::endl; return GENERIC_FILE_ERROR; } ReturnValue_t FileSystemHandler::removeDirectory(const char* repositoryPath, const char* dirname, bool deleteRecurively, FileSystemArgsIF* args) { std::string fullPath; bool useMountPrefix = true; parseCfg(reinterpret_cast(args), useMountPrefix); if(useMountPrefix) { fullPath += currentMountPrefix; } fullPath += std::string(repositoryPath); fullPath += "/" + std::string(dirname); if(not std::filesystem::exists(fullPath)) { return DIRECTORY_DOES_NOT_EXIST; } std::error_code err; if(not deleteRecurively) { if(std::filesystem::remove(fullPath, 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(fullPath, 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; } void FileSystemHandler::parseCfg(FsCommandCfg *cfg, bool& useMountPrefix) { if(cfg != nullptr) { useMountPrefix = cfg->useMountPrefix; } } ReturnValue_t FileSystemHandler::renameFile(const char *repositoryPath, const char *oldFilename, const char *newFilename, FileSystemArgsIF *args) { // TODO: Implement return HasReturnvaluesIF::RETURN_OK; }