| 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 |  | 
| 26 | QT_BEGIN_NAMESPACE | 
| 27 |  | 
| 28 | using namespace Qt::StringLiterals; | 
| 29 |  | 
| 30 | Q_DECL_COLD_FUNCTION | 
| 31 | static 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 | 
| 38 | QFilePrivate::QFilePrivate() | 
| 39 | { | 
| 40 | } | 
| 41 |  | 
| 42 | QFilePrivate::~QFilePrivate() | 
| 43 | { | 
| 44 | } | 
| 45 |  | 
| 46 | bool | 
| 47 | QFilePrivate::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 |  | 
| 61 | bool | 
| 62 | QFilePrivate::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 |  | 
| 76 | QAbstractFileEngine *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 | 
| 199 | QFile::QFile() | 
| 200 |     : QFileDevice(*new QFilePrivate) | 
| 201 | { | 
| 202 | } | 
| 203 | QFile::QFile(const QString &name) | 
| 204 |     : QFileDevice(*new QFilePrivate) | 
| 205 | { | 
| 206 |     d_func()->fileName = name; | 
| 207 | } | 
| 208 | QFile::QFile(QFilePrivate &dd) | 
| 209 |     : QFileDevice(dd) | 
| 210 | { | 
| 211 | } | 
| 212 | #else | 
| 213 | /*! | 
| 214 |     Constructs a QFile object. | 
| 215 | */ | 
| 216 | QFile::QFile() | 
| 217 |     : QFileDevice(*new QFilePrivate, nullptr) | 
| 218 | { | 
| 219 | } | 
| 220 | /*! | 
| 221 |     Constructs a new file object with the given \a parent. | 
| 222 | */ | 
| 223 | QFile::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 | */ | 
| 239 | QFile::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 | */ | 
| 249 | QFile::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 | */ | 
| 258 | QFile::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 | */ | 
| 267 | QFile::~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 | */ | 
| 277 | QString 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 | */ | 
| 301 | void | 
| 302 | QFile::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 |  | 
| 350 | bool | 
| 351 | QFile::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 |  | 
| 367 | bool | 
| 368 | QFile::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 | */ | 
| 387 | QString 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 | */ | 
| 404 | QString 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 |  | 
| 418 | bool | 
| 419 | QFile::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 |  | 
| 449 | bool | 
| 450 | QFile::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 | */ | 
| 486 | bool | 
| 487 | QFile::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 | */ | 
| 526 | bool | 
| 527 | QFile::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 |  | 
| 555 | bool | 
| 556 | QFile::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 |  | 
| 706 | bool | 
| 707 | QFile::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 |  | 
| 728 | bool | 
| 729 | QFile::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 |  | 
| 756 | bool | 
| 757 | QFile::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 |  | 
| 773 | bool | 
| 774 | QFile::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 |  | 
| 886 | bool | 
| 887 | QFile::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 | */ | 
| 911 | bool 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 | */ | 
| 956 | bool 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 | */ | 
| 1026 | bool 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 | */ | 
| 1078 | bool 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 | */ | 
| 1110 | bool 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 |  | 
| 1128 | bool | 
| 1129 | QFile::resize(const QString &fileName, qint64 sz) | 
| 1130 | { | 
| 1131 |     return QFile(fileName).resize(sz); | 
| 1132 | } | 
| 1133 |  | 
| 1134 | /*! | 
| 1135 |     \reimp | 
| 1136 | */ | 
| 1137 | QFile::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 |  | 
| 1149 | QFile::Permissions | 
| 1150 | QFile::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 |  | 
| 1166 | bool 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 |  | 
| 1177 | bool | 
| 1178 | QFile::setPermissions(const QString &fileName, Permissions permissions) | 
| 1179 | { | 
| 1180 |     return QFile(fileName).setPermissions(permissions); | 
| 1181 | } | 
| 1182 |  | 
| 1183 | /*! | 
| 1184 |   \reimp | 
| 1185 | */ | 
| 1186 | qint64 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 |  | 
| 1384 | QT_END_NAMESPACE | 
| 1385 |  | 
| 1386 | #ifndef QT_NO_QOBJECT | 
| 1387 | #include "moc_qfile.cpp" | 
| 1388 | #endif | 
| 1389 |  |