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
parent
db433bdf65
commit
6c3a3d498a
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -113,9 +113,10 @@ public:
|
|||
OwnerGroup
|
||||
};
|
||||
enum FileTime {
|
||||
CreationTime,
|
||||
ModificationTime,
|
||||
AccessTime
|
||||
AccessTime,
|
||||
BirthTime,
|
||||
MetadataChangeTime,
|
||||
ModificationTime
|
||||
};
|
||||
|
||||
virtual ~QAbstractFileEngine();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -75,9 +75,10 @@ public:
|
|||
};
|
||||
|
||||
enum FileTime {
|
||||
FileCreationTime,
|
||||
FileModificationTime,
|
||||
FileAccessTime
|
||||
FileAccessTime,
|
||||
FileBirthTime,
|
||||
FileMetadataChangeTime,
|
||||
FileModificationTime
|
||||
};
|
||||
|
||||
enum Permission {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue