23 #include "datapaths.h" 
   25 #include "application.h" 
   26 #include "doomseekerfilepaths.h" 
   27 #include "fileutils.h" 
   29 #include "plugins/engineplugin.h" 
   30 #include "strings.hpp" 
   35 #include <QCoreApplication> 
   36 #include <QDesktopServices> 
   38 #include <QProcessEnvironment> 
   41 #include <QStandardPaths> 
   44 #if !defined(INSTALL_PREFIX) || !defined(INSTALL_LIBDIR) 
   45 #error Build system should provide definition for INSTALL_PREFIX and INSTALL_LIBDIR 
   53 extern Q_CORE_EXPORT 
int qt_ntfs_permission_lookup;
 
   56 int qt_ntfs_permission_lookup;
 
   59 static QList<DataPaths::DirErrno> uniqueErrnosByDir(
const QList<DataPaths::DirErrno> &errnos)
 
   61         QSet<QString> uniqueDirs;
 
   62         QList<DataPaths::DirErrno> uniqueErrnos;
 
   65                 if (!uniqueDirs.contains(dirErrno.directory.path()))
 
   67                         uniqueDirs.insert(dirErrno.directory.path());
 
   68                         uniqueErrnos << dirErrno;
 
   74 static QStringList uniquePaths(
const QStringList &paths)
 
   76         QList<QFileInfo> uniqueMarkers;
 
   78         for (
const QString &path : paths)
 
   80                 if (!uniqueMarkers.contains(path))
 
   82                         uniqueMarkers << path;
 
   92         static const QString PLUGINS_DIR_NAME;
 
   98         QString workingDirectory;
 
  100         bool bIsPortableModeOn;
 
  107 static const QString LEGACY_APPDATA_DIR_NAME = ".doomseeker";
 
  108 static const QString DEMOS_DIR_NAME = "demos";
 
  110 const QString 
DataPaths::CHATLOGS_DIR_NAME = "chatlogs";
 
  112 const QString 
DataPaths::TRANSLATIONS_DIR_NAME = "translations";
 
  113 const QString 
DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
 
  114 const QString 
DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
 
  118         d->bIsPortableModeOn = bPortableModeOn;
 
  126                 d->cacheDirectory.setPath(systemAppDataDirectory(
".cache"));
 
  127                 d->configDirectory.setPath(systemAppDataDirectory(LEGACY_APPDATA_DIR_NAME));
 
  128                 d->dataDirectory.setPath(systemAppDataDirectory(
".static"));
 
  132                 d->cacheDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
 
  133                 #if QT_VERSION >= 0x050500 
  135                 d->configDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
 
  139                         QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
 
  142                 d->dataDirectory.setPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
 
  145         gLog << QString(
"Cache directory: %1").arg(d->cacheDirectory.absolutePath());
 
  146         gLog << QString(
"Config directory: %1").arg(d->configDirectory.absolutePath());
 
  147         gLog << QString(
"Data directory: %1").arg(d->dataDirectory.absolutePath());
 
  150 DataPaths::~DataPaths()
 
  156         return d->cacheDirectory.absolutePath();
 
  161         QStringList failedList;
 
  165                 failedList.append(dataDirectory);
 
  172         QList<DirErrno> failedDirs;
 
  177         if (cacheDirError.isError())
 
  178                 failedDirs << cacheDirError;
 
  184         if (!d->configDirectory.exists(DoomseekerFilePaths::INI_FILENAME))
 
  187                 if (configDirError.isError())
 
  188                         failedDirs << configDirError;
 
  190                 #if !defined(Q_OS_DARWIN) 
  191                 else if (appDataDir.exists(
".doomseeker"))
 
  194                         const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() + 
".doomseeker");
 
  195                         gLog << QString(
"Migrating configuration data from '%1'\n\tto '%2'.")
 
  196                                 .arg(oldConfigDir.absolutePath())
 
  197                                 .arg(d->configDirectory.absolutePath());
 
  199                         for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QStringList(
"*.ini"), QDir::Files))
 
  201                                 QFile(fileinfo.absoluteFilePath()).copy(d->configDirectory.absoluteFilePath(fileinfo.fileName()));
 
  210         if (!d->dataDirectory.exists(DEMOS_DIR_NAME))
 
  213                 const QString legacyPrefDirectory = 
"Library/Preferences/Doomseeker";
 
  215                 const QString legacyPrefDirectory = 
".doomseeker";
 
  218                 if (dataDirError.isError())
 
  219                         failedDirs << dataDirError;
 
  220                 else if (appDataDir.exists(legacyPrefDirectory))
 
  223                         const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() + legacyPrefDirectory);
 
  224                         gLog << QString(
"Migrating user data from '%1'\n\tto '%2'.")
 
  225                                 .arg(oldConfigDir.absolutePath())
 
  226                                 .arg(d->dataDirectory.absolutePath());
 
  228                         for (QFileInfo fileinfo : oldConfigDir.entryInfoList(QDir::Dirs))
 
  230                                 const QString origPath = fileinfo.absoluteFilePath();
 
  231                                 QFile file(origPath);
 
  232                                 if (file.rename(d->dataDirectory.absoluteFilePath(fileinfo.fileName())))
 
  236                                         #if !defined(Q_OS_WIN32) 
  245         if (demosDirError.isError())
 
  246                 failedDirs << demosDirError;
 
  248         return uniqueErrnosByDir(failedDirs);
 
  253         return staticDefaultInstance;
 
  259         QStringList filePaths;
 
  266         if (progBinDirName != 
"bin" && progBinDirName != 
"MacOS")
 
  272 QString DataPaths::demosDirectoryPath()
 const 
  274         return d->dataDirectory.absoluteFilePath(DEMOS_DIR_NAME);
 
  280         if (!isPortableModeOn())
 
  282                 rootPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
 
  290 QString DataPaths::env(
const QString &key)
 
  292         return QProcessEnvironment::systemEnvironment().value(key);
 
  295 void DataPaths::initDefault(
bool bPortableModeOn)
 
  297         assert(staticDefaultInstance == 
nullptr && 
"DataPaths can have only one default.");
 
  298         if (staticDefaultInstance == 
nullptr)
 
  299                 staticDefaultInstance = 
new DataPaths(bPortableModeOn);
 
  302 bool DataPaths::isPortableModeOn()
 const 
  304         return d->bIsPortableModeOn;
 
  330         #if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN32) 
  334         const QString installDir = INSTALL_PREFIX 
"/" INSTALL_LIBDIR 
"/doomseeker/";
 
  336                 paths = QStringList(installDir);
 
  338                 paths.append(installDir);
 
  341         paths = uniquePaths(paths);
 
  348         QString envVarName = 
"";
 
  353                 envVarName = 
"ProgramFiles(x86)";
 
  357                 envVarName = 
"ProgramW6432";
 
  361                 envVarName = 
"ProgramFiles";
 
  368         QString path = env(envVarName);
 
  369         if (path.isEmpty() && machineType != Preferred)
 
  382         Q_UNUSED(machineType);
 
  389         return d->configDirectory.absolutePath();
 
  400         paths.append(QDir::currentPath()); 
 
  401         paths.append(QCoreApplication::applicationDirPath()); 
 
  403         paths.append(INSTALL_PREFIX 
"/share/doomseeker"); 
 
  405         paths = uniquePaths(paths);
 
  406         QString subdirFiltered = subdir.trimmed();
 
  407         if (!subdirFiltered.isEmpty())
 
  409                 for (
int i = 0; i < paths.size(); ++i)
 
  417         Strings::triml(append, 
"/\\");
 
  419         if (isPortableModeOn())
 
  421                 QString path = d->workingDirectory + 
"/" + append;
 
  422                 return QDir(path).absolutePath();
 
  431                 QString envVar = env(
"APPDATA");
 
  439                 dir = QDir::homePath();
 
  444         Strings::trimr(dir, 
"/\\");
 
  446         dir += QDir::separator() + append;
 
  448         return QDir(dir).absolutePath();
 
  457         if (!rootDir.mkpath(dirToCreate))
 
  459                 int errnoval = errno;
 
  461                         return DirErrno(fullDirPath, errnoval, strerror(errnoval));
 
  469                         if (!pathToBottomMostExisting.isEmpty())
 
  471                                 QFileInfo parentDir(pathToBottomMostExisting);
 
  472                                 if (parentDir.exists() && !parentDir.isDir())
 
  474                                         return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
 
  475                                                 QObject::tr(
"parent node is not a directory: %1")
 
  476                                                         .arg(parentDir.filePath()));
 
  480                                 ++qt_ntfs_permission_lookup;
 
  481                                 bool permissions = parentDir.isReadable()
 
  482                                         && parentDir.isWritable()
 
  483                                         && parentDir.isExecutable();
 
  484                                 --qt_ntfs_permission_lookup;
 
  488                                         return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
 
  489                                                 QObject::tr(
"lack of necessary permissions to the parent directory: %1")
 
  490                                                         .arg(parentDir.filePath()));
 
  494                         return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR, QObject::tr(
"cannot create directory"));
 
  507         QFileInfo fileInfo(path);
 
  509         bool bCondition1 = !path.isEmpty();
 
  510         bool bCondition2 = fileInfo.exists();
 
  511         bool bCondition3 = fileInfo.isDir();
 
  513         return bCondition1 && bCondition2 && bCondition3;
 
  518         return d->workingDirectory;