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