1 /*
2     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #ifndef BTCACHE_H
7 #define BTCACHE_H
8 
9 #include <QMultiMap>
10 #include <QSet>
11 #include <QString>
12 #include <diskio/piecedata.h>
13 #include <ktorrent_export.h>
14 #include <torrent/torrent.h>
15 #include <util/constants.h>
16 
17 class QStringList;
18 
19 namespace bt
20 {
21 class TorrentFile;
22 class Chunk;
23 class PreallocationThread;
24 class TorrentFileInterface;
25 class Job;
26 
27 /**
28  * @author Joris Guisson
29  * @brief Manages the temporary data
30  *
31  * Interface for a class which manages downloaded data.
32  * Subclasses should implement the load and save methods.
33  */
34 class KTORRENT_EXPORT Cache
35 {
36 public:
37     Cache(Torrent &tor, const QString &tmpdir, const QString &datadir);
38     virtual ~Cache();
39 
40     /**
41      * Load the file map of a torrent.
42      * If it doesn't exist, it needs to be created.
43      */
44     virtual void loadFileMap() = 0;
45 
46     /**
47      * Save the file map of a torrent
48      */
49     virtual void saveFileMap() = 0;
50 
51     /// Get the datadir
52     QString getDataDir() const
53     {
54         return datadir;
55     }
56 
57     /**
58      * Get the actual output path.
59      * @return The output path
60      */
61     virtual QString getOutputPath() const = 0;
62 
63     /**
64      * Changes the tmp dir. All data files should already been moved.
65      * This just modifies the tmpdir variable.
66      * @param ndir The new tmpdir
67      */
68     virtual void changeTmpDir(const QString &ndir);
69 
70     /**
71      * Changes output path. All data files should already been moved.
72      * This just modifies the datadir variable.
73      * @param outputpath New output path
74      */
75     virtual void changeOutputPath(const QString &outputpath) = 0;
76 
77     /**
78      * Move the data files to a new directory.
79      * @param ndir The directory
80      * @return The job doing the move
81      */
82     virtual Job *moveDataFiles(const QString &ndir) = 0;
83 
84     /**
85      * A move of a bunch of data files has finished
86      * @param job The job doing the move
87      */
88     virtual void moveDataFilesFinished(Job *job) = 0;
89 
90     /**
91      * Load a piece into memory. If something goes wrong,
92      * an Error should be thrown.
93      * @param c The Chunk
94      * @param off The offset of the piece
95      * @param length The length of the piece
96      * @return Pointer to the data
97      */
98     virtual PieceData::Ptr loadPiece(Chunk *c, Uint32 off, Uint32 length) = 0;
99 
100     /**
101      * Prepare a piece for writing. If something goes wrong,
102      * an Error should be thrown.
103      * @param c The Chunk
104      * @param off The offset of the piece
105      * @param length The length of the piece
106      * @return Pointer to the data
107      */
108     virtual PieceData::Ptr preparePiece(Chunk *c, Uint32 off, Uint32 length) = 0;
109 
110     /**
111      * Save a piece to disk, will only actually save in buffered mode
112      * @param piece The piece
113      */
114     virtual void savePiece(PieceData::Ptr piece) = 0;
115 
116     /**
117      * Create all the data files to store the data.
118      */
119     virtual void create() = 0;
120 
121     /**
122      * Close the cache file(s).
123      */
124     virtual void close() = 0;
125 
126     /**
127      * Open the cache file(s)
128      */
129     virtual void open() = 0;
130 
131     /// Does nothing, can be overridden to be alerted of download status changes of a TorrentFile
132     virtual void downloadStatusChanged(TorrentFile *, bool){};
133 
134     /**
135      * Prepare disksapce preallocation
136      * @param prealloc The thread going to do the preallocation
137      */
138     virtual void preparePreallocation(PreallocationThread *prealloc) = 0;
139 
140     /// See if the download has existing files
141     bool hasExistingFiles() const
142     {
143         return preexisting_files;
144     }
145 
146     /**
147      * Test all files and see if they are not missing.
148      * If so put them in a list
149      */
150     virtual bool hasMissingFiles(QStringList &sl) = 0;
151 
152     /**
153      * Delete all data files, in case of multi file torrents
154      * empty directories should also be deleted.
155      * @return The job doing the delete
156      */
157     virtual Job *deleteDataFiles() = 0;
158 
159     /**
160      * Move some files to a new location
161      * @param files Map of files to move and their new location
162      * @return Job The job doing the move
163      */
164     virtual Job *moveDataFiles(const QMap<TorrentFileInterface *, QString> &files);
165 
166     /**
167      * The job doing moveDataFiles (with the map parameter) has finished
168      * @param files The files map with all the moves
169      * @param job The job doing the move
170      */
171     virtual void moveDataFilesFinished(const QMap<TorrentFileInterface *, QString> &files, Job *job);
172 
173     /**
174      * See if we are allowed to use mmap, when loading chunks.
175      * This will return false if we are close to system limits.
176      */
177     static bool mappedModeAllowed();
178 
179     /**
180      * Get the number of bytes all the files of this torrent are currently using on disk.
181      * */
182     virtual Uint64 diskUsage() = 0;
183 
184     /**
185      * Determine the mount points of all the files in this torrent
186      * @return bool True if we can, false if not
187      **/
188     virtual bool getMountPoints(QSet<QString> &mps) = 0;
189 
190     /**
191      * Enable or disable diskspace preallocation
192      * @param on
193      */
194     static void setPreallocationEnabled(bool on)
195     {
196         preallocate_files = on;
197     }
198 
199     /**
200      * Check if diskspace preallocation is enabled
201      * @return true if it is
202      */
203     static bool preallocationEnabled()
204     {
205         return preallocate_files;
206     }
207 
208     /**
209      * Enable or disable full diskspace preallocation
210      * @param on
211      */
212     static void setPreallocateFully(bool on)
213     {
214         preallocate_fully = on;
215     }
216 
217     /**
218      * Check if full diskspace preallocation is enabled.
219      * @return true if it is
220      */
221     static bool preallocateFully()
222     {
223         return preallocate_fully;
224     }
225 
226     /**
227      * Check memory usage and free all PieceData objects which are no longer needed.
228      */
229     void checkMemoryUsage();
230 
231     /**
232      * Clear all pieces of a chunk
233      * @param c The chunk
234      * */
235     void clearPieces(Chunk *c);
236 
237     /**
238      * Load the mount points of this torrent
239      **/
240     void loadMountPoints();
241 
242     /// Is the storage mounted ?
243     bool isStorageMounted(QStringList &missing);
244 
245 protected:
246     PieceData::Ptr findPiece(Chunk *c, Uint32 off, Uint32 len, bool read_only);
247     void insertPiece(Chunk *c, PieceData::Ptr p);
248     void clearPieceCache();
249     void cleanupPieceCache();
250     void saveMountPoints(const QSet<QString> &mp);
251 
252 protected:
253     Torrent &tor;
254     QString tmpdir;
255     QString datadir;
256     bool preexisting_files;
257     Uint32 mmap_failures;
258 
259     typedef QMultiMap<Chunk *, PieceData::Ptr> PieceCache;
260     PieceCache piece_cache;
261 
262     QSet<QString> mount_points;
263 
264 private:
265     static bool preallocate_files;
266     static bool preallocate_fully;
267 };
268 
269 }
270 
271 #endif
272