1 /*
2     This file is part of the KDE project
3     SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef TRASHIMPL_H
9 #define TRASHIMPL_H
10 
11 #include <kio/job.h>
12 
13 #include <KConfig>
14 
15 #include <QDateTime>
16 #include <QMap>
17 
18 namespace Solid
19 {
20 class Device;
21 }
22 
23 /**
24  * Implementation of all low-level operations done by kio_trash.
25  * The structure of the trash directory follows the freedesktop.org standard:
26  * https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
27  */
28 class TrashImpl : public QObject
29 {
30     Q_OBJECT
31 public:
32     TrashImpl();
33 
34     /// Check the "home" trash directory
35     /// This MUST be called before doing anything else
36     bool init();
37 
38     /// Create info for a file to be trashed
39     /// Returns trashId and fileId
40     /// The caller is then responsible for actually trashing the file
41     bool createInfo(const QString &origPath, int &trashId, QString &fileId);
42 
43     /// Delete info file for a file to be trashed
44     /// Usually used for undoing what createInfo did if trashing failed
45     bool deleteInfo(int trashId, const QString &fileId);
46 
47     /// Moving a file or directory into the trash. The ids come from createInfo.
48     bool moveToTrash(const QString &origPath, int trashId, const QString &fileId);
49 
50     /// Moving a file or directory out of the trash. The ids come from createInfo.
51     bool moveFromTrash(const QString &origPath, int trashId, const QString &fileId, const QString &relativePath);
52 
53     /// Copying a file or directory into the trash. The ids come from createInfo.
54     bool copyToTrash(const QString &origPath, int trashId, const QString &fileId);
55 
56     /// Copying a file or directory out of the trash. The ids come from createInfo.
57     bool copyFromTrash(const QString &origPath, int trashId, const QString &fileId, const QString &relativePath);
58 
59     /// Renaming a file or directory in the trash.
60     bool moveInTrash(int trashId, const QString &oldFileId, const QString &newFileId);
61 
62     /// Get rid of a trashed file
63     bool del(int trashId, const QString &fileId);
64 
65     /// Empty trash, i.e. delete all trashed files
66     bool emptyTrash();
67 
68     /// Return true if the trash is empty
69     bool isEmpty() const;
70 
71     struct TrashedFileInfo {
72         int trashId; // for the url
73         QString fileId; // for the url
74         QString physicalPath; // for stat'ing etc.
75         QString origPath; // from info file
76         QDateTime deletionDate; // from info file
77     };
78     /// List trashed files
79     using TrashedFileInfoList = QList<TrashedFileInfo>;
80 
81     /// Returns the TrashedFileInfo of all files in all trashes
82     /// uses scanTrashDirectories() to refresh m_trashDirectories
83     TrashedFileInfoList list();
84 
85     /// Return the info for a given trashed file
86     bool infoForFile(int trashId, const QString &fileId, TrashedFileInfo &info);
87 
88     struct TrashSpaceInfo {
89         qint64 totalSize; // total trash size in bytes
90         qint64 availableSize; // available trash space in bytes
91     };
92     /// Get the space info for a given trash path
93     /// Space information is only valid if trashSpaceInfo returns true
94     bool trashSpaceInfo(const QString &path, TrashSpaceInfo &info);
95 
96     /// Returns an UDSEntry corresponding to trash:/
97     KIO::UDSEntry trashUDSEntry(KIO::StatDetails details);
98 
99     /// Return the physicalPath for a given trashed file - helper method which
100     /// encapsulates the call to infoForFile. Don't use if you need more info from TrashedFileInfo.
101     QString physicalPath(int trashId, const QString &fileId, const QString &relativePath);
102 
103     /// Move data from the old trash system to the new one
104     void migrateOldTrash();
105 
106     /// KIO error code
lastErrorCode()107     int lastErrorCode() const
108     {
109         return m_lastErrorCode;
110     }
lastErrorMessage()111     QString lastErrorMessage() const
112     {
113         return m_lastErrorMessage;
114     }
115 
116     QStringList listDir(const QString &physicalPath);
117 
118     static QUrl makeURL(int trashId, const QString &fileId, const QString &relativePath);
119     static bool parseURL(const QUrl &url, int &trashId, QString &fileId, QString &relativePath);
120 
121     using TrashDirMap = QMap<int, QString>;
122     /// @internal This method is for TestTrash only. Home trash is included (id 0).
123     TrashDirMap trashDirectories() const;
124     /// @internal This method is for TestTrash only. No entry with id 0.
125     TrashDirMap topDirectories() const;
126 
127 Q_SIGNALS:
128     void leaveModality();
129 
130 private:
131     /// Helper method. Moves a file or directory using the appropriate method.
132     bool move(const QString &src, const QString &dest);
133     bool copy(const QString &src, const QString &dest);
134     /// Helper method. Tries to call ::rename(src,dest) and does error handling.
135     bool directRename(const QString &src, const QString &dest);
136 
137     void fileAdded();
138     void fileRemoved();
139 
140     bool adaptTrashSize(const QString &origPath, int trashId);
141 
142     // Warning, returns error code, not a bool
143     int testDir(const QString &name) const;
144     void error(int e, const QString &s);
145 
146     bool readInfoFile(const QString &infoPath, TrashedFileInfo &info, int trashId);
147 
148     QString infoPath(int trashId, const QString &fileId) const;
149     QString filesPath(int trashId, const QString &fileId) const;
150 
151 #ifdef Q_OS_OSX
152     int idForMountPoint(const QString &mountPoint) const;
153 #else
154     int idForDevice(const Solid::Device &device) const;
155 #endif
156     void refreshDevices() const;
157 
158     /// Find the trash dir to use for a given file to delete, based on original path
159     int findTrashDirectory(const QString &origPath);
160 
161     QString trashDirectoryPath(int trashId) const;
162     QString topDirectoryPath(int trashId) const;
163 
164     bool synchronousDel(const QString &path, bool setLastErrorCode, bool isDir);
165 
166     void scanTrashDirectories() const;
167 
168     int idForTrashDirectory(const QString &trashDir) const;
169     bool initTrashDirectory(const QByteArray &trashDir_c) const;
170     bool checkTrashSubdirs(const QByteArray &trashDir_c) const;
171     QString trashForMountPoint(const QString &topdir, bool createIfNeeded) const;
172     static QString makeRelativePath(const QString &topdir, const QString &path);
173 
174     void enterLoop();
175 
176 private Q_SLOTS:
177     void jobFinished(KJob *job);
178 
179 private:
180     // delete the files and info subdirectories from all known trash directories
181     // (supposed to be empty!) to make sure OS X sees the trash as empty too.
182     // Stub except on OS X.
183     void deleteEmptyTrashInfrastructure();
184     // create the trash infrastructure; also called
185     // to recreate it on OS X.
186     bool createTrashInfrastructure(int trashId, const QString &path = QString());
187 
188     // Inserts a newly found @p trashDir, under @p topdir with @p id
189     void insertTrashDir(int id, const QString &trashDir, const QString &topdir) const;
190 
191     /// Last error code stored in class to simplify API.
192     /// Note that this means almost no method can be const.
193     int m_lastErrorCode;
194     QString m_lastErrorMessage;
195 
196     enum { InitToBeDone, InitOK, InitError } m_initStatus;
197 
198     // A "trash directory" is a physical directory on disk,
199     // e.g. $HOME/.local/share/Trash or /mnt/foo/.Trash-$uid
200     // It has an id (int) and a path.
201     // The home trash has id 0.
202     mutable TrashDirMap m_trashDirectories; // id -> path of trash directory
203     mutable TrashDirMap m_topDirectories; // id -> $topdir of partition
204     dev_t m_homeDevice;
205     mutable bool m_trashDirectoriesScanned;
206 
207     mutable KConfig m_config;
208 
209     // We don't cache any data related to the trashed files.
210     // Another kioslave could change that behind our feet.
211     // If we want to start caching data - and avoiding some race conditions -,
212     // we should turn this class into a kded module and use DCOP to talk to it
213     // from the kioslave.
214 };
215 
216 #endif
217