From 7ef398e8fa7e283bf42eacfa9f0a514f6490aad2 Mon Sep 17 00:00:00 2001 From: Nikita Krupenko Date: Tue, 11 Aug 2015 17:12:56 -0300 Subject: QFileDevice/QFileInfo: Add fileTime() and setFileTime() [ChangeLog][QtCore][QFileDevice] Added fileTime() and setFileTime(). [ChangeLog][QtCore][QFileInfo] Added fileTime(). Task-number: QTBUG-984 Change-Id: I84dfb05b9454a54e26b57b78edee5773dc4c5c3c Initial-patch-by: Raphael Gozzo Reviewed-by: Thiago Macieira --- config.tests/unix/futimens/futimens.cpp | 47 +++++++++ config.tests/unix/futimens/futimens.pro | 1 + config.tests/unix/futimes/futimes.cpp | 47 +++++++++ config.tests/unix/futimes/futimes.pro | 1 + config.tests/unix/futimesat/futimesat.cpp | 47 +++++++++ config.tests/unix/futimesat/futimesat.pro | 1 + src/corelib/configure.json | 30 ++++++ src/corelib/global/qconfig-bootstrapped.h | 3 + src/corelib/io/qabstractfileengine.cpp | 12 +++ src/corelib/io/qabstractfileengine_p.h | 1 + src/corelib/io/qfiledevice.cpp | 76 ++++++++++++++ src/corelib/io/qfiledevice.h | 10 ++ src/corelib/io/qfileinfo.cpp | 47 ++++++++- src/corelib/io/qfileinfo.h | 7 ++ src/corelib/io/qfsfileengine.cpp | 4 + src/corelib/io/qfsfileengine_p.h | 1 + src/corelib/io/qfsfileengine_unix.cpp | 115 +++++++++++++++++++++ src/corelib/io/qfsfileengine_win.cpp | 96 +++++++++++++++++ src/corelib/io/qresource.cpp | 7 ++ src/corelib/io/qresource_p.h | 1 + .../android/qandroidassetsfileenginehandler.cpp | 7 ++ .../qiosfileengineassetslibrary.h | 1 + .../qiosfileengineassetslibrary.mm | 7 ++ src/plugins/platforms/winrt/qwinrtfileengine.cpp | 8 ++ src/plugins/platforms/winrt/qwinrtfileengine.h | 1 + .../tst_qabstractfileengine.cpp | 7 ++ tests/auto/corelib/io/qfile/tst_qfile.cpp | 1 + 27 files changed, 582 insertions(+), 4 deletions(-) create mode 100644 config.tests/unix/futimens/futimens.cpp create mode 100644 config.tests/unix/futimens/futimens.pro create mode 100644 config.tests/unix/futimes/futimes.cpp create mode 100644 config.tests/unix/futimes/futimes.pro create mode 100644 config.tests/unix/futimesat/futimesat.cpp create mode 100644 config.tests/unix/futimesat/futimesat.pro diff --git a/config.tests/unix/futimens/futimens.cpp b/config.tests/unix/futimens/futimens.cpp new file mode 100644 index 0000000000..1b66386ca1 --- /dev/null +++ b/config.tests/unix/futimens/futimens.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Raphael Gozzo +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +int main(int, char **) +{ + futimens(-1,0); + return 0; +} + diff --git a/config.tests/unix/futimens/futimens.pro b/config.tests/unix/futimens/futimens.pro new file mode 100644 index 0000000000..eb3ccc56c5 --- /dev/null +++ b/config.tests/unix/futimens/futimens.pro @@ -0,0 +1 @@ +SOURCES += futimens.cpp diff --git a/config.tests/unix/futimes/futimes.cpp b/config.tests/unix/futimes/futimes.cpp new file mode 100644 index 0000000000..553b39068e --- /dev/null +++ b/config.tests/unix/futimes/futimes.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Raphael Gozzo +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +int main(int, char **) +{ + futimes(-1,0); + return 0; +} + diff --git a/config.tests/unix/futimes/futimes.pro b/config.tests/unix/futimes/futimes.pro new file mode 100644 index 0000000000..8e7f2c0f62 --- /dev/null +++ b/config.tests/unix/futimes/futimes.pro @@ -0,0 +1 @@ +SOURCES += futimes.cpp diff --git a/config.tests/unix/futimesat/futimesat.cpp b/config.tests/unix/futimesat/futimesat.cpp new file mode 100644 index 0000000000..a0e2c5848d --- /dev/null +++ b/config.tests/unix/futimesat/futimesat.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Raphael Gozzo +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +int main(int, char **) +{ + futimesat(-1,0,0); + return 0; +} + diff --git a/config.tests/unix/futimesat/futimesat.pro b/config.tests/unix/futimesat/futimesat.pro new file mode 100644 index 0000000000..1b364e1977 --- /dev/null +++ b/config.tests/unix/futimesat/futimesat.pro @@ -0,0 +1 @@ +SOURCES += futimesat.cpp diff --git a/src/corelib/configure.json b/src/corelib/configure.json index c6c5c93ddb..0e9830c5e2 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -139,6 +139,21 @@ "type": "compile", "test": "unix/eventfd" }, + "futimens": { + "label": "futimens()", + "type": "compile", + "test": "unix/futimens" + }, + "futimes": { + "label": "futimes()", + "type": "compile", + "test": "unix/futimes" + }, + "futimesat": { + "label": "futimesat()", + "type": "compile", + "test": "unix/futimesat" + }, "posix-iconv": { "label": "POSIX iconv", "type": "compile", @@ -228,6 +243,21 @@ "condition": "tests.eventfd", "output": [ "feature" ] }, + "futimens": { + "label": "futimens()", + "condition": "!config.win32 && tests.futimens", + "output": [ "privateFeature" ] + }, + "futimes": { + "label": "futimes()", + "condition": "!config.win32 && !features.futimens && tests.futimes", + "output": [ "privateFeature" ] + }, + "futimesat": { + "label": "futimesat()", + "condition": "!config.win32 && !features.futimens && !features.futimes && tests.futimesat", + "output": [ "privateFeature" ] + }, "glib": { "label": "GLib", "autoDetect": "!config.win32", diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index bda8ad7916..5b8fee630a 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -71,6 +71,9 @@ #define QT_FEATURE_iconv -1 #define QT_FEATURE_icu -1 #define QT_FEATURE_journald -1 +#define QT_FEATURE_futimens -1 +#define QT_FEATURE_futimes -1 +#define QT_FEATURE_futimesat -1 #define QT_FEATURE_library -1 #define QT_NO_QOBJECT #define QT_FEATURE_process -1 diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 5f1f7e381e..85dc2f33a2 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -726,6 +726,18 @@ QString QAbstractFileEngine::owner(FileOwner owner) const return QString(); } +/*! + \fn bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time) + + \since 5.10 + Sets the file \a time to \a newDate, returning true if successful; + otherwise returns false. + + This virtual function must be reimplemented by all subclasses. + + \sa fileTime() +*/ + /*! If \a time is \c CreationTime, return when the file was created. If \a time is \c ModificationTime, return when the file was most diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h index dbf0d77b15..9d0a101b49 100644 --- a/src/corelib/io/qabstractfileengine_p.h +++ b/src/corelib/io/qabstractfileengine_p.h @@ -144,6 +144,7 @@ public: virtual QString fileName(FileName file=DefaultName) const; virtual uint ownerId(FileOwner) const; virtual QString owner(FileOwner) const; + virtual bool setFileTime(const QDateTime &newDate, FileTime time) = 0; virtual QDateTime fileTime(FileTime time) const; virtual void setFileName(const QString &file); virtual int handle() const; diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index ce9c8275ce..9e2e3fe741 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -738,4 +738,80 @@ bool QFileDevice::unmap(uchar *address) return false; } +/*! + \enum QFileDevice::FileTime + \since 5.10 + + This enum is used by the fileTime() and setFileTime() functions. + + \value FileCreationTime When the file was created (not supported on UNIX). + \value FileModificationTime When the file was most recently modified. + \value FileAccessTime When the file was most recently accessed (e.g. + read or written to). + + \sa setFileName(), fileTime() +*/ + +static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time) +{ + switch (time) { + case QFileDevice::FileAccessTime: + return QAbstractFileEngine::AccessTime; + + case QFileDevice::FileCreationTime: + return QAbstractFileEngine::CreationTime; + + case QFileDevice::FileModificationTime: + return QAbstractFileEngine::ModificationTime; + } + + Q_UNREACHABLE(); + return QAbstractFileEngine::AccessTime; +} + +/*! + \since 5.10 + Returns the file time specified by \a time. + If the time cannot be determined return QDateTime() (an invalid + date time). + + \sa setFileName(), FileTime, QDateTime::isValid() +*/ +QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const +{ + Q_D(const QFileDevice); + + if (d->engine()) + return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time)); + + return QDateTime(); +} + +/*! + \since 5.10 + Sets the file \a time to \a newDate, returning true if successful; + otherwise returns false. + + \note The file must be open to use this function. + + \sa fileTime(), FileTime +*/ +bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime) +{ + Q_D(QFileDevice); + + if (!d->engine()) { + d->setError(QFileDevice::UnspecifiedError, tr("No file engine available")); + return false; + } + + if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) { + d->setError(d->fileEngine->error(), d->fileEngine->errorString()); + return false; + } + + unsetError(); + return true; +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h index 4cfda1b044..3519a049a9 100644 --- a/src/corelib/io/qfiledevice.h +++ b/src/corelib/io/qfiledevice.h @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +class QDateTime; class QFileDevicePrivate; class Q_CORE_EXPORT QFileDevice : public QIODevice @@ -73,6 +74,12 @@ public: CopyError = 14 }; + enum FileTime { + FileCreationTime, + FileModificationTime, + FileAccessTime + }; + enum Permission { ReadOwner = 0x4000, WriteOwner = 0x2000, ExeOwner = 0x1000, ReadUser = 0x0400, WriteUser = 0x0200, ExeUser = 0x0100, @@ -119,6 +126,9 @@ public: uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions); bool unmap(uchar *address); + QDateTime fileTime(QFileDevice::FileTime time) const; + bool setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime); + protected: QFileDevice(); #ifdef QT_NO_QOBJECT diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 12fd7d3048..8025587a8b 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -262,8 +262,8 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) info objects, just append one to the file name given to the constructors or setFile(). - The file's dates are returned by created(), lastModified() and - lastRead(). Information about the file's access permissions is + The file's dates are returned by created(), lastModified(), lastRead() and + fileTime(). Information about the file's access permissions is obtained with isReadable(), isWritable() and isExecutable(). The file's ownership is available from owner(), ownerId(), group() and groupId(). You can examine a file's permissions and ownership in a @@ -1324,7 +1324,7 @@ QDateTime QFileInfo::created() const /*! Returns the date and local time when the file was last modified. - \sa created(), lastRead() + \sa created(), lastRead(), fileTime() */ QDateTime QFileInfo::lastModified() const { @@ -1346,7 +1346,7 @@ QDateTime QFileInfo::lastModified() const On platforms where this information is not available, returns the same as lastModified(). - \sa created(), lastModified() + \sa created(), lastModified(), fileTime() */ QDateTime QFileInfo::lastRead() const { @@ -1362,6 +1362,45 @@ QDateTime QFileInfo::lastRead() const return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime(); } +/*! + \enum QFileInfo::FileTime + \since 5.10 + + This enum is used by the fileTime() function. + + \value FileCreationTime When the file was created (not supported on UNIX). + \value FileModificationTime When the file was most recently modified. + \value FileAccessTime When the file was most recently accessed (e.g. + read or written to). + + \sa fileTime() +*/ + +/*! + \since 5.10 + Returns the file time specified by \a time. + If the time cannot be determined return QDateTime() (an invalid + date time). + + \sa FileTime, QDateTime::isValid() +*/ +QDateTime QFileInfo::fileTime(QFileInfo::FileTime time) const +{ + switch (time) { + case QFileInfo::FileCreationTime: + return created(); + + case QFileInfo::FileModificationTime: + return lastModified(); + + case QFileInfo::FileAccessTime: + return lastRead(); + + default: + Q_UNREACHABLE(); + } +} + /*! \internal */ diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index a160e8463e..669a1b6ad3 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -57,6 +57,12 @@ class Q_CORE_EXPORT QFileInfo { friend class QDirIteratorPrivate; public: + enum FileTime { + FileCreationTime, + FileModificationTime, + FileAccessTime + }; + explicit QFileInfo(QFileInfoPrivate *d); QFileInfo(); @@ -132,6 +138,7 @@ public: QDateTime created() const; QDateTime lastModified() const; QDateTime lastRead() const; + QDateTime fileTime(QFileInfo::FileTime time) const; bool caching() const; void setCaching(bool on); diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index e5f7e5b418..75478f0467 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -899,6 +899,10 @@ bool QFSFileEngine::supportsExtension(Extension extension) const \reimp */ +/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time) + \reimp +*/ + /*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const \reimp */ diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 742cebad87..80dd9363db 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -96,6 +96,7 @@ public: QString fileName(FileName file) const Q_DECL_OVERRIDE; uint ownerId(FileOwner) const Q_DECL_OVERRIDE; QString owner(FileOwner) const Q_DECL_OVERRIDE; + bool setFileTime(const QDateTime &newDate, FileTime time) Q_DECL_OVERRIDE; QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE; void setFileName(const QString &file) Q_DECL_OVERRIDE; int handle() const Q_DECL_OVERRIDE; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 51938d6967..4617d09874 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -100,6 +100,44 @@ static inline QString msgOpenDirectory() #endif } +#if !QT_CONFIG(futimens) && (QT_CONFIG(futimes) || QT_CONFIG(futimesat)) +namespace { +namespace GetFileTimes { + +template +static inline typename QtPrivate::QEnableIf<(&T::st_atim, &T::st_mtim, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification) +{ + access->tv_sec = p->st_atim.tv_sec; + access->tv_usec = p->st_atim.tv_nsec / 1000; + + modification->tv_sec = p->st_mtim.tv_sec; + modification->tv_usec = p->st_mtim.tv_nsec / 1000; +} + +template +static inline typename QtPrivate::QEnableIf<(&T::st_atimespec, &T::st_mtimespec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification) +{ + access->tv_sec = p->st_atimespec.tv_sec; + access->tv_usec = p->st_atimespec.tv_nsec / 1000; + + modification->tv_sec = p->st_mtimespec.tv_sec; + modification->tv_usec = p->st_mtimespec.tv_nsec / 1000; +} + +template +static inline typename QtPrivate::QEnableIf<(&T::st_atimensec, &T::st_mtimensec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification) +{ + access->tv_sec = p->st_atime; + access->tv_usec = p->st_atimensec / 1000; + + modification->tv_sec = p->st_mtime; + modification->tv_usec = p->st_mtimensec / 1000; +} + +} +} +#endif + /*! \internal */ @@ -584,6 +622,83 @@ bool QFSFileEngine::setSize(qint64 size) return ret; } +bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time) +{ + Q_D(QFSFileEngine); + + if (d->openMode == QIODevice::NotOpen) { + setError(QFile::PermissionsError, qt_error_string(EACCES)); + return false; + } + + if (!newDate.isValid() || time == QAbstractFileEngine::CreationTime) { + setError(QFile::UnspecifiedError, qt_error_string(EINVAL)); + return false; + } + +#if QT_CONFIG(futimens) + struct timespec ts[2]; + + ts[0].tv_sec = ts[1].tv_sec = 0; + ts[0].tv_nsec = ts[1].tv_nsec = UTIME_OMIT; + + const qint64 msecs = newDate.toMSecsSinceEpoch(); + + if (time == QAbstractFileEngine::AccessTime) { + ts[0].tv_sec = msecs / 1000; + ts[0].tv_nsec = (msecs % 1000) * 1000000; + } else if (time == QAbstractFileEngine::ModificationTime) { + ts[1].tv_sec = msecs / 1000; + ts[1].tv_nsec = (msecs % 1000) * 1000000; + } + + if (futimens(d->nativeHandle(), ts) == -1) { + setError(QFile::PermissionsError, qt_error_string()); + return false; + } + + d->metaData.clearFlags(QFileSystemMetaData::Times); + + return true; +#elif QT_CONFIG(futimes) || QT_CONFIG(futimesat) + struct timeval tv[2]; + QT_STATBUF st; + + if (QT_FSTAT(d->nativeHandle(), &st) == -1) { + setError(QFile::PermissionsError, qt_error_string()); + return false; + } + + GetFileTimes::get(&st, &tv[0], &tv[1]); + + const qint64 msecs = newDate.toMSecsSinceEpoch(); + + if (time == QAbstractFileEngine::AccessTime) { + tv[0].tv_sec = msecs / 1000; + tv[0].tv_usec = (msecs % 1000) * 1000; + } else if (time == QAbstractFileEngine::ModificationTime) { + tv[1].tv_sec = msecs / 1000; + tv[1].tv_usec = (msecs % 1000) * 1000; + } + +#if QT_CONFIG(futimes) + if (futimes(d->nativeHandle(), tv) == -1) { +#else + if (futimesat(d->nativeHandle(), NULL, tv) == -1) { +#endif + setError(QFile::PermissionsError, qt_error_string()); + return false; + } + + d->metaData.clearFlags(QFileSystemMetaData::Times); + + return true; +#else + setError(QFile::UnspecifiedError, qt_error_string(ENOSYS)); + return false; +#endif +} + QDateTime QFSFileEngine::fileTime(FileTime time) const { Q_D(const QFSFileEngine); diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 4a477b8429..5c6098c3b0 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -80,6 +80,39 @@ static inline bool isUncPath(const QString &path) && path.size() > 2 && path.at(2) != QLatin1Char('.')); } +static inline void QDateTimeToSystemTime(const QDateTime &date, SYSTEMTIME *systemTime) +{ + const QDate d = date.date(); + const QTime t = date.time(); + + systemTime->wYear = d.year(); + systemTime->wMonth = d.month(); + systemTime->wDay = d.day(); + systemTime->wHour = t.hour(); + systemTime->wMinute = t.minute(); + systemTime->wSecond = t.second(); + systemTime->wMilliseconds = t.msec(); + systemTime->wDayOfWeek = d.dayOfWeek() % 7; +} + +static inline bool QDateTimeToFileTime(const QDateTime &date, FILETIME *fileTime) +{ + SYSTEMTIME sTime; + +#if defined(Q_OS_WINCE) + QDateTimeToSystemTime(date, &sTime); +#else + SYSTEMTIME lTime; + + QDateTimeToSystemTime(date, &lTime); + + if (!::TzSpecificLocalTimeToSystemTime(0, &lTime, &sTime)) + return false; +#endif + + return ::SystemTimeToFileTime(&sTime, fileTime); +} + /*! \internal */ @@ -850,6 +883,69 @@ bool QFSFileEngine::setSize(qint64 size) return false; } +bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time) +{ + Q_D(QFSFileEngine); + + if (d->openMode == QFile::NotOpen) { + setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); + return false; + } + + if (!newDate.isValid()) { + setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER)); + return false; + } + + HANDLE handle = d->fileHandle; + +#ifndef Q_OS_WINCE + if (handle == INVALID_HANDLE_VALUE) { + if (d->fh) + handle = reinterpret_cast(::_get_osfhandle(QT_FILENO(d->fh))); + else if (d->fd != -1) + handle = reinterpret_cast(::_get_osfhandle(d->fd)); + } +#endif + + if (handle == INVALID_HANDLE_VALUE) { + setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); + return false; + } + + FILETIME fTime; + FILETIME *pLastWrite = NULL; + FILETIME *pLastAccess = NULL; + FILETIME *pCreationTime = NULL; + + switch (time) { + case QAbstractFileEngine::ModificationTime: + pLastWrite = &fTime; + break; + + case QAbstractFileEngine::AccessTime: + pLastAccess = &fTime; + break; + + case QAbstractFileEngine::CreationTime: + pCreationTime = &fTime; + break; + } + + if (!QDateTimeToFileTime(newDate, &fTime)) { + setError(QFile::UnspecifiedError, qt_error_string()); + return false; + } + + if (!::SetFileTime(handle, pCreationTime, pLastAccess, pLastWrite)) { + setError(QFile::PermissionsError, qt_error_string()); + return false; + } + + d->metaData.clearFlags(QFileSystemMetaData::Times); + + return true; +} QDateTime QFSFileEngine::fileTime(FileTime time) const { diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 984ed23812..ff31524c1c 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -1457,6 +1457,13 @@ QString QResourceFileEngine::owner(FileOwner) const return QString(); } +bool QResourceFileEngine::setFileTime(const QDateTime &newDate, FileTime time) +{ + Q_UNUSED(newDate); + Q_UNUSED(time); + return false; +} + QDateTime QResourceFileEngine::fileTime(FileTime time) const { Q_D(const QResourceFileEngine); diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h index e08ba64d2b..1b0f4f66e4 100644 --- a/src/corelib/io/qresource_p.h +++ b/src/corelib/io/qresource_p.h @@ -103,6 +103,7 @@ public: virtual uint ownerId(FileOwner) const Q_DECL_OVERRIDE; virtual QString owner(FileOwner) const Q_DECL_OVERRIDE; + virtual bool setFileTime(const QDateTime &newDate, FileTime time) Q_DECL_OVERRIDE; virtual QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE; virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index e1dcebfa4c..953377a3a9 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -206,6 +206,13 @@ public: return type & flags; } + bool setFileTime(const QDateTime &newDate, FileTime time) override + { + Q_UNUSED(newDate); + Q_UNUSED(time); + return false; + } + QString fileName(FileName file = DefaultName) const override { int pos; diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h index 8d7cabf15b..2387efc1f9 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h @@ -61,6 +61,7 @@ public: qint64 read(char *data, qint64 maxlen) override; qint64 pos() const override; bool seek(qint64 pos) override; + bool setFileTime(const QDateTime &newDate, FileTime time) override; QString fileName(FileName file) const override; void setFileName(const QString &file) override; QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override; diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm index bea2897240..fce257356f 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm @@ -435,6 +435,13 @@ bool QIOSFileEngineAssetsLibrary::seek(qint64 pos) return true; } +bool QIOSFileEngineAssetsLibrary::setFileTime(const QDateTime &newDate, FileTime time) +{ + Q_UNUSED(newDate); + Q_UNUSED(time); + return false; +} + QString QIOSFileEngineAssetsLibrary::fileName(FileName file) const { Q_UNUSED(file); diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp index dab2482ab3..f2f8b83e16 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -440,6 +440,14 @@ QDateTime QWinRTFileEngine::fileTime(FileTime type) const return QDateTime(date, time); } +bool QWinRTFileEngine::setFileTime(const QDateTime &newDate, FileTime time) +{ + Q_UNUSED(newDate); + Q_UNUSED(time); + Q_UNIMPLEMENTED(); + return false; +} + qint64 QWinRTFileEngine::read(char *data, qint64 maxlen) { Q_D(QWinRTFileEngine); diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h index 73ff54b0c8..5db83360ce 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.h +++ b/src/plugins/platforms/winrt/qwinrtfileengine.h @@ -89,6 +89,7 @@ public: bool setPermissions(uint perms) override; QString fileName(FileName type=DefaultName) const override; QDateTime fileTime(FileTime type) const override; + bool setFileTime(const QDateTime &newDate, FileTime time) override; qint64 read(char *data, qint64 maxlen) override; qint64 write(const char *data, qint64 len) override; diff --git a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp index dba920d1f7..4e5059c1a2 100644 --- a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp +++ b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp @@ -353,6 +353,13 @@ public: return QDateTime(); } + bool setFileTime(const QDateTime &newDate, FileTime time) + { + Q_UNUSED(newDate); + Q_UNUSED(time); + return false; + } + void setFileName(const QString &file) { if (openForRead_ || openForWrite_) diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 81c11ef085..9b12aa9616 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -2075,6 +2075,7 @@ public: uint ownerId(FileOwner) const { return 0; } QString owner(FileOwner) const { return QString(); } QDateTime fileTime(FileTime) const { return QDateTime(); } + bool setFileTime(const QDateTime &newDate, FileTime time) { return false; } private: int number; -- cgit v1.2.3