makes all tracker requests 'stopped' when aborting
[libtorrent.git] / include / libtorrent / storage.hpp
blobd2847cb8e80b5afece58f4035e0b19b6347d5bd8
1 /*
3 Copyright (c) 2003, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #ifndef TORRENT_STORAGE_HPP_INCLUDE
34 #define TORRENT_STORAGE_HPP_INCLUDE
36 #include <vector>
37 #include <bitset>
39 #ifdef _MSC_VER
40 #pragma warning(push, 1)
41 #endif
43 #include <boost/limits.hpp>
44 #include <boost/thread.hpp>
45 #include <boost/shared_ptr.hpp>
46 #include <boost/intrusive_ptr.hpp>
47 #include <boost/filesystem/path.hpp>
49 #ifdef _MSC_VER
50 #pragma warning(pop)
51 #endif
54 #include "libtorrent/torrent_info.hpp"
55 #include "libtorrent/piece_picker.hpp"
56 #include "libtorrent/intrusive_ptr_base.hpp"
57 #include "libtorrent/peer_request.hpp"
58 #include "libtorrent/hasher.hpp"
59 #include "libtorrent/config.hpp"
60 #include "libtorrent/buffer.hpp"
62 namespace libtorrent
64 namespace aux
66 struct piece_checker_data;
69 namespace fs = boost::filesystem;
71 class session;
72 struct file_pool;
73 struct disk_io_job;
74 struct disk_buffer_holder;
76 enum storage_mode_t
78 storage_mode_allocate = 0,
79 storage_mode_sparse,
80 storage_mode_compact
83 #if defined(_WIN32) && defined(UNICODE)
85 TORRENT_EXPORT std::wstring safe_convert(std::string const& s);
87 #endif
89 TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
90 file_storage const& t
91 , fs::path p);
93 TORRENT_EXPORT bool match_filesizes(
94 file_storage const& t
95 , fs::path p
96 , std::vector<std::pair<size_type, std::time_t> > const& sizes
97 , bool compact_mode
98 , std::string* error = 0);
100 struct TORRENT_EXPORT file_allocation_failed: std::exception
102 file_allocation_failed(const char* error_msg): m_msg(error_msg) {}
103 virtual const char* what() const throw() { return m_msg.c_str(); }
104 virtual ~file_allocation_failed() throw() {}
105 std::string m_msg;
108 struct TORRENT_EXPORT partial_hash
110 partial_hash(): offset(0) {}
111 // the number of bytes in the piece that has been hashed
112 int offset;
113 // the sha-1 context
114 hasher h;
117 struct TORRENT_EXPORT storage_interface
119 // create directories and set file sizes
120 // if allocate_files is true.
121 // allocate_files is true if allocation mode
122 // is set to full and sparse files are supported
123 // false return value indicates an error
124 virtual bool initialize(bool allocate_files) = 0;
126 // negative return value indicates an error
127 virtual int read(char* buf, int slot, int offset, int size) = 0;
129 // negative return value indicates an error
130 virtual int write(const char* buf, int slot, int offset, int size) = 0;
132 // non-zero return value indicates an error
133 virtual bool move_storage(fs::path save_path) = 0;
135 // verify storage dependent fast resume entries
136 virtual bool verify_resume_data(lazy_entry const& rd, std::string& error) = 0;
138 // write storage dependent fast resume entries
139 virtual bool write_resume_data(entry& rd) const = 0;
141 // moves (or copies) the content in src_slot to dst_slot
142 virtual bool move_slot(int src_slot, int dst_slot) = 0;
144 // swaps the data in slot1 and slot2
145 virtual bool swap_slots(int slot1, int slot2) = 0;
147 // swaps the puts the data in slot1 in slot2, the data in slot2
148 // in slot3 and the data in slot3 in slot1
149 virtual bool swap_slots3(int slot1, int slot2, int slot3) = 0;
151 // returns the sha1-hash for the data at the given slot
152 virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;
154 // this will close all open files that are opened for
155 // writing. This is called when a torrent has finished
156 // downloading.
157 // non-zero return value indicates an error
158 virtual bool release_files() = 0;
160 // this will rename the file specified by index.
161 virtual bool rename_file(int index, std::string const& new_filename) = 0;
163 // this will close all open files and delete them
164 // non-zero return value indicates an error
165 virtual bool delete_files() = 0;
167 void set_error(boost::filesystem::path const& file, error_code const& ec) const
169 m_error_file = file.string();
170 m_error = ec;
173 error_code const& error() const { return m_error; }
174 std::string const& error_file() const { return m_error_file; }
175 void clear_error() { m_error = error_code(); m_error_file.clear(); }
177 mutable error_code m_error;
178 mutable std::string m_error_file;
180 virtual ~storage_interface() {}
183 typedef storage_interface* (&storage_constructor_type)(
184 file_storage const&, fs::path const&, file_pool&);
186 TORRENT_EXPORT storage_interface* default_storage_constructor(
187 file_storage const&, fs::path const&, file_pool&);
188 TORRENT_EXPORT storage_interface* mapped_storage_constructor(
189 file_storage const&, fs::path const&, file_pool&);
191 struct disk_io_thread;
193 class TORRENT_EXPORT piece_manager
194 : public intrusive_ptr_base<piece_manager>
195 , boost::noncopyable
197 friend class invariant_access;
198 friend struct disk_io_thread;
199 public:
201 piece_manager(
202 boost::shared_ptr<void> const& torrent
203 , boost::intrusive_ptr<torrent_info const> info
204 , fs::path const& path
205 , file_pool& fp
206 , disk_io_thread& io
207 , storage_constructor_type sc
208 , storage_mode_t sm);
210 ~piece_manager();
212 boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
213 void write_resume_data(entry& rd) const;
215 void async_check_fastresume(lazy_entry const* resume_data
216 , boost::function<void(int, disk_io_job const&)> const& handler);
218 void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
220 void async_rename_file(int index, std::string const& name
221 , boost::function<void(int, disk_io_job const&)> const& handler);
223 void async_read(
224 peer_request const& r
225 , boost::function<void(int, disk_io_job const&)> const& handler
226 , int priority = 0);
228 void async_write(
229 peer_request const& r
230 , disk_buffer_holder& buffer
231 , boost::function<void(int, disk_io_job const&)> const& f);
233 void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
235 void async_release_files(
236 boost::function<void(int, disk_io_job const&)> const& handler
237 = boost::function<void(int, disk_io_job const&)>());
239 void async_clear_read_cache(
240 boost::function<void(int, disk_io_job const&)> const& handler
241 = boost::function<void(int, disk_io_job const&)>());
243 void async_delete_files(
244 boost::function<void(int, disk_io_job const&)> const& handler
245 = boost::function<void(int, disk_io_job const&)>());
247 void async_move_storage(fs::path const& p
248 , boost::function<void(int, disk_io_job const&)> const& handler);
250 void async_save_resume_data(
251 boost::function<void(int, disk_io_job const&)> const& handler);
253 enum return_t
255 // return values from check_fastresume and check_files
256 no_error = 0,
257 need_full_check = -1,
258 fatal_disk_error = -2,
259 disk_check_aborted = -3
262 private:
264 fs::path save_path() const;
266 bool verify_resume_data(lazy_entry const& rd, std::string& error)
267 { return m_storage->verify_resume_data(rd, error); }
269 bool is_allocating() const
270 { return m_state == state_expand_pieces; }
272 void mark_failed(int index);
274 error_code const& error() const { return m_storage->error(); }
275 std::string const& error_file() const { return m_storage->error_file(); }
276 void clear_error() { m_storage->clear_error(); }
278 int slot_for(int piece) const;
279 int piece_for(int slot) const;
281 // helper functions for check_dastresume
282 int check_no_fastresume(std::string& error);
283 int check_init_storage(std::string& error);
285 // if error is set and return value is 'no_error' or 'need_full_check'
286 // the error message indicates that the fast resume data was rejected
287 // if 'fatal_disk_error' is returned, the error message indicates what
288 // when wrong in the disk access
289 int check_fastresume(lazy_entry const& rd, std::string& error);
291 // this function returns true if the checking is complete
292 int check_files(int& current_slot, int& have_piece, std::string& error);
294 bool compact_allocation() const
295 { return m_storage_mode == storage_mode_compact; }
297 #ifndef NDEBUG
298 std::string name() const { return m_info->name(); }
299 #endif
301 bool allocate_slots(int num_slots, bool abort_on_disk = false);
303 int read_impl(
304 char* buf
305 , int piece_index
306 , int offset
307 , int size);
309 int write_impl(
310 const char* buf
311 , int piece_index
312 , int offset
313 , int size);
315 // -1=error 0=ok 1=skip
316 int check_one_piece(int& have_piece);
317 int identify_data(
318 const std::vector<char>& piece_data
319 , int current_slot);
321 void switch_to_full_mode();
322 sha1_hash hash_for_piece_impl(int piece);
324 int release_files_impl() { return m_storage->release_files(); }
325 int delete_files_impl() { return m_storage->delete_files(); }
326 int rename_file_impl(int index, std::string const& new_filename)
327 { return m_storage->rename_file(index, new_filename); }
329 int move_storage_impl(fs::path const& save_path);
331 int allocate_slot_for_piece(int piece_index);
332 #ifndef NDEBUG
333 void check_invariant() const;
334 #ifdef TORRENT_STORAGE_DEBUG
335 void debug_log() const;
336 #endif
337 #endif
338 boost::intrusive_ptr<torrent_info const> m_info;
339 file_storage const& m_files;
341 boost::scoped_ptr<storage_interface> m_storage;
343 storage_mode_t m_storage_mode;
345 // slots that haven't had any file storage allocated
346 std::vector<int> m_unallocated_slots;
347 // slots that have file storage, but isn't assigned to a piece
348 std::vector<int> m_free_slots;
350 enum
352 has_no_slot = -3 // the piece has no storage
355 // maps piece indices to slots. If a piece doesn't
356 // have any storage, it is set to 'has_no_slot'
357 std::vector<int> m_piece_to_slot;
359 enum
361 unallocated = -1, // the slot is unallocated
362 unassigned = -2 // the slot is allocated but not assigned to a piece
365 // maps slots to piece indices, if a slot doesn't have a piece
366 // it can either be 'unassigned' or 'unallocated'
367 std::vector<int> m_slot_to_piece;
369 fs::path m_save_path;
371 mutable boost::recursive_mutex m_mutex;
373 enum {
374 // the default initial state
375 state_none,
376 // the file checking is complete
377 state_finished,
378 // checking the files
379 state_full_check,
380 // move pieces to their final position
381 state_expand_pieces
382 } m_state;
383 int m_current_slot;
384 // used during check. If any piece is found
385 // that is not in its final position, this
386 // is set to true
387 bool m_out_of_place;
388 // used to move pieces while expanding
389 // the storage from compact allocation
390 // to full allocation
391 buffer m_scratch_buffer;
392 buffer m_scratch_buffer2;
393 // the piece that is in the scratch buffer
394 int m_scratch_piece;
396 // this is saved in case we need to instantiate a new
397 // storage (osed when remapping files)
398 storage_constructor_type m_storage_constructor;
400 // temporary buffer used while checking
401 std::vector<char> m_piece_data;
403 // this maps a piece hash to piece index. It will be
404 // build the first time it is used (to save time if it
405 // isn't needed)
406 std::multimap<sha1_hash, int> m_hash_to_piece;
408 // this map contains partial hashes for downloading
409 // pieces. This is only accessed from within the
410 // disk-io thread.
411 std::map<int, partial_hash> m_piece_hasher;
413 disk_io_thread& m_io_thread;
415 // the reason for this to be a void pointer
416 // is to avoid creating a dependency on the
417 // torrent. This shared_ptr is here only
418 // to keep the torrent object alive until
419 // the piece_manager destructs. This is because
420 // the torrent_info object is owned by the torrent.
421 boost::shared_ptr<void> m_torrent;
426 #endif // TORRENT_STORAGE_HPP_INCLUDED