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