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 \l{QIODeviceBase::}{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 // Engine was unable to rename and the fallback will delete the original file,
639 // so we have to back out here on case-insensitive file systems:
640 if (changingCase) {
641 d->setError(err: QFile::RenameError, errorString: d->fileEngine->errorString());
642 return false;
643 }
644
645 if (isSequential()) {
646 d->setError(err: QFile::RenameError, errorString: tr(s: "Will not rename sequential file using block copy"));
647 return false;
648 }
649
650 QFile out(newName);
651 if (open(flags: QIODevice::ReadOnly)) {
652 if (out.open(flags: QIODevice::WriteOnly | QIODevice::Truncate)) {
653 bool error = false;
654 char block[4096];
655 qint64 bytes;
656 while ((bytes = read(data: block, maxlen: sizeof(block))) > 0) {
657 if (bytes != out.write(data: block, len: bytes)) {
658 d->setError(err: QFile::RenameError, errorString: out.errorString());
659 error = true;
660 break;
661 }
662 }
663 if (bytes == -1) {
664 d->setError(err: QFile::RenameError, errorString: errorString());
665 error = true;
666 }
667 if (!error) {
668 if (!remove()) {
669 d->setError(err: QFile::RenameError, errorString: tr(s: "Cannot remove source file"));
670 error = true;
671 }
672 }
673 if (error) {
674 out.remove();
675 } else {
676 d->fileEngine->setFileName(newName);
677 setPermissions(permissions());
678 unsetError();
679 setFileName(newName);
680 }
681 close();
682 return !error;
683 }
684 close();
685 d->setError(err: QFile::RenameError,
686 errorString: tr(s: "Cannot open destination file: %1").arg(a: out.errorString()));
687 } else {
688 d->setError(err: QFile::RenameError, errorString: errorString());
689 }
690 }
691 return false;
692}
693
694/*!
695 \overload
696
697 Renames the file \a oldName to \a newName. Returns \c true if
698 successful; otherwise returns \c false.
699
700 If a file with the name \a newName already exists, rename() returns \c false
701 (i.e., QFile will not overwrite it).
702
703 \sa rename()
704*/
705
706bool
707QFile::rename(const QString &oldName, const QString &newName)
708{
709 return QFile(oldName).rename(newName);
710}
711
712/*!
713
714 Creates a link named \a linkName that points to the file currently specified by
715 fileName(). What a link is depends on the underlying filesystem (be it a
716 shortcut on Windows or a symbolic link on Unix). Returns \c true if successful;
717 otherwise returns \c false.
718
719 This function will not overwrite an already existing entity in the file system;
720 in this case, \c link() will return false and set \l{QFile::}{error()} to
721 return \l{QFile::}{RenameError}.
722
723 \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension.
724
725 \sa setFileName()
726*/
727
728bool
729QFile::link(const QString &linkName)
730{
731 Q_D(QFile);
732 if (fileName().isEmpty()) {
733 qWarning(msg: "QFile::link: Empty or null file name");
734 return false;
735 }
736 QFileInfo fi(linkName);
737 if (d->engine()->link(newName: fi.absoluteFilePath())) {
738 unsetError();
739 return true;
740 }
741 d->setError(err: QFile::RenameError, errorString: d->fileEngine->errorString());
742 return false;
743}
744
745/*!
746 \overload
747
748 Creates a link named \a linkName that points to the file \a fileName. What a link is
749 depends on the underlying filesystem (be it a shortcut on Windows
750 or a symbolic link on Unix). Returns \c true if successful; otherwise
751 returns \c false.
752
753 \sa link()
754*/
755
756bool
757QFile::link(const QString &fileName, const QString &linkName)
758{
759 return QFile(fileName).link(linkName);
760}
761
762/*!
763 Copies the file named fileName() to \a newName.
764
765 \include qfile-copy.qdocinc
766
767 \note On Android, this operation is not yet supported for \c content
768 scheme URIs.
769
770 \sa setFileName()
771*/
772
773bool
774QFile::copy(const QString &newName)
775{
776 Q_D(QFile);
777 if (fileName().isEmpty()) {
778 qWarning(msg: "QFile::copy: Empty or null file name");
779 return false;
780 }
781 if (QFile::exists(fileName: newName)) {
782 // ### Race condition. If a file is moved in after this, it /will/ be
783 // overwritten. On Unix, the proper solution is to use hardlinks:
784 // return ::link(old, new) && ::remove(old); See also rename().
785 d->setError(err: QFile::CopyError, errorString: tr(s: "Destination file exists"));
786 return false;
787 }
788 unsetError();
789 close();
790 if (error() == QFile::NoError) {
791 if (d->engine()->copy(newName)) {
792 unsetError();
793 return true;
794 } else {
795 bool error = false;
796 if (!open(flags: QFile::ReadOnly)) {
797 error = true;
798 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open %1 for input").arg(a: d->fileName));
799 } else {
800 const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1;
801#if !QT_CONFIG(temporaryfile)
802 QFile out(fileTemplate.arg(QFileInfo(newName).path()));
803 if (!out.open(QIODevice::ReadWrite))
804 error = true;
805#else
806 QTemporaryFile out(fileTemplate.arg(args: QFileInfo(newName).path()));
807 if (!out.open()) {
808 out.setFileTemplate(fileTemplate.arg(args: QDir::tempPath()));
809 if (!out.open())
810 error = true;
811 }
812#endif
813 if (error) {
814 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot open for output: %1").arg(a: out.errorString()));
815 out.close();
816 close();
817 } else {
818 if (!d->engine()->cloneTo(target: out.d_func()->engine())) {
819 char block[4096];
820 qint64 totalRead = 0;
821 while (!atEnd()) {
822 qint64 in = read(data: block, maxlen: sizeof(block));
823 if (in <= 0)
824 break;
825 totalRead += in;
826 if (in != out.write(data: block, len: in)) {
827 close();
828 d->setError(err: QFile::CopyError, errorString: tr(s: "Failure to write block: %1")
829 .arg(a: out.errorString()));
830 error = true;
831 break;
832 }
833 }
834
835 if (totalRead != size()) {
836 // Unable to read from the source. The error string is
837 // already set from read().
838 error = true;
839 }
840 }
841
842 if (!error) {
843 // Sync to disk if possible. Ignore errors (e.g. not supported).
844 out.d_func()->fileEngine->syncToDisk();
845
846 if (!out.rename(newName)) {
847 error = true;
848 close();
849 d->setError(err: QFile::CopyError, errorString: tr(s: "Cannot create %1 for output: %2")
850 .arg(args: newName, args: out.errorString()));
851 }
852 }
853#if !QT_CONFIG(temporaryfile)
854 if (error)
855 out.remove();
856#else
857 if (!error)
858 out.setAutoRemove(false);
859#endif
860 }
861 }
862 if (!error) {
863 QFile::setPermissions(filename: newName, permissionSpec: permissions());
864 close();
865 unsetError();
866 return true;
867 }
868 }
869 }
870 return false;
871}
872
873/*!
874 \overload
875
876 Copies the file named \a fileName to \a newName.
877
878 \include qfile-copy.qdocinc
879
880 \note On Android, this operation is not yet supported for \c content
881 scheme URIs.
882
883 \sa rename()
884*/
885
886bool
887QFile::copy(const QString &fileName, const QString &newName)
888{
889 return QFile(fileName).copy(newName);
890}
891
892/*!
893 Opens the file using \a mode flags, returning \c true if successful;
894 otherwise returns \c false.
895
896 The flags for \a mode must include \l QIODeviceBase::ReadOnly,
897 \l WriteOnly, or \l ReadWrite. It may also have additional flags,
898 such as \l Text and \l Unbuffered.
899
900 \note In \l{WriteOnly} or \l{ReadWrite}
901 mode, if the relevant file does not already exist, this function
902 will try to create a new file before opening it. The file will be
903 created with mode 0666 masked by the umask on POSIX systems, and
904 with permissions inherited from the parent directory on Windows.
905 On Android, it's expected to have access permission to the parent
906 of the file name, otherwise, it won't be possible to create this
907 non-existing file.
908
909 \sa QT_USE_NODISCARD_FILE_OPEN, setFileName()
910*/
911bool QFile::open(OpenMode mode)
912{
913 Q_D(QFile);
914 if (isOpen())
915 return file_already_open(file&: *this);
916 // Either Append or NewOnly implies WriteOnly
917 if (mode & (Append | NewOnly))
918 mode |= WriteOnly;
919 unsetError();
920 if ((mode & (ReadOnly | WriteOnly)) == 0) {
921 qWarning(msg: "QIODevice::open: File access not specified");
922 return false;
923 }
924
925 // QIODevice provides the buffering, so there's no need to request it from the file engine.
926 if (d->engine()->open(openMode: mode | QIODevice::Unbuffered)) {
927 QIODevice::open(mode);
928 if (mode & Append)
929 seek(offset: size());
930 return true;
931 }
932 QFile::FileError err = d->fileEngine->error();
933 if (err == QFile::UnspecifiedError)
934 err = QFile::OpenError;
935 d->setError(err, errorString: d->fileEngine->errorString());
936 return false;
937}
938
939/*!
940 \overload
941
942 If the file does not exist and \a mode implies creating it, it is created
943 with the specified \a permissions.
944
945 On POSIX systems the actual permissions are influenced by the
946 value of \c umask.
947
948 On Windows the permissions are emulated using ACLs. These ACLs may be in non-canonical
949 order when the group is granted less permissions than others. Files and directories with
950 such permissions will generate warnings when the Security tab of the Properties dialog
951 is opened. Granting the group all permissions granted to others avoids such warnings.
952
953 \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN
954 \since 6.3
955*/
956bool QFile::open(OpenMode mode, QFile::Permissions permissions)
957{
958 Q_D(QFile);
959 if (isOpen())
960 return file_already_open(file&: *this);
961 // Either Append or NewOnly implies WriteOnly
962 if (mode & (Append | NewOnly))
963 mode |= WriteOnly;
964 unsetError();
965 if ((mode & (ReadOnly | WriteOnly)) == 0) {
966 qWarning(msg: "QIODevice::open: File access not specified");
967 return false;
968 }
969
970 // QIODevice provides the buffering, so there's no need to request it from the file engine.
971 if (d->engine()->open(openMode: mode | QIODevice::Unbuffered, permissions)) {
972 QIODevice::open(mode);
973 if (mode & Append)
974 seek(offset: size());
975 return true;
976 }
977 QFile::FileError err = d->fileEngine->error();
978 if (err == QFile::UnspecifiedError)
979 err = QFile::OpenError;
980 d->setError(err, errorString: d->fileEngine->errorString());
981 return false;
982}
983
984/*!
985 \overload
986
987 Opens the existing file handle \a fh in the given \a mode.
988 \a handleFlags may be used to specify additional options.
989 Returns \c true if successful; otherwise returns \c false.
990
991 Example:
992 \snippet code/src_corelib_io_qfile.cpp 3
993
994 When a QFile is opened using this function, behaviour of close() is
995 controlled by the AutoCloseHandle flag.
996 If AutoCloseHandle is specified, and this function succeeds,
997 then calling close() closes the adopted handle.
998 Otherwise, close() does not actually close the file, but only flushes it.
999
1000 \b{Warning:}
1001 \list 1
1002 \li If \a fh does not refer to a regular file, e.g., it is \c stdin,
1003 \c stdout, or \c stderr, you may not be able to seek(). size()
1004 returns \c 0 in those cases. See QIODevice::isSequential() for
1005 more information.
1006 \li Since this function opens the file without specifying the file name,
1007 you cannot use this QFile with a QFileInfo.
1008 \endlist
1009
1010 \sa close(), QT_USE_NODISCARD_FILE_OPEN
1011
1012 \b{Note for the Windows Platform}
1013
1014 \a fh must be opened in binary mode (i.e., the mode string must contain
1015 'b', as in "rb" or "wb") when accessing files and other random-access
1016 devices. Qt will translate the end-of-line characters if you pass
1017 QIODevice::Text to \a mode. Sequential devices, such as stdin and stdout,
1018 are unaffected by this limitation.
1019
1020 You need to enable support for console applications in order to use the
1021 stdin, stdout and stderr streams at the console. To do this, add the
1022 following declaration to your application's project file:
1023
1024 \snippet code/src_corelib_io_qfile.cpp 4
1025*/
1026bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
1027{
1028 Q_D(QFile);
1029 if (isOpen())
1030 return file_already_open(file&: *this);
1031 // Either Append or NewOnly implies WriteOnly
1032 if (mode & (Append | NewOnly))
1033 mode |= WriteOnly;
1034 unsetError();
1035 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1036 qWarning(msg: "QFile::open: File access not specified");
1037 return false;
1038 }
1039
1040 // QIODevice provides the buffering, so request unbuffered file engines
1041 if (d->openExternalFile(flags: mode | Unbuffered, fh, handleFlags)) {
1042 QIODevice::open(mode);
1043 if (!(mode & Append) && !isSequential()) {
1044 qint64 pos = (qint64)QT_FTELL(stream: fh);
1045 if (pos != -1) {
1046 // Skip redundant checks in QFileDevice::seek().
1047 QIODevice::seek(pos);
1048 }
1049 }
1050 return true;
1051 }
1052 return false;
1053}
1054
1055/*!
1056 \overload
1057
1058 Opens the existing file descriptor \a fd in the given \a mode.
1059 \a handleFlags may be used to specify additional options.
1060 Returns \c true if successful; otherwise returns \c false.
1061
1062 When a QFile is opened using this function, behaviour of close() is
1063 controlled by the AutoCloseHandle flag.
1064 If AutoCloseHandle is specified, and this function succeeds,
1065 then calling close() closes the adopted handle.
1066 Otherwise, close() does not actually close the file, but only flushes it.
1067
1068 \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin),
1069 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In
1070 those cases, size() returns \c 0. See QIODevice::isSequential()
1071 for more information.
1072
1073 \warning Since this function opens the file without specifying the file name,
1074 you cannot use this QFile with a QFileInfo.
1075
1076 \sa close(), QT_USE_NODISCARD_FILE_OPEN
1077*/
1078bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
1079{
1080 Q_D(QFile);
1081 if (isOpen())
1082 return file_already_open(file&: *this);
1083 // Either Append or NewOnly implies WriteOnly
1084 if (mode & (Append | NewOnly))
1085 mode |= WriteOnly;
1086 unsetError();
1087 if ((mode & (ReadOnly | WriteOnly)) == 0) {
1088 qWarning(msg: "QFile::open: File access not specified");
1089 return false;
1090 }
1091
1092 // QIODevice provides the buffering, so request unbuffered file engines
1093 if (d->openExternalFile(flags: mode | Unbuffered, fd, handleFlags)) {
1094 QIODevice::open(mode);
1095 if (!(mode & Append) && !isSequential()) {
1096 qint64 pos = (qint64)QT_LSEEK(fd: fd, QT_OFF_T(0), SEEK_CUR);
1097 if (pos != -1) {
1098 // Skip redundant checks in QFileDevice::seek().
1099 QIODevice::seek(pos);
1100 }
1101 }
1102 return true;
1103 }
1104 return false;
1105}
1106
1107/*!
1108 \reimp
1109*/
1110bool QFile::resize(qint64 sz)
1111{
1112 return QFileDevice::resize(sz); // for now
1113}
1114
1115/*!
1116 \overload
1117
1118 Sets \a fileName to size (in bytes) \a sz. Returns \c true if
1119 the resize succeeds; false otherwise. If \a sz is larger than \a
1120 fileName currently is the new bytes will be set to 0, if \a sz is
1121 smaller the file is simply truncated.
1122
1123 \warning This function can fail if the file doesn't exist.
1124
1125 \sa resize()
1126*/
1127
1128bool
1129QFile::resize(const QString &fileName, qint64 sz)
1130{
1131 return QFile(fileName).resize(sz);
1132}
1133
1134/*!
1135 \reimp
1136*/
1137QFile::Permissions QFile::permissions() const
1138{
1139 return QFileDevice::permissions(); // for now
1140}
1141
1142/*!
1143 \overload
1144
1145 Returns the complete OR-ed together combination of
1146 QFile::Permission for \a fileName.
1147*/
1148
1149QFile::Permissions
1150QFile::permissions(const QString &fileName)
1151{
1152 return QFile(fileName).permissions();
1153}
1154
1155/*!
1156 Sets the permissions for the file to the \a permissions specified.
1157 Returns \c true if successful, or \c false if the permissions cannot be
1158 modified.
1159
1160 \warning This function does not manipulate ACLs, which may limit its
1161 effectiveness.
1162
1163 \sa permissions(), setFileName()
1164*/
1165
1166bool QFile::setPermissions(Permissions permissions)
1167{
1168 return QFileDevice::setPermissions(permissions); // for now
1169}
1170
1171/*!
1172 \overload
1173
1174 Sets the permissions for \a fileName file to \a permissions.
1175*/
1176
1177bool
1178QFile::setPermissions(const QString &fileName, Permissions permissions)
1179{
1180 return QFile(fileName).setPermissions(permissions);
1181}
1182
1183/*!
1184 \reimp
1185*/
1186qint64 QFile::size() const
1187{
1188 return QFileDevice::size(); // for now
1189}
1190
1191/*!
1192 \fn QFile::QFile(const std::filesystem::path &name)
1193 \since 6.0
1194
1195 Constructs a new file object to represent the file with the given \a name.
1196
1197 \include qfile.cpp qfile-explicit-constructor-note
1198*/
1199/*!
1200 \fn QFile::QFile(const std::filesystem::path &name, QObject *parent)
1201 \since 6.0
1202
1203 Constructs a new file object with the given \a parent to represent the
1204 file with the specified \a name.
1205*/
1206/*!
1207 \fn std::filesystem::path QFile::filesystemFileName() const
1208 \since 6.0
1209 Returns fileName() as \c{std::filesystem::path}.
1210*/
1211/*!
1212 \fn void QFile::setFileName(const std::filesystem::path &name)
1213 \since 6.0
1214 \overload
1215*/
1216/*!
1217 \fn bool QFile::rename(const std::filesystem::path &newName)
1218 \since 6.0
1219 \overload
1220*/
1221/*!
1222 \fn bool QFile::link(const std::filesystem::path &newName)
1223 \since 6.0
1224 \overload
1225*/
1226/*!
1227 \fn bool QFile::copy(const std::filesystem::path &newName)
1228 \since 6.0
1229 \overload
1230*/
1231/*!
1232 \fn QFile::Permissions QFile::permissions(const std::filesystem::path &filename)
1233 \since 6.0
1234 \overload
1235*/
1236/*!
1237 \fn bool QFile::setPermissions(const std::filesystem::path &filename, Permissions permissionSpec)
1238 \since 6.0
1239 \overload
1240*/
1241/*!
1242 \fn bool exists(const std::filesystem::path &fileName)
1243 \since 6.3
1244 \overload
1245*/
1246/*!
1247 \fn std::filesystem::path QFile::filesystemSymLinkTarget() const
1248 \since 6.3
1249 Returns symLinkTarget() as \c{std::filesystem::path}.
1250*/
1251/*!
1252 \fn std::filesystem::path QFile::filesystemSymLinkTarget(const std::filesystem::path &fileName)
1253 \since 6.3
1254 Returns symLinkTarget() as \c{std::filesystem::path} of \a fileName.
1255*/
1256/*!
1257 \fn bool remove(const std::filesystem::path &fileName)
1258 \since 6.3
1259 \overload
1260*/
1261/*!
1262 \fn bool moveToTrash(const std::filesystem::path &fileName, QString *pathInTrash)
1263 \since 6.3
1264 \overload
1265*/
1266/*!
1267 \fn bool rename(const std::filesystem::path &oldName, const std::filesystem::path &newName)
1268 \since 6.3
1269 \overload
1270*/
1271/*!
1272 \fn bool link(const std::filesystem::path &fileName, const std::filesystem::path &newName);
1273 \since 6.3
1274 \overload
1275*/
1276/*!
1277 \fn bool copy(const std::filesystem::path &fileName, const std::filesystem::path &newName);
1278 \since 6.3
1279 \overload
1280*/
1281
1282
1283/*!
1284 \class QNtfsPermissionCheckGuard
1285 \since 6.6
1286 \inmodule QtCore
1287 \brief The QNtfsPermissionCheckGuard class is a RAII class to manage NTFS
1288 permission checking.
1289
1290 \ingroup io
1291
1292 For performance reasons, QFile, QFileInfo, and related classes do not
1293 perform full ownership and permission (ACL) checking on NTFS file systems
1294 by default. During the lifetime of any instance of this class, that
1295 default is overridden and advanced checking is performed. This provides
1296 a safe and easy way to manage enabling and disabling this change to the
1297 default behavior.
1298
1299 Example:
1300
1301 \snippet ntfsp.cpp raii
1302
1303 This class is available only on Windows.
1304
1305 \section1 qt_ntfs_permission_lookup
1306
1307 Prior to Qt 6.6, the user had to directly manipulate the global variable
1308 \c qt_ntfs_permission_lookup. However, this was a non-atomic global
1309 variable and as such it was prone to data races.
1310
1311 The variable \c qt_ntfs_permission_lookup is therefore deprecated since Qt
1312 6.6.
1313*/
1314
1315/*!
1316 \fn QNtfsPermissionCheckGuard::QNtfsPermissionCheckGuard()
1317
1318 Creates a guard and calls the function qEnableNtfsPermissionChecks().
1319*/
1320
1321/*!
1322 \fn QNtfsPermissionCheckGuard::~QNtfsPermissionCheckGuard()
1323
1324 Destroys the guard and calls the function qDisableNtfsPermissionChecks().
1325*/
1326
1327
1328/*!
1329 \fn bool qEnableNtfsPermissionChecks()
1330 \since 6.6
1331 \threadsafe
1332 \relates QNtfsPermissionCheckGuard
1333
1334 Enables permission checking on NTFS file systems. Returns \c true if the check
1335 was already enabled before the call to this function, meaning that there
1336 are other users.
1337
1338 This function is only available on Windows and makes the direct
1339 manipulation of \l qt_ntfs_permission_lookup obsolete.
1340
1341 This is a low-level function, please consider the RAII class
1342 \l QNtfsPermissionCheckGuard instead.
1343
1344 \note The thread-safety of this function holds only as long as there are no
1345 concurrent updates to \l qt_ntfs_permission_lookup.
1346*/
1347
1348/*!
1349 \fn bool qDisableNtfsPermissionChecks()
1350 \since 6.6
1351 \threadsafe
1352 \relates QNtfsPermissionCheckGuard
1353
1354 Disables permission checking on NTFS file systems. Returns \c true if the
1355 check is disabled, meaning that there are no more users.
1356
1357 This function is only available on Windows and makes the direct
1358 manipulation of \l qt_ntfs_permission_lookup obsolete.
1359
1360 This is a low-level function and must (only) be called to match one earlier
1361 call to qEnableNtfsPermissionChecks(). Please consider the RAII class
1362 \l QNtfsPermissionCheckGuard instead.
1363
1364 \note The thread-safety of this function holds only as long as there are no
1365 concurrent updates to \l qt_ntfs_permission_lookup.
1366*/
1367
1368/*!
1369 \fn bool qAreNtfsPermissionChecksEnabled()
1370 \since 6.6
1371 \threadsafe
1372 \relates QNtfsPermissionCheckGuard
1373
1374 Checks the status of the permission checks on NTFS file systems. Returns
1375 \c true if the check is enabled.
1376
1377 This function is only available on Windows and makes the direct
1378 manipulation of \l qt_ntfs_permission_lookup obsolete.
1379
1380 \note The thread-safety of this function holds only as long as there are no
1381 concurrent updates to \l qt_ntfs_permission_lookup.
1382*/
1383
1384QT_END_NAMESPACE
1385
1386#ifndef QT_NO_QOBJECT
1387#include "moc_qfile.cpp"
1388#endif
1389

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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