2021-07-08 12:22:41 +02:00
|
|
|
#include "FileSystemHandler.h"
|
|
|
|
|
2021-07-19 12:44:43 +02:00
|
|
|
#include "bsp_q7s/core/CoreController.h"
|
|
|
|
|
2021-07-08 12:22:41 +02:00
|
|
|
#include "fsfw/tasks/TaskFactory.h"
|
2021-07-08 12:32:24 +02:00
|
|
|
#include "fsfw/memory/GenericFileSystemMessage.h"
|
|
|
|
#include "fsfw/ipc/QueueFactory.h"
|
2021-07-08 12:22:41 +02:00
|
|
|
|
2021-07-19 19:21:34 +02:00
|
|
|
#include <cstring>
|
2021-07-19 12:44:43 +02:00
|
|
|
#include <fstream>
|
2021-07-12 17:39:36 +02:00
|
|
|
#include <filesystem>
|
|
|
|
|
2021-07-08 12:22:41 +02:00
|
|
|
FileSystemHandler::FileSystemHandler(object_id_t fileSystemHandler):
|
|
|
|
SystemObject(fileSystemHandler) {
|
2021-07-12 16:32:14 +02:00
|
|
|
mq = QueueFactory::instance()->createMessageQueue(FS_MAX_QUEUE_SIZE);
|
2021-07-08 12:32:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemHandler::~FileSystemHandler() {
|
|
|
|
QueueFactory::instance()->deleteMessageQueue(mq);
|
2021-07-08 12:22:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t FileSystemHandler::performOperation(uint8_t unsignedChar) {
|
|
|
|
while(true) {
|
2021-07-12 17:23:32 +02:00
|
|
|
try {
|
|
|
|
fileSystemHandlerLoop();
|
2021-07-08 12:32:24 +02:00
|
|
|
}
|
2021-07-12 17:23:32 +02:00
|
|
|
catch(std::bad_alloc& e) {
|
|
|
|
// Restart OBSW, hints at a memory leak
|
|
|
|
sif::error << "Allocation error in FileSystemHandler::performOperation"
|
|
|
|
<< e.what() << std::endl;
|
2021-07-19 12:44:43 +02:00
|
|
|
// Set up an error file or a special flag in the scratch buffer for these cases
|
|
|
|
triggerEvent(CoreController::ALLOC_FAILURE, 0 , 0);
|
|
|
|
CoreController::incrementAllocationFailureCount();
|
2021-07-12 17:23:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileSystemHandler::fileSystemHandlerLoop() {
|
|
|
|
CommandMessage filemsg;
|
|
|
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
|
|
while(true) {
|
|
|
|
if(opCounter % 5 == 0) {
|
|
|
|
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
|
2021-07-19 14:02:17 +02:00
|
|
|
opCounter++;
|
2021-07-12 17:23:32 +02:00
|
|
|
TaskFactory::instance()->delayTask(1000);
|
|
|
|
}
|
2021-07-08 12:32:24 +02:00
|
|
|
|
2021-07-12 17:23:32 +02:00
|
|
|
void FileSystemHandler::fileSystemCheckup() {
|
|
|
|
SdCardManager::SdStatusPair statusPair;
|
|
|
|
sdcMan->getSdCardActiveStatus(statusPair);
|
|
|
|
sd::SdCard preferredSdCard;
|
|
|
|
sdcMan->getPreferredSdCard(preferredSdCard);
|
|
|
|
if((preferredSdCard == sd::SdCard::SLOT_0) and
|
|
|
|
(statusPair.first == sd::SdStatus::MOUNTED)) {
|
|
|
|
currentMountPrefix = SdCardManager::SD_0_MOUNT_POINT;
|
|
|
|
}
|
2021-07-19 14:02:17 +02:00
|
|
|
else if((preferredSdCard == sd::SdCard::SLOT_1) and
|
2021-07-12 17:23:32 +02:00
|
|
|
(statusPair.second == sd::SdStatus::MOUNTED)) {
|
|
|
|
currentMountPrefix = SdCardManager::SD_1_MOUNT_POINT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::string sdString;
|
|
|
|
if(preferredSdCard == sd::SdCard::SLOT_0) {
|
|
|
|
sdString = "0";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sdString = "1";
|
|
|
|
}
|
2021-07-19 14:02:17 +02:00
|
|
|
sif::warning << "FileSystemHandler::performOperation: "
|
|
|
|
"Inconsistent state detected" << std::endl;
|
|
|
|
sif::warning << "Preferred SD card is " << sdString <<
|
2021-07-12 17:23:32 +02:00
|
|
|
" but does not appear to be mounted. Attempting fix.." << std::endl;
|
|
|
|
// This function will appear to fix the inconsistent state
|
2021-07-16 20:32:13 +02:00
|
|
|
ReturnValue_t result = sdcMan->sanitizeState(&statusPair, preferredSdCard);
|
2021-07-12 17:23:32 +02:00
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
2021-07-12 17:50:01 +02:00
|
|
|
// Oh no.
|
2021-07-19 12:44:43 +02:00
|
|
|
triggerEvent(SdCardManager::SANITIZATION_FAILED, 0, 0);
|
|
|
|
sif::error << "FileSystemHandler::fileSystemCheckup: Sanitization failed" << std::endl;
|
2021-07-12 17:23:32 +02:00
|
|
|
}
|
2021-07-08 12:22:41 +02:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 12:32:24 +02:00
|
|
|
|
|
|
|
MessageQueueId_t FileSystemHandler::getCommandQueue() const {
|
|
|
|
return mq->getId();
|
|
|
|
}
|
|
|
|
|
2021-07-12 17:23:32 +02:00
|
|
|
ReturnValue_t FileSystemHandler::initialize() {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-07-08 12:32:24 +02:00
|
|
|
ReturnValue_t FileSystemHandler::appendToFile(const char *repositoryPath, const char *filename,
|
|
|
|
const uint8_t *data, size_t size, uint16_t packetNumber, void *args) {
|
2021-07-12 17:41:13 +02:00
|
|
|
// 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);
|
2021-07-19 12:44:43 +02:00
|
|
|
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<const char*>(data), size);
|
|
|
|
if(not file.good()) {
|
|
|
|
return GENERIC_FILE_ERROR;
|
|
|
|
}
|
2021-07-08 12:32:24 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t FileSystemHandler::createFile(const char *repositoryPath, const char *filename,
|
|
|
|
const uint8_t *data, size_t size, void *args) {
|
2021-07-19 14:34:03 +02:00
|
|
|
std::string fullPath;
|
|
|
|
bool useMountPrefix = true;
|
|
|
|
parseCfg(reinterpret_cast<FsCommandCfg*>(args), useMountPrefix);
|
|
|
|
if(useMountPrefix) {
|
|
|
|
fullPath += currentMountPrefix;
|
|
|
|
}
|
|
|
|
|
2021-07-12 17:41:13 +02:00
|
|
|
// A double slash between repo and filename should not be an issue, so add it in any case
|
2021-07-19 14:34:03 +02:00
|
|
|
fullPath += std::string(repositoryPath) + "/" + std::string(filename);
|
2021-07-19 12:44:43 +02:00
|
|
|
if(std::filesystem::exists(fullPath)) {
|
|
|
|
return FILE_ALREADY_EXISTS;
|
|
|
|
}
|
|
|
|
std::ofstream file(fullPath);
|
|
|
|
file.write(reinterpret_cast<const char*>(data), size);
|
|
|
|
if(not file.good()) {
|
|
|
|
return GENERIC_FILE_ERROR;
|
|
|
|
}
|
2021-07-08 12:32:24 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-07-19 19:21:34 +02:00
|
|
|
ReturnValue_t FileSystemHandler::removeFile(const char *repositoryPath, const char *filename,
|
2021-07-08 12:32:24 +02:00
|
|
|
void *args) {
|
2021-07-19 14:34:03 +02:00
|
|
|
std::string fullPath;
|
|
|
|
bool useMountPrefix = true;
|
|
|
|
parseCfg(reinterpret_cast<FsCommandCfg*>(args), useMountPrefix);
|
|
|
|
if(useMountPrefix) {
|
|
|
|
fullPath += currentMountPrefix;
|
|
|
|
}
|
|
|
|
|
2021-07-12 17:41:13 +02:00
|
|
|
// A double slash between repo and filename should not be an issue, so add it in any case
|
2021-07-19 14:34:03 +02:00
|
|
|
fullPath += std::string(repositoryPath) + "/" + std::string(filename);
|
2021-07-19 12:44:43 +02:00
|
|
|
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;
|
|
|
|
}
|
2021-07-08 12:32:24 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
2021-07-12 17:23:32 +02:00
|
|
|
|
|
|
|
ReturnValue_t FileSystemHandler::createDirectory(const char *repositoryPath, void *args) {
|
2021-07-19 14:34:03 +02:00
|
|
|
std::string fullPath;
|
|
|
|
bool useMountPrefix = true;
|
|
|
|
parseCfg(reinterpret_cast<FsCommandCfg*>(args), useMountPrefix);
|
|
|
|
if(useMountPrefix) {
|
|
|
|
fullPath += currentMountPrefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
fullPath += std::string(repositoryPath);
|
2021-07-12 17:39:36 +02:00
|
|
|
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;
|
2021-07-12 17:23:32 +02:00
|
|
|
}
|
|
|
|
|
2021-07-12 17:39:36 +02:00
|
|
|
ReturnValue_t FileSystemHandler::removeDirectory(const char *repositoryPath,
|
|
|
|
bool deleteRecurively, void *args) {
|
2021-07-19 14:34:03 +02:00
|
|
|
std::string fullPath;
|
|
|
|
bool useMountPrefix = true;
|
|
|
|
parseCfg(reinterpret_cast<FsCommandCfg*>(args), useMountPrefix);
|
|
|
|
if(useMountPrefix) {
|
|
|
|
fullPath += currentMountPrefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
fullPath += std::string(repositoryPath);
|
2021-07-12 17:39:36 +02:00
|
|
|
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
|
2021-07-19 12:44:43 +02:00
|
|
|
sif::warning << "FileSystemHandler::removeDirectory: Deleting directory failed with "
|
2021-08-03 15:29:45 +02:00
|
|
|
"code " << err.value() << ": " << strerror(err.value()) << std::endl;
|
2021-07-19 19:21:34 +02:00
|
|
|
if(err.value() == ENOTEMPTY) {
|
|
|
|
return DIRECTORY_NOT_EMPTY;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return GENERIC_FILE_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-07-12 17:39:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(std::filesystem::remove_all(fullPath, err)) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
else {
|
2021-07-19 19:21:34 +02:00
|
|
|
sif::warning << "FileSystemHandler::removeDirectory: Deleting directory failed with "
|
2021-08-03 15:29:45 +02:00
|
|
|
"code " << err.value() << ": " << strerror(err.value()) << std::endl;
|
2021-07-12 17:39:36 +02:00
|
|
|
// Check error code
|
2021-07-19 19:21:34 +02:00
|
|
|
if(err.value() == ENOTEMPTY) {
|
|
|
|
return DIRECTORY_NOT_EMPTY;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return GENERIC_FILE_ERROR;
|
|
|
|
}
|
2021-07-12 17:39:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 17:23:32 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
2021-07-19 14:34:03 +02:00
|
|
|
|
|
|
|
void FileSystemHandler::parseCfg(FsCommandCfg *cfg, bool& useMountPrefix) {
|
|
|
|
if(cfg != nullptr) {
|
|
|
|
useMountPrefix = cfg->useMountPrefix;
|
|
|
|
}
|
|
|
|
}
|