Filesystem: Use "birth time" to avoid confusion with Unix ctime

The Unix stat fields "st_ctime" and "st_ctim" mean "change time", the
last time that the file/inode status fields were changed. It does not
mean "creation time". So this commit splits all of the internal API to
"birth" and "metadata change" instead of "creation" to avoid the
conflict.

Change-Id: I149e0540c00745fe8119fffd1463fe78b619649e
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
bb10
Thiago Macieira 2016-07-23 11:14:57 -07:00
parent db433bdf65
commit 6c3a3d498a
15 changed files with 228 additions and 185 deletions

View File

@ -328,7 +328,8 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
These are used by the fileTime() function.
\value CreationTime When the file was created.
\value BirthTime When the file was born (created).
\value MetadataChangeTime When the file's metadata was last changed.
\value ModificationTime When the file was most recently modified.
\value AccessTime When the file was most recently accessed (e.g.
read or written to).
@ -756,12 +757,12 @@ bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
}
/*!
If \a time is \c CreationTime, return when the file was created.
If \a time is \c ModificationTime, return when the file was most
recently modified. If \a time is \c AccessTime, return when the
file was most recently accessed (e.g. read or written).
If the time cannot be determined return QDateTime() (an invalid
date time).
If \a time is \c BirthTime, return when the file was born (created). If \a
time is \c MetadataChangeTime, return when the file's metadata was last
changed. If \a time is \c ModificationTime, return when the file was most
recently modified. If \a time is \c AccessTime, return when the file was
most recently accessed (e.g. read or written). If the time cannot be
determined return QDateTime() (an invalid date time).
This virtual function must be reimplemented by all subclasses.

View File

@ -113,9 +113,10 @@ public:
OwnerGroup
};
enum FileTime {
CreationTime,
ModificationTime,
AccessTime
AccessTime,
BirthTime,
MetadataChangeTime,
ModificationTime
};
virtual ~QAbstractFileEngine();

View File

@ -744,29 +744,23 @@ bool QFileDevice::unmap(uchar *address)
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).
\value FileAccessTime When the file was most recently accessed
(e.g. read or written to).
\value FileBirthTime When the file was created (may not be not
supported on UNIX).
\value FileMetadataChangeTime When the file's metadata was last changed.
\value FileModificationTime When the file was most recently modified.
\sa setFileTime(), fileTime()
\sa setFileTime(), fileTime(), QFileInfo::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;
Q_STATIC_ASSERT(int(QFileDevice::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
Q_STATIC_ASSERT(int(QFileDevice::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
Q_STATIC_ASSERT(int(QFileDevice::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
Q_STATIC_ASSERT(int(QFileDevice::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
return QAbstractFileEngine::FileTime(time);
}
/*!

View File

@ -75,9 +75,10 @@ public:
};
enum FileTime {
FileCreationTime,
FileModificationTime,
FileAccessTime
FileAccessTime,
FileBirthTime,
FileMetadataChangeTime,
FileModificationTime
};
enum Permission {

View File

@ -194,8 +194,11 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
case QAbstractFileEngine::AccessTime:
cf = CachedATime;
break;
case QAbstractFileEngine::CreationTime:
cf = CachedCTime;
case QAbstractFileEngine::BirthTime:
cf = CachedBTime;
break;
case QAbstractFileEngine::MetadataChangeTime:
cf = CachedMCTime;
break;
case QAbstractFileEngine::ModificationTime:
cf = CachedMTime;
@ -1316,7 +1319,10 @@ qint64 QFileInfo::size() const
*/
QDateTime QFileInfo::created() const
{
return fileTime(QFile::FileCreationTime);
QDateTime d = fileTime(QFile::FileBirthTime);
if (d.isValid())
return d;
return fileTime(QFile::FileMetadataChangeTime);
}
#endif
@ -1331,7 +1337,7 @@ QDateTime QFileInfo::created() const
*/
QDateTime QFileInfo::birthTime() const
{
return fileTime(QFile::FileCreationTime);
return fileTime(QFile::FileBirthTime);
}
/*!
@ -1345,7 +1351,7 @@ QDateTime QFileInfo::birthTime() const
*/
QDateTime QFileInfo::metadataChangeTime() const
{
return fileTime(QFile::FileCreationTime);
return fileTime(QFile::FileMetadataChangeTime);
}
/*!
@ -1373,16 +1379,17 @@ QDateTime QFileInfo::lastRead() const
/*!
\since 5.10
Returns the file time specified by \a time.
If the time cannot be determined return QDateTime() (an invalid
date time).
Returns the file time specified by \a time. If the time cannot be
determined, an invalid date time is returned.
\sa QFile::FileTime, QDateTime::isValid()
*/
QDateTime QFileInfo::fileTime(QFile::FileTime time) const
{
Q_STATIC_ASSERT(int(QFile::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
Q_STATIC_ASSERT(int(QFile::FileCreationTime) == int(QAbstractFileEngine::CreationTime));
Q_STATIC_ASSERT(int(QFile::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
Q_STATIC_ASSERT(int(QFile::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
Q_STATIC_ASSERT(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
Q_D(const QFileInfo);
@ -1397,8 +1404,11 @@ QDateTime QFileInfo::fileTime(QFile::FileTime time) const
case QFile::FileAccessTime:
flag = QFileSystemMetaData::AccessTime;
break;
case QFile::FileCreationTime:
flag = QFileSystemMetaData::CreationTime;
case QFile::FileBirthTime:
flag = QFileSystemMetaData::BirthTime;
break;
case QFile::FileMetadataChangeTime:
flag = QFileSystemMetaData::MetadataChangeTime;
break;
case QFile::FileModificationTime:
flag = QFileSystemMetaData::ModificationTime;

View File

@ -66,9 +66,18 @@ QT_BEGIN_NAMESPACE
class QFileInfoPrivate : public QSharedData
{
public:
enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
CachedSize =0x08, CachedPerms=0x80 };
enum {
// note: cachedFlags is only 30-bits wide
CachedFileFlags = 0x01,
CachedLinkTypeFlag = 0x02,
CachedBundleTypeFlag = 0x04,
CachedSize = 0x08,
CachedATime = 0x10,
CachedBTime = 0x20,
CachedMCTime = 0x40,
CachedMTime = 0x80,
CachedPerms = 0x100
};
inline QFileInfoPrivate()
: QSharedData(), fileEngine(0),

View File

@ -293,15 +293,14 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
#endif
// Times
birthTime_ = 0;
#if _POSIX_VERSION >= 200809L
modificationTime_ = timespecToMSecs(statBuffer.st_mtim);
creationTime_ = timespecToMSecs(statBuffer.st_ctim);
if (!creationTime_)
creationTime_ = modificationTime_;
metadataChangeTime_ = timespecToMSecs(statBuffer.st_ctim);
accessTime_ = timespecToMSecs(statBuffer.st_atim);
#else
creationTime_ = qint64(statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime) * 1000;
modificationTime_ = qint64(statBuffer.st_mtime) * 1000;
metadataChangeTime_ = qint64(statBuffer.st_ctime) * 1000;
accessTime_ = qint64(statBuffer.st_atime) * 1000;
#endif
userId_ = statBuffer.st_uid;

View File

@ -518,7 +518,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
data.fillFromStatBuf(statBuffer);
else {
entryExists = false;
data.creationTime_ = 0;
data.birthTime_ = 0;
data.metadataChangeTime_ = 0;
data.modificationTime_ = 0;
data.accessTime_ = 0;
data.size_ = 0;
@ -844,7 +845,8 @@ bool QFileSystemEngine::setPermissions(int fd, QFile::Permissions permissions, Q
//static
bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractFileEngine::FileTime time, QSystemError &error)
{
if (!newDate.isValid() || time == QAbstractFileEngine::CreationTime) {
if (!newDate.isValid() || time == QAbstractFileEngine::BirthTime ||
time == QAbstractFileEngine::MetadataChangeTime) {
error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
return false;
}

View File

@ -412,7 +412,8 @@ void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
{
data.size_ = 0;
data.fileAttribute_ = 0;
data.creationTime_ = FILETIME();
data.birthTime_ = FILETIME();
data.changeTime_ = FILETIME();
data.lastAccessTime_ = FILETIME();
data.lastWriteTime_ = FILETIME();
}
@ -610,7 +611,7 @@ bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
pLastAccess = &fTime;
break;
case QAbstractFileEngine::CreationTime:
case QAbstractFileEngine::BirthTime:
pCreationTime = &fTime;
break;
@ -889,8 +890,10 @@ bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
FILE_BASIC_INFO fileBasicInfo;
if (GetFileInformationByHandleEx(fHandle, FileBasicInfo, &fileBasicInfo, sizeof(fileBasicInfo))) {
data.fillFromFileAttribute(fileBasicInfo.FileAttributes);
data.creationTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart;
data.creationTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart;
data.birthTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart;
data.birthTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart;
data.changeTime_.dwHighDateTime = fileBasicInfo.ChangeTime.HighPart;
data.changeTime_.dwLowDateTime = fileBasicInfo.ChangeTime.LowPart;
data.lastAccessTime_.dwHighDateTime = fileBasicInfo.LastAccessTime.HighPart;
data.lastAccessTime_.dwLowDateTime = fileBasicInfo.LastAccessTime.LowPart;
data.lastWriteTime_.dwHighDateTime = fileBasicInfo.LastWriteTime.HighPart;
@ -1347,6 +1350,9 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
if (time->dwHighDateTime == 0 && time->dwLowDateTime == 0)
return QDateTime();
SYSTEMTIME sTime;
FileTimeToSystemTime(time, &sTime);
return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
@ -1354,9 +1360,13 @@ static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
Qt::UTC);
}
QDateTime QFileSystemMetaData::creationTime() const
QDateTime QFileSystemMetaData::birthTime() const
{
return fileTimeToQDateTime(&creationTime_);
return fileTimeToQDateTime(&birthTime_);
}
QDateTime QFileSystemMetaData::metadataChangeTime() const
{
return fileTimeToQDateTime(&changeTime_);
}
QDateTime QFileSystemMetaData::modificationTime() const
{

View File

@ -129,12 +129,13 @@ public:
Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute | WasDeletedAttribute,
// Times
CreationTime = 0x01000000, // Note: overlaps with QAbstractFileEngine::Refresh
// Times - if we know one of them, we know them all
AccessTime = 0x02000000,
BirthTime = 0x02000000,
MetadataChangeTime = 0x02000000,
ModificationTime = 0x02000000,
AccessTime = 0x04000000,
Times = CreationTime | ModificationTime | AccessTime,
Times = AccessTime | BirthTime | MetadataChangeTime | ModificationTime,
// Owner IDs
UserId = 0x10000000,
@ -208,9 +209,10 @@ public:
QFile::Permissions permissions() const { return QFile::Permissions(Permissions & entryFlags); }
QDateTime creationTime() const;
QDateTime modificationTime() const;
QDateTime accessTime() const;
QDateTime birthTime() const;
QDateTime metadataChangeTime() const;
QDateTime modificationTime() const;
QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
uint userId() const;
@ -240,14 +242,16 @@ private:
// Platform-specific data goes here:
#if defined(Q_OS_WIN)
DWORD fileAttribute_;
FILETIME creationTime_;
FILETIME birthTime_;
FILETIME changeTime_;
FILETIME lastAccessTime_;
FILETIME lastWriteTime_;
#else
// msec precision
qint64 creationTime_;
qint64 modificationTime_;
qint64 accessTime_;
qint64 birthTime_;
qint64 metadataChangeTime_;
qint64 modificationTime_;
uint userId_;
uint groupId_;
@ -275,8 +279,11 @@ inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime tim
case QAbstractFileEngine::AccessTime:
return accessTime();
case QAbstractFileEngine::CreationTime:
return creationTime();
case QAbstractFileEngine::BirthTime:
return birthTime();
case QAbstractFileEngine::MetadataChangeTime:
return metadataChangeTime();
}
return QDateTime();
@ -284,7 +291,9 @@ inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime tim
#endif
#if defined(Q_OS_UNIX)
inline QDateTime QFileSystemMetaData::creationTime() const { return QDateTime::fromMSecsSinceEpoch(creationTime_); }
inline QDateTime QFileSystemMetaData::birthTime() const
{ return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_) : QDateTime(); }
inline QDateTime QFileSystemMetaData::metadataChangeTime() const { return QDateTime::fromMSecsSinceEpoch(metadataChangeTime_); }
inline QDateTime QFileSystemMetaData::modificationTime() const { return QDateTime::fromMSecsSinceEpoch(modificationTime_); }
inline QDateTime QFileSystemMetaData::accessTime() const { return QDateTime::fromMSecsSinceEpoch(accessTime_); }
@ -325,9 +334,9 @@ inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool
inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot)
{
fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot);
creationTime_ = findData.ftCreationTime;
birthTime_ = findData.ftCreationTime;
lastAccessTime_ = findData.ftLastAccessTime;
lastWriteTime_ = findData.ftLastWriteTime;
changeTime_ = lastWriteTime_ = findData.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {
@ -350,9 +359,9 @@ inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, boo
inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
{
fillFromFileAttribute(fileInfo.dwFileAttributes);
creationTime_ = fileInfo.ftCreationTime;
birthTime_ = fileInfo.ftCreationTime;
lastAccessTime_ = fileInfo.ftLastAccessTime;
lastWriteTime_ = fileInfo.ftLastWriteTime;
changeTime_ = lastWriteTime_ = fileInfo.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {

View File

@ -864,7 +864,7 @@ bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
return false;
}
if (!newDate.isValid()) {
if (!newDate.isValid() || time == QAbstractFileEngine::MetadataChangeTime) {
setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
return false;
}

View File

@ -414,10 +414,11 @@ QDateTime QWinRTFileEngine::fileTime(FileTime type) const
HRESULT hr;
DateTime dateTime = { 0 };
switch (type) {
case CreationTime:
case BirthTime:
hr = d->file->get_DateCreated(&dateTime);
RETURN_IF_FAILED("Failed to get file creation time", return QDateTime());
break;
case MetadataChangeTime:
case ModificationTime:
case AccessTime: {
ComPtr<IAsyncOperation<FileProperties::BasicProperties *>> op;

View File

@ -341,8 +341,10 @@ public:
if (file) {
QMutexLocker lock(&file->mutex);
switch (time) {
case CreationTime:
return file->creation;
case BirthTime:
return file->birth;
case MetadataChangeTime:
return file->change;
case ModificationTime:
return file->modification;
case AccessTime:
@ -456,7 +458,7 @@ protected:
uint userId, groupId;
QAbstractFileEngine::FileFlags fileFlags;
QDateTime creation, modification, access;
QDateTime birth, change, modification, access;
QByteArray content;
};

View File

@ -35,6 +35,7 @@
#include <qtemporarydir.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qstorageinfo.h>
#ifdef Q_OS_UNIX
#include <errno.h>
#include <fcntl.h>
@ -64,84 +65,38 @@
#define Q_NO_SYMLINKS
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
inline bool qt_isEvilFsTypeName(const char *name)
inline bool qIsLikelyToBeFat(const QString &path)
{
QByteArray name = QStorageInfo(path).fileSystemType().toLower();
return name.contains("fat") || name.contains("msdos");
}
inline bool qIsLikelyToBeNfs(const QString &path)
{
#ifdef Q_OS_WIN
Q_UNUSED(path);
return false;
#else
QByteArray type = QStorageInfo(path).fileSystemType();
const char *name = type.constData();
return (qstrncmp(name, "nfs", 3) == 0
|| qstrncmp(name, "autofs", 6) == 0
|| qstrncmp(name, "autofsng", 8) == 0
|| qstrncmp(name, "cachefs", 7) == 0);
}
#if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)
# include <sys/param.h>
# include <sys/mount.h>
bool qIsLikelyToBeNfs(int handle)
{
struct statfs buf;
if (fstatfs(handle, &buf) != 0)
return false;
return qt_isEvilFsTypeName(buf.f_fstypename);
}
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
# include <sys/vfs.h>
# ifdef QT_LINUXBASE
// LSB 3.2 has fstatfs in sys/statfs.h, sys/vfs.h is just an empty dummy header
# include <sys/statfs.h>
# endif
# ifndef NFS_SUPER_MAGIC
# define NFS_SUPER_MAGIC 0x00006969
# endif
# ifndef AUTOFS_SUPER_MAGIC
# define AUTOFS_SUPER_MAGIC 0x00000187
# endif
# ifndef AUTOFSNG_SUPER_MAGIC
# define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
# endif
bool qIsLikelyToBeNfs(int handle)
{
struct statfs buf;
if (fstatfs(handle, &buf) != 0)
return false;
return buf.f_type == NFS_SUPER_MAGIC
|| buf.f_type == AUTOFS_SUPER_MAGIC
|| buf.f_type == AUTOFSNG_SUPER_MAGIC;
}
#elif defined(Q_OS_SOLARIS) || defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) \
|| defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_SCO) \
|| defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT) || defined(Q_OS_NETBSD)
# include <sys/statvfs.h>
bool qIsLikelyToBeNfs(int handle)
{
struct statvfs buf;
if (fstatvfs(handle, &buf) != 0)
return false;
#if defined(Q_OS_NETBSD)
return qt_isEvilFsTypeName(buf.f_fstypename);
#else
return qt_isEvilFsTypeName(buf.f_basetype);
#endif
}
#else
inline bool qIsLikelyToBeNfs(int /* handle */)
{
return false;
}
#endif
#endif
static QString seedAndTemplate()
{
qsrand(QDateTime::currentSecsSinceEpoch());
return QDir::tempPath() + "/tst_qfileinfo-XXXXXX";
QString base;
#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID)
// use XDG_RUNTIME_DIR as it's a fully-capable FS
base = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
#endif
if (base.isEmpty())
base = QDir::tempPath();
return base + "/tst_qfileinfo-XXXXXX";
}
static QByteArray msgDoesNotExist(const QString &name)
@ -1129,43 +1084,92 @@ void tst_QFileInfo::fileTimes_data()
void tst_QFileInfo::fileTimes()
{
int sleepTime = 2000;
auto datePairString = [](const QDateTime &actual, const QDateTime &before) {
return (actual.toString(Qt::ISODateWithMs) + " (should be >) " + before.toString(Qt::ISODateWithMs))
.toLatin1();
};
QFETCH(QString, fileName);
int sleepTime = 100;
// on Linux and Windows, the filesystem timestamps may be slightly out of
// sync with the system clock (maybe they're using CLOCK_REALTIME_COARSE),
// so add a margin of error to our comparisons
int fsClockSkew = 10;
#ifdef Q_OS_WIN
fsClockSkew = 500;
#endif
// NFS clocks may be WAY out of sync
if (qIsLikelyToBeNfs(fileName))
QSKIP("This test doesn't work on NFS");
bool noAccessTime = false;
{
// try to guess if file times on this filesystem round to the second
QFileInfo cwd(".");
if (cwd.lastModified().toMSecsSinceEpoch() % 1000 == 0
&& cwd.lastRead().toMSecsSinceEpoch() % 1000 == 0) {
fsClockSkew = sleepTime = 1000;
noAccessTime = qIsLikelyToBeFat(fileName);
if (noAccessTime) {
// FAT filesystems (but maybe not exFAT) store timestamps with 2-second
// granularity and access time with 1-day granularity
fsClockSkew = sleepTime = 2000;
}
}
}
if (QFile::exists(fileName)) {
QVERIFY(QFile::remove(fileName));
}
QTest::qSleep(sleepTime);
QDateTime beforeBirth, beforeWrite, beforeMetadataChange, beforeRead;
QDateTime birthTime, writeTime, metadataChangeTime, readTime;
// --- Create file and write to it
beforeBirth = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
if (qIsLikelyToBeNfs(file.handle()))
QSKIP("This Test doesn't work on NFS");
#endif
QFileInfo fileInfo(fileName);
birthTime = fileInfo.birthTime();
QVERIFY2(!birthTime.isValid() || birthTime > beforeBirth,
datePairString(birthTime, beforeBirth));
QTest::qSleep(sleepTime);
beforeWrite = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
QTextStream ts(&file);
ts << fileName << endl;
}
QTest::qSleep(sleepTime);
QDateTime beforeWrite = QDateTime::currentDateTime();
QTest::qSleep(sleepTime);
{
QFileInfo fileInfo(fileName);
QVERIFY(!fileInfo.birthTime().isValid() || fileInfo.birthTime() < beforeWrite);
QVERIFY(fileInfo.metadataChangeTime() < beforeWrite);
QVERIFY(fileInfo.created() < beforeWrite);
writeTime = fileInfo.lastModified();
QVERIFY2(writeTime > beforeWrite, datePairString(writeTime, beforeWrite));
QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
}
// --- Change the file's metadata
QTest::qSleep(sleepTime);
beforeMetadataChange = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::ReadWrite | QFile::Text));
QTextStream ts(&file);
ts << fileName << endl;
file.setPermissions(file.permissions());
}
QTest::qSleep(sleepTime);
QDateTime beforeRead = QDateTime::currentDateTime();
QTest::qSleep(sleepTime);
{
QFileInfo fileInfo(fileName);
QVERIFY(!fileInfo.birthTime().isValid() || fileInfo.birthTime() < beforeWrite);
QVERIFY(fileInfo.metadataChangeTime() > beforeWrite);
QVERIFY(fileInfo.lastModified() > beforeWrite);
metadataChangeTime = fileInfo.metadataChangeTime();
QVERIFY2(metadataChangeTime > beforeMetadataChange,
datePairString(metadataChangeTime, beforeMetadataChange));
QVERIFY(metadataChangeTime >= writeTime); // not all filesystems can store both times
QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
}
// --- Read the file
QTest::qSleep(sleepTime);
beforeRead = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
QTextStream ts(&file);
@ -1174,13 +1178,17 @@ void tst_QFileInfo::fileTimes()
}
QFileInfo fileInfo(fileName);
QVERIFY(!fileInfo.birthTime().isValid() || fileInfo.birthTime() < beforeWrite);
QVERIFY(fileInfo.metadataChangeTime() > beforeWrite);
readTime = fileInfo.lastRead();
QCOMPARE(fileInfo.lastModified(), writeTime); // mustn't have changed
QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
QVERIFY(readTime.isValid());
#if defined(Q_OS_WINRT) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID)
noAccessTime = true;
#elif defined(Q_OS_WIN)
//In Vista the last-access timestamp is not updated when the file is accessed/touched (by default).
//To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate
//is set to 0, in the test machine.
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
HKEY key;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
0, KEY_READ, &key)) {
@ -1189,22 +1197,16 @@ void tst_QFileInfo::fileTimes()
LONG error = RegQueryValueEx(key, L"NtfsDisableLastAccessUpdate"
, NULL, NULL, (LPBYTE)&disabledAccessTimes, &size);
if (ERROR_SUCCESS == error && disabledAccessTimes)
QEXPECT_FAIL("", "File access times are disabled in windows registry (this is the default setting)", Continue);
noAccessTime = true;
RegCloseKey(key);
}
#endif
#if defined(Q_OS_WINRT)
QEXPECT_FAIL("", "WinRT does not allow timestamp handling change in the filesystem due to sandboxing", Continue);
#elif defined(Q_OS_QNX)
QEXPECT_FAIL("", "QNX uses the noatime filesystem option", Continue);
#elif defined(Q_OS_ANDROID)
if (fileInfo.lastRead() <= beforeRead)
QEXPECT_FAIL("", "Android may use relatime or noatime on mounts", Continue);
#endif
QVERIFY(fileInfo.lastRead() > beforeRead);
QVERIFY(fileInfo.lastModified() > beforeWrite);
QVERIFY(fileInfo.lastModified() < beforeRead);
if (noAccessTime)
return;
QVERIFY2(readTime > beforeRead, datePairString(readTime, beforeRead));
QVERIFY(writeTime < beforeRead);
}
void tst_QFileInfo::fileTimes_oldFile()

View File

@ -66,14 +66,16 @@ void tst_QFileSystemMetaData::timeSinceEpoch()
/* data.ftLastAccessTime = data.ftLastWriteTime = */
data.ftCreationTime = epochToFileTime(afterEpochUtc);
meta.fillFromFindData(data);
QCOMPARE(meta.birthTime().toUTC(),
QDateTime::fromMSecsSinceEpoch(afterEpochUtc * qint64(1000), Qt::UTC));
#else
QT_STATBUF data;
memset(&data, 0, sizeof(data));
data.st_ctime = afterEpochUtc;
meta.fillFromStatBuf(data);
#endif
QCOMPARE(meta.creationTime().toUTC(),
QCOMPARE(meta.metadataChangeTime().toUTC(),
QDateTime::fromMSecsSinceEpoch(afterEpochUtc * qint64(1000), Qt::UTC));
#endif
}
#else // i.e. no Q_AUTOTEST_EXPORT
void tst_QFileSystemMetaData::timeSinceEpoch()