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.reset(p: 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 \note On systems where the system API doesn't report the location of the file in the
463 trash, fileName() will be set to the null string once the file has been moved. On
464 systems that don't have a trash can, this function always returns false.
465*/
466bool
467QFile::moveToTrash()
468{
469 Q_D(QFile);
470 if (d->fileName.isEmpty() &&
471 !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
472 qWarning(msg: "QFile::remove: Empty or null file name");
473 return false;
474 }
475 unsetError();
476 close();
477 if (error() == QFile::NoError) {
478 QFileSystemEntry fileEntry(d->fileName);
479 QFileSystemEntry trashEntry;
480 QSystemError error;
481 if (QFileSystemEngine::moveFileToTrash(source: fileEntry, newLocation&: trashEntry, error)) {
482 setFileName(trashEntry.filePath());
483 unsetError();
484 return true;
485 }
486 d->setError(err: QFile::RenameError, errorString: error.toString());
487 }
488 return false;
489}
490
491/*!
492 \since 5.15
493 \overload
494
495 Moves the file specified by fileName() to the trash. Returns \c true if successful,
496 and sets \a pathInTrash (if provided) to the path at which the file can be found within
497 the trash; otherwise returns \c false.
498
499 \note On systems where the system API doesn't report the path of the file in the
500 trash, \a pathInTrash will be set to the null string once the file has been moved.
501 On systems that don't have a trash can, this function always returns false.
502*/
503bool
504QFile::moveToTrash(const QString &fileName, QString *pathInTrash)
505{
506 QFile file(fileName);
507 if (file.moveToTrash()) {
508 if (pathInTrash)
509 *pathInTrash = file.fileName();
510 return true;
511 }
512 return false;
513}
514
515/*!
516 Renames the file currently specified by fileName() to \a newName.
517 Returns \c true if successful; otherwise returns \c false.
518
519 If a file with the name \a newName already exists, rename() returns \c false
520 (i.e., QFile will not overwrite it).
521
522 The file is closed before it is renamed.
523
524 If the rename operation fails, Qt will attempt to copy this file's
525 contents to \a newName, and then remove this file, keeping only
526 \a newName. If that copy operation fails or this file can't be removed,
527 the destination file \a newName is removed to restore the old state.
528
529 \sa setFileName()
530*/
531
532bool
533QFile::rename(const QString &newName)
534{
535 Q_D(QFile);
536
537 // if this is a QTemporaryFile, the virtual fileName() call here may do something
538 if (fileName().isEmpty()) {
539 qWarning(msg: "QFile::rename: Empty or null file name");
540 return false;
541 }
542 if (d->fileName == newName) {
543 d->setError(err: QFile::RenameError, errorString: tr(s: "Destination file is the same file."));
544 return false;
545 }
546 if (!exists()) {
547 d->setError(err: QFile::RenameError, errorString: tr(s: "Source file does not exist."));
548 return false;
549 }
550
551 // If the file exists and it is a case-changing rename ("foo" -> "Foo"),
552 // compare Ids to make sure it really is a different file.
553 // Note: this does not take file engines into account.
554 bool changingCase = false;
555 QByteArray targetId = QFileSystemEngine::id(entry: QFileSystemEntry(newName));
556 if (!targetId.isNull()) {
557 QByteArray fileId = d->fileEngine ?
558 d->fileEngine->id() :
559 QFileSystemEngine::id(entry: QFileSystemEntry(d->fileName));
560 changingCase = (fileId == targetId && d->fileName.compare(s: newName, cs: Qt::CaseInsensitive) == 0);
561 if (!changingCase) {
562 d->setError(err: QFile::RenameError, errorString: tr(s: "Destination file exists"));
563 return false;
564 }
565
566#ifdef Q_OS_LINUX
567 // rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
568 // FS, such as FAT32. Move the file away and rename in 2 steps to work around.
569 QTemporaryFileName tfn(d->fileName);
570 QFileSystemEntry src(d->fileName);
571 QSystemError error;
572 for (int attempt = 0; attempt < 16; ++attempt) {
573 QFileSystemEntry tmp(tfn.generateNext(), QFileSystemEntry::FromNativePath());
574
575 // rename to temporary name
576 if (!QFileSystemEngine::renameFile(source: src, target: tmp, error))
577 continue;
578
579 // rename to final name
580 if (QFileSystemEngine::renameFile(source: tmp, target: QFileSystemEntry(newName), error)) {
581 d->fileEngine->setFileName(newName);
582 d->fileName = newName;
583 return true;
584 }
585
586 // We need to restore the original file.
587 QSystemError error2;
588 if (QFileSystemEngine::renameFile(source: tmp, target: src, error&: error2))
589 break; // report the original error, below
590
591 // report both errors
592 d->setError(err: QFile::RenameError,
593 errorString: tr(s: "Error while renaming: %1").arg(a: error.toString())
594 + u'\n'
595 + tr(s: "Unable to restore from %1: %2").
596 arg(args: QDir::toNativeSeparators(pathName: tmp.filePath()), args: error2.toString()));
597 return false;
598 }
599 d->setError(err: QFile::RenameError,
600 errorString: tr(s: "Error while renaming: %1").arg(a: error.toString()));
601 return false;
602#endif // Q_OS_LINUX
603 }
604 unsetError();
605 close();
606 if (error() == QFile::NoError) {
607 if (changingCase ? d->engine()->renameOverwrite(newName) : d->engine()->rename(newName)) {
608 unsetError();
609 // engine was able to handle the new name so we just reset it
610 d->fileEngine->setFileName(newName);
611 d->fileName = newName;
612 return true;
613 }
614
615 if (isSequential()) {
616 d->setError(err: QFile::RenameError, errorString: tr(s: "Will not rename sequential file using block copy"));
617 return false;
618 }
619
620 QFile out(newName);
621 if (open(flags: QIODevice::ReadOnly)) {
622 if (out.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)) {
623 bool error = false;
624 char block[4096];
625 qint64 bytes;
626 while ((bytes = read(data: block, maxlen: sizeof(block))) > 0) {
627 if (bytes != out.write(data: block, len: bytes)) {
628 d->setError(err: QFile::RenameError, errorString: out.errorString());
629 error = true;
630 break;
631 }
632 }
633 if (bytes == -1) {
634 d->setError(err: QFile::RenameError, errorString: errorString());
635 error = true;
636 }
637 if (!error) {
638 if (!remove()) {
639 d->setError(err: QFile::RenameError, errorString: tr(s: "Cannot remove source file"));
640 error = true;
641 }
642 }
643 if (error) {
644 out.remove();
645 } else {
646 d->fileEngine->setFileName(newName);
647 setPermissions(permissions());
648 unsetError();
649 setFileName(newName);
650 }
651 close();
652 return !error;
653 }
654 close();
655 d->setError(err: QFile::RenameError,
656 errorString: tr(s: "Cannot open destination file: %1").arg(a: out.errorString()));
657 } else {
658 d->setError(err: QFile::RenameError, errorString: errorString());
659 }
660 }
661 return false;
662}
663
664/*!
665 \overload
666
667 Renames the file \a oldName to \a newName. Returns \c true if
668 successful; otherwise returns \c false.
669
670 If a file with the name \a newName already exists, rename() returns \c false
671 (i.e., QFile will not overwrite it).
672
673 \sa rename()
674*/
675
676bool
677QFile::rename(const QString &oldName, const QString &newName)
678{
679 return QFile(oldName).rename(newName);
680}
681
682/*!
683
684 Creates a link named \a linkName that points to the file currently specified by
685 fileName(). What a link is depends on the underlying filesystem (be it a
686 shortcut on Windows or a symbolic link on Unix). Returns \c true if successful;
687 otherwise returns \c false.
688
689 This function will not overwrite an already existing entity in the file system;
690 in this case, \c link() will return false and set \l{QFile::}{error()} to
691 return \l{QFile::}{RenameError}.
692
693 \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension.
694
695 \sa setFileName()
696*/
697
698bool
699QFile::link(const QString &linkName)
700{
701 Q_D(QFile);
702 if (fileName().isEmpty()) {
703 qWarning(msg: "QFile::link: Empty or null file name");
704 return false;
705 }
706 QFileInfo fi(linkName);
707 if (d->engine()->link(newName: fi.absoluteFilePath())) {
708 unsetError();
709 return true;
710 }
711 d->setError(err: QFile::RenameError, errorString: d->fileEngine->errorString());
712 return false;
713}
714
715/*!
716 \overload
717
718 Creates a link named \a linkName that points to the file \a fileName. What a link is
719 depends on the underlying filesystem (be it a shortcut on Windows
720 or a symbolic link on Unix). Returns \c true if successful; otherwise
721 returns \c false.
722
723 \sa link()
724*/
725
726bool
727QFile::link(const QString &fileName, const QString &linkName)
728{
729 return QFile(fileName).link(linkName);
730}
731
732/*!
733 Copies the file named fileName() to \a newName.
734
735 \include qfile-copy.qdocinc
736
737 \note On Android, this operation is not yet supported for \c content
738 scheme URIs.
739
740 \sa setFileName()
741*/
742
743bool
744QFile::copy(const QString &newName)
745{
746 Q_D(QFile);
747 if (fileName().isEmpty()) {
748 qWarning(msg: "QFile::copy: Empty or null file name");
749 return false;
750 }
751 if (QFile::exists(fileName: newName)) {
752 // ### Race condition. If a file is moved in after this, it /will/ be
753 // overwritten. On Unix, the proper solution is to use hardlinks:
754 // return ::link(old, new) && ::remove(old); See also rename().
755 d->setError(err: QFile::CopyError, errorString: tr(s: "Destination file exists"));
756 return false;
757 }
758 unsetError();
759 close();
760 if (error() == QFile::NoError) {
761 if (d->engine()->copy(newName)) {
762 unsetError();
763 return true;
764 } else {
765 bool error = false;
766 if (!open(flags: QFile::ReadOnly)) {
767 error = true;
768 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open %1 for input").arg(a: d->fileName));
769 } else {
770 const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1;
771#ifdef QT_NO_TEMPORARYFILE
772 QFile out(fileTemplate.arg(QFileInfo(newName).path()));
773 if (!out.open(QIODevice::ReadWrite))
774 error = true;
775#else
776 QTemporaryFile out(fileTemplate.arg(args: QFileInfo(newName).path()));
777 if (!out.open()) {
778 out.setFileTemplate(fileTemplate.arg(args: QDir::tempPath()));
779 if (!out.open())
780 error = true;
781 }
782#endif
783 if (error) {
784 out.close();
785 close();
786 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open for output: %1").arg(a: out.errorString()));
787 } else {
788 if (!d->engine()->cloneTo(target: out.d_func()->engine())) {
789 char block[4096];
790 qint64 totalRead = 0;
791 while (!atEnd()) {
792 qint64 in = read(data: block, maxlen: sizeof(block));
793 if (in <= 0)
794 break;
795 totalRead += in;
796 if (in != out.write(data: block, len: in)) {
797 close();
798 d->setError(err: QFile::CopyError, errorString: tr(s: "Failure to write block: %1")
799 .arg(a: out.errorString()));
800 error = true;
801 break;
802 }
803 }
804
805 if (totalRead != size()) {
806 // Unable to read from the source. The error string is
807 // already set from read().
808 error = true;
809 }
810 }
811
812 if (!error) {
813 // Sync to disk if possible. Ignore errors (e.g. not supported).
814 out.d_func()->fileEngine->syncToDisk();
815
816 if (!out.rename(newName)) {
817 error = true;
818 close();
819 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot create %1 for output: %2")
820 .arg(args: newName, args: out.errorString()));
821 }
822 }
823#ifdef QT_NO_TEMPORARYFILE
824 if (error)
825 out.remove();
826#else
827 if (!error)
828 out.setAutoRemove(false);
829#endif
830 }
831 }
832 if (!error) {
833 QFile::setPermissions(filename: newName, permissionSpec: permissions());
834 close();
835 unsetError();
836 return true;
837 }
838 }
839 }
840 return false;
841}
842
843/*!
844 \overload
845
846 Copies the file named \a fileName to \a newName.
847
848 \include qfile-copy.qdocinc
849
850 \note On Android, this operation is not yet supported for \c content
851 scheme URIs.
852
853 \sa rename()
854*/
855
856bool
857QFile::copy(const QString &fileName, const QString &newName)
858{
859 return QFile(fileName).copy(newName);
860}
861
862/*!
863 Opens the file using OpenMode \a mode, returning true if successful;
864 otherwise false.
865
866 The \a mode must be QIODevice::ReadOnly, QIODevice::WriteOnly, or
867 QIODevice::ReadWrite. It may also have additional flags, such as
868 QIODevice::Text and QIODevice::Unbuffered.
869
870 \note In \l{QIODevice::}{WriteOnly} or \l{QIODevice::}{ReadWrite}
871 mode, if the relevant file does not already exist, this function
872 will try to create a new file before opening it. The file will be
873 created with mode 0666 masked by the umask on POSIX systems, and
874 with permissions inherited from the parent directory on Windows.
875 On Android, it's expected to have access permission to the parent
876 of the file name, otherwise, it won't be possible to create this
877 non-existing file.
878
879 \sa QIODevice::OpenMode, setFileName()
880*/
881bool QFile::open(OpenMode mode)
882{
883 Q_D(QFile);
884 if (isOpen())
885 return file_already_open(file&: *this);
886 // Either Append or NewOnly implies WriteOnly
887 if (mode & (Append | NewOnly))
888 mode |= WriteOnly;
889 unsetError();
890 if ((mode & (ReadOnly | WriteOnly)) == 0) {
891 qWarning(msg: "QIODevice::open: File access not specified");
892 return false;
893 }
894
895 // QIODevice provides the buffering, so there's no need to request it from the file engine.
896 if (d->engine()->open(openMode: mode | QIODevice::Unbuffered)) {
897 QIODevice::open(mode);
898 if (mode & Append)
899 seek(offset: size());
900 return true;
901 }
902 QFile::FileError err = d->fileEngine->error();
903 if (err == QFile::UnspecifiedError)
904 err = QFile::OpenError;
905 d->setError(err, errorString: d->fileEngine->errorString());
906 return false;
907}
908
909/*!
910 \overload
911
912 If the file does not exist and \a mode implies creating it, it is created
913 with the specified \a permissions.
914
915 On POSIX systems the actual permissions are influenced by the
916 value of \c umask.
917
918 On Windows the permissions are emulated using ACLs. These ACLs may be in non-canonical
919 order when the group is granted less permissions than others. Files and directories with
920 such permissions will generate warnings when the Security tab of the Properties dialog
921 is opened. Granting the group all permissions granted to others avoids such warnings.
922
923 \sa QIODevice::OpenMode, setFileName()
924 \since 6.3
925*/
926bool QFile::open(OpenMode mode, QFile::Permissions permissions)
927{
928 Q_D(QFile);
929 if (isOpen())
930 return file_already_open(file&: *this);
931 // Either Append or NewOnly implies WriteOnly
932 if (mode & (Append | NewOnly))
933 mode |= WriteOnly;
934 unsetError();
935 if ((mode & (ReadOnly | WriteOnly)) == 0) {
936 qWarning(msg: "QIODevice::open: File access not specified");
937 return false;
938 }
939
940 // QIODevice provides the buffering, so there's no need to request it from the file engine.
941 if (d->engine()->open(openMode: mode | QIODevice::Unbuffered, permissions)) {
942 QIODevice::open(mode);
943 if (mode & Append)
944 seek(offset: size());
945 return true;
946 }
947 QFile::FileError err = d->fileEngine->error();
948 if (err == QFile::UnspecifiedError)
949 err = QFile::OpenError;
950 d->setError(err, errorString: d->fileEngine->errorString());
951 return false;
952}
953
954/*!
955 \overload
956
957 Opens the existing file handle \a fh in the given \a mode.
958 \a handleFlags may be used to specify additional options.
959 Returns \c true if successful; otherwise returns \c false.
960
961 Example:
962 \snippet code/src_corelib_io_qfile.cpp 3
963
964 When a QFile is opened using this function, behaviour of close() is
965 controlled by the AutoCloseHandle flag.
966 If AutoCloseHandle is specified, and this function succeeds,
967 then calling close() closes the adopted handle.
968 Otherwise, close() does not actually close the file, but only flushes it.
969
970 \b{Warning:}
971 \list 1
972 \li If \a fh does not refer to a regular file, e.g., it is \c stdin,
973 \c stdout, or \c stderr, you may not be able to seek(). size()
974 returns \c 0 in those cases. See QIODevice::isSequential() for
975 more information.
976 \li Since this function opens the file without specifying the file name,
977 you cannot use this QFile with a QFileInfo.
978 \endlist
979
980 \sa close()
981
982 \b{Note for the Windows Platform}
983
984 \a fh must be opened in binary mode (i.e., the mode string must contain
985 'b', as in "rb" or "wb") when accessing files and other random-access
986 devices. Qt will translate the end-of-line characters if you pass
987 QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout,
988 are unaffected by this limitation.
989
990 You need to enable support for console applications in order to use the
991 stdin, stdout and stderr streams at the console. To do this, add the
992 following declaration to your application's project file:
993
994 \snippet code/src_corelib_io_qfile.cpp 4
995*/
996bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
997{
998 Q_D(QFile);
999 if (isOpen())
1000 return file_already_open(file&: *this);
1001 // Either Append or NewOnly implies WriteOnly
1002 if (mode & (Append | NewOnly))
1003 mode |= WriteOnly;
1004 unsetError();
1005 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1006 qWarning(msg: "QFile::open: File access not specified");
1007 return false;
1008 }
1009
1010 // QIODevice provides the buffering, so request unbuffered file engines
1011 if (d->openExternalFile(flags: mode | Unbuffered, fh, handleFlags)) {
1012 QIODevice::open(mode);
1013 if (!(mode & Append) && !isSequential()) {
1014 qint64 pos = (qint64)QT_FTELL(stream: fh);
1015 if (pos != -1) {
1016 // Skip redundant checks in QFileDevice::seek().
1017 QIODevice::seek(pos);
1018 }
1019 }
1020 return true;
1021 }
1022 return false;
1023}
1024
1025/*!
1026 \overload
1027
1028 Opens the existing file descriptor \a fd in the given \a mode.
1029 \a handleFlags may be used to specify additional options.
1030 Returns \c true if successful; otherwise returns \c false.
1031
1032 When a QFile is opened using this function, behaviour of close() is
1033 controlled by the AutoCloseHandle flag.
1034 If AutoCloseHandle is specified, and this function succeeds,
1035 then calling close() closes the adopted handle.
1036 Otherwise, close() does not actually close the file, but only flushes it.
1037
1038 \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin),
1039 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
1040 those cases, size() returns \c 0. See QIODevice::isSequential()
1041 for more information.
1042
1043 \warning Since this function opens the file without specifying the file name,
1044 you cannot use this QFile with a QFileInfo.
1045
1046 \sa close()
1047*/
1048bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
1049{
1050 Q_D(QFile);
1051 if (isOpen())
1052 return file_already_open(file&: *this);
1053 // Either Append or NewOnly implies WriteOnly
1054 if (mode & (Append | NewOnly))
1055 mode |= WriteOnly;
1056 unsetError();
1057 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1058 qWarning(msg: "QFile::open: File access not specified");
1059 return false;
1060 }
1061
1062 // QIODevice provides the buffering, so request unbuffered file engines
1063 if (d->openExternalFile(flags: mode | Unbuffered, fd, handleFlags)) {
1064 QIODevice::open(mode);
1065 if (!(mode & Append) && !isSequential()) {
1066 qint64 pos = (qint64)QT_LSEEK(fd: fd, QT_OFF_T(0), SEEK_CUR);
1067 if (pos != -1) {
1068 // Skip redundant checks in QFileDevice::seek().
1069 QIODevice::seek(pos);
1070 }
1071 }
1072 return true;
1073 }
1074 return false;
1075}
1076
1077/*!
1078 \reimp
1079*/
1080bool QFile::resize(qint64 sz)
1081{
1082 return QFileDevice::resize(sz); // for now
1083}
1084
1085/*!
1086 \overload
1087
1088 Sets \a fileName to size (in bytes) \a sz. Returns \c true if
1089 the resize succeeds; false otherwise. If \a sz is larger than \a
1090 fileName currently is the new bytes will be set to 0, if \a sz is
1091 smaller the file is simply truncated.
1092
1093 \warning This function can fail if the file doesn't exist.
1094
1095 \sa resize()
1096*/
1097
1098bool
1099QFile::resize(const QString &fileName, qint64 sz)
1100{
1101 return QFile(fileName).resize(sz);
1102}
1103
1104/*!
1105 \reimp
1106*/
1107QFile::Permissions QFile::permissions() const
1108{
1109 return QFileDevice::permissions(); // for now
1110}
1111
1112/*!
1113 \overload
1114
1115 Returns the complete OR-ed together combination of
1116 QFile::Permission for \a fileName.
1117*/
1118
1119QFile::Permissions
1120QFile::permissions(const QString &fileName)
1121{
1122 return QFile(fileName).permissions();
1123}
1124
1125/*!
1126 Sets the permissions for the file to the \a permissions specified.
1127 Returns \c true if successful, or \c false if the permissions cannot be
1128 modified.
1129
1130 \warning This function does not manipulate ACLs, which may limit its
1131 effectiveness.
1132
1133 \sa permissions(), setFileName()
1134*/
1135
1136bool QFile::setPermissions(Permissions permissions)
1137{
1138 return QFileDevice::setPermissions(permissions); // for now
1139}
1140
1141/*!
1142 \overload
1143
1144 Sets the permissions for \a fileName file to \a permissions.
1145*/
1146
1147bool
1148QFile::setPermissions(const QString &fileName, Permissions permissions)
1149{
1150 return QFile(fileName).setPermissions(permissions);
1151}
1152
1153/*!
1154 \reimp
1155*/
1156qint64 QFile::size() const
1157{
1158 return QFileDevice::size(); // for now
1159}
1160
1161/*!
1162 \fn QFile::QFile(const std::filesystem::path &name)
1163 \since 6.0
1164
1165 Constructs a new file object to represent the file with the given \a name.
1166
1167 \include qfile.cpp qfile-explicit-constructor-note
1168*/
1169/*!
1170 \fn QFile::QFile(const std::filesystem::path &name, QObject *parent)
1171 \since 6.0
1172
1173 Constructs a new file object with the given \a parent to represent the
1174 file with the specified \a name.
1175*/
1176/*!
1177 \fn std::filesystem::path QFile::filesystemFileName() const
1178 \since 6.0
1179 Returns fileName() as \c{std::filesystem::path}.
1180*/
1181/*!
1182 \fn void QFile::setFileName(const std::filesystem::path &name)
1183 \since 6.0
1184 \overload
1185*/
1186/*!
1187 \fn bool QFile::rename(const std::filesystem::path &newName)
1188 \since 6.0
1189 \overload
1190*/
1191/*!
1192 \fn bool QFile::link(const std::filesystem::path &newName)
1193 \since 6.0
1194 \overload
1195*/
1196/*!
1197 \fn bool QFile::copy(const std::filesystem::path &newName)
1198 \since 6.0
1199 \overload
1200*/
1201/*!
1202 \fn QFile::Permissions QFile::permissions(const std::filesystem::path &filename)
1203 \since 6.0
1204 \overload
1205*/
1206/*!
1207 \fn bool QFile::setPermissions(const std::filesystem::path &filename, Permissions permissionSpec)
1208 \since 6.0
1209 \overload
1210*/
1211/*!
1212 \fn bool exists(const std::filesystem::path &fileName)
1213 \since 6.3
1214 \overload
1215*/
1216/*!
1217 \fn std::filesystem::path QFile::filesystemSymLinkTarget() const
1218 \since 6.3
1219 Returns symLinkTarget() as \c{std::filesystem::path}.
1220*/
1221/*!
1222 \fn std::filesystem::path QFile::filesystemSymLinkTarget(const std::filesystem::path &fileName)
1223 \since 6.3
1224 Returns symLinkTarget() as \c{std::filesystem::path} of \a fileName.
1225*/
1226/*!
1227 \fn bool remove(const std::filesystem::path &fileName)
1228 \since 6.3
1229 \overload
1230*/
1231/*!
1232 \fn bool moveToTrash(const std::filesystem::path &fileName, QString *pathInTrash)
1233 \since 6.3
1234 \overload
1235*/
1236/*!
1237 \fn bool rename(const std::filesystem::path &oldName, const std::filesystem::path &newName)
1238 \since 6.3
1239 \overload
1240*/
1241/*!
1242 \fn bool link(const std::filesystem::path &fileName, const std::filesystem::path &newName);
1243 \since 6.3
1244 \overload
1245*/
1246/*!
1247 \fn bool copy(const std::filesystem::path &fileName, const std::filesystem::path &newName);
1248 \since 6.3
1249 \overload
1250*/
1251
1252
1253QT_END_NAMESPACE
1254
1255#ifndef QT_NO_QOBJECT
1256#include "moc_qfile.cpp"
1257#endif
1258

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