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

source code of qtbase/src/corelib/io/qfile.cpp