File indexing completed on 2024-05-05 03:56:09

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef TRASHIMPL_H
0009 #define TRASHIMPL_H
0010 
0011 #include "global.h"
0012 #include "udsentry.h"
0013 #include <kio/job.h>
0014 
0015 #include <KConfig>
0016 
0017 #include <QDateTime>
0018 #include <QMap>
0019 
0020 namespace Solid
0021 {
0022 class Device;
0023 }
0024 
0025 /**
0026  * Implementation of all low-level operations done by kio_trash.
0027  * The structure of the trash directory follows the freedesktop.org standard:
0028  * https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
0029  */
0030 class TrashImpl : public QObject
0031 {
0032     Q_OBJECT
0033 public:
0034     TrashImpl();
0035 
0036     /// Check the "home" trash directory
0037     /// This MUST be called before doing anything else
0038     bool init();
0039 
0040     /// Create info for a file to be trashed
0041     /// Returns trashId and fileId
0042     /// The caller is then responsible for actually trashing the file
0043     bool createInfo(const QString &origPath, int &trashId, QString &fileId);
0044 
0045     /// Delete info file for a file to be trashed
0046     /// Usually used for undoing what createInfo did if trashing failed
0047     bool deleteInfo(int trashId, const QString &fileId);
0048 
0049     /// Moving a file or directory into the trash. The ids come from createInfo.
0050     bool moveToTrash(const QString &origPath, int trashId, const QString &fileId);
0051 
0052     /// Moving a file or directory out of the trash. The ids come from createInfo.
0053     bool moveFromTrash(const QString &origPath, int trashId, const QString &fileId, const QString &relativePath);
0054 
0055     /// Copying a file or directory into the trash. The ids come from createInfo.
0056     bool copyToTrash(const QString &origPath, int trashId, const QString &fileId);
0057 
0058     /// Copying a file or directory out of the trash. The ids come from createInfo.
0059     bool copyFromTrash(const QString &origPath, int trashId, const QString &fileId, const QString &relativePath);
0060 
0061     /// Renaming a file or directory in the trash.
0062     bool moveInTrash(int trashId, const QString &oldFileId, const QString &newFileId);
0063 
0064     /// Get rid of a trashed file
0065     bool del(int trashId, const QString &fileId);
0066 
0067     /// Empty trash, i.e. delete all trashed files
0068     bool emptyTrash();
0069 
0070     /// Return true if the trash is empty
0071     bool isEmpty() const;
0072 
0073     struct TrashedFileInfo {
0074         int trashId; // for the url
0075         QString fileId; // for the url
0076         QString physicalPath; // for stat'ing etc.
0077         QString origPath; // from info file
0078         QDateTime deletionDate; // from info file
0079     };
0080     /// List trashed files
0081     using TrashedFileInfoList = QList<TrashedFileInfo>;
0082 
0083     /// Returns the TrashedFileInfo of all files in all trashes
0084     /// uses scanTrashDirectories() to refresh m_trashDirectories
0085     TrashedFileInfoList list();
0086 
0087     /// Return the info for a given trashed file
0088     bool infoForFile(int trashId, const QString &fileId, TrashedFileInfo &info);
0089 
0090     struct TrashSpaceInfo {
0091         qint64 totalSize; // total trash size in bytes
0092         qint64 availableSize; // available trash space in bytes
0093     };
0094     /// Get the space info for a given trash path
0095     /// Space information is only valid if trashSpaceInfo returns true
0096     bool trashSpaceInfo(const QString &path, TrashSpaceInfo &info);
0097 
0098     /// Returns an UDSEntry corresponding to trash:/
0099     KIO::UDSEntry trashUDSEntry(KIO::StatDetails details);
0100 
0101     /// Return the physicalPath for a given trashed file - helper method which
0102     /// encapsulates the call to infoForFile. Don't use if you need more info from TrashedFileInfo.
0103     QString physicalPath(int trashId, const QString &fileId, const QString &relativePath);
0104 
0105     /// Move data from the old trash system to the new one
0106     void migrateOldTrash();
0107 
0108     /// KIO error code
0109     int lastErrorCode() const
0110     {
0111         return m_lastErrorCode;
0112     }
0113     QString lastErrorMessage() const
0114     {
0115         return m_lastErrorMessage;
0116     }
0117 
0118     QStringList listDir(const QString &physicalPath);
0119 
0120     static QUrl makeURL(int trashId, const QString &fileId, const QString &relativePath);
0121     static bool parseURL(const QUrl &url, int &trashId, QString &fileId, QString &relativePath);
0122 
0123     using TrashDirMap = QMap<int, QString>;
0124     /// @internal This method is for TestTrash only. Home trash is included (id 0).
0125     TrashDirMap trashDirectories() const;
0126     /// @internal This method is for TestTrash only. No entry with id 0.
0127     TrashDirMap topDirectories() const;
0128 
0129 Q_SIGNALS:
0130     void leaveModality();
0131 
0132 private:
0133     /// Helper method. Moves a file or directory using the appropriate method.
0134     bool move(const QString &src, const QString &dest);
0135     bool copy(const QString &src, const QString &dest);
0136     /// Helper method. Tries to call ::rename(src,dest) and does error handling.
0137     bool directRename(const QString &src, const QString &dest);
0138 
0139     void fileAdded();
0140     void fileRemoved();
0141 
0142     bool adaptTrashSize(const QString &origPath, int trashId);
0143 
0144     // Warning, returns error code, not a bool
0145     int testDir(const QString &name) const;
0146     void error(int e, const QString &s);
0147 
0148     bool readInfoFile(const QString &infoPath, TrashedFileInfo &info, int trashId);
0149 
0150     QString infoPath(int trashId, const QString &fileId) const;
0151     QString filesPath(int trashId, const QString &fileId) const;
0152 
0153 #ifdef Q_OS_OSX
0154     int idForMountPoint(const QString &mountPoint) const;
0155 #else
0156     int idForDevice(const Solid::Device &device) const;
0157 #endif
0158     void refreshDevices() const;
0159 
0160     /// Find the trash dir to use for a given file to delete, based on original path
0161     int findTrashDirectory(const QString &origPath);
0162 
0163     QString trashDirectoryPath(int trashId) const;
0164     QString topDirectoryPath(int trashId) const;
0165 
0166     bool synchronousDel(const QString &path, bool setLastErrorCode, bool isDir);
0167 
0168     void scanTrashDirectories() const;
0169 
0170     int idForTrashDirectory(const QString &trashDir) const;
0171     bool initTrashDirectory(const QByteArray &trashDir_c) const;
0172     bool checkTrashSubdirs(const QByteArray &trashDir_c) const;
0173     QString trashForMountPoint(const QString &topdir, bool createIfNeeded) const;
0174     static QString makeRelativePath(const QString &topdir, const QString &path);
0175 
0176     void enterLoop();
0177 
0178 private Q_SLOTS:
0179     void jobFinished(KJob *job);
0180 
0181 private:
0182     // delete the files and info subdirectories from all known trash directories
0183     // (supposed to be empty!) to make sure OS X sees the trash as empty too.
0184     // Stub except on OS X.
0185     void deleteEmptyTrashInfrastructure();
0186     // create the trash infrastructure; also called
0187     // to recreate it on OS X.
0188     bool createTrashInfrastructure(int trashId, const QString &path = QString());
0189 
0190     // Inserts a newly found @p trashDir, under @p topdir with @p id
0191     void insertTrashDir(int id, const QString &trashDir, const QString &topdir) const;
0192 
0193     /// Last error code stored in class to simplify API.
0194     /// Note that this means almost no method can be const.
0195     int m_lastErrorCode;
0196     QString m_lastErrorMessage;
0197 
0198     enum { InitToBeDone, InitOK, InitError } m_initStatus;
0199 
0200     // A "trash directory" is a physical directory on disk,
0201     // e.g. $HOME/.local/share/Trash or /mnt/foo/.Trash-$uid
0202     // It has an id (int) and a path.
0203     // The home trash has id 0.
0204     mutable TrashDirMap m_trashDirectories; // id -> path of trash directory
0205     mutable TrashDirMap m_topDirectories; // id -> $topdir of partition
0206     dev_t m_homeDevice;
0207     mutable bool m_trashDirectoriesScanned;
0208 
0209     mutable KConfig m_config;
0210 
0211     // We don't cache any data related to the trashed files.
0212     // Another KIO worker could change that behind our feet.
0213     // If we want to start caching data - and avoiding some race conditions -,
0214     // we should turn this class into a kded module and use DCOP to talk to it
0215     // from the KIO worker.
0216 };
0217 
0218 #endif