filesystem.cpp 6.26 KB
Newer Older
1
/*
2
 * Copyright (C) 2014-2019 CZ.NIC
3 4 5 6 7 8 9 10
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 13 14
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 17 18 19 20 21 22 23
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

24
#include <QDateTime>
25
#include <QDir>
26
#include <QDirIterator>
27 28 29 30
#include <QRegExp>
#include <QStandardPaths>
#include <QTextStream>

31
#include "src/datovka_shared/log/log.h"
32 33 34 35 36 37 38 39 40 41 42
#include "src/io/filesystem.h"

/*!
 * @brief Illegal characters in file name.
 */
#define ILL_FNAME_CH "\\/:*?\"<>|"
/*!
 * @brief Replacement character for illegal characters.
 */
#define ILL_FNAME_REP "_"

43
QString joinDirs(const QString &dirName1, const QString &dirName2)
44
{
45
	return dirName1 + QDir::separator() + dirName2;
46 47
}

48
QString appCertDirPath(void)
49
{
50
	return existingAppPath(dfltAttachSavingLoc(), DATOVKA_CERT_DIR_NAME);
51
}
52

53
QString appEmailDirPath(const QString &msgIdStr)
54
{
55 56
	return existingAppPath(dfltAttachSavingLoc(),
	    QLatin1String(DATOVKA_MAIL_DIR_NAME) + QDir::separator() + msgIdStr);
57
}
58

59 60 61 62 63
QString appLogDirPath(void)
{
	return existingAppPath(dfltAttachSavingLoc(), DATOVKA_LOG_DIR_NAME);
}

64
QString appMsgAttachDirPath(const QString &msgIdStr)
65
{
66
	return existingAppPath(dfltAttachSavingLoc(), msgIdStr);
67 68
}

69
QString appTmpDirPath(void)
70
{
71
	return existingAppPath(dfltAttachSavingLoc(), DATOVKA_TEMP_DIR_NAME);
72 73
}

74
void removeDirFromDocLoc(const QString &dirName)
75
{
76
	QString folderPath(
77
	     existingAppPath(dfltAttachSavingLoc(), dirName));
78 79 80

	if (folderPath.isEmpty()) {
		return;
81 82
	}

83 84
	QDir dir(folderPath);
	dir.removeRecursively();
85 86
}

87
QString existingWritableLoc(int type)
88 89 90 91 92 93
{
	enum QStandardPaths::StandardLocation locationType;

	switch (type) {
	case QStandardPaths::AppDataLocation:
	case QStandardPaths::AppLocalDataLocation:
94
	case QStandardPaths::DocumentsLocation:
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
		locationType = (enum QStandardPaths::StandardLocation) type;
		break;
	default: /* All other types are not used. */
		Q_ASSERT(0);
		return QString();
		break;
	}

	QString dirName(QStandardPaths::writableLocation(locationType));
	/* Return if no such path exists. */
	if (dirName.isEmpty()) {
		return QString();
	}

	/* Create the path if it does not exist. */
	QDir dir(dirName);
	if (!dir.exists() && !dir.mkpath(".")) {
		return QString();
	}
	Q_ASSERT(dir.exists());

	return dirName;
}

119
QString dfltAttachSavingLoc(void)
120
{
121
	return existingWritableLoc(QStandardPaths::DocumentsLocation);
122 123
}

124
QString dfltDbAndConfigLoc(void)
125
{
126
	return existingWritableLoc(QStandardPaths::AppDataLocation);
127 128
}

129
QStringList zfoFilesFromDir(const QString &dirPath, bool subdirs)
130 131 132 133 134
{
	QStringList filters("*.zfo");
	QStringList fileList, filePathList;
	QDir directory(QDir::home());

135 136
	if (subdirs) {
		QDirIterator it(dirPath, filters, QDir::Files,
137
		    QDirIterator::Subdirectories);
138 139 140 141 142
		if (!it.filePath().isEmpty()) {
			filePathList.append(it.filePath());
			while (it.hasNext()) {
				filePathList.append(it.next());
			}
143 144
		}
	} else {
145
		directory.setPath(dirPath);
146 147
		fileList = directory.entryList(filters);
		foreach (const QString &file, fileList) {
148
			filePathList.append(dirPath + QDir::separator() + file);
149 150 151 152 153 154
		}
	}

	return filePathList;
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
QString nonconflictingFileName(QString filePath)
{
	if (filePath.isEmpty()) {
		return QString();
	}

	if (QFile::exists(filePath)) {

		int fileCnt = 0;
		QFileInfo fi(filePath);

		const QString baseName(fi.baseName());
		const QString path(fi.path());
		const QString suffix(fi.completeSuffix());

		do {
			++fileCnt;
			QString newName(
			    baseName + "_" + QString::number(fileCnt));
			filePath =
			    path + QDir::separator() + newName + "." + suffix;
		} while (QFile::exists(filePath));
	}

	return filePath;
}

182
QString existingAppPath(const QString &basePath, const QString &dirName)
183
{
184 185
	QString newPath = basePath + QDir::separator() +
	    QLatin1String(DATOVKA_BASE_DIR_NAME) + QDir::separator() + dirName;
186

187 188
	QDir dir(newPath);
	if (!dir.exists() && !dir.mkpath(".")) {
189
		logErrorNL("Location '%s' could not be created.",
190
		    newPath.toUtf8().constData());
191 192
		return QString();
	}
193
	Q_ASSERT(dir.exists());
194 195 196 197

	return newPath;
}

198 199 200 201 202 203 204
QString writeFile(const QString &filePath, const QString &fileName,
    const QByteArray &data, bool deleteOnError)
{
	QString nameCopy(fileName);
	nameCopy.replace(QRegExp("[" + QRegExp::escape(ILL_FNAME_CH) + "]"),
	    ILL_FNAME_REP);

205 206
	QFile fout(nonconflictingFileName(filePath + QDir::separator()
	    + nameCopy));
207
	if (!fout.open(QIODevice::WriteOnly)) {
208 209
		logErrorNL("Cannot open file '%s'.",
		    nameCopy.toUtf8().constData());
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
		return QString();
	}

	/* Get whole path. */
	QString fullName = fout.fileName();
	int written = fout.write(data);
	bool flushed = fout.flush();
	fout.close();

	if ((written != data.size()) || !flushed) {
		if (deleteOnError) {
			QFile::remove(fullName);
		}
		return QString();
	}

	return fullName;
}
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

void deleteOldestLogFile(void)
{
	debugFuncCall();

	QDir locFileLocation(appLogDirPath());
	QFileInfoList logFiles(locFileLocation.entryInfoList(
	    QStringList() << "*.log", QDir::Files));

	if (logFiles.count() <= DATOVKA_MAX_LOG_FILES) {
		return;
	}

	/* Find and delete oldest log file */
	QFileInfo oldest;
	foreach (QFileInfo fileInfo, logFiles) {
		if (oldest.filePath().isEmpty() ||
		    fileInfo.created() < oldest.created()) {
			oldest = fileInfo;
		}
	}

	QFile logFile(oldest.filePath());
	if (logFile.remove()) {
		logInfoNL("Deleted oldest log file: '%s'.",
		    oldest.filePath().toUtf8().constData());
	}
}

QString constructLogFileName(void) {

	QString logFileName("mdatovka_"
	    + QDateTime::currentDateTime().toString("MMddhhmmss")
	    + ".log");
	return appLogDirPath() + QDir::separator() + logFileName;
}