1 | // Copyright (C) 2020 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 "qplatformdefs.h" |
6 | #include "qdebug.h" |
7 | #include "qfile.h" |
8 | #include "qfsfileengine_p.h" |
9 | #include "qtemporaryfile.h" |
10 | #include "qtemporaryfile_p.h" |
11 | #include "qlist.h" |
12 | #include "qfileinfo.h" |
13 | #include "private/qiodevice_p.h" |
14 | #include "private/qfile_p.h" |
15 | #include "private/qfilesystemengine_p.h" |
16 | #include "private/qsystemerror_p.h" |
17 | #include "private/qtemporaryfile_p.h" |
18 | #if defined(QT_BUILD_CORE_LIB) |
19 | # include "qcoreapplication.h" |
20 | #endif |
21 | |
22 | #ifdef QT_NO_QOBJECT |
23 | #define tr(X) QString::fromLatin1(X) |
24 | #endif |
25 | |
26 | QT_BEGIN_NAMESPACE |
27 | |
28 | using namespace Qt::StringLiterals; |
29 | |
30 | Q_DECL_COLD_FUNCTION |
31 | static bool file_already_open(QFile &file, const char *where = nullptr) |
32 | { |
33 | qWarning(msg: "QFile::%s: File (%ls) already open", where ? where : "open", qUtf16Printable(file.fileName())); |
34 | return false; |
35 | } |
36 | |
37 | //************* QFilePrivate |
38 | QFilePrivate::QFilePrivate() |
39 | { |
40 | } |
41 | |
42 | QFilePrivate::~QFilePrivate() |
43 | { |
44 | } |
45 | |
46 | bool |
47 | QFilePrivate::openExternalFile(QIODevice::OpenMode flags, int fd, QFile::FileHandleFlags handleFlags) |
48 | { |
49 | #ifdef QT_NO_FSFILEENGINE |
50 | Q_UNUSED(flags); |
51 | Q_UNUSED(fd); |
52 | return false; |
53 | #else |
54 | auto fs = std::make_unique<QFSFileEngine>(); |
55 | auto fe = fs.get(); |
56 | fileEngine = std::move(fs); |
57 | return fe->open(flags, fd, handleFlags); |
58 | #endif |
59 | } |
60 | |
61 | bool |
62 | QFilePrivate::openExternalFile(QIODevice::OpenMode flags, FILE *fh, QFile::FileHandleFlags handleFlags) |
63 | { |
64 | #ifdef QT_NO_FSFILEENGINE |
65 | Q_UNUSED(flags); |
66 | Q_UNUSED(fh); |
67 | return false; |
68 | #else |
69 | auto fs = std::make_unique<QFSFileEngine>(); |
70 | auto fe = fs.get(); |
71 | fileEngine = std::move(fs); |
72 | return fe->open(flags, fh, handleFlags); |
73 | #endif |
74 | } |
75 | |
76 | QAbstractFileEngine *QFilePrivate::engine() const |
77 | { |
78 | if (!fileEngine) |
79 | fileEngine = QAbstractFileEngine::create(fileName); |
80 | return fileEngine.get(); |
81 | } |
82 | |
83 | //************* QFile |
84 | |
85 | /*! |
86 | \class QFile |
87 | \inmodule QtCore |
88 | \brief The QFile class provides an interface for reading from and writing to files. |
89 | |
90 | \ingroup io |
91 | |
92 | \reentrant |
93 | |
94 | QFile is an I/O device for reading and writing text and binary |
95 | files and \l{The Qt Resource System}{resources}. A QFile may be |
96 | used by itself or, more conveniently, with a QTextStream or |
97 | QDataStream. |
98 | |
99 | The file name is usually passed in the constructor, but it can be |
100 | set at any time using setFileName(). QFile expects the file |
101 | separator to be '/' regardless of operating system. The use of |
102 | other separators (e.g., '\\') is not supported. |
103 | |
104 | You can check for a file's existence using exists(), and remove a |
105 | file using remove(). (More advanced file system related operations |
106 | are provided by QFileInfo and QDir.) |
107 | |
108 | The file is opened with open(), closed with close(), and flushed |
109 | with flush(). Data is usually read and written using QDataStream |
110 | or QTextStream, but you can also call the QIODevice-inherited |
111 | functions read(), readLine(), readAll(), write(). QFile also |
112 | inherits getChar(), putChar(), and ungetChar(), which work one |
113 | character at a time. |
114 | |
115 | The size of the file is returned by size(). You can get the |
116 | current file position using pos(), or move to a new file position |
117 | using seek(). If you've reached the end of the file, atEnd() |
118 | returns \c true. |
119 | |
120 | \section1 Reading Files Directly |
121 | |
122 | The following example reads a text file line by line: |
123 | |
124 | \snippet file/file.cpp 0 |
125 | |
126 | The \l{QIODeviceBase::}{Text} flag passed to open() tells Qt to convert |
127 | Windows-style line terminators ("\\r\\n") into C++-style |
128 | terminators ("\\n"). By default, QFile assumes binary, i.e. it |
129 | doesn't perform any conversion on the bytes stored in the file. |
130 | |
131 | \section1 Using Streams to Read Files |
132 | |
133 | The next example uses QTextStream to read a text file |
134 | line by line: |
135 | |
136 | \snippet file/file.cpp 1 |
137 | |
138 | QTextStream takes care of converting the 8-bit data stored on |
139 | disk into a 16-bit Unicode QString. By default, it assumes that |
140 | the file is encoded in UTF-8. This can be changed using |
141 | \l QTextStream::setEncoding(). |
142 | |
143 | To write text, we can use operator<<(), which is overloaded to |
144 | take a QTextStream on the left and various data types (including |
145 | QString) on the right: |
146 | |
147 | \snippet file/file.cpp 2 |
148 | |
149 | QDataStream is similar, in that you can use operator<<() to write |
150 | data and operator>>() to read it back. See the class |
151 | documentation for details. |
152 | |
153 | \section1 Signals |
154 | |
155 | Unlike other QIODevice implementations, such as QTcpSocket, QFile does not |
156 | emit the aboutToClose(), bytesWritten(), or readyRead() signals. This |
157 | implementation detail means that QFile is not suitable for reading and |
158 | writing certain types of files, such as device files on Unix platforms. |
159 | |
160 | \section1 Platform Specific Issues |
161 | |
162 | \l{Input/Output and Networking}{Qt APIs related to I/O} use UTF-16 based |
163 | QStrings to represent file paths. Standard C++ APIs (\c <cstdio> or |
164 | \c <iostream>) or platform-specific APIs however often need a 8-bit encoded |
165 | path. You can use encodeName() and decodeName() to convert between both |
166 | representations. |
167 | |
168 | On Unix, there are some special system files (e.g. in \c /proc) for which |
169 | size() will always return 0, yet you may still be able to read more data |
170 | from such a file; the data is generated in direct response to you calling |
171 | read(). In this case, however, you cannot use atEnd() to determine if |
172 | there is more data to read (since atEnd() will return true for a file that |
173 | claims to have size 0). Instead, you should either call readAll(), or call |
174 | read() or readLine() repeatedly until no more data can be read. The next |
175 | example uses QTextStream to read \c /proc/modules line by line: |
176 | |
177 | \snippet file/file.cpp 3 |
178 | |
179 | File permissions are handled differently on Unix-like systems and |
180 | Windows. In a non \l{QIODevice::isWritable()}{writable} |
181 | directory on Unix-like systems, files cannot be created. This is not always |
182 | the case on Windows, where, for instance, the 'My Documents' |
183 | directory usually is not writable, but it is still possible to |
184 | create files in it. |
185 | |
186 | Qt's understanding of file permissions is limited, which affects especially |
187 | the \l QFile::setPermissions() function. On Windows, Qt will set only the |
188 | legacy read-only flag, and that only when none of the Write* flags are |
189 | passed. Qt does not manipulate access control lists (ACLs), which makes this |
190 | function mostly useless for NTFS volumes. It may still be of use for USB |
191 | sticks that use VFAT file systems. POSIX ACLs are not manipulated, either. |
192 | |
193 | \include android-content-uri-limitations.qdocinc |
194 | |
195 | \sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System} |
196 | */ |
197 | |
198 | #ifdef QT_NO_QOBJECT |
199 | QFile::QFile() |
200 | : QFileDevice(*new QFilePrivate) |
201 | { |
202 | } |
203 | QFile::QFile(const QString &name) |
204 | : QFileDevice(*new QFilePrivate) |
205 | { |
206 | d_func()->fileName = name; |
207 | } |
208 | QFile::QFile(QFilePrivate &dd) |
209 | : QFileDevice(dd) |
210 | { |
211 | } |
212 | #else |
213 | /*! |
214 | Constructs a QFile object. |
215 | */ |
216 | QFile::QFile() |
217 | : QFileDevice(*new QFilePrivate, nullptr) |
218 | { |
219 | } |
220 | /*! |
221 | Constructs a new file object with the given \a parent. |
222 | */ |
223 | QFile::QFile(QObject *parent) |
224 | : QFileDevice(*new QFilePrivate, parent) |
225 | { |
226 | } |
227 | /*! |
228 | Constructs a new file object to represent the file with the given \a name. |
229 | |
230 | //! [qfile-explicit-constructor-note] |
231 | \note In versions up to and including Qt 6.8, this constructor is |
232 | implicit, for backward compatibility. Starting from Qt 6.9 this |
233 | constructor is unconditionally \c{explicit}. Users can force this |
234 | constructor to be \c{explicit} even in earlier versions of Qt by |
235 | defining the \c{QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH} macro |
236 | before including any Qt header. |
237 | //! [qfile-explicit-constructor-note] |
238 | */ |
239 | QFile::QFile(const QString &name) |
240 | : QFileDevice(*new QFilePrivate, nullptr) |
241 | { |
242 | Q_D(QFile); |
243 | d->fileName = name; |
244 | } |
245 | /*! |
246 | Constructs a new file object with the given \a parent to represent the |
247 | file with the specified \a name. |
248 | */ |
249 | QFile::QFile(const QString &name, QObject *parent) |
250 | : QFileDevice(*new QFilePrivate, parent) |
251 | { |
252 | Q_D(QFile); |
253 | d->fileName = name; |
254 | } |
255 | /*! |
256 | \internal |
257 | */ |
258 | QFile::QFile(QFilePrivate &dd, QObject *parent) |
259 | : QFileDevice(dd, parent) |
260 | { |
261 | } |
262 | #endif |
263 | |
264 | /*! |
265 | Destroys the file object, closing it if necessary. |
266 | */ |
267 | QFile::~QFile() |
268 | { |
269 | } |
270 | |
271 | /*! |
272 | Returns the name set by setFileName() or to the QFile |
273 | constructors. |
274 | |
275 | \sa setFileName(), QFileInfo::fileName() |
276 | */ |
277 | QString QFile::fileName() const |
278 | { |
279 | Q_D(const QFile); |
280 | return d->engine()->fileName(file: QAbstractFileEngine::DefaultName); |
281 | } |
282 | |
283 | /*! |
284 | Sets the \a name of the file. The name can have no path, a |
285 | relative path, or an absolute path. |
286 | |
287 | Do not call this function if the file has already been opened. |
288 | |
289 | If the file name has no path or a relative path, the path used |
290 | will be the application's current directory path |
291 | \e{at the time of the open()} call. |
292 | |
293 | Example: |
294 | \snippet code/src_corelib_io_qfile.cpp 0 |
295 | |
296 | Note that the directory separator "/" works for all operating |
297 | systems supported by Qt. |
298 | |
299 | \sa fileName(), QFileInfo, QDir |
300 | */ |
301 | void |
302 | QFile::setFileName(const QString &name) |
303 | { |
304 | Q_D(QFile); |
305 | if (isOpen()) { |
306 | file_already_open(file&: *this, where: "setFileName"); |
307 | close(); |
308 | } |
309 | d->fileEngine.reset(); //get a new file engine later |
310 | d->fileName = name; |
311 | } |
312 | |
313 | /*! |
314 | \fn QString QFile::decodeName(const char *localFileName) |
315 | |
316 | \overload |
317 | |
318 | Returns the Unicode version of the given \a localFileName. See |
319 | encodeName() for details. |
320 | */ |
321 | |
322 | /*! |
323 | \fn QByteArray QFile::encodeName(const QString &fileName) |
324 | |
325 | Converts \a fileName to an 8-bit encoding that you can use in native |
326 | APIs. On Windows, the encoding is the one from active Windows (ANSI) |
327 | codepage. On other platforms, this is UTF-8, for \macos in decomposed |
328 | form (NFD). |
329 | |
330 | \sa decodeName() |
331 | */ |
332 | |
333 | /*! |
334 | \fn QString QFile::decodeName(const QByteArray &localFileName) |
335 | |
336 | This does the reverse of QFile::encodeName() using \a localFileName. |
337 | |
338 | \sa encodeName() |
339 | */ |
340 | |
341 | /*! |
342 | \overload |
343 | |
344 | Returns \c true if the file specified by fileName() exists; otherwise |
345 | returns \c false. |
346 | |
347 | \sa fileName(), setFileName() |
348 | */ |
349 | |
350 | bool |
351 | QFile::exists() const |
352 | { |
353 | Q_D(const QFile); |
354 | // 0x1000000 = QAbstractFileEngine::Refresh, forcing an update |
355 | return d->engine()->fileFlags(type: QAbstractFileEngine::FlagsMask |
356 | | QAbstractFileEngine::Refresh).testAnyFlag(flag: QAbstractFileEngine::ExistsFlag); |
357 | } |
358 | |
359 | /*! |
360 | Returns \c true if the file specified by \a fileName exists; otherwise |
361 | returns \c false. |
362 | |
363 | \note If \a fileName is a symlink that points to a non-existing |
364 | file, false is returned. |
365 | */ |
366 | |
367 | bool |
368 | QFile::exists(const QString &fileName) |
369 | { |
370 | return QFileInfo::exists(file: fileName); |
371 | } |
372 | |
373 | /*! |
374 | \fn QString QFile::symLinkTarget() const |
375 | \since 4.2 |
376 | \overload |
377 | |
378 | Returns the absolute path of the file or directory a symlink (or shortcut |
379 | on Windows) points to, or a an empty string if the object isn't a symbolic |
380 | link. |
381 | |
382 | This name may not represent an existing file; it is only a string. |
383 | QFile::exists() returns \c true if the symlink points to an existing file. |
384 | |
385 | \sa fileName(), setFileName() |
386 | */ |
387 | QString QFile::symLinkTarget() const |
388 | { |
389 | Q_D(const QFile); |
390 | return d->engine()->fileName(file: QAbstractFileEngine::AbsoluteLinkTarget); |
391 | } |
392 | |
393 | /*! |
394 | \fn static QString QFile::symLinkTarget(const QString &fileName) |
395 | \since 4.2 |
396 | |
397 | Returns the absolute path of the file or directory referred to by the |
398 | symlink (or shortcut on Windows) specified by \a fileName, or returns an |
399 | empty string if the \a fileName does not correspond to a symbolic link. |
400 | |
401 | This name may not represent an existing file; it is only a string. |
402 | QFile::exists() returns \c true if the symlink points to an existing file. |
403 | */ |
404 | QString QFile::symLinkTarget(const QString &fileName) |
405 | { |
406 | return QFileInfo(fileName).symLinkTarget(); |
407 | } |
408 | |
409 | /*! |
410 | Removes the file specified by fileName(). Returns \c true if successful; |
411 | otherwise returns \c false. |
412 | |
413 | The file is closed before it is removed. |
414 | |
415 | \sa setFileName() |
416 | */ |
417 | |
418 | bool |
419 | QFile::remove() |
420 | { |
421 | Q_D(QFile); |
422 | if (d->fileName.isEmpty() && |
423 | !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) { |
424 | qWarning(msg: "QFile::remove: Empty or null file name"); |
425 | return false; |
426 | } |
427 | unsetError(); |
428 | close(); |
429 | if (error() == QFile::NoError) { |
430 | if (d->engine()->remove()) { |
431 | unsetError(); |
432 | return true; |
433 | } |
434 | d->setError(err: QFile::RemoveError, errorString: d->fileEngine->errorString()); |
435 | } |
436 | return false; |
437 | } |
438 | |
439 | /*! |
440 | \overload |
441 | |
442 | Removes the file specified by the \a fileName given. |
443 | |
444 | Returns \c true if successful; otherwise returns \c false. |
445 | |
446 | \sa remove() |
447 | */ |
448 | |
449 | bool |
450 | QFile::remove(const QString &fileName) |
451 | { |
452 | return QFile(fileName).remove(); |
453 | } |
454 | |
455 | /*! |
456 | \since 5.15 |
457 | |
458 | Moves the file specified by fileName() to the trash. Returns \c true if successful, |
459 | and sets the fileName() to the path at which the file can be found within the trash; |
460 | otherwise returns \c false. |
461 | |
462 | //! [move-to-trash-common] |
463 | The time for this function to run is independent of the size of the file |
464 | being trashed. If this function is called on a directory, it may be |
465 | proportional to the number of files being trashed. If the current |
466 | fileName() points to a symbolic link, this function will move the link to |
467 | the trash, possibly breaking it, not the target of the link. |
468 | |
469 | This function uses the Windows and \macos APIs to perform the trashing on |
470 | those two operating systems. Elsewhere (Unix systems), this function |
471 | implements the \l{FreeDesktop.org Trash specification version 1.0}. |
472 | |
473 | \note When using the FreeDesktop.org Trash implementation, this function |
474 | will fail if it is unable to move the files to the trash location by way of |
475 | file renames and hardlinks. This condition arises if the file being trashed |
476 | resides on a volume (mount point) on which the current user does not have |
477 | permission to create the \c{.Trash} directory, or with some unusual |
478 | filesystem types or configurations (such as sub-volumes that aren't |
479 | themselves mount points). |
480 | //! [move-to-trash-common] |
481 | |
482 | \note On systems where the system API doesn't report the location of the file in the |
483 | trash, fileName() will be set to the null string once the file has been moved. On |
484 | systems that don't have a trash can, this function always returns false. |
485 | */ |
486 | bool |
487 | QFile::moveToTrash() |
488 | { |
489 | Q_D(QFile); |
490 | if (d->fileName.isEmpty() && |
491 | !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) { |
492 | qWarning(msg: "QFile::remove: Empty or null file name"); |
493 | return false; |
494 | } |
495 | unsetError(); |
496 | close(); |
497 | if (error() == QFile::NoError) { |
498 | QFileSystemEntry fileEntry(d->fileName); |
499 | QFileSystemEntry trashEntry; |
500 | QSystemError error; |
501 | if (QFileSystemEngine::moveFileToTrash(source: fileEntry, newLocation&: trashEntry, error)) { |
502 | setFileName(trashEntry.filePath()); |
503 | unsetError(); |
504 | return true; |
505 | } |
506 | d->setError(err: QFile::RenameError, errorString: error.toString()); |
507 | } |
508 | return false; |
509 | } |
510 | |
511 | /*! |
512 | \since 5.15 |
513 | \overload |
514 | |
515 | Moves the file specified by \a fileName to the trash. Returns \c true if successful, |
516 | and sets \a pathInTrash (if provided) to the path at which the file can be found within |
517 | the trash; otherwise returns \c false. |
518 | |
519 | \include qfile.cpp move-to-trash-common |
520 | |
521 | \note On systems where the system API doesn't report the path of the file in the |
522 | trash, \a pathInTrash will be set to the null string once the file has been moved. |
523 | On systems that don't have a trash can, this function always returns false. |
524 | |
525 | */ |
526 | bool |
527 | QFile::moveToTrash(const QString &fileName, QString *pathInTrash) |
528 | { |
529 | QFile file(fileName); |
530 | if (file.moveToTrash()) { |
531 | if (pathInTrash) |
532 | *pathInTrash = file.fileName(); |
533 | return true; |
534 | } |
535 | return false; |
536 | } |
537 | |
538 | /*! |
539 | Renames the file currently specified by fileName() to \a newName. |
540 | Returns \c true if successful; otherwise returns \c false. |
541 | |
542 | If a file with the name \a newName already exists, rename() returns \c false |
543 | (i.e., QFile will not overwrite it). |
544 | |
545 | The file is closed before it is renamed. |
546 | |
547 | If the rename operation fails, Qt will attempt to copy this file's |
548 | contents to \a newName, and then remove this file, keeping only |
549 | \a newName. If that copy operation fails or this file can't be removed, |
550 | the destination file \a newName is removed to restore the old state. |
551 | |
552 | \sa setFileName() |
553 | */ |
554 | |
555 | bool |
556 | QFile::rename(const QString &newName) |
557 | { |
558 | Q_D(QFile); |
559 | |
560 | // if this is a QTemporaryFile, the virtual fileName() call here may do something |
561 | if (fileName().isEmpty()) { |
562 | qWarning(msg: "QFile::rename: Empty or null file name"); |
563 | return false; |
564 | } |
565 | if (d->fileName == newName) { |
566 | d->setError(err: QFile::RenameError, errorString: tr(s: "Destination file is the same file.")); |
567 | return false; |
568 | } |
569 | if (!exists()) { |
570 | d->setError(err: QFile::RenameError, errorString: tr(s: "Source file does not exist.")); |
571 | return false; |
572 | } |
573 | |
574 | // If the file exists and it is a case-changing rename ("foo" -> "Foo"), |
575 | // compare Ids to make sure it really is a different file. |
576 | // Note: this does not take file engines into account. |
577 | bool changingCase = false; |
578 | QByteArray targetId = QFileSystemEngine::id(entry: QFileSystemEntry(newName)); |
579 | if (!targetId.isNull()) { |
580 | QByteArray fileId = d->fileEngine ? |
581 | d->fileEngine->id() : |
582 | QFileSystemEngine::id(entry: QFileSystemEntry(d->fileName)); |
583 | changingCase = (fileId == targetId && d->fileName.compare(s: newName, cs: Qt::CaseInsensitive) == 0); |
584 | if (!changingCase) { |
585 | d->setError(err: QFile::RenameError, errorString: tr(s: "Destination file exists")); |
586 | return false; |
587 | } |
588 | |
589 | #if defined(Q_OS_LINUX) && QT_CONFIG(temporaryfile) |
590 | // rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive |
591 | // FS, such as FAT32. Move the file away and rename in 2 steps to work around. |
592 | QTemporaryFileName tfn(d->fileName); |
593 | QFileSystemEntry src(d->fileName); |
594 | QSystemError error; |
595 | for (int attempt = 0; attempt < 16; ++attempt) { |
596 | QFileSystemEntry tmp(tfn.generateNext(), QFileSystemEntry::FromNativePath()); |
597 | |
598 | // rename to temporary name |
599 | if (!QFileSystemEngine::renameFile(source: src, target: tmp, error)) |
600 | continue; |
601 | |
602 | // rename to final name |
603 | if (QFileSystemEngine::renameFile(source: tmp, target: QFileSystemEntry(newName), error)) { |
604 | d->fileEngine->setFileName(newName); |
605 | d->fileName = newName; |
606 | return true; |
607 | } |
608 | |
609 | // We need to restore the original file. |
610 | QSystemError error2; |
611 | if (QFileSystemEngine::renameFile(source: tmp, target: src, error&: error2)) |
612 | break; // report the original error, below |
613 | |
614 | // report both errors |
615 | d->setError(err: QFile::RenameError, |
616 | errorString: tr(s: "Error while renaming: %1").arg(a: error.toString()) |
617 | + u'\n' |
618 | + tr(s: "Unable to restore from %1: %2"). |
619 | arg(args: QDir::toNativeSeparators(pathName: tmp.filePath()), args: error2.toString())); |
620 | return false; |
621 | } |
622 | d->setError(err: QFile::RenameError, |
623 | errorString: tr(s: "Error while renaming: %1").arg(a: error.toString())); |
624 | return false; |
625 | #endif // Q_OS_LINUX |
626 | } |
627 | unsetError(); |
628 | close(); |
629 | if (error() == QFile::NoError) { |
630 | if (changingCase ? d->engine()->renameOverwrite(newName) : d->engine()->rename(newName)) { |
631 | unsetError(); |
632 | // engine was able to handle the new name so we just reset it |
633 | d->fileEngine->setFileName(newName); |
634 | d->fileName = newName; |
635 | return true; |
636 | } |
637 | |
638 | // Engine was unable to rename and the fallback will delete the original file, |
639 | // so we have to back out here on case-insensitive file systems: |
640 | if (changingCase) { |
641 | d->setError(err: QFile::RenameError, errorString: d->fileEngine->errorString()); |
642 | return false; |
643 | } |
644 | |
645 | if (isSequential()) { |
646 | d->setError(err: QFile::RenameError, errorString: tr(s: "Will not rename sequential file using block copy")); |
647 | return false; |
648 | } |
649 | |
650 | QFile out(newName); |
651 | if (open(flags: QIODevice::ReadOnly)) { |
652 | if (out.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)) { |
653 | bool error = false; |
654 | char block[4096]; |
655 | qint64 bytes; |
656 | while ((bytes = read(data: block, maxlen: sizeof(block))) > 0) { |
657 | if (bytes != out.write(data: block, len: bytes)) { |
658 | d->setError(err: QFile::RenameError, errorString: out.errorString()); |
659 | error = true; |
660 | break; |
661 | } |
662 | } |
663 | if (bytes == -1) { |
664 | d->setError(err: QFile::RenameError, errorString: errorString()); |
665 | error = true; |
666 | } |
667 | if (!error) { |
668 | if (!remove()) { |
669 | d->setError(err: QFile::RenameError, errorString: tr(s: "Cannot remove source file")); |
670 | error = true; |
671 | } |
672 | } |
673 | if (error) { |
674 | out.remove(); |
675 | } else { |
676 | d->fileEngine->setFileName(newName); |
677 | setPermissions(permissions()); |
678 | unsetError(); |
679 | setFileName(newName); |
680 | } |
681 | close(); |
682 | return !error; |
683 | } |
684 | close(); |
685 | d->setError(err: QFile::RenameError, |
686 | errorString: tr(s: "Cannot open destination file: %1").arg(a: out.errorString())); |
687 | } else { |
688 | d->setError(err: QFile::RenameError, errorString: errorString()); |
689 | } |
690 | } |
691 | return false; |
692 | } |
693 | |
694 | /*! |
695 | \overload |
696 | |
697 | Renames the file \a oldName to \a newName. Returns \c true if |
698 | successful; otherwise returns \c false. |
699 | |
700 | If a file with the name \a newName already exists, rename() returns \c false |
701 | (i.e., QFile will not overwrite it). |
702 | |
703 | \sa rename() |
704 | */ |
705 | |
706 | bool |
707 | QFile::rename(const QString &oldName, const QString &newName) |
708 | { |
709 | return QFile(oldName).rename(newName); |
710 | } |
711 | |
712 | /*! |
713 | |
714 | Creates a link named \a linkName that points to the file currently specified by |
715 | fileName(). What a link is depends on the underlying filesystem (be it a |
716 | shortcut on Windows or a symbolic link on Unix). Returns \c true if successful; |
717 | otherwise returns \c false. |
718 | |
719 | This function will not overwrite an already existing entity in the file system; |
720 | in this case, \c link() will return false and set \l{QFile::}{error()} to |
721 | return \l{QFile::}{RenameError}. |
722 | |
723 | \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension. |
724 | |
725 | \sa setFileName() |
726 | */ |
727 | |
728 | bool |
729 | QFile::link(const QString &linkName) |
730 | { |
731 | Q_D(QFile); |
732 | if (fileName().isEmpty()) { |
733 | qWarning(msg: "QFile::link: Empty or null file name"); |
734 | return false; |
735 | } |
736 | QFileInfo fi(linkName); |
737 | if (d->engine()->link(newName: fi.absoluteFilePath())) { |
738 | unsetError(); |
739 | return true; |
740 | } |
741 | d->setError(err: QFile::RenameError, errorString: d->fileEngine->errorString()); |
742 | return false; |
743 | } |
744 | |
745 | /*! |
746 | \overload |
747 | |
748 | Creates a link named \a linkName that points to the file \a fileName. What a link is |
749 | depends on the underlying filesystem (be it a shortcut on Windows |
750 | or a symbolic link on Unix). Returns \c true if successful; otherwise |
751 | returns \c false. |
752 | |
753 | \sa link() |
754 | */ |
755 | |
756 | bool |
757 | QFile::link(const QString &fileName, const QString &linkName) |
758 | { |
759 | return QFile(fileName).link(linkName); |
760 | } |
761 | |
762 | /*! |
763 | Copies the file named fileName() to \a newName. |
764 | |
765 | \include qfile-copy.qdocinc |
766 | |
767 | \note On Android, this operation is not yet supported for \c content |
768 | scheme URIs. |
769 | |
770 | \sa setFileName() |
771 | */ |
772 | |
773 | bool |
774 | QFile::copy(const QString &newName) |
775 | { |
776 | Q_D(QFile); |
777 | if (fileName().isEmpty()) { |
778 | qWarning(msg: "QFile::copy: Empty or null file name"); |
779 | return false; |
780 | } |
781 | if (QFile::exists(fileName: newName)) { |
782 | // ### Race condition. If a file is moved in after this, it /will/ be |
783 | // overwritten. On Unix, the proper solution is to use hardlinks: |
784 | // return ::link(old, new) && ::remove(old); See also rename(). |
785 | d->setError(err: QFile::CopyError, errorString: tr(s: "Destination file exists")); |
786 | return false; |
787 | } |
788 | unsetError(); |
789 | close(); |
790 | if (error() == QFile::NoError) { |
791 | if (d->engine()->copy(newName)) { |
792 | unsetError(); |
793 | return true; |
794 | } else { |
795 | bool error = false; |
796 | if (!open(flags: QFile::ReadOnly)) { |
797 | error = true; |
798 | d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open %1 for input").arg(a: d->fileName)); |
799 | } else { |
800 | const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1; |
801 | #if !QT_CONFIG(temporaryfile) |
802 | QFile out(fileTemplate.arg(QFileInfo(newName).path())); |
803 | if (!out.open(QIODevice::ReadWrite)) |
804 | error = true; |
805 | #else |
806 | QTemporaryFile out(fileTemplate.arg(args: QFileInfo(newName).path())); |
807 | if (!out.open()) { |
808 | out.setFileTemplate(fileTemplate.arg(args: QDir::tempPath())); |
809 | if (!out.open()) |
810 | error = true; |
811 | } |
812 | #endif |
813 | if (error) { |
814 | d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open for output: %1").arg(a: out.errorString())); |
815 | out.close(); |
816 | close(); |
817 | } else { |
818 | if (!d->engine()->cloneTo(target: out.d_func()->engine())) { |
819 | char block[4096]; |
820 | qint64 totalRead = 0; |
821 | while (!atEnd()) { |
822 | qint64 in = read(data: block, maxlen: sizeof(block)); |
823 | if (in <= 0) |
824 | break; |
825 | totalRead += in; |
826 | if (in != out.write(data: block, len: in)) { |
827 | close(); |
828 | d->setError(err: QFile::CopyError, errorString: tr(s: "Failure to write block: %1") |
829 | .arg(a: out.errorString())); |
830 | error = true; |
831 | break; |
832 | } |
833 | } |
834 | |
835 | if (totalRead != size()) { |
836 | // Unable to read from the source. The error string is |
837 | // already set from read(). |
838 | error = true; |
839 | } |
840 | } |
841 | |
842 | if (!error) { |
843 | // Sync to disk if possible. Ignore errors (e.g. not supported). |
844 | out.d_func()->fileEngine->syncToDisk(); |
845 | |
846 | if (!out.rename(newName)) { |
847 | error = true; |
848 | close(); |
849 | d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot create %1 for output: %2") |
850 | .arg(args: newName, args: out.errorString())); |
851 | } |
852 | } |
853 | #if !QT_CONFIG(temporaryfile) |
854 | if (error) |
855 | out.remove(); |
856 | #else |
857 | if (!error) |
858 | out.setAutoRemove(false); |
859 | #endif |
860 | } |
861 | } |
862 | if (!error) { |
863 | QFile::setPermissions(filename: newName, permissionSpec: permissions()); |
864 | close(); |
865 | unsetError(); |
866 | return true; |
867 | } |
868 | } |
869 | } |
870 | return false; |
871 | } |
872 | |
873 | /*! |
874 | \overload |
875 | |
876 | Copies the file named \a fileName to \a newName. |
877 | |
878 | \include qfile-copy.qdocinc |
879 | |
880 | \note On Android, this operation is not yet supported for \c content |
881 | scheme URIs. |
882 | |
883 | \sa rename() |
884 | */ |
885 | |
886 | bool |
887 | QFile::copy(const QString &fileName, const QString &newName) |
888 | { |
889 | return QFile(fileName).copy(newName); |
890 | } |
891 | |
892 | /*! |
893 | Opens the file using \a mode flags, returning \c true if successful; |
894 | otherwise returns \c false. |
895 | |
896 | The flags for \a mode must include \l QIODeviceBase::ReadOnly, |
897 | \l WriteOnly, or \l ReadWrite. It may also have additional flags, |
898 | such as \l Text and \l Unbuffered. |
899 | |
900 | \note In \l{WriteOnly} or \l{ReadWrite} |
901 | mode, if the relevant file does not already exist, this function |
902 | will try to create a new file before opening it. The file will be |
903 | created with mode 0666 masked by the umask on POSIX systems, and |
904 | with permissions inherited from the parent directory on Windows. |
905 | On Android, it's expected to have access permission to the parent |
906 | of the file name, otherwise, it won't be possible to create this |
907 | non-existing file. |
908 | |
909 | \sa QT_USE_NODISCARD_FILE_OPEN, setFileName() |
910 | */ |
911 | bool QFile::open(OpenMode mode) |
912 | { |
913 | Q_D(QFile); |
914 | if (isOpen()) |
915 | return file_already_open(file&: *this); |
916 | // Either Append or NewOnly implies WriteOnly |
917 | if (mode & (Append | NewOnly)) |
918 | mode |= WriteOnly; |
919 | unsetError(); |
920 | if ((mode & (ReadOnly | WriteOnly)) == 0) { |
921 | qWarning(msg: "QIODevice::open: File access not specified"); |
922 | return false; |
923 | } |
924 | |
925 | // QIODevice provides the buffering, so there's no need to request it from the file engine. |
926 | if (d->engine()->open(openMode: mode | QIODevice::Unbuffered)) { |
927 | QIODevice::open(mode); |
928 | if (mode & Append) |
929 | seek(offset: size()); |
930 | return true; |
931 | } |
932 | QFile::FileError err = d->fileEngine->error(); |
933 | if (err == QFile::UnspecifiedError) |
934 | err = QFile::OpenError; |
935 | d->setError(err, errorString: d->fileEngine->errorString()); |
936 | return false; |
937 | } |
938 | |
939 | /*! |
940 | \overload |
941 | |
942 | If the file does not exist and \a mode implies creating it, it is created |
943 | with the specified \a permissions. |
944 | |
945 | On POSIX systems the actual permissions are influenced by the |
946 | value of \c umask. |
947 | |
948 | On Windows the permissions are emulated using ACLs. These ACLs may be in non-canonical |
949 | order when the group is granted less permissions than others. Files and directories with |
950 | such permissions will generate warnings when the Security tab of the Properties dialog |
951 | is opened. Granting the group all permissions granted to others avoids such warnings. |
952 | |
953 | \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN |
954 | \since 6.3 |
955 | */ |
956 | bool QFile::open(OpenMode mode, QFile::Permissions permissions) |
957 | { |
958 | Q_D(QFile); |
959 | if (isOpen()) |
960 | return file_already_open(file&: *this); |
961 | // Either Append or NewOnly implies WriteOnly |
962 | if (mode & (Append | NewOnly)) |
963 | mode |= WriteOnly; |
964 | unsetError(); |
965 | if ((mode & (ReadOnly | WriteOnly)) == 0) { |
966 | qWarning(msg: "QIODevice::open: File access not specified"); |
967 | return false; |
968 | } |
969 | |
970 | // QIODevice provides the buffering, so there's no need to request it from the file engine. |
971 | if (d->engine()->open(openMode: mode | QIODevice::Unbuffered, permissions)) { |
972 | QIODevice::open(mode); |
973 | if (mode & Append) |
974 | seek(offset: size()); |
975 | return true; |
976 | } |
977 | QFile::FileError err = d->fileEngine->error(); |
978 | if (err == QFile::UnspecifiedError) |
979 | err = QFile::OpenError; |
980 | d->setError(err, errorString: d->fileEngine->errorString()); |
981 | return false; |
982 | } |
983 | |
984 | /*! |
985 | \overload |
986 | |
987 | Opens the existing file handle \a fh in the given \a mode. |
988 | \a handleFlags may be used to specify additional options. |
989 | Returns \c true if successful; otherwise returns \c false. |
990 | |
991 | Example: |
992 | \snippet code/src_corelib_io_qfile.cpp 3 |
993 | |
994 | When a QFile is opened using this function, behaviour of close() is |
995 | controlled by the AutoCloseHandle flag. |
996 | If AutoCloseHandle is specified, and this function succeeds, |
997 | then calling close() closes the adopted handle. |
998 | Otherwise, close() does not actually close the file, but only flushes it. |
999 | |
1000 | \b{Warning:} |
1001 | \list 1 |
1002 | \li If \a fh does not refer to a regular file, e.g., it is \c stdin, |
1003 | \c stdout, or \c stderr, you may not be able to seek(). size() |
1004 | returns \c 0 in those cases. See QIODevice::isSequential() for |
1005 | more information. |
1006 | \li Since this function opens the file without specifying the file name, |
1007 | you cannot use this QFile with a QFileInfo. |
1008 | \endlist |
1009 | |
1010 | \sa close(), QT_USE_NODISCARD_FILE_OPEN |
1011 | |
1012 | \b{Note for the Windows Platform} |
1013 | |
1014 | \a fh must be opened in binary mode (i.e., the mode string must contain |
1015 | 'b', as in "rb" or "wb") when accessing files and other random-access |
1016 | devices. Qt will translate the end-of-line characters if you pass |
1017 | QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout, |
1018 | are unaffected by this limitation. |
1019 | |
1020 | You need to enable support for console applications in order to use the |
1021 | stdin, stdout and stderr streams at the console. To do this, add the |
1022 | following declaration to your application's project file: |
1023 | |
1024 | \snippet code/src_corelib_io_qfile.cpp 4 |
1025 | */ |
1026 | bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags) |
1027 | { |
1028 | Q_D(QFile); |
1029 | if (isOpen()) |
1030 | return file_already_open(file&: *this); |
1031 | // Either Append or NewOnly implies WriteOnly |
1032 | if (mode & (Append | NewOnly)) |
1033 | mode |= WriteOnly; |
1034 | unsetError(); |
1035 | if ((mode & (ReadOnly | WriteOnly)) == 0) { |
1036 | qWarning(msg: "QFile::open: File access not specified"); |
1037 | return false; |
1038 | } |
1039 | |
1040 | // QIODevice provides the buffering, so request unbuffered file engines |
1041 | if (d->openExternalFile(flags: mode | Unbuffered, fh, handleFlags)) { |
1042 | QIODevice::open(mode); |
1043 | if (!(mode & Append) && !isSequential()) { |
1044 | qint64 pos = (qint64)QT_FTELL(stream: fh); |
1045 | if (pos != -1) { |
1046 | // Skip redundant checks in QFileDevice::seek(). |
1047 | QIODevice::seek(pos); |
1048 | } |
1049 | } |
1050 | return true; |
1051 | } |
1052 | return false; |
1053 | } |
1054 | |
1055 | /*! |
1056 | \overload |
1057 | |
1058 | Opens the existing file descriptor \a fd in the given \a mode. |
1059 | \a handleFlags may be used to specify additional options. |
1060 | Returns \c true if successful; otherwise returns \c false. |
1061 | |
1062 | When a QFile is opened using this function, behaviour of close() is |
1063 | controlled by the AutoCloseHandle flag. |
1064 | If AutoCloseHandle is specified, and this function succeeds, |
1065 | then calling close() closes the adopted handle. |
1066 | Otherwise, close() does not actually close the file, but only flushes it. |
1067 | |
1068 | \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin), |
1069 | 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In |
1070 | those cases, size() returns \c 0. See QIODevice::isSequential() |
1071 | for more information. |
1072 | |
1073 | \warning Since this function opens the file without specifying the file name, |
1074 | you cannot use this QFile with a QFileInfo. |
1075 | |
1076 | \sa close(), QT_USE_NODISCARD_FILE_OPEN |
1077 | */ |
1078 | bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags) |
1079 | { |
1080 | Q_D(QFile); |
1081 | if (isOpen()) |
1082 | return file_already_open(file&: *this); |
1083 | // Either Append or NewOnly implies WriteOnly |
1084 | if (mode & (Append | NewOnly)) |
1085 | mode |= WriteOnly; |
1086 | unsetError(); |
1087 | if ((mode & (ReadOnly | WriteOnly)) == 0) { |
1088 | qWarning(msg: "QFile::open: File access not specified"); |
1089 | return false; |
1090 | } |
1091 | |
1092 | // QIODevice provides the buffering, so request unbuffered file engines |
1093 | if (d->openExternalFile(flags: mode | Unbuffered, fd, handleFlags)) { |
1094 | QIODevice::open(mode); |
1095 | if (!(mode & Append) && !isSequential()) { |
1096 | qint64 pos = (qint64)QT_LSEEK(fd: fd, QT_OFF_T(0), SEEK_CUR); |
1097 | if (pos != -1) { |
1098 | // Skip redundant checks in QFileDevice::seek(). |
1099 | QIODevice::seek(pos); |
1100 | } |
1101 | } |
1102 | return true; |
1103 | } |
1104 | return false; |
1105 | } |
1106 | |
1107 | /*! |
1108 | \reimp |
1109 | */ |
1110 | bool QFile::resize(qint64 sz) |
1111 | { |
1112 | return QFileDevice::resize(sz); // for now |
1113 | } |
1114 | |
1115 | /*! |
1116 | \overload |
1117 | |
1118 | Sets \a fileName to size (in bytes) \a sz. Returns \c true if |
1119 | the resize succeeds; false otherwise. If \a sz is larger than \a |
1120 | fileName currently is the new bytes will be set to 0, if \a sz is |
1121 | smaller the file is simply truncated. |
1122 | |
1123 | \warning This function can fail if the file doesn't exist. |
1124 | |
1125 | \sa resize() |
1126 | */ |
1127 | |
1128 | bool |
1129 | QFile::resize(const QString &fileName, qint64 sz) |
1130 | { |
1131 | return QFile(fileName).resize(sz); |
1132 | } |
1133 | |
1134 | /*! |
1135 | \reimp |
1136 | */ |
1137 | QFile::Permissions QFile::permissions() const |
1138 | { |
1139 | return QFileDevice::permissions(); // for now |
1140 | } |
1141 | |
1142 | /*! |
1143 | \overload |
1144 | |
1145 | Returns the complete OR-ed together combination of |
1146 | QFile::Permission for \a fileName. |
1147 | */ |
1148 | |
1149 | QFile::Permissions |
1150 | QFile::permissions(const QString &fileName) |
1151 | { |
1152 | return QFile(fileName).permissions(); |
1153 | } |
1154 | |
1155 | /*! |
1156 | Sets the permissions for the file to the \a permissions specified. |
1157 | Returns \c true if successful, or \c false if the permissions cannot be |
1158 | modified. |
1159 | |
1160 | \warning This function does not manipulate ACLs, which may limit its |
1161 | effectiveness. |
1162 | |
1163 | \sa permissions(), setFileName() |
1164 | */ |
1165 | |
1166 | bool QFile::setPermissions(Permissions permissions) |
1167 | { |
1168 | return QFileDevice::setPermissions(permissions); // for now |
1169 | } |
1170 | |
1171 | /*! |
1172 | \overload |
1173 | |
1174 | Sets the permissions for \a fileName file to \a permissions. |
1175 | */ |
1176 | |
1177 | bool |
1178 | QFile::setPermissions(const QString &fileName, Permissions permissions) |
1179 | { |
1180 | return QFile(fileName).setPermissions(permissions); |
1181 | } |
1182 | |
1183 | /*! |
1184 | \reimp |
1185 | */ |
1186 | qint64 QFile::size() const |
1187 | { |
1188 | return QFileDevice::size(); // for now |
1189 | } |
1190 | |
1191 | /*! |
1192 | \fn QFile::QFile(const std::filesystem::path &name) |
1193 | \since 6.0 |
1194 | |
1195 | Constructs a new file object to represent the file with the given \a name. |
1196 | |
1197 | \include qfile.cpp qfile-explicit-constructor-note |
1198 | */ |
1199 | /*! |
1200 | \fn QFile::QFile(const std::filesystem::path &name, QObject *parent) |
1201 | \since 6.0 |
1202 | |
1203 | Constructs a new file object with the given \a parent to represent the |
1204 | file with the specified \a name. |
1205 | */ |
1206 | /*! |
1207 | \fn std::filesystem::path QFile::filesystemFileName() const |
1208 | \since 6.0 |
1209 | Returns fileName() as \c{std::filesystem::path}. |
1210 | */ |
1211 | /*! |
1212 | \fn void QFile::setFileName(const std::filesystem::path &name) |
1213 | \since 6.0 |
1214 | \overload |
1215 | */ |
1216 | /*! |
1217 | \fn bool QFile::rename(const std::filesystem::path &newName) |
1218 | \since 6.0 |
1219 | \overload |
1220 | */ |
1221 | /*! |
1222 | \fn bool QFile::link(const std::filesystem::path &newName) |
1223 | \since 6.0 |
1224 | \overload |
1225 | */ |
1226 | /*! |
1227 | \fn bool QFile::copy(const std::filesystem::path &newName) |
1228 | \since 6.0 |
1229 | \overload |
1230 | */ |
1231 | /*! |
1232 | \fn QFile::Permissions QFile::permissions(const std::filesystem::path &filename) |
1233 | \since 6.0 |
1234 | \overload |
1235 | */ |
1236 | /*! |
1237 | \fn bool QFile::setPermissions(const std::filesystem::path &filename, Permissions permissionSpec) |
1238 | \since 6.0 |
1239 | \overload |
1240 | */ |
1241 | /*! |
1242 | \fn bool exists(const std::filesystem::path &fileName) |
1243 | \since 6.3 |
1244 | \overload |
1245 | */ |
1246 | /*! |
1247 | \fn std::filesystem::path QFile::filesystemSymLinkTarget() const |
1248 | \since 6.3 |
1249 | Returns symLinkTarget() as \c{std::filesystem::path}. |
1250 | */ |
1251 | /*! |
1252 | \fn std::filesystem::path QFile::filesystemSymLinkTarget(const std::filesystem::path &fileName) |
1253 | \since 6.3 |
1254 | Returns symLinkTarget() as \c{std::filesystem::path} of \a fileName. |
1255 | */ |
1256 | /*! |
1257 | \fn bool remove(const std::filesystem::path &fileName) |
1258 | \since 6.3 |
1259 | \overload |
1260 | */ |
1261 | /*! |
1262 | \fn bool moveToTrash(const std::filesystem::path &fileName, QString *pathInTrash) |
1263 | \since 6.3 |
1264 | \overload |
1265 | */ |
1266 | /*! |
1267 | \fn bool rename(const std::filesystem::path &oldName, const std::filesystem::path &newName) |
1268 | \since 6.3 |
1269 | \overload |
1270 | */ |
1271 | /*! |
1272 | \fn bool link(const std::filesystem::path &fileName, const std::filesystem::path &newName); |
1273 | \since 6.3 |
1274 | \overload |
1275 | */ |
1276 | /*! |
1277 | \fn bool copy(const std::filesystem::path &fileName, const std::filesystem::path &newName); |
1278 | \since 6.3 |
1279 | \overload |
1280 | */ |
1281 | |
1282 | |
1283 | /*! |
1284 | \class QNtfsPermissionCheckGuard |
1285 | \since 6.6 |
1286 | \inmodule QtCore |
1287 | \brief The QNtfsPermissionCheckGuard class is a RAII class to manage NTFS |
1288 | permission checking. |
1289 | |
1290 | \ingroup io |
1291 | |
1292 | For performance reasons, QFile, QFileInfo, and related classes do not |
1293 | perform full ownership and permission (ACL) checking on NTFS file systems |
1294 | by default. During the lifetime of any instance of this class, that |
1295 | default is overridden and advanced checking is performed. This provides |
1296 | a safe and easy way to manage enabling and disabling this change to the |
1297 | default behavior. |
1298 | |
1299 | Example: |
1300 | |
1301 | \snippet ntfsp.cpp raii |
1302 | |
1303 | This class is available only on Windows. |
1304 | |
1305 | \section1 qt_ntfs_permission_lookup |
1306 | |
1307 | Prior to Qt 6.6, the user had to directly manipulate the global variable |
1308 | \c qt_ntfs_permission_lookup. However, this was a non-atomic global |
1309 | variable and as such it was prone to data races. |
1310 | |
1311 | The variable \c qt_ntfs_permission_lookup is therefore deprecated since Qt |
1312 | 6.6. |
1313 | */ |
1314 | |
1315 | /*! |
1316 | \fn QNtfsPermissionCheckGuard::QNtfsPermissionCheckGuard() |
1317 | |
1318 | Creates a guard and calls the function qEnableNtfsPermissionChecks(). |
1319 | */ |
1320 | |
1321 | /*! |
1322 | \fn QNtfsPermissionCheckGuard::~QNtfsPermissionCheckGuard() |
1323 | |
1324 | Destroys the guard and calls the function qDisableNtfsPermissionChecks(). |
1325 | */ |
1326 | |
1327 | |
1328 | /*! |
1329 | \fn bool qEnableNtfsPermissionChecks() |
1330 | \since 6.6 |
1331 | \threadsafe |
1332 | \relates QNtfsPermissionCheckGuard |
1333 | |
1334 | Enables permission checking on NTFS file systems. Returns \c true if the check |
1335 | was already enabled before the call to this function, meaning that there |
1336 | are other users. |
1337 | |
1338 | This function is only available on Windows and makes the direct |
1339 | manipulation of \l qt_ntfs_permission_lookup obsolete. |
1340 | |
1341 | This is a low-level function, please consider the RAII class |
1342 | \l QNtfsPermissionCheckGuard instead. |
1343 | |
1344 | \note The thread-safety of this function holds only as long as there are no |
1345 | concurrent updates to \l qt_ntfs_permission_lookup. |
1346 | */ |
1347 | |
1348 | /*! |
1349 | \fn bool qDisableNtfsPermissionChecks() |
1350 | \since 6.6 |
1351 | \threadsafe |
1352 | \relates QNtfsPermissionCheckGuard |
1353 | |
1354 | Disables permission checking on NTFS file systems. Returns \c true if the |
1355 | check is disabled, meaning that there are no more users. |
1356 | |
1357 | This function is only available on Windows and makes the direct |
1358 | manipulation of \l qt_ntfs_permission_lookup obsolete. |
1359 | |
1360 | This is a low-level function and must (only) be called to match one earlier |
1361 | call to qEnableNtfsPermissionChecks(). Please consider the RAII class |
1362 | \l QNtfsPermissionCheckGuard instead. |
1363 | |
1364 | \note The thread-safety of this function holds only as long as there are no |
1365 | concurrent updates to \l qt_ntfs_permission_lookup. |
1366 | */ |
1367 | |
1368 | /*! |
1369 | \fn bool qAreNtfsPermissionChecksEnabled() |
1370 | \since 6.6 |
1371 | \threadsafe |
1372 | \relates QNtfsPermissionCheckGuard |
1373 | |
1374 | Checks the status of the permission checks on NTFS file systems. Returns |
1375 | \c true if the check is enabled. |
1376 | |
1377 | This function is only available on Windows and makes the direct |
1378 | manipulation of \l qt_ntfs_permission_lookup obsolete. |
1379 | |
1380 | \note The thread-safety of this function holds only as long as there are no |
1381 | concurrent updates to \l qt_ntfs_permission_lookup. |
1382 | */ |
1383 | |
1384 | QT_END_NAMESPACE |
1385 | |
1386 | #ifndef QT_NO_QOBJECT |
1387 | #include "moc_qfile.cpp" |
1388 | #endif |
1389 |
Definitions
- file_already_open
- QFilePrivate
- ~QFilePrivate
- openExternalFile
- openExternalFile
- engine
- QFile
- QFile
- QFile
- QFile
- QFile
- ~QFile
- fileName
- setFileName
- exists
- exists
- symLinkTarget
- symLinkTarget
- remove
- remove
- moveToTrash
- moveToTrash
- rename
- rename
- link
- link
- copy
- copy
- open
- open
- open
- open
- resize
- resize
- permissions
- permissions
- setPermissions
- setPermissions
Start learning QML with our Intro Training
Find out more