123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 | // Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qstandardpaths.h"#include <qdir.h>#include <qstringlist.h>#ifndef QT_BOOTSTRAPPED#include <qcoreapplication.h>#endif#include <qt_windows.h>#include <shlobj.h>#include <intshcut.h>#include <qvarlengtharray.h>#ifndef QT_NO_STANDARDPATHS QT_BEGIN_NAMESPACE using namespaceQt::StringLiterals;static QString convertCharArray(const wchar_t*path){returnQDir::fromNativeSeparators(QString::fromWCharArray(path));}staticinlineboolisGenericConfigLocation(QStandardPaths::StandardLocation type){return type ==QStandardPaths::GenericConfigLocation || type ==QStandardPaths::GenericDataLocation;}staticinlineboolisConfigLocation(QStandardPaths::StandardLocation type){return type ==QStandardPaths::ConfigLocation || type ==QStandardPaths::AppConfigLocation || type ==QStandardPaths::AppDataLocation || type ==QStandardPaths::AppLocalDataLocation ||isGenericConfigLocation(type);}static voidappendOrganizationAndApp(QString &path)// Courtesy qstandardpaths_unix.cpp{#ifndef QT_BOOTSTRAPPEDconst QString &org =QCoreApplication::organizationName();if(!org.isEmpty()) path += u'/'+ org;const QString &appName =QCoreApplication::applicationName();if(!appName.isEmpty()) path += u'/'+ appName;#else// !QT_BOOTSTRAPPEDQ_UNUSED(path);#endif}staticinlinevoidappendTestMode(QString &path){if(QStandardPaths::isTestModeEnabled()) path +="/qttest"_L1;}static boolisProcessLowIntegrity(){// same as GetCurrentProcessToken()constauto process_token =HANDLE(quintptr(-4)); QVarLengthArray<char,256>token_info_buf(256);auto* token_info =reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_info_buf.data()); DWORD token_info_length = token_info_buf.size();if(!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) {// grow buffer and retry GetTokenInformation token_info_buf.resize(token_info_length); token_info =reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_info_buf.data());if(!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length))return false;// assume "normal" process}// The GetSidSubAuthorityCount return-code is undefined on failure, so// there's no point in checking before dereferencing DWORD integrity_level = *GetSidSubAuthority(token_info->Label.Sid, *GetSidSubAuthorityCount(token_info->Label.Sid) -1);return(integrity_level < SECURITY_MANDATORY_MEDIUM_RID);}// Map QStandardPaths::StandardLocation to KNOWNFOLDERID of SHGetKnownFolderPath()static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type){// folders for medium & high integrity processesstatic const GUID folderIds[] = { FOLDERID_Desktop,// DesktopLocation FOLDERID_Documents,// DocumentsLocation FOLDERID_Fonts,// FontsLocation FOLDERID_Programs,// ApplicationsLocation FOLDERID_Music,// MusicLocation FOLDERID_Videos,// MoviesLocation FOLDERID_Pictures,// PicturesLocationGUID(),GUID(),// TempLocation/HomeLocation FOLDERID_LocalAppData,// AppLocalDataLocation ("Local" path)GUID(),// CacheLocation FOLDERID_LocalAppData,// GenericDataLocation ("Local" path)GUID(),// RuntimeLocation FOLDERID_LocalAppData,// ConfigLocation ("Local" path) FOLDERID_Downloads,// DownloadLocationGUID(),// GenericCacheLocation FOLDERID_LocalAppData,// GenericConfigLocation ("Local" path) FOLDERID_RoamingAppData,// AppDataLocation ("Roaming" path) FOLDERID_LocalAppData,// AppConfigLocation ("Local" path) FOLDERID_Public,// PublicShareLocation FOLDERID_Templates,// TemplatesLocationGUID(),// StateLocationGUID(),// GenericStateLocation};static_assert(sizeof(folderIds) /sizeof(folderIds[0]) ==size_t(QStandardPaths::GenericStateLocation +1));// folders for low integrity processesstatic const GUID folderIds_li[] = { FOLDERID_Desktop,// DesktopLocation FOLDERID_Documents,// DocumentsLocation FOLDERID_Fonts,// FontsLocation FOLDERID_Programs,// ApplicationsLocation FOLDERID_Music,// MusicLocation FOLDERID_Videos,// MoviesLocation FOLDERID_Pictures,// PicturesLocationGUID(),GUID(),// TempLocation/HomeLocation FOLDERID_LocalAppDataLow,// AppLocalDataLocation ("Local" path)GUID(),// CacheLocation FOLDERID_LocalAppDataLow,// GenericDataLocation ("Local" path)GUID(),// RuntimeLocation FOLDERID_LocalAppDataLow,// ConfigLocation ("Local" path) FOLDERID_Downloads,// DownloadLocationGUID(),// GenericCacheLocation FOLDERID_LocalAppDataLow,// GenericConfigLocation ("Local" path) FOLDERID_RoamingAppData,// AppDataLocation ("Roaming" path) FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path) FOLDERID_Public,// PublicShareLocation FOLDERID_Templates,// TemplatesLocationGUID(),// StateLocationGUID(),// GenericStateLocation};static_assert(sizeof(folderIds_li) ==sizeof(folderIds));static bool low_integrity_process =isProcessLowIntegrity();if(size_t(type) <sizeof(folderIds) /sizeof(folderIds[0]))return low_integrity_process ? folderIds_li[type] : folderIds[type];returnGUID();}// Convenience for SHGetKnownFolderPath().static QString sHGetKnownFolderPath(const GUID &clsid){ QString result; LPWSTR path;if(Q_LIKELY(SUCCEEDED(SHGetKnownFolderPath(clsid, KF_FLAG_DONT_VERIFY,0, &path)))) { result =convertCharArray(path);CoTaskMemFree(path);}return result;} QString QStandardPaths::writableLocation(StandardLocation type){ QString result;switch(type) {case CacheLocation:// Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache// location for everyone. Most applications seem to be using a// cache directory located in their AppData directory result =sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));if(!result.isEmpty()) {appendTestMode(result);appendOrganizationAndApp(result); result +="/cache"_L1;}break;case GenericCacheLocation: result =sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));if(!result.isEmpty()) {appendTestMode(result); result +="/cache"_L1;}break;case RuntimeLocation:case HomeLocation: result =QDir::homePath();break;case TempLocation: result =QDir::tempPath();break;case StateLocation: result =sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));if(!result.isEmpty()) {appendTestMode(result);appendOrganizationAndApp(result); result +="/State"_L1;}break;case GenericStateLocation: result =sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));if(!result.isEmpty()) {appendTestMode(result); result +="/State"_L1;}break;default: result =sHGetKnownFolderPath(writableSpecialFolderId(type));if(!result.isEmpty() &&isConfigLocation(type)) {appendTestMode(result);if(!isGenericConfigLocation(type))appendOrganizationAndApp(result);}break;}return result;}#ifndef QT_BOOTSTRAPPEDextern QString qAppFileName();#endif QStringList QStandardPaths::standardLocations(StandardLocation type){ QStringList dirs;const QString localDir =writableLocation(type);if(!localDir.isEmpty()) dirs.append(localDir);// type-specific handling goes hereif(isConfigLocation(type)) { QString programData =sHGetKnownFolderPath(FOLDERID_ProgramData);if(!programData.isEmpty()) {if(!isGenericConfigLocation(type))appendOrganizationAndApp(programData); dirs.append(programData);}#ifndef QT_BOOTSTRAPPED// Note: QCoreApplication::applicationDirPath(), while static, requires// an application instance. But we might need to resolve the standard// locations earlier than that, so we fall back to qAppFileName(). QString applicationDirPath = qApp ?QCoreApplication::applicationDirPath():QFileInfo(qAppFileName()).path(); dirs.append(applicationDirPath);const QString dataDir = applicationDirPath +"/data"_L1; dirs.append(dataDir);if(!isGenericConfigLocation(type)) { QString appDataDir = dataDir;appendOrganizationAndApp(appDataDir);if(appDataDir != dataDir) dirs.append(appDataDir);}#endif// !QT_BOOTSTRAPPED}// isConfigLocation()return dirs;} QT_END_NAMESPACE #endif// QT_NO_STANDARDPATHS
|