Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstandardpaths_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:provides-trusted-directory-paths
4
6
7#include <qdir.h>
8#include <qstringlist.h>
9
10#ifndef QT_BOOTSTRAPPED
11#include <qcoreapplication.h>
12#endif
13
14#include <qt_windows.h>
15#include <shlobj.h>
16#include <intshcut.h>
17#include <qvarlengtharray.h>
18
19#ifndef QT_NO_STANDARDPATHS
20
22
23using namespace Qt::StringLiterals;
24
25static QString convertCharArray(const wchar_t *path)
26{
27 return QDir::fromNativeSeparators(QString::fromWCharArray(path));
28}
29
30static inline bool isGenericConfigLocation(QStandardPaths::StandardLocation type)
31{
32 return type == QStandardPaths::GenericConfigLocation || type == QStandardPaths::GenericDataLocation;
33}
34
35static inline bool isConfigLocation(QStandardPaths::StandardLocation type)
36{
37 return type == QStandardPaths::ConfigLocation || type == QStandardPaths::AppConfigLocation
38 || type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation
39 || isGenericConfigLocation(type);
40}
41
42static void appendOrganizationAndApp(QString &path) // Courtesy qstandardpaths_unix.cpp
43{
44#ifndef QT_BOOTSTRAPPED
45 const QString &org = QCoreApplication::organizationName();
46 if (!org.isEmpty())
47 path += u'/' + org;
48 const QString &appName = QCoreApplication::applicationName();
49 if (!appName.isEmpty())
50 path += u'/' + appName;
51#else // !QT_BOOTSTRAPPED
52 Q_UNUSED(path);
53#endif
54}
55
56static inline void appendTestMode(QString &path)
57{
58 if (QStandardPaths::isTestModeEnabled())
59 path += "/qttest"_L1;
60}
61
63{
64 // same as GetCurrentProcessToken()
65 const auto process_token = HANDLE(quintptr(-4));
66
67 QVarLengthArray<char,256> token_info_buf(256);
68 auto* token_info = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_info_buf.data());
69 DWORD token_info_length = token_info_buf.size();
70 if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) {
71 // grow buffer and retry GetTokenInformation
72 token_info_buf.resize(token_info_length);
73 token_info = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_info_buf.data());
74 if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length))
75 return false; // assume "normal" process
76 }
77
78 // The GetSidSubAuthorityCount return-code is undefined on failure, so
79 // there's no point in checking before dereferencing
80 DWORD integrity_level = *GetSidSubAuthority(token_info->Label.Sid, *GetSidSubAuthorityCount(token_info->Label.Sid) - 1);
81 return (integrity_level < SECURITY_MANDATORY_MEDIUM_RID);
82}
83
84// Map QStandardPaths::StandardLocation to KNOWNFOLDERID of SHGetKnownFolderPath()
85static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
86{
87 // folders for medium & high integrity processes
88 static const GUID folderIds[] = {
89 FOLDERID_Desktop, // DesktopLocation
90 FOLDERID_Documents, // DocumentsLocation
91 FOLDERID_Fonts, // FontsLocation
92 FOLDERID_Programs, // ApplicationsLocation
93 FOLDERID_Music, // MusicLocation
94 FOLDERID_Videos, // MoviesLocation
95 FOLDERID_Pictures, // PicturesLocation
96 GUID(), GUID(), // TempLocation/HomeLocation
97 FOLDERID_LocalAppData, // AppLocalDataLocation ("Local" path)
98 GUID(), // CacheLocation
99 FOLDERID_LocalAppData, // GenericDataLocation ("Local" path)
100 GUID(), // RuntimeLocation
101 FOLDERID_LocalAppData, // ConfigLocation ("Local" path)
102 FOLDERID_Downloads, // DownloadLocation
103 GUID(), // GenericCacheLocation
104 FOLDERID_LocalAppData, // GenericConfigLocation ("Local" path)
105 FOLDERID_RoamingAppData,// AppDataLocation ("Roaming" path)
106 FOLDERID_LocalAppData, // AppConfigLocation ("Local" path)
107 FOLDERID_Public, // PublicShareLocation
108 FOLDERID_Templates, // TemplatesLocation
109 GUID(), // StateLocation
110 GUID(), // GenericStateLocation
111 };
112 static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::GenericStateLocation + 1));
113
114 // folders for low integrity processes
115 static const GUID folderIds_li[] = {
116 FOLDERID_Desktop, // DesktopLocation
117 FOLDERID_Documents, // DocumentsLocation
118 FOLDERID_Fonts, // FontsLocation
119 FOLDERID_Programs, // ApplicationsLocation
120 FOLDERID_Music, // MusicLocation
121 FOLDERID_Videos, // MoviesLocation
122 FOLDERID_Pictures, // PicturesLocation
123 GUID(), GUID(), // TempLocation/HomeLocation
124 FOLDERID_LocalAppDataLow,// AppLocalDataLocation ("Local" path)
125 GUID(), // CacheLocation
126 FOLDERID_LocalAppDataLow,// GenericDataLocation ("Local" path)
127 GUID(), // RuntimeLocation
128 FOLDERID_LocalAppDataLow,// ConfigLocation ("Local" path)
129 FOLDERID_Downloads, // DownloadLocation
130 GUID(), // GenericCacheLocation
131 FOLDERID_LocalAppDataLow,// GenericConfigLocation ("Local" path)
132 FOLDERID_RoamingAppData, // AppDataLocation ("Roaming" path)
133 FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path)
134 FOLDERID_Public, // PublicShareLocation
135 FOLDERID_Templates, // TemplatesLocation
136 GUID(), // StateLocation
137 GUID(), // GenericStateLocation
138 };
139 static_assert(sizeof(folderIds_li) == sizeof(folderIds));
140
141 static bool low_integrity_process = isProcessLowIntegrity();
142 if (size_t(type) < sizeof(folderIds) / sizeof(folderIds[0]))
143 return low_integrity_process ? folderIds_li[type] : folderIds[type];
144 return GUID();
145}
146
147// Convenience for SHGetKnownFolderPath().
148static QString sHGetKnownFolderPath(const GUID &clsid)
149{
150 QString result;
151 LPWSTR path;
152 if (Q_LIKELY(SUCCEEDED(SHGetKnownFolderPath(clsid, KF_FLAG_DONT_VERIFY, 0, &path)))) {
153 result = convertCharArray(path);
154 CoTaskMemFree(path);
155 }
156 return result;
157}
158
159QString QStandardPaths::writableLocation(StandardLocation type)
160{
161 QString result;
162 switch (type) {
163 case CacheLocation:
164 // Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache
165 // location for everyone. Most applications seem to be using a
166 // cache directory located in their AppData directory
167 result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));
168 if (!result.isEmpty()) {
169 appendTestMode(result);
170 appendOrganizationAndApp(result);
171 result += "/cache"_L1;
172 }
173 break;
174
175 case GenericCacheLocation:
176 result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
177 if (!result.isEmpty()) {
178 appendTestMode(result);
179 result += "/cache"_L1;
180 }
181 break;
182
183 case RuntimeLocation:
184 case HomeLocation:
185 result = QDir::homePath();
186 break;
187
188 case TempLocation:
189 result = QDir::tempPath();
190 break;
191
192 case StateLocation:
193 result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));
194 if (!result.isEmpty()) {
195 appendTestMode(result);
196 appendOrganizationAndApp(result);
197 result += "/State"_L1;
198 }
199 break;
200
201 case GenericStateLocation:
202 result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
203 if (!result.isEmpty()) {
204 appendTestMode(result);
205 result += "/State"_L1;
206 }
207 break;
208
209 default:
210 result = sHGetKnownFolderPath(writableSpecialFolderId(type));
211 if (!result.isEmpty() && isConfigLocation(type)) {
212 appendTestMode(result);
213 if (!isGenericConfigLocation(type))
214 appendOrganizationAndApp(result);
215 }
216 break;
217 }
218 return result;
219}
220
221#ifndef QT_BOOTSTRAPPED
222extern QString qAppFileName();
223#endif
224
225QStringList QStandardPaths::standardLocations(StandardLocation type)
226{
227 QStringList dirs;
228 const QString localDir = writableLocation(type);
229 if (!localDir.isEmpty())
230 dirs.append(localDir);
231
232 // type-specific handling goes here
233 if (isConfigLocation(type)) {
234 QString programData = sHGetKnownFolderPath(FOLDERID_ProgramData);
235 if (!programData.isEmpty()) {
236 if (!isGenericConfigLocation(type))
237 appendOrganizationAndApp(programData);
238 dirs.append(programData);
239 }
240#ifndef QT_BOOTSTRAPPED
241 // Note: QCoreApplication::applicationDirPath(), while static, requires
242 // an application instance. But we might need to resolve the standard
243 // locations earlier than that, so we fall back to qAppFileName().
244 QString applicationDirPath = qApp ? QCoreApplication::applicationDirPath()
245 : QFileInfo(qAppFileName()).path();
246 dirs.append(applicationDirPath);
247 const QString dataDir = applicationDirPath + "/data"_L1;
248 dirs.append(dataDir);
249
250 if (!isGenericConfigLocation(type)) {
251 QString appDataDir = dataDir;
252 appendOrganizationAndApp(appDataDir);
253 if (appDataDir != dataDir)
254 dirs.append(appDataDir);
255 }
256#endif // !QT_BOOTSTRAPPED
257 } // isConfigLocation()
258
259 return dirs;
260}
261
262QT_END_NAMESPACE
263
264#endif // QT_NO_STANDARDPATHS
#define qApp
static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
static bool isGenericConfigLocation(QStandardPaths::StandardLocation type)
QString qAppFileName()
static bool isProcessLowIntegrity()
static void appendTestMode(QString &path)
static void appendOrganizationAndApp(QString &path)
static bool isConfigLocation(QStandardPaths::StandardLocation type)
static QString sHGetKnownFolderPath(const GUID &clsid)
static QString convertCharArray(const wchar_t *path)