diff --git a/thumbnail/thumbnail.h b/thumbnail/thumbnail.h --- a/thumbnail/thumbnail.h +++ b/thumbnail/thumbnail.h @@ -69,6 +69,13 @@ **/ bool drawSubThumbnail(QPainter& p, const QString& filePath, int width, int height, int xPos, int yPos, int frameWidth); + + /** + * Checks if path is on the same filesystem as thumbnail cache directory. + * Returns true if so. False otherwise or if filesystem couldn't be checked. + */ + bool sharesFilesystemWithThumbRoot(const QString &path); + private: QString m_mimeType; int m_width; @@ -83,6 +90,7 @@ QSet m_propagationDirectories; QString m_thumbBasePath; qint64 m_maxFileSize; + dev_t m_thumbnailDirDeviceId = 0; }; #endif diff --git a/thumbnail/thumbnail.cpp b/thumbnail/thumbnail.cpp --- a/thumbnail/thumbnail.cpp +++ b/thumbnail/thumbnail.cpp @@ -28,6 +28,7 @@ #ifndef Q_OS_WIN #include #include +#include #include // nice() #endif @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +57,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -100,6 +106,8 @@ // int depth // Otherwise, the data returned is the image in PNG format. +Q_LOGGING_CATEGORY(KIO_THUMBNAIL_LOG, "kio_thumbnail") + using namespace KIO; //using namespace KCodecs; @@ -550,8 +558,9 @@ } dir.next(); + QString canonicalFilePath = dir.fileInfo().canonicalFilePath(); - if (validThumbnails > 0 && hadFirstThumbnail == dir.filePath()) { + if (validThumbnails > 0 && hadFirstThumbnail == canonicalFilePath) { break; // Never show the same thumbnail twice } @@ -561,7 +570,7 @@ continue; } - if (!drawSubThumbnail(p, dir.filePath(), segmentWidth, segmentHeight, xPos, yPos, frameWidth)) { + if (!drawSubThumbnail(p, canonicalFilePath, segmentWidth, segmentHeight, xPos, yPos, frameWidth)) { continue; } @@ -724,6 +733,20 @@ if (!thumbnail.load(thumbPath.absoluteFilePath(thumbName))) { // no cached version is available, a new thumbnail must be created + // If file is on encrypted filesystem, we can't cache it unless it's on the same filesystem as thumbnail directory + bool allowCache; +#ifdef _SYS_STAT_H + allowCache = sharesFilesystemWithThumbRoot(filePath); +#else + allowCache = false; +#endif + if (!allowCache) { + Solid::Device device = Solid::Device::storageAccessFromPath(filePath); + if (device.is()) { + allowCache = device.as()->usage() != Solid::StorageVolume::UsageType::Encrypted; + } + } + QSaveFile thumbnailfile(thumbPath.absoluteFilePath(thumbName)); bool savedCorrectly = false; if (subCreator->create(filePath, cacheSize, cacheSize, thumbnail)) { @@ -731,7 +754,7 @@ // The thumbnail has been created successfully. Store the thumbnail // to the cache for future access. - if (thumbnailfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + if (allowCache && thumbnailfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { savedCorrectly = thumbnail.save(&thumbnailfile, "PNG"); } } else { @@ -748,6 +771,24 @@ return true; } +bool ThumbnailProtocol::sharesFilesystemWithThumbRoot(const QString& path) +{ + if (!m_thumbnailDirDeviceId) { + struct stat baseStat; + if (lstat(QFile::encodeName(m_thumbBasePath).data(), &baseStat) == -1) { + qCWarning(KIO_THUMBNAIL_LOG) << "Cannot read information about filesystem"; + return false; + } + m_thumbnailDirDeviceId = baseStat.st_dev; + } + struct stat fileStat; + if(lstat(QFile::encodeName(path).data(), &fileStat) == -1) { + qCWarning(KIO_THUMBNAIL_LOG) << "Cannot read information about filesystem"; + return false; + } + return m_thumbnailDirDeviceId == fileStat.st_dev; +} + void ThumbnailProtocol::scaleDownImage(QImage& img, int maxWidth, int maxHeight) { if (img.width() > maxWidth || img.height() > maxHeight) {