| 1 | // Copyright (C) 2016 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 3 |  | 
| 4 | #include "qplatformdefs.h" | 
| 5 | #include "qfiledevice.h" | 
| 6 | #include "qfiledevice_p.h" | 
| 7 | #include "qfsfileengine_p.h" | 
| 8 |  | 
| 9 | #ifdef QT_NO_QOBJECT | 
| 10 | #define tr(X) QString::fromLatin1(X) | 
| 11 | #endif | 
| 12 |  | 
| 13 | QT_BEGIN_NAMESPACE | 
| 14 |  | 
| 15 | #ifndef QFILE_WRITEBUFFER_SIZE | 
| 16 | #define QFILE_WRITEBUFFER_SIZE 16384 | 
| 17 | #endif | 
| 18 |  | 
| 19 | QFileDevicePrivate::QFileDevicePrivate() | 
| 20 |     : cachedSize(0), | 
| 21 |       error(QFile::NoError), lastWasWrite(false) | 
| 22 | { | 
| 23 |     writeBufferChunkSize = QFILE_WRITEBUFFER_SIZE; | 
| 24 | } | 
| 25 |  | 
| 26 | QFileDevicePrivate::~QFileDevicePrivate() = default; | 
| 27 |  | 
| 28 | QAbstractFileEngine *QFileDevicePrivate::engine() const | 
| 29 | { | 
| 30 |     if (!fileEngine) | 
| 31 |         fileEngine = std::make_unique<QFSFileEngine>(); | 
| 32 |     return fileEngine.get(); | 
| 33 | } | 
| 34 |  | 
| 35 | void QFileDevicePrivate::setError(QFileDevice::FileError err) | 
| 36 | { | 
| 37 |     error = err; | 
| 38 |     errorString.clear(); | 
| 39 | } | 
| 40 |  | 
| 41 | void QFileDevicePrivate::setError(QFileDevice::FileError err, const QString &errStr) | 
| 42 | { | 
| 43 |     error = err; | 
| 44 |     errorString = errStr; | 
| 45 | } | 
| 46 |  | 
| 47 | void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum) | 
| 48 | { | 
| 49 |     error = err; | 
| 50 |     errorString = qt_error_string(errorCode: errNum); | 
| 51 | } | 
| 52 |  | 
| 53 | /*! | 
| 54 |     \enum QFileDevice::FileError | 
| 55 |  | 
| 56 |     This enum describes the errors that may be returned by the error() | 
| 57 |     function. | 
| 58 |  | 
| 59 |     \value NoError          No error occurred. | 
| 60 |     \value ReadError        An error occurred when reading from the file. | 
| 61 |     \value WriteError       An error occurred when writing to the file. | 
| 62 |     \value FatalError       A fatal error occurred. | 
| 63 |     \value ResourceError    Out of resources (e.g., too many open files, out of memory, etc.) | 
| 64 |     \value OpenError        The file could not be opened. | 
| 65 |     \value AbortError       The operation was aborted. | 
| 66 |     \value TimeOutError     A timeout occurred. | 
| 67 |     \value UnspecifiedError An unspecified error occurred. | 
| 68 |     \value RemoveError      The file could not be removed. | 
| 69 |     \value RenameError      The file could not be renamed. | 
| 70 |     \value PositionError    The position in the file could not be changed. | 
| 71 |     \value ResizeError      The file could not be resized. | 
| 72 |     \value PermissionsError The file could not be accessed. | 
| 73 |     \value CopyError        The file could not be copied. | 
| 74 | */ | 
| 75 |  | 
| 76 | /*! | 
| 77 |     \enum QFileDevice::Permission | 
| 78 |  | 
| 79 |     This enum is used by the permission() function to report the | 
| 80 |     permissions and ownership of a file. The values may be OR-ed | 
| 81 |     together to test multiple permissions and ownership values. | 
| 82 |  | 
| 83 |     \value ReadOwner The file is readable by the owner of the file. | 
| 84 |     \value WriteOwner The file is writable by the owner of the file. | 
| 85 |     \value ExeOwner The file is executable by the owner of the file. | 
| 86 |     \value ReadUser The file is readable by the user. | 
| 87 |     \value WriteUser The file is writable by the user. | 
| 88 |     \value ExeUser The file is executable by the user. | 
| 89 |     \value ReadGroup The file is readable by the group. | 
| 90 |     \value WriteGroup The file is writable by the group. | 
| 91 |     \value ExeGroup The file is executable by the group. | 
| 92 |     \value ReadOther The file is readable by others. | 
| 93 |     \value WriteOther The file is writable by others. | 
| 94 |     \value ExeOther The file is executable by others. | 
| 95 |  | 
| 96 |     \warning Because of differences in the platforms supported by Qt, | 
| 97 |     the semantics of ReadUser, WriteUser and ExeUser are | 
| 98 |     platform-dependent: On Unix, the rights of the owner of the file | 
| 99 |     are returned and on Windows the rights of the current user are | 
| 100 |     returned. This behavior might change in a future Qt version. | 
| 101 |  | 
| 102 |     \note On NTFS file systems, ownership and permissions checking is | 
| 103 |     disabled by default for performance reasons. To enable it, | 
| 104 |     include the following line: | 
| 105 |  | 
| 106 |     \snippet ntfsp.cpp 0 | 
| 107 |  | 
| 108 |     Permission checking is then turned on and off by incrementing and | 
| 109 |     decrementing \c qt_ntfs_permission_lookup by 1. | 
| 110 |  | 
| 111 |     \snippet ntfsp.cpp 1 | 
| 112 |  | 
| 113 |     \note Since this is a non-atomic global variable, it is only safe | 
| 114 |     to increment or decrement \c qt_ntfs_permission_lookup before any | 
| 115 |     threads other than the main thread have started or after every thread | 
| 116 |     other than the main thread has ended. | 
| 117 |  | 
| 118 |     \note From Qt 6.6 the variable \c qt_ntfs_permission_lookup is | 
| 119 |     deprecated. Please use the following alternatives. | 
| 120 |  | 
| 121 |     The safe and easy way to manage permission checks is to use the RAII class | 
| 122 |     \c QNtfsPermissionCheckGuard. | 
| 123 |  | 
| 124 |     \snippet ntfsp.cpp raii | 
| 125 |  | 
| 126 |     If you need more fine-grained control, it is possible to manage the permission | 
| 127 |     with the following functions instead: | 
| 128 |  | 
| 129 |     \snippet ntfsp.cpp free-funcs | 
| 130 |  | 
| 131 | */ | 
| 132 |  | 
| 133 | //************* QFileDevice | 
| 134 |  | 
| 135 | /*! | 
| 136 |     \class QFileDevice | 
| 137 |     \inmodule QtCore | 
| 138 |     \since 5.0 | 
| 139 |  | 
| 140 |     \brief The QFileDevice class provides an interface for reading from and writing to open files. | 
| 141 |  | 
| 142 |     \ingroup io | 
| 143 |  | 
| 144 |     \reentrant | 
| 145 |  | 
| 146 |     QFileDevice is the base class for I/O devices that can read and write text and binary files | 
| 147 |     and \l{The Qt Resource System}{resources}. QFile offers the main functionality, | 
| 148 |     QFileDevice serves as a base class for sharing functionality with other file devices such | 
| 149 |     as QSaveFile, by providing all the operations that can be done on files that have | 
| 150 |     been opened by QFile or QSaveFile. | 
| 151 |  | 
| 152 |     \sa QFile, QSaveFile | 
| 153 | */ | 
| 154 |  | 
| 155 | /*! | 
| 156 |     \enum QFileDevice::FileHandleFlag | 
| 157 |  | 
| 158 |     This enum is used when opening a file to specify additional | 
| 159 |     options which only apply to files and not to a generic | 
| 160 |     QIODevice. | 
| 161 |  | 
| 162 |     \value AutoCloseHandle The file handle passed into open() should be | 
| 163 |     closed by close(), the default behavior is that close just flushes | 
| 164 |     the file and the application is responsible for closing the file handle. | 
| 165 |     When opening a file by name, this flag is ignored as Qt always owns the | 
| 166 |     file handle and must close it. | 
| 167 |     \value DontCloseHandle If not explicitly closed, the underlying file | 
| 168 |     handle is left open when the QFile object is destroyed. | 
| 169 |  */ | 
| 170 |  | 
| 171 | /*! | 
| 172 |     \macro QT_USE_NODISCARD_FILE_OPEN | 
| 173 |     \macro QT_NO_USE_NODISCARD_FILE_OPEN | 
| 174 |     \relates QFileDevice | 
| 175 |     \since 6.8 | 
| 176 |  | 
| 177 |     File-related I/O classes (such as QFile, QSaveFile, QTemporaryFile) | 
| 178 |     have an \c{open()} method to open the file they act upon. It is | 
| 179 |     important to check the return value of the call to \c{open()} | 
| 180 |     before proceeding with reading or writing data into the file. | 
| 181 |  | 
| 182 |     For this reason, starting with Qt 6.8, some overloads of \c{open()} | 
| 183 |     have been marked with the \c{[[nodiscard]]} attribute. Since this | 
| 184 |     change may raise warnings in existing codebases, user code can | 
| 185 |     opt-in or opt-out from having the attribute applied by defining | 
| 186 |     certain macros: | 
| 187 |  | 
| 188 |     \list | 
| 189 |         \li If the \c{QT_USE_NODISCARD_FILE_OPEN} macro is defined, | 
| 190 |         overloads of \c{open()} are marked as \c{[[nodiscard]]}. | 
| 191 |         \li If the \c{QT_NO_USE_NODISCARD_FILE_OPEN} is defined, the | 
| 192 |         overloads of \c{open()} are \e{not} marked as \c{[[nodiscard]]}. | 
| 193 |         \li If neither macro is defined, then the default up to and | 
| 194 |         including Qt 6.9 is not to have the attribute. Starting from Qt 6.10, | 
| 195 |         the attribute is automatically applied. | 
| 196 |         \li If both macros are defined, the program is ill-formed. | 
| 197 |     \endlist | 
| 198 | */ | 
| 199 |  | 
| 200 | #ifdef QT_NO_QOBJECT | 
| 201 | QFileDevice::QFileDevice() | 
| 202 |     : QIODevice(*new QFileDevicePrivate) | 
| 203 | { | 
| 204 | } | 
| 205 | QFileDevice::QFileDevice(QFileDevicePrivate &dd) | 
| 206 |     : QIODevice(dd) | 
| 207 | { | 
| 208 | } | 
| 209 | #else | 
| 210 | /*! | 
| 211 |     \internal | 
| 212 | */ | 
| 213 | QFileDevice::QFileDevice() | 
| 214 |     : QIODevice(*new QFileDevicePrivate, nullptr) | 
| 215 | { | 
| 216 | } | 
| 217 | /*! | 
| 218 |     \internal | 
| 219 | */ | 
| 220 | QFileDevice::QFileDevice(QObject *parent) | 
| 221 |     : QIODevice(*new QFileDevicePrivate, parent) | 
| 222 | { | 
| 223 | } | 
| 224 | /*! | 
| 225 |     \internal | 
| 226 | */ | 
| 227 | QFileDevice::QFileDevice(QFileDevicePrivate &dd, QObject *parent) | 
| 228 |     : QIODevice(dd, parent) | 
| 229 | { | 
| 230 | } | 
| 231 | #endif | 
| 232 |  | 
| 233 | /*! | 
| 234 |     Destroys the file device, closing it if necessary. | 
| 235 | */ | 
| 236 | QFileDevice::~QFileDevice() | 
| 237 | { | 
| 238 |     close(); | 
| 239 | } | 
| 240 |  | 
| 241 | /*! | 
| 242 |     Returns \c true if the file can only be manipulated sequentially; | 
| 243 |     otherwise returns \c false. | 
| 244 |  | 
| 245 |     Most files support random-access, but some special files may not. | 
| 246 |  | 
| 247 |     \sa QIODevice::isSequential() | 
| 248 | */ | 
| 249 | bool QFileDevice::isSequential() const | 
| 250 | { | 
| 251 |     Q_D(const QFileDevice); | 
| 252 |     return d->fileEngine && d->fileEngine->isSequential(); | 
| 253 | } | 
| 254 |  | 
| 255 | /*! | 
| 256 |   Returns the file handle of the file. | 
| 257 |  | 
| 258 |   This is a small positive integer, suitable for use with C library | 
| 259 |   functions such as \c fdopen() and \c fcntl(). On systems that use file | 
| 260 |   descriptors for sockets (i.e. Unix systems, but not Windows) the handle | 
| 261 |   can be used with QSocketNotifier as well. | 
| 262 |  | 
| 263 |   If the file is not open, or there is an error, handle() returns -1. | 
| 264 |  | 
| 265 |   \sa QSocketNotifier | 
| 266 | */ | 
| 267 | int QFileDevice::handle() const | 
| 268 | { | 
| 269 |     Q_D(const QFileDevice); | 
| 270 |     if (!isOpen() || !d->fileEngine) | 
| 271 |         return -1; | 
| 272 |  | 
| 273 |     return d->fileEngine->handle(); | 
| 274 | } | 
| 275 |  | 
| 276 | /*! | 
| 277 |     Returns the name of the file. | 
| 278 |     The default implementation in QFileDevice returns a null string. | 
| 279 | */ | 
| 280 | QString QFileDevice::fileName() const | 
| 281 | { | 
| 282 |     return QString(); | 
| 283 | } | 
| 284 |  | 
| 285 | /*! | 
| 286 |     Flushes any buffered data to the file. Returns \c true if successful; | 
| 287 |     otherwise returns \c false. | 
| 288 | */ | 
| 289 | bool QFileDevice::flush() | 
| 290 | { | 
| 291 |     Q_D(QFileDevice); | 
| 292 |     if (!d->fileEngine) { | 
| 293 |         qWarning(msg: "QFileDevice::flush: No file engine. Is IODevice open?" ); | 
| 294 |         return false; | 
| 295 |     } | 
| 296 |  | 
| 297 |     if (!d->writeBuffer.isEmpty()) { | 
| 298 |         qint64 size = d->writeBuffer.nextDataBlockSize(); | 
| 299 |         qint64 written = d->fileEngine->write(data: d->writeBuffer.readPointer(), len: size); | 
| 300 |         if (written > 0) | 
| 301 |             d->writeBuffer.free(bytes: written); | 
| 302 |         if (written != size) { | 
| 303 |             QFileDevice::FileError err = d->fileEngine->error(); | 
| 304 |             if (err == QFileDevice::UnspecifiedError) | 
| 305 |                 err = QFileDevice::WriteError; | 
| 306 |             d->setError(err, errStr: d->fileEngine->errorString()); | 
| 307 |             return false; | 
| 308 |         } | 
| 309 |     } | 
| 310 |  | 
| 311 |     if (!d->fileEngine->flush()) { | 
| 312 |         QFileDevice::FileError err = d->fileEngine->error(); | 
| 313 |         if (err == QFileDevice::UnspecifiedError) | 
| 314 |             err = QFileDevice::WriteError; | 
| 315 |         d->setError(err, errStr: d->fileEngine->errorString()); | 
| 316 |         return false; | 
| 317 |     } | 
| 318 |     return true; | 
| 319 | } | 
| 320 |  | 
| 321 | /*! | 
| 322 |   Calls QFileDevice::flush() and closes the file. Errors from flush are ignored. | 
| 323 |  | 
| 324 |   \sa QIODevice::close() | 
| 325 | */ | 
| 326 | void QFileDevice::close() | 
| 327 | { | 
| 328 |     Q_D(QFileDevice); | 
| 329 |     if (!isOpen()) | 
| 330 |         return; | 
| 331 |     bool flushed = flush(); | 
| 332 |     QIODevice::close(); | 
| 333 |  | 
| 334 |     // reset write buffer | 
| 335 |     d->lastWasWrite = false; | 
| 336 |     d->writeBuffer.clear(); | 
| 337 |  | 
| 338 |     // reset cached size | 
| 339 |     d->cachedSize = 0; | 
| 340 |  | 
| 341 |     // If flush() succeeded but close() failed, copy its error condition; | 
| 342 |     // otherwise, keep the earlier flush() error. | 
| 343 |     if (d->fileEngine->close() && flushed) | 
| 344 |         unsetError(); | 
| 345 |     else if (flushed) | 
| 346 |         d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString()); | 
| 347 | } | 
| 348 |  | 
| 349 | /*! | 
| 350 |   \reimp | 
| 351 | */ | 
| 352 | qint64 QFileDevice::pos() const | 
| 353 | { | 
| 354 |     return QIODevice::pos(); | 
| 355 | } | 
| 356 |  | 
| 357 | /*! | 
| 358 |   Returns \c true if the end of the file has been reached; otherwise returns | 
| 359 |   false. | 
| 360 |  | 
| 361 |   For regular empty files on Unix (e.g. those in \c /proc), this function | 
| 362 |   returns \c true, since the file system reports that the size of such a file is | 
| 363 |   0. Therefore, you should not depend on atEnd() when reading data from such a | 
| 364 |   file, but rather call read() until no more data can be read. | 
| 365 | */ | 
| 366 | bool QFileDevice::atEnd() const | 
| 367 | { | 
| 368 |     Q_D(const QFileDevice); | 
| 369 |  | 
| 370 |     // If there's buffered data left, we're not at the end. | 
| 371 |     if (!d->isBufferEmpty()) | 
| 372 |         return false; | 
| 373 |  | 
| 374 |     if (!isOpen()) | 
| 375 |         return true; | 
| 376 |  | 
| 377 |     if (!d->ensureFlushed()) | 
| 378 |         return false; | 
| 379 |  | 
| 380 |     // If the file engine knows best, say what it says. | 
| 381 |     if (d->fileEngine->supportsExtension(extension: QAbstractFileEngine::AtEndExtension)) { | 
| 382 |         // Check if the file engine supports AtEndExtension, and if it does, | 
| 383 |         // check if the file engine claims to be at the end. | 
| 384 |         return d->fileEngine->atEnd(); | 
| 385 |     } | 
| 386 |  | 
| 387 |     // if it looks like we are at the end, or if size is not cached, | 
| 388 |     // fall through to bytesAvailable() to make sure. | 
| 389 |     if (pos() < d->cachedSize) | 
| 390 |         return false; | 
| 391 |  | 
| 392 |     // Fall back to checking how much is available (will stat files). | 
| 393 |     return bytesAvailable() == 0; | 
| 394 | } | 
| 395 |  | 
| 396 | /*! | 
| 397 |     \fn bool QFileDevice::seek(qint64 pos) | 
| 398 |  | 
| 399 |     For random-access devices, this function sets the current position | 
| 400 |     to \a pos, returning true on success, or false if an error occurred. | 
| 401 |     For sequential devices, the default behavior is to do nothing and | 
| 402 |     return false. | 
| 403 |  | 
| 404 |     Seeking beyond the end of a file: | 
| 405 |     If the position is beyond the end of a file, then seek() will not | 
| 406 |     immediately extend the file. If a write is performed at this position, | 
| 407 |     then the file will be extended. The content of the file between the | 
| 408 |     previous end of file and the newly written data is UNDEFINED and | 
| 409 |     varies between platforms and file systems. | 
| 410 | */ | 
| 411 | bool QFileDevice::seek(qint64 off) | 
| 412 | { | 
| 413 |     Q_D(QFileDevice); | 
| 414 |     if (!isOpen()) { | 
| 415 |         qWarning(msg: "QFileDevice::seek: IODevice is not open" ); | 
| 416 |         return false; | 
| 417 |     } | 
| 418 |  | 
| 419 |     if (!d->ensureFlushed()) | 
| 420 |         return false; | 
| 421 |  | 
| 422 |     if (!d->fileEngine->seek(pos: off) || !QIODevice::seek(pos: off)) { | 
| 423 |         QFileDevice::FileError err = d->fileEngine->error(); | 
| 424 |         if (err == QFileDevice::UnspecifiedError) | 
| 425 |             err = QFileDevice::PositionError; | 
| 426 |         d->setError(err, errStr: d->fileEngine->errorString()); | 
| 427 |         return false; | 
| 428 |     } | 
| 429 |     unsetError(); | 
| 430 |     return true; | 
| 431 | } | 
| 432 |  | 
| 433 | /*! | 
| 434 |   \reimp | 
| 435 | */ | 
| 436 | qint64 QFileDevice::readLineData(char *data, qint64 maxlen) | 
| 437 | { | 
| 438 |     Q_D(QFileDevice); | 
| 439 |     if (!d->ensureFlushed()) | 
| 440 |         return -1; | 
| 441 |  | 
| 442 |     qint64 read; | 
| 443 |     if (d->fileEngine->supportsExtension(extension: QAbstractFileEngine::FastReadLineExtension)) { | 
| 444 |         read = d->fileEngine->readLine(data, maxlen); | 
| 445 |     } else { | 
| 446 |         // Fall back to QIODevice's readLine implementation if the engine | 
| 447 |         // cannot do it faster. | 
| 448 |         read = QIODevice::readLineData(data, maxlen); | 
| 449 |     } | 
| 450 |  | 
| 451 |     if (read < maxlen) { | 
| 452 |         // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked | 
| 453 |         d->cachedSize = 0; | 
| 454 |     } | 
| 455 |  | 
| 456 |     return read; | 
| 457 | } | 
| 458 |  | 
| 459 | /*! | 
| 460 |   \reimp | 
| 461 | */ | 
| 462 | qint64 QFileDevice::readData(char *data, qint64 len) | 
| 463 | { | 
| 464 |     Q_D(QFileDevice); | 
| 465 |     if (!len) | 
| 466 |         return 0; | 
| 467 |     unsetError(); | 
| 468 |     if (!d->ensureFlushed()) | 
| 469 |         return -1; | 
| 470 |  | 
| 471 |     const qint64 read = d->fileEngine->read(data, maxlen: len); | 
| 472 |     if (read < 0) { | 
| 473 |         QFileDevice::FileError err = d->fileEngine->error(); | 
| 474 |         if (err == QFileDevice::UnspecifiedError) | 
| 475 |             err = QFileDevice::ReadError; | 
| 476 |         d->setError(err, errStr: d->fileEngine->errorString()); | 
| 477 |     } | 
| 478 |  | 
| 479 |     if (read < len) { | 
| 480 |         // failed to read all requested, may be at the end of file, stop caching size so that it's rechecked | 
| 481 |         d->cachedSize = 0; | 
| 482 |     } | 
| 483 |  | 
| 484 |     return read; | 
| 485 | } | 
| 486 |  | 
| 487 | /*! | 
| 488 |     \internal | 
| 489 | */ | 
| 490 | bool QFileDevicePrivate::putCharHelper(char c) | 
| 491 | { | 
| 492 | #ifdef QT_NO_QOBJECT | 
| 493 |     return QIODevicePrivate::putCharHelper(c); | 
| 494 | #else | 
| 495 |  | 
| 496 |     // Cutoff for code that doesn't only touch the buffer. | 
| 497 |     qint64 writeBufferSize = writeBuffer.size(); | 
| 498 |     if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= writeBufferChunkSize | 
| 499 | #ifdef Q_OS_WIN | 
| 500 |         || ((openMode & QIODevice::Text) && c == '\n' | 
| 501 |             && writeBufferSize + 2 >= writeBufferChunkSize) | 
| 502 | #endif | 
| 503 |         ) { | 
| 504 |         return QIODevicePrivate::putCharHelper(c); | 
| 505 |     } | 
| 506 |  | 
| 507 |     if (!(openMode & QIODevice::WriteOnly)) { | 
| 508 |         if (openMode == QIODevice::NotOpen) | 
| 509 |             qWarning(msg: "QIODevice::putChar: Closed device" ); | 
| 510 |         else | 
| 511 |             qWarning(msg: "QIODevice::putChar: ReadOnly device" ); | 
| 512 |         return false; | 
| 513 |     } | 
| 514 |  | 
| 515 |     // Make sure the device is positioned correctly. | 
| 516 |     const bool sequential = isSequential(); | 
| 517 |     if (pos != devicePos && !sequential && !q_func()->seek(off: pos)) | 
| 518 |         return false; | 
| 519 |  | 
| 520 |     lastWasWrite = true; | 
| 521 |  | 
| 522 |     int len = 1; | 
| 523 | #ifdef Q_OS_WIN | 
| 524 |     if ((openMode & QIODevice::Text) && c == '\n') { | 
| 525 |         ++len; | 
| 526 |         *writeBuffer.reserve(1) = '\r'; | 
| 527 |     } | 
| 528 | #endif | 
| 529 |  | 
| 530 |     // Write to buffer. | 
| 531 |     *writeBuffer.reserve(bytes: 1) = c; | 
| 532 |  | 
| 533 |     if (!sequential) { | 
| 534 |         pos += len; | 
| 535 |         devicePos += len; | 
| 536 |         if (!buffer.isEmpty()) | 
| 537 |             buffer.skip(length: len); | 
| 538 |     } | 
| 539 |  | 
| 540 |     return true; | 
| 541 | #endif | 
| 542 | } | 
| 543 |  | 
| 544 | /*! | 
| 545 |   \reimp | 
| 546 | */ | 
| 547 | qint64 QFileDevice::writeData(const char *data, qint64 len) | 
| 548 | { | 
| 549 |     Q_D(QFileDevice); | 
| 550 |     unsetError(); | 
| 551 |     d->lastWasWrite = true; | 
| 552 |     bool buffered = !(d->openMode & Unbuffered); | 
| 553 |  | 
| 554 |     // Flush buffered data if this read will overflow. | 
| 555 |     if (buffered && (d->writeBuffer.size() + len) > d->writeBufferChunkSize) { | 
| 556 |         if (!flush()) | 
| 557 |             return -1; | 
| 558 |     } | 
| 559 |  | 
| 560 |     // Write directly to the engine if the block size is larger than | 
| 561 |     // the write buffer size. | 
| 562 |     if (!buffered || len > d->writeBufferChunkSize) { | 
| 563 |         const qint64 ret = d->fileEngine->write(data, len); | 
| 564 |         if (ret < 0) { | 
| 565 |             QFileDevice::FileError err = d->fileEngine->error(); | 
| 566 |             if (err == QFileDevice::UnspecifiedError) | 
| 567 |                 err = QFileDevice::WriteError; | 
| 568 |             d->setError(err, errStr: d->fileEngine->errorString()); | 
| 569 |         } | 
| 570 |         return ret; | 
| 571 |     } | 
| 572 |  | 
| 573 |     // Write to the buffer. | 
| 574 |     d->writeBuffer.append(data, size: len); | 
| 575 |     return len; | 
| 576 | } | 
| 577 |  | 
| 578 | /*! | 
| 579 |     Returns the file error status. | 
| 580 |  | 
| 581 |     The I/O device status returns an error code. For example, if open() | 
| 582 |     returns \c false, or a read/write operation returns -1, this function can | 
| 583 |     be called to find out the reason why the operation failed. | 
| 584 |  | 
| 585 |     \sa unsetError() | 
| 586 | */ | 
| 587 | QFileDevice::FileError QFileDevice::error() const | 
| 588 | { | 
| 589 |     Q_D(const QFileDevice); | 
| 590 |     return d->error; | 
| 591 | } | 
| 592 |  | 
| 593 | /*! | 
| 594 |     Sets the file's error to QFileDevice::NoError. | 
| 595 |  | 
| 596 |     \sa error() | 
| 597 | */ | 
| 598 | void QFileDevice::unsetError() | 
| 599 | { | 
| 600 |     Q_D(QFileDevice); | 
| 601 |     d->setError(QFileDevice::NoError); | 
| 602 | } | 
| 603 |  | 
| 604 | /*! | 
| 605 |   Returns the size of the file. | 
| 606 |  | 
| 607 |   For regular empty files on Unix (e.g. those in \c /proc), this function | 
| 608 |   returns 0; the contents of such a file are generated on demand in response | 
| 609 |   to you calling read(). | 
| 610 | */ | 
| 611 | qint64 QFileDevice::size() const | 
| 612 | { | 
| 613 |     Q_D(const QFileDevice); | 
| 614 |     if (!d->ensureFlushed()) | 
| 615 |         return 0; | 
| 616 |     d->cachedSize = d->engine()->size(); | 
| 617 |     return d->cachedSize; | 
| 618 | } | 
| 619 |  | 
| 620 | /*! | 
| 621 |     Sets the file size (in bytes) \a sz. Returns \c true if the | 
| 622 |     resize succeeds; false otherwise. If \a sz is larger than the file | 
| 623 |     currently is, the new bytes will be set to 0; if \a sz is smaller, the | 
| 624 |     file is simply truncated. | 
| 625 |  | 
| 626 |     \warning This function can fail if the file doesn't exist. | 
| 627 |  | 
| 628 |     \sa size() | 
| 629 | */ | 
| 630 | bool QFileDevice::resize(qint64 sz) | 
| 631 | { | 
| 632 |     Q_D(QFileDevice); | 
| 633 |     if (!d->ensureFlushed()) | 
| 634 |         return false; | 
| 635 |     d->engine(); | 
| 636 |     if (isOpen() && d->fileEngine->pos() > sz) | 
| 637 |         seek(off: sz); | 
| 638 |     if (d->fileEngine->setSize(sz)) { | 
| 639 |         unsetError(); | 
| 640 |         d->cachedSize = sz; | 
| 641 |         return true; | 
| 642 |     } | 
| 643 |     d->cachedSize = 0; | 
| 644 |     d->setError(err: QFile::ResizeError, errStr: d->fileEngine->errorString()); | 
| 645 |     return false; | 
| 646 | } | 
| 647 |  | 
| 648 | /*! | 
| 649 |     Returns the complete OR-ed together combination of | 
| 650 |     QFile::Permission for the file. | 
| 651 |  | 
| 652 |     \sa setPermissions() | 
| 653 | */ | 
| 654 | QFile::Permissions QFileDevice::permissions() const | 
| 655 | { | 
| 656 |     Q_D(const QFileDevice); | 
| 657 |     QAbstractFileEngine::FileFlags perms = d->engine()->fileFlags(type: QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask; | 
| 658 |     return QFile::Permissions::fromInt(i: perms.toInt()); //ewww | 
| 659 | } | 
| 660 |  | 
| 661 | /*! | 
| 662 |     Sets the permissions for the file to the \a permissions specified. | 
| 663 |     Returns \c true if successful, or \c false if the permissions cannot be | 
| 664 |     modified. | 
| 665 |  | 
| 666 |     \warning This function does not manipulate ACLs, which may limit its | 
| 667 |     effectiveness. | 
| 668 |  | 
| 669 |     \sa permissions() | 
| 670 | */ | 
| 671 | bool QFileDevice::setPermissions(Permissions permissions) | 
| 672 | { | 
| 673 |     Q_D(QFileDevice); | 
| 674 |     if (d->engine()->setPermissions(permissions.toInt())) { | 
| 675 |         unsetError(); | 
| 676 |         return true; | 
| 677 |     } | 
| 678 |     d->setError(err: QFile::PermissionsError, errStr: d->fileEngine->errorString()); | 
| 679 |     return false; | 
| 680 | } | 
| 681 |  | 
| 682 | /*! | 
| 683 |     \enum QFileDevice::MemoryMapFlag | 
| 684 |     \since 4.4 | 
| 685 |  | 
| 686 |     This enum describes special options that may be used by the map() | 
| 687 |     function. | 
| 688 |  | 
| 689 |     \value NoOptions        No options. | 
| 690 |     \value MapPrivateOption The mapped memory will be private, so any | 
| 691 |     modifications will not be visible to other processes and will not | 
| 692 |     be written to disk.  Any such modifications will be lost when the | 
| 693 |     memory is unmapped.  It is unspecified whether modifications made | 
| 694 |     to the file made after the mapping is created will be visible through | 
| 695 |     the mapped memory. This enum value was introduced in Qt 5.4. | 
| 696 | */ | 
| 697 |  | 
| 698 | /*! | 
| 699 |     Maps \a size bytes of the file into memory starting at \a offset.  A file | 
| 700 |     should be open for a map to succeed but the file does not need to stay | 
| 701 |     open after the memory has been mapped.  When the QFile is destroyed | 
| 702 |     or a new file is opened with this object, any maps that have not been | 
| 703 |     unmapped will automatically be unmapped. | 
| 704 |  | 
| 705 |     The mapping will have the same open mode as the file (read and/or write), | 
| 706 |     except when using MapPrivateOption, in which case it is always possible | 
| 707 |     to write to the mapped memory. | 
| 708 |  | 
| 709 |     Any mapping options can be passed through \a flags. | 
| 710 |  | 
| 711 |     Returns a pointer to the memory or \nullptr if there is an error. | 
| 712 |  | 
| 713 |     \sa unmap() | 
| 714 |  */ | 
| 715 | uchar *QFileDevice::map(qint64 offset, qint64 size, MemoryMapFlags flags) | 
| 716 | { | 
| 717 |     Q_D(QFileDevice); | 
| 718 |     if (d->engine() | 
| 719 |             && d->fileEngine->supportsExtension(extension: QAbstractFileEngine::MapExtension)) { | 
| 720 |         unsetError(); | 
| 721 |         uchar *address = d->fileEngine->map(offset, size, flags); | 
| 722 |         if (address == nullptr) | 
| 723 |             d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString()); | 
| 724 |         return address; | 
| 725 |     } | 
| 726 |     return nullptr; | 
| 727 | } | 
| 728 |  | 
| 729 | /*! | 
| 730 |     Unmaps the memory \a address. | 
| 731 |  | 
| 732 |     Returns \c true if the unmap succeeds; false otherwise. | 
| 733 |  | 
| 734 |     \sa map() | 
| 735 |  */ | 
| 736 | bool QFileDevice::unmap(uchar *address) | 
| 737 | { | 
| 738 |     Q_D(QFileDevice); | 
| 739 |     if (d->engine() | 
| 740 |         && d->fileEngine->supportsExtension(extension: QAbstractFileEngine::UnMapExtension)) { | 
| 741 |         unsetError(); | 
| 742 |         bool success = d->fileEngine->unmap(ptr: address); | 
| 743 |         if (!success) | 
| 744 |             d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString()); | 
| 745 |         return success; | 
| 746 |     } | 
| 747 |     d->setError(err: PermissionsError, errStr: tr(s: "No file engine available or engine does not support UnMapExtension" )); | 
| 748 |     return false; | 
| 749 | } | 
| 750 |  | 
| 751 | /*! | 
| 752 |     \enum QFileDevice::FileTime | 
| 753 |     \since 5.10 | 
| 754 |  | 
| 755 |     This enum is used by the fileTime() and setFileTime() functions. | 
| 756 |  | 
| 757 |     \value FileAccessTime           When the file was most recently accessed | 
| 758 |                                     (e.g. read or written to). | 
| 759 |     \value FileBirthTime            When the file was created (may not be not | 
| 760 |                                     supported on UNIX). | 
| 761 |     \value FileMetadataChangeTime   When the file's metadata was last changed. | 
| 762 |     \value FileModificationTime     When the file was most recently modified. | 
| 763 |  | 
| 764 |     \sa setFileTime(), fileTime(), QFileInfo::fileTime() | 
| 765 | */ | 
| 766 |  | 
| 767 | /*! | 
| 768 |     \since 5.10 | 
| 769 |     Returns the file time specified by \a time. | 
| 770 |     If the time cannot be determined return QDateTime() (an invalid | 
| 771 |     date time). | 
| 772 |  | 
| 773 |     \sa setFileTime(), FileTime, QDateTime::isValid() | 
| 774 | */ | 
| 775 | QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const | 
| 776 | { | 
| 777 |     Q_D(const QFileDevice); | 
| 778 |  | 
| 779 |     if (d->engine()) | 
| 780 |         return d->engine()->fileTime(time); | 
| 781 |  | 
| 782 |     return QDateTime(); | 
| 783 | } | 
| 784 |  | 
| 785 | /*! | 
| 786 |     \since 5.10 | 
| 787 |     Sets the file time specified by \a fileTime to \a newDate, returning true | 
| 788 |     if successful; otherwise returns false. | 
| 789 |  | 
| 790 |     \note The file must be open to use this function. | 
| 791 |  | 
| 792 |     \sa fileTime(), FileTime | 
| 793 | */ | 
| 794 | bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime) | 
| 795 | { | 
| 796 |     Q_D(QFileDevice); | 
| 797 |  | 
| 798 |     if (!d->engine()) { | 
| 799 |         d->setError(err: QFileDevice::UnspecifiedError, errStr: tr(s: "No file engine available" )); | 
| 800 |         return false; | 
| 801 |     } | 
| 802 |  | 
| 803 |     if (!d->fileEngine->setFileTime(newDate, time: fileTime)) { | 
| 804 |         d->setError(err: d->fileEngine->error(), errStr: d->fileEngine->errorString()); | 
| 805 |         return false; | 
| 806 |     } | 
| 807 |  | 
| 808 |     unsetError(); | 
| 809 |     return true; | 
| 810 | } | 
| 811 |  | 
| 812 | QT_END_NAMESPACE | 
| 813 |  | 
| 814 | #ifndef QT_NO_QOBJECT | 
| 815 | #include "moc_qfiledevice.cpp" | 
| 816 | #endif | 
| 817 |  |