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