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