Index: autotests/jobtest.h =================================================================== --- autotests/jobtest.h +++ autotests/jobtest.h @@ -73,6 +73,9 @@ void rmdirEmpty(); void rmdirNotEmpty(); void stat(); +#ifndef Q_OS_WIN + void statSymlink(); +#endif void mostLocalUrl(); void chmodFile(); void chmodFileError(); Index: autotests/jobtest.cpp =================================================================== --- autotests/jobtest.cpp +++ autotests/jobtest.cpp @@ -1188,15 +1188,30 @@ #if 1 const QString filePath = homeTmpDir() + "fileFromHome"; createTestFile(filePath); - KIO::StatJob *job = KIO::stat(QUrl::fromLocalFile(filePath), KIO::HideProgressInfo); + const QUrl url(QUrl::fromLocalFile(filePath)); + KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo); QVERIFY(job); bool ok = job->exec(); QVERIFY(ok); // TODO set setSide, setDetails const KIO::UDSEntry &entry = job->statResult(); QVERIFY(!entry.isDir()); QVERIFY(!entry.isLink()); QCOMPARE(entry.stringValue(KIO::UDSEntry::UDS_NAME), QStringLiteral("fileFromHome")); + + // Compare what we get via kio_file and what we get when KFileItem stat()s directly + const KFileItem kioItem(entry, url); + const KFileItem fileItem(url); + QCOMPARE(kioItem.name(), fileItem.name()); + QCOMPARE(kioItem.url(), fileItem.url()); + QCOMPARE(kioItem.size(), fileItem.size()); + QCOMPARE(kioItem.user(), fileItem.user()); + QCOMPARE(kioItem.group(), fileItem.group()); + QCOMPARE(kioItem.mimetype(), fileItem.mimetype()); + QCOMPARE(kioItem.permissions(), fileItem.permissions()); + QCOMPARE(kioItem.time(KFileItem::ModificationTime), fileItem.time(KFileItem::ModificationTime)); + QCOMPARE(kioItem.time(KFileItem::AccessTime), fileItem.time(KFileItem::AccessTime)); + #else // Testing stat over HTTP KIO::StatJob *job = KIO::stat(QUrl("http://www.kde.org"), KIO::HideProgressInfo); @@ -1211,6 +1226,45 @@ #endif } +#ifndef Q_OS_WIN +void JobTest::statSymlink() +{ + const QString filePath = homeTmpDir() + "fileFromHome"; + createTestFile(filePath); + const QString symlink = otherTmpDir() + "link"; + QVERIFY(QFile(filePath).link(symlink)); + QVERIFY(QFile::exists(symlink)); + setTimeStamp(symlink, QDateTime::currentDateTime().addSecs(-20)); // differenciate link time and source file time + + const QUrl url(QUrl::fromLocalFile(symlink)); + KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo); + QVERIFY(job); + bool ok = job->exec(); + QVERIFY(ok); + // TODO set setSide, setDetails + const KIO::UDSEntry &entry = job->statResult(); + QVERIFY(!entry.isDir()); + QVERIFY(entry.isLink()); + QCOMPARE(entry.stringValue(KIO::UDSEntry::UDS_NAME), QStringLiteral("link")); + + // Compare what we get via kio_file and what we get when KFileItem stat()s directly + const KFileItem kioItem(entry, url); + const KFileItem fileItem(url); + QCOMPARE(kioItem.name(), fileItem.name()); + QCOMPARE(kioItem.url(), fileItem.url()); + QVERIFY(kioItem.isLink()); + QVERIFY(fileItem.isLink()); + QCOMPARE(kioItem.linkDest(), fileItem.linkDest()); + QCOMPARE(kioItem.size(), fileItem.size()); + QCOMPARE(kioItem.user(), fileItem.user()); + QCOMPARE(kioItem.group(), fileItem.group()); + QCOMPARE(kioItem.mimetype(), fileItem.mimetype()); + QCOMPARE(kioItem.permissions(), fileItem.permissions()); + QCOMPARE(kioItem.time(KFileItem::ModificationTime), fileItem.time(KFileItem::ModificationTime)); + QCOMPARE(kioItem.time(KFileItem::AccessTime), fileItem.time(KFileItem::AccessTime)); +} +#endif + void JobTest::mostLocalUrl() { const QString filePath = homeTmpDir() + "fileFromHome"; Index: autotests/kfileitemtest.cpp =================================================================== --- autotests/kfileitemtest.cpp +++ autotests/kfileitemtest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include "kiotesthelper.h" #include @@ -279,44 +280,57 @@ void KFileItemTest::testRefresh() { QTemporaryDir tempDir; + QFileInfo dirInfo(tempDir.path()); // Refresh on a dir KFileItem dirItem(QUrl::fromLocalFile(tempDir.path())); QVERIFY(dirItem.isDir()); QVERIFY(dirItem.entry().isDir()); + QCOMPARE(dirItem.time(KFileItem::ModificationTime), dirInfo.lastModified()); dirItem.refresh(); QVERIFY(dirItem.isDir()); QVERIFY(dirItem.entry().isDir()); + QCOMPARE(dirItem.time(KFileItem::ModificationTime), dirInfo.lastModified()); // Refresh on a file QFile file(tempDir.path() + "/afile"); QVERIFY(file.open(QIODevice::WriteOnly)); file.write("Hello world\n"); file.close(); + QFileInfo fileInfo(file.fileName()); const KIO::filesize_t expectedSize = 12; + QCOMPARE(KIO::filesize_t(fileInfo.size()), expectedSize); file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadOther); // 0604 KFileItem fileItem(QUrl::fromLocalFile(file.fileName())); QVERIFY(fileItem.isFile()); QVERIFY(!fileItem.isLink()); QCOMPARE(fileItem.size(), expectedSize); QCOMPARE(fileItem.user(), KUser().loginName()); + QCOMPARE(fileItem.time(KFileItem::ModificationTime), fileInfo.lastModified()); fileItem.refresh(); QVERIFY(fileItem.isFile()); QVERIFY(!fileItem.isLink()); QCOMPARE(fileItem.size(), expectedSize); QCOMPARE(fileItem.user(), KUser().loginName()); + QCOMPARE(fileItem.time(KFileItem::ModificationTime), fileInfo.lastModified()); // Refresh on a symlink to a file - QString symlink = tempDir.path() + "/asymlink"; + const QString symlink = tempDir.path() + "/asymlink"; QVERIFY(file.link(symlink)); - QUrl symlinkUrl = QUrl::fromLocalFile(symlink); + QDateTime symlinkTime = QDateTime::currentDateTime().addSecs(-20); + // we currently lose milliseconds.... + symlinkTime = symlinkTime.addMSecs(-symlinkTime.time().msec()); + setTimeStamp(symlink, symlinkTime); // differenciate link time and source file time + const QUrl symlinkUrl = QUrl::fromLocalFile(symlink); KFileItem symlinkItem(symlinkUrl); QVERIFY(symlinkItem.isFile()); QVERIFY(symlinkItem.isLink()); QCOMPARE(symlinkItem.size(), expectedSize); + QCOMPARE(symlinkItem.time(KFileItem::ModificationTime), symlinkTime); symlinkItem.refresh(); QVERIFY(symlinkItem.isFile()); QVERIFY(symlinkItem.isLink()); QCOMPARE(symlinkItem.size(), expectedSize); + QCOMPARE(symlinkItem.time(KFileItem::ModificationTime), symlinkTime); // Symlink to directory (#162544) QVERIFY(QFile::remove(symlink)); Index: src/core/kfileitem.cpp =================================================================== --- src/core/kfileitem.cpp +++ src/core/kfileitem.cpp @@ -172,9 +172,6 @@ // For special case like link to dirs over FTP QString m_guessedMimeType; mutable QString m_access; - - enum { NumFlags = KFileItem::CreationTime + 1 }; - mutable QDateTime m_time[3]; }; void KFileItemPrivate::init() @@ -199,12 +196,6 @@ if (QT_LSTAT(pathBA.constData(), &buf) == 0) { m_entry.insert(KIO::UDSEntry::UDS_DEVICE_ID, buf.st_dev); m_entry.insert(KIO::UDSEntry::UDS_INODE, buf.st_ino); - m_entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, buf.st_mtime); - m_entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, buf.st_atime); -#ifndef Q_OS_WIN - m_entry.insert(KIO::UDSEntry::UDS_USER, KUser(buf.st_uid).loginName()); - m_entry.insert(KIO::UDSEntry::UDS_GROUP, KUserGroup(buf.st_gid).name()); -#endif mode_t mode = buf.st_mode; if ((buf.st_mode & QT_STAT_MASK) == QT_STAT_LNK) { @@ -218,11 +209,12 @@ m_entry.insert(KIO::UDSEntry::UDS_SIZE, buf.st_size); m_entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, buf.st_mode & QT_STAT_MASK); // extract file type m_entry.insert(KIO::UDSEntry::UDS_ACCESS, buf.st_mode & 07777); // extract permissions - - // While we're at it, store the times - // TODO: the array of times can be removed, we can use UDS_*_TIME everywhere - setTime(KFileItem::ModificationTime, buf.st_mtime); - setTime(KFileItem::AccessTime, buf.st_atime); + m_entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, buf.st_mtime); // TODO: we could use msecs too... + m_entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, buf.st_atime); +#ifndef Q_OS_WIN + m_entry.insert(KIO::UDSEntry::UDS_USER, KUser(buf.st_uid).loginName()); + m_entry.insert(KIO::UDSEntry::UDS_GROUP, KUserGroup(buf.st_gid).name()); +#endif // TODO: these can be removed, we can use UDS_FILE_TYPE and UDS_ACCESS everywhere if (m_fileMode == KFileItem::Unknown) { @@ -297,48 +289,41 @@ return 0; } +static uint udsFieldForTime(KFileItem::FileTimes mappedWhich) +{ + switch (mappedWhich) { + case KFileItem::ModificationTime: + return KIO::UDSEntry::UDS_MODIFICATION_TIME; + case KFileItem::AccessTime: + return KIO::UDSEntry::UDS_ACCESS_TIME; + case KFileItem::CreationTime: + return KIO::UDSEntry::UDS_CREATION_TIME; + } + return 0; +} + void KFileItemPrivate::setTime(KFileItem::FileTimes mappedWhich, uint time_t_val) const { - setTime(mappedWhich, QDateTime::fromTime_t(time_t_val)); + m_entry.insert(udsFieldForTime(mappedWhich), time_t_val); } void KFileItemPrivate::setTime(KFileItem::FileTimes mappedWhich, const QDateTime &val) const { - m_time[mappedWhich] = val.toLocalTime(); // #160979 + const QDateTime dt = val.toLocalTime(); // #160979 + setTime(mappedWhich, dt.toTime_t()); } QDateTime KFileItemPrivate::time(KFileItem::FileTimes mappedWhich) const { - if (!m_time[mappedWhich].isNull()) { - return m_time[mappedWhich]; - } - // Extract it from the KIO::UDSEntry - long long fieldVal = -1; - switch (mappedWhich) { - case KFileItem::ModificationTime: - fieldVal = m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1); - break; - case KFileItem::AccessTime: - fieldVal = m_entry.numberValue(KIO::UDSEntry::UDS_ACCESS_TIME, -1); - break; - case KFileItem::CreationTime: - fieldVal = m_entry.numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1); - break; - } - if (fieldVal != -1) { - setTime(mappedWhich, QDateTime::fromMSecsSinceEpoch(1000 * fieldVal)); - return m_time[mappedWhich]; + const uint uds = udsFieldForTime(mappedWhich); + if (uds > 0) { + const long long fieldVal = m_entry.numberValue(uds, -1); + if (fieldVal != -1) { + return QDateTime::fromMSecsSinceEpoch(1000 * fieldVal); + } } - // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] - if (m_bIsLocalUrl) { - QFileInfo info(localPath()); - setTime(KFileItem::ModificationTime, info.lastModified()); - setTime(KFileItem::AccessTime, info.lastRead()); - setTime(KFileItem::CreationTime, info.created()); - return m_time[mappedWhich]; - } return QDateTime(); } @@ -357,7 +342,7 @@ //qDebug() << " m_bLink" << (m_bLink == item.m_bLink); //qDebug() << " m_hidden" << (m_hidden == item.m_hidden); //qDebug() << " size" << (size() == item.size()); - //qDebug() << " ModificationTime" << (time(KFileItem::ModificationTime) == item.time(KFileItem::ModificationTime)); + //qDebug() << " ModificationTime" << m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) << item.m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME); //qDebug() << " UDS_ICON_NAME" << (m_entry.stringValue( KIO::UDSEntry::UDS_ICON_NAME ) == item.m_entry.stringValue( KIO::UDSEntry::UDS_ICON_NAME )); #endif return (m_strName == item.m_strName @@ -370,7 +355,7 @@ && m_bLink == item.m_bLink && m_hidden == item.m_hidden && size() == item.size() - && time(KFileItem::ModificationTime) == item.time(KFileItem::ModificationTime) // TODO only if already known! + && m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) == item.m_entry.numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME) && m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME) == item.m_entry.stringValue(KIO::UDSEntry::UDS_ICON_NAME) );