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
qmakevfs.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qmakevfs.h"
5
6#include "ioutils.h"
7using namespace QMakeInternal;
8
9#include <qdir.h>
10#include <qfile.h>
11#include <qfileinfo.h>
12
13#define fL1S(s) QString::fromLatin1(s)
14
15QT_BEGIN_NAMESPACE
16
17QMakeVfs::QMakeVfs()
18#ifndef PROEVALUATOR_FULL
19 : m_magicMissing(fL1S("missing"))
20 , m_magicExisting(fL1S("existing"))
21#endif
22{
23 ref();
24}
25
27{
28 deref();
29}
30
32{
33#ifdef PROEVALUATOR_THREAD_SAFE
34 QMutexLocker locker(&s_mutex);
35#endif
36 ++s_refCount;
37}
38
40{
41#ifdef PROEVALUATOR_THREAD_SAFE
42 QMutexLocker locker(&s_mutex);
43#endif
44 if (!--s_refCount) {
45 s_fileIdCounter = 0;
46 s_fileIdMap.clear();
47 s_idFileMap.clear();
48 }
49}
50
51#ifdef PROPARSER_THREAD_SAFE
52QMutex QMakeVfs::s_mutex;
53#endif
54int QMakeVfs::s_refCount;
55QAtomicInt QMakeVfs::s_fileIdCounter;
56QHash<QString, int> QMakeVfs::s_fileIdMap;
57QHash<int, QString> QMakeVfs::s_idFileMap;
58
59int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags)
60{
61#ifdef PROEVALUATOR_DUAL_VFS
62 {
63# ifdef PROPARSER_THREAD_SAFE
64 QMutexLocker locker(&m_vmutex);
65# endif
66 int idx = (flags & VfsCumulative) ? 1 : 0;
67 if (flags & VfsCreate) {
68 int &id = m_virtualFileIdMap[idx][fn];
69 if (!id) {
70 id = ++s_fileIdCounter;
71 m_virtualIdFileMap[id] = fn;
72 }
73 return id;
74 }
75 int id = m_virtualFileIdMap[idx].value(fn);
76 if (id || (flags & VfsCreatedOnly))
77 return id;
78 }
79#endif
80#ifdef PROPARSER_THREAD_SAFE
81 QMutexLocker locker(&s_mutex);
82#endif
83 if (!(flags & VfsAccessedOnly)) {
84 int &id = s_fileIdMap[fn];
85 if (!id) {
86 id = ++s_fileIdCounter;
87 s_idFileMap[id] = fn;
88 }
89 return id;
90 }
91 return s_fileIdMap.value(fn);
92}
93
94QString QMakeVfs::fileNameForId(int id)
95{
96#ifdef PROEVALUATOR_DUAL_VFS
97 {
98# ifdef PROPARSER_THREAD_SAFE
99 QMutexLocker locker(&m_vmutex);
100# endif
101 const QString &fn = m_virtualIdFileMap.value(id);
102 if (!fn.isEmpty())
103 return fn;
104 }
105#endif
106#ifdef PROPARSER_THREAD_SAFE
107 QMutexLocker locker(&s_mutex);
108#endif
109 return s_idFileMap.value(id);
110}
111
112bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags,
113 const QString &contents, QString *errStr)
114{
115#ifndef PROEVALUATOR_FULL
116# ifdef PROEVALUATOR_THREAD_SAFE
117 QMutexLocker locker(&m_mutex);
118# endif
119 QString *cont = &m_files[id];
120 Q_UNUSED(flags);
121 if (mode & QIODevice::Append)
122 *cont += contents;
123 else
124 *cont = contents;
125 Q_UNUSED(errStr);
126 return true;
127#else
128 QFileInfo qfi(fileNameForId(id));
129 if (!QDir::current().mkpath(qfi.path())) {
130 *errStr = fL1S("Cannot create parent directory");
131 return false;
132 }
133 QByteArray bytes = contents.toLocal8Bit();
134 QFile cfile(qfi.filePath());
135 if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
136 if (cfile.readAll() == bytes) {
137 if (flags & VfsExecutable) {
138 cfile.setPermissions(cfile.permissions()
139 | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
140 } else {
141 cfile.setPermissions(cfile.permissions()
142 & ~(QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther));
143 }
144 return true;
145 }
146 cfile.close();
147 }
148 if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
149 *errStr = cfile.errorString();
150 return false;
151 }
152 cfile.write(bytes);
153 cfile.close();
154 if (cfile.error() != QFile::NoError) {
155 *errStr = cfile.errorString();
156 return false;
157 }
158 if (flags & VfsExecutable)
159 cfile.setPermissions(cfile.permissions()
160 | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
161 return true;
162#endif
163}
164
165QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errStr,
166 bool utf8)
167{
168#ifndef PROEVALUATOR_FULL
169# ifdef PROEVALUATOR_THREAD_SAFE
170 QMutexLocker locker(&m_mutex);
171# endif
172 auto it = m_files.constFind(id);
173 if (it != m_files.constEnd()) {
174 if (it->constData() == m_magicMissing.constData()) {
175 *errStr = fL1S("No such file or directory");
176 return ReadNotFound;
177 }
178 if (it->constData() != m_magicExisting.constData()) {
179 *contents = *it;
180 return ReadOk;
181 }
182 }
183#endif
184
185 QFile file(fileNameForId(id));
186 if (!file.open(QIODevice::ReadOnly)) {
187 if (!file.exists()) {
188#ifndef PROEVALUATOR_FULL
189 m_files[id] = m_magicMissing;
190#endif
191 *errStr = fL1S("No such file or directory");
192 return ReadNotFound;
193 }
194 *errStr = file.errorString();
195 return ReadOtherError;
196 }
197#ifndef PROEVALUATOR_FULL
198 m_files[id] = m_magicExisting;
199#endif
200
201 QByteArray bcont = file.readAll();
202 if (bcont.startsWith("\xef\xbb\xbf")) {
203 // UTF-8 BOM will cause subtle errors
204 *errStr = fL1S("Unexpected UTF-8 BOM");
205 return ReadOtherError;
206 }
207 *contents = utf8 ? QString::fromUtf8(bcont) : QString::fromLocal8Bit(bcont);
208 return ReadOk;
209}
210
211bool QMakeVfs::exists(const QString &fn, VfsFlags flags)
212{
213#ifndef PROEVALUATOR_FULL
214# ifdef PROEVALUATOR_THREAD_SAFE
215 QMutexLocker locker(&m_mutex);
216# endif
217 int id = idForFileName(fn, flags);
218 auto it = m_files.constFind(id);
219 if (it != m_files.constEnd())
220 return it->constData() != m_magicMissing.constData();
221#else
222 Q_UNUSED(flags);
223#endif
224 bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular;
225#ifndef PROEVALUATOR_FULL
226 m_files[id] = ex ? m_magicExisting : m_magicMissing;
227#endif
228 return ex;
229}
230
231#ifndef PROEVALUATOR_FULL
232// This should be called when the sources may have changed (e.g., VCS update).
234{
235# ifdef PROEVALUATOR_THREAD_SAFE
236 QMutexLocker locker(&m_mutex);
237# endif
238 auto it = m_files.begin(), eit = m_files.end();
239 while (it != eit) {
240 if (it->constData() == m_magicMissing.constData()
241 ||it->constData() == m_magicExisting.constData())
242 it = m_files.erase(it);
243 else
244 ++it;
245 }
246}
247
248// This should be called when generated files may have changed (e.g., actual build).
250{
251# ifdef PROEVALUATOR_THREAD_SAFE
252 QMutexLocker locker(&m_mutex);
253# endif
254 m_files.clear();
255}
256#endif
257
258QT_END_NAMESPACE
Definition qfile.h:71
\inmodule QtCore
Definition qhash.h:843
bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr)
Definition qmakevfs.cpp:112
QString fileNameForId(int id)
Definition qmakevfs.cpp:94
bool exists(const QString &fn, QMakeVfs::VfsFlags flags)
Definition qmakevfs.cpp:211
@ ReadOtherError
Definition qmakevfs.h:30
@ ReadNotFound
Definition qmakevfs.h:29
void invalidateContents()
Definition qmakevfs.cpp:249
int idForFileName(const QString &fn, VfsFlags flags)
Definition qmakevfs.cpp:59
void invalidateCache()
Definition qmakevfs.cpp:233
ReadResult readFile(int id, QString *contents, QString *errStr, bool utf8=false)
Definition qmakevfs.cpp:165
static void ref()
Definition qmakevfs.cpp:31
@ VfsAccessedOnly
Definition qmakevfs.h:45
static void deref()
Definition qmakevfs.cpp:39
#define fL1S(s)
Definition ioutils.cpp:21