1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2017 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qtemporarydir.h"
6
7#if QT_CONFIG(temporaryfile)
8
9#include "qdebug.h"
10#include "qplatformdefs.h"
11#include "qrandom.h"
12#include "private/qtemporaryfile_p.h"
13
14#if defined(QT_BUILD_CORE_LIB)
15#include "qcoreapplication.h"
16#endif
17
18#if !defined(Q_OS_WIN)
19#include <errno.h>
20#endif
21
22#include <type_traits>
23
24QT_BEGIN_NAMESPACE
25
26using namespace Qt::StringLiterals;
27
28static_assert(std::is_nothrow_move_constructible_v<QTemporaryDir>);
29static_assert(std::is_nothrow_move_assignable_v<QTemporaryDir>);
30
31//************* QTemporaryDirPrivate
32class QTemporaryDirPrivate
33{
34public:
35 QTemporaryDirPrivate();
36 ~QTemporaryDirPrivate();
37
38 void create(const QString &templateName);
39
40 QString pathOrError;
41 bool autoRemove;
42 bool success;
43};
44
45QTemporaryDirPrivate::QTemporaryDirPrivate()
46 : autoRemove(true),
47 success(false)
48{
49}
50
51QTemporaryDirPrivate::~QTemporaryDirPrivate()
52{
53}
54
55static QString defaultTemplateName()
56{
57 QString baseName;
58#if defined(QT_BUILD_CORE_LIB)
59 baseName = QCoreApplication::applicationName();
60 if (baseName.isEmpty())
61#endif
62 baseName = "qt_temp"_L1;
63
64 return QDir::tempPath() + u'/' + baseName + "-XXXXXX"_L1;
65}
66
67void QTemporaryDirPrivate::create(const QString &templateName)
68{
69 QTemporaryFileName tfn(templateName);
70 for (int i = 0; i < 256; ++i) {
71 tfn.generateNext();
72 QFileSystemEntry fileSystemEntry(tfn.path, QFileSystemEntry::FromNativePath());
73 if (QFileSystemEngine::createDirectory(entry: fileSystemEntry, createParents: false,
74 permissions: QFile::ReadOwner | QFile::WriteOwner
75 | QFile::ExeOwner)) {
76 success = true;
77 pathOrError = fileSystemEntry.filePath();
78 return;
79 }
80# ifdef Q_OS_WIN
81 const int exists = ERROR_ALREADY_EXISTS;
82 int code = GetLastError();
83# else
84 const int exists = EEXIST;
85 int code = errno;
86# endif
87 if (code != exists)
88 break;
89 }
90 pathOrError = qt_error_string();
91 success = false;
92}
93
94//************* QTemporaryDir
95
96/*!
97 \class QTemporaryDir
98 \inmodule QtCore
99 \reentrant
100 \brief The QTemporaryDir class creates a unique directory for temporary use.
101
102 \ingroup io
103
104
105 QTemporaryDir is used to create unique temporary directories safely.
106 The directory itself is created by the constructor. The name of the
107 temporary directory is guaranteed to be unique (i.e., you are
108 guaranteed to not overwrite an existing directory), and the directory will
109 subsequently be removed upon destruction of the QTemporaryDir
110 object. The directory name is either auto-generated, or created based
111 on a template, which is passed to QTemporaryDir's constructor.
112
113 Example:
114
115 \snippet code/src_corelib_io_qtemporarydir.cpp 0
116
117 It is very important to test that the temporary directory could be
118 created, using isValid(). Do not use \l {QDir::exists()}{exists()}, since a default-constructed
119 QDir represents the current directory, which exists.
120
121 The path to the temporary directory can be found by calling path().
122
123 A temporary directory will have some static part of the name and some
124 part that is calculated to be unique. The default path will be
125 determined from QCoreApplication::applicationName() (otherwise \c qt_temp) and will
126 be placed into the temporary path as returned by QDir::tempPath().
127 If you specify your own path, a relative path will not be placed in the
128 temporary directory by default, but be relative to the current working directory.
129 In all cases, a random string will be appended to the path in order to make it unique.
130
131 \sa QDir::tempPath(), QDir, QTemporaryFile
132*/
133
134/*!
135 Constructs a QTemporaryDir using as template the application name
136 returned by QCoreApplication::applicationName() (otherwise \c qt_temp).
137 The directory is stored in the system's temporary directory, QDir::tempPath().
138
139 \sa QDir::tempPath()
140*/
141QTemporaryDir::QTemporaryDir()
142 : d_ptr(new QTemporaryDirPrivate)
143{
144 d_ptr->create(templateName: defaultTemplateName());
145}
146
147/*!
148 Constructs a QTemporaryDir with a template of \a templatePath.
149
150 If \a templatePath is a relative path, the path will be relative to the
151 current working directory. You can use QDir::tempPath() to construct \a
152 templatePath if you want use the system's temporary directory.
153
154 If the \a templatePath ends with XXXXXX it will be used as the dynamic portion
155 of the directory name, otherwise it will be appended.
156 Unlike QTemporaryFile, XXXXXX in the middle of the template string is not supported.
157
158 \sa QDir::tempPath()
159*/
160QTemporaryDir::QTemporaryDir(const QString &templatePath)
161 : d_ptr(new QTemporaryDirPrivate)
162{
163 if (templatePath.isEmpty())
164 d_ptr->create(templateName: defaultTemplateName());
165 else
166 d_ptr->create(templateName: templatePath);
167}
168
169/*!
170 \fn QTemporaryDir::QTemporaryDir(QTemporaryDir &&other)
171
172 Move-constructs a new QTemporaryDir from \a other.
173
174 \note The moved-from object \a other is placed in a
175 partially-formed state, in which the only valid operations are
176 destruction and assignment of a new value.
177
178 \since 6.4
179*/
180
181/*!
182 \fn QTemporaryDir &QTemporaryDir::operator=(QTemporaryDir&& other)
183
184 Move-assigns \a other to this QTemporaryDir instance.
185
186 \note The moved-from object \a other is placed in a
187 partially-formed state, in which the only valid operations are
188 destruction and assignment of a new value.
189
190 \since 6.4
191*/
192
193/*!
194 \fn void QTemporaryDir::swap(QTemporaryDir &other)
195 \memberswap{temporary-dir}
196 \since 6.4
197*/
198
199/*!
200 Destroys the temporary directory object.
201 If auto remove mode was set, it will automatically delete the directory
202 including all its contents.
203
204 \sa autoRemove()
205*/
206QTemporaryDir::~QTemporaryDir()
207{
208 if (d_ptr) {
209 if (d_ptr->autoRemove)
210 remove();
211
212 delete d_ptr;
213 }
214}
215
216/*!
217 Returns \c true if the QTemporaryDir was created successfully.
218*/
219bool QTemporaryDir::isValid() const
220{
221 return d_ptr->success;
222}
223
224/*!
225 \since 5.6
226
227 If isValid() returns \c false, this function returns the error string that
228 explains why the creation of the temporary directory failed. Otherwise, this
229 function return an empty string.
230*/
231QString QTemporaryDir::errorString() const
232{
233 return d_ptr->success ? QString() : d_ptr->pathOrError;
234}
235
236/*!
237 Returns the path to the temporary directory.
238 Empty if the QTemporaryDir could not be created.
239
240//! [relative-or-absolute-path]
241 The returned path will be relative or absolulte depending on whether
242 QTemporaryDir was constructed with a relative or absolute path,
243 respectively.
244//! [relative-or-absolute-path]
245
246
247*/
248QString QTemporaryDir::path() const
249{
250 return d_ptr->success ? d_ptr->pathOrError : QString();
251}
252
253/*!
254 \since 5.9
255
256 Returns the path name of a file in the temporary directory.
257 Does \e not check if the file actually exists in the directory.
258 Redundant multiple separators or "." and ".." directories in
259 \a fileName are not removed (see QDir::cleanPath()). Absolute
260 paths are not allowed.
261
262 \include qtemporarydir.cpp relative-or-absolute-path
263*/
264QString QTemporaryDir::filePath(const QString &fileName) const
265{
266 if (QDir::isAbsolutePath(path: fileName)) {
267 qWarning(msg: "QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName));
268 return QString();
269 }
270
271 if (!d_ptr->success)
272 return QString();
273
274 QString ret = d_ptr->pathOrError;
275 if (!fileName.isEmpty()) {
276 ret += u'/';
277 ret += fileName;
278 }
279 return ret;
280}
281
282/*!
283 Returns \c true if the QTemporaryDir is in auto remove
284 mode. Auto-remove mode will automatically delete the directory from
285 disk upon destruction. This makes it very easy to create your
286 QTemporaryDir object on the stack, fill it with files, do something with
287 the files, and finally on function return it will automatically clean up
288 after itself.
289
290 Auto-remove is on by default.
291
292 \sa setAutoRemove(), remove()
293*/
294bool QTemporaryDir::autoRemove() const
295{
296 return d_ptr->autoRemove;
297}
298
299/*!
300 Sets the QTemporaryDir into auto-remove mode if \a b is true.
301
302 Auto-remove is on by default.
303
304 \sa autoRemove(), remove()
305*/
306void QTemporaryDir::setAutoRemove(bool b)
307{
308 d_ptr->autoRemove = b;
309}
310
311/*!
312 Removes the temporary directory, including all its contents.
313
314 Returns \c true if removing was successful.
315*/
316bool QTemporaryDir::remove()
317{
318 if (!d_ptr->success)
319 return false;
320 Q_ASSERT(!path().isEmpty());
321 Q_ASSERT(path() != "."_L1);
322
323 const bool result = QDir(path()).removeRecursively();
324 if (!result) {
325 qWarning() << "QTemporaryDir: Unable to remove"
326 << QDir::toNativeSeparators(pathName: path())
327 << "most likely due to the presence of read-only files.";
328 }
329 return result;
330}
331
332QT_END_NAMESPACE
333
334#endif // QT_CONFIG(temporaryfile)
335

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/corelib/io/qtemporarydir.cpp