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