Index: sources/storage/filehandler.cpp =================================================================== diff -u -r90d3f5b31186834168c9ad869f8d2d038200dfcf -r56e378f7504701b9e9a9dccaf205aef2fd52c58e --- sources/storage/filehandler.cpp (.../filehandler.cpp) (revision 90d3f5b31186834168c9ad869f8d2d038200dfcf) +++ sources/storage/filehandler.cpp (.../filehandler.cpp) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) @@ -1,78 +1,209 @@ /*! * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. - * \copyright \n - * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, \n - * IN PART OR IN WHOLE, \n - * WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. \n + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * - * \file filehandler.cpp - * \date 2019/09/30 - * \author Behrouz NematiPour + * \file filehandler.cpp + * \author (last) Behrouz NematiPour + * \date (last) 25-Aug-2020 + * \author (original) Behrouz NematiPour + * \date (original) 24-Sep-2019 * */ #include "filehandler.h" -#include //Qt +#include +#include +#include +#include +#include #include -#include +#include // Project +#include "logger.h" +// namespace using namespace Storage; -FileHandler::FileHandler(QObject *parent) : QObject(parent) + +/*! + * \brief FileHandler::write + * \details Writes the content of vContent into the file vFileName. + * \param vFileName - Source file name + * \param vContent - The content which is going to be written in the file. + * \param vAppend - if set to true the content will be appended at the end of the file. + * \return false if file can't be opened. + */ +void FileHandler::errOut(const QString &vMessage) { - connect(&fsWatcher, SIGNAL(directoryChanged(QString)), - this , SLOT(directoryChanged(QString))); + static uint count; + static QString mCritical; + // coco begin validated : This has been manually test. Needs file system access to produce errors for hundred times. + if (mCritical != vMessage || !(count % 1000)) { + // coco end + count = 0; + mCritical = vMessage; + QTextStream err(stderr); + err << "FS" << " " + << QDate::currentDate().toString("yyyy_MM_dd") << " " + << QTime::currentTime().toString("HH:mm:ss" ) << " " + << mCritical + << endl; + } + ++count; } -bool FileHandler::init() +bool FileHandler::write(const QString &vFileName, const QString &vContent, bool vAppend) { - fsWatcher.addPath("/dev/"); + QFile file(vFileName); + QFile::OpenMode openMode = vAppend ? + QFile::Text | QFile::Append : + QFile::Text | QFile::WriteOnly; + // coco begin validated : This has been manually test. Needs file system access to make file the way it can't be opened for writing. + if (! file.open(openMode)) { + QString msg = QString("Can't open file for write (%1).Possible corrupted file system").arg(vFileName); + // here can't use LOG_XXXX because if the folder can't be created then the log can't be written. + errOut (msg); + return false; + } + // coco end + QTextStream out(&file); + out << vContent; + out.flush(); return true; } -void FileHandler::directoryChanged(const QString &vPath) +/*! + * \brief FileHandler::read + * \details reads file vFilename content into vContent variable. + * \param vFileName - Source file name + * \param vContent - The content of the file which will be set when done. + * \return false if file can't be opened. + */ +bool FileHandler::read(const QString &vFileName, QString &vContent) { - Q_UNUSED(vPath) - bool available = false; - QString device = ""; - if ( ! _mounted ) { - for (int a = 'a'; a <= 'z'; a++) { - device = QString("/dev/sd%1%2").arg(QChar(a)).arg(QChar('1')); - if (QFileInfo::exists(device)) { - available = true; - break; - } - umount(device.toLatin1().constData()); - } + QFile file(vFileName); + if (! file.open(QFile::Text | QFile::ReadOnly)) { + QString msg = QString("Can't open file for read (%1).Possible corrupted file system").arg(vFileName); + // here can't use LOG_XXXX because if the folder can't be created then the log can't be written. + errOut (msg); + return false; } - if (available) { - if ( ! _mounted ) { - if ( mountUsb(device) ) { - _mounted = true; - } else { - qDebug() << tr("1 - USB drive %1 can't be mounted").arg(_usbMount); + QTextStream in(&file); + vContent = in.readAll(); + return true; +} + +/*! + * \brief FileHandler::copyFolder + * \details Copies all the file and folders recursively. + * \param vSource - The source folder + * \param vDestination - The destination folder + * \return Tue on successful execution. + * \note This method uses the Linux "cp -r vSource vDestination" command + * Not a Thread-Safe. + * + */ +int FileHandler::copyFolder(const QString &vSource, const QString &vDestination ) +{ + // coco begin validated: This needs user interaction to export to USB device + // has been tested manually since currently it is the only place it has been used. + QString cp = "cp"; + QStringList arguments; + arguments << "-r" << vSource << vDestination; + int result = QProcess::execute(cp, arguments); + return result; +} +// coco end + +/*! + * \brief FileHandler::removeFiles + * \details + * \param vFolder + * \param vFilter + * \param vDateOlderThan + * \return + */ +int FileHandler::removeFiles(const QStringList &vFolders, const QStringList &vNameFilter, const QDate &vDateOlderThan) +{ + int countRemoved = 0; + for (const auto &folder : vFolders) { + QDir dir(folder); + dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + dir.setSorting(QDir::Time | QDir::Reversed); + QFileInfoList infoList = dir.entryInfoList(vNameFilter); + for (const auto &info : infoList) { + QDateTime fileTime = info.lastModified(); + QString fileName = info.absoluteFilePath(); + // coco begin validated : This has been manually tested since requires to change in file system to reproduce the error. + if (fileTime.isValid()) { + if (fileTime.date() <= vDateOlderThan) { + if (QFile::remove(fileName)) { + ++countRemoved; + errOut(QString("%1 File(s) %2 removed").arg(countRemoved).arg(fileName)); + } + else { + errOut(QString("Can't delete file : ") + fileName); + } + } } + else { + errOut(QString("Can't get last modified date of file : ") + fileName); + } + // coco end } - } else { - umount(_usbMount); - _mounted = false; - qDebug() << tr("2 - USB drive %1 can't be mounted").arg(_usbMount); - return; } - emit usbStatusChanged(available); + return countRemoved; } -bool FileHandler::mountUsb(QString device) +/*! + * \brief FileHandler::makeFolder + * \details Create the folder vFolder if it doesn't exist. + * \param vFolder - the folder to create + * \return true on successful creation + */ +bool FileHandler::makeFolder(const QString &vFolder) { - int result = mount(device.toLatin1().constData(), _usbMount, _usbfsys, 0, ""); - if (result == 0) { - qDebug() << tr("USB flash drive %1 has been mounted to %2").arg(device).arg(_usbMount); - } else { - return false; + QDir dir(vFolder); + if ( ! dir.exists(vFolder) ) { + if ( ! dir.mkpath(vFolder) ) { + QString msg = "Can't create folder " + vFolder; + // here can't use LOG_XXXX because if the folder can't be created then the log can't be written. + errOut(msg); + return false; + } } return true; } +/*! + * \brief FileHandler::isMounted + * \param vPath - the rootPath of the device mount point + * \return true - if the given vPath is not empty and is in list of mounted devices + * if so it also has to be ready and valid. + */ +bool FileHandler::isMounted(const QString &vPath, bool *vIsReadOnly) +{ + // coco begin validated: Needed User Interaction to make the device not ready so tested manually + bool mounted = false; + // removing the extra '/' from the vPath if there is to be able to compare to the root path of the storage + QString path = vPath.trimmed(); + if (path.isEmpty()) return false; + int lastIndex = path.size() - 1; + if (path.at(lastIndex) == "/") path.remove(lastIndex, 1); + // check to see if the path in the list of mounted rootPaths + foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) { + if (storage.isValid() && storage.isReady()) { + if ( storage.rootPath() == path ) { + if (vIsReadOnly) *vIsReadOnly = storage.isReadOnly(); + mounted = true; + break; + } + } + } + return mounted; +} +// coco end