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