3 Copyright (c) 2003, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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
40 #pragma warning(push, 1)
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>
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"
66 struct piece_checker_data
;
69 namespace fs
= boost::filesystem
;
74 struct disk_buffer_holder
;
78 storage_mode_allocate
= 0,
83 #if defined(_WIN32) && defined(UNICODE)
85 TORRENT_EXPORT
std::wstring
safe_convert(std::string
const& s
);
89 TORRENT_EXPORT
std::vector
<std::pair
<size_type
, std::time_t> > get_filesizes(
93 TORRENT_EXPORT
bool match_filesizes(
96 , std::vector
<std::pair
<size_type
, std::time_t> > const& sizes
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() {}
108 struct TORRENT_EXPORT partial_hash
110 partial_hash(): offset(0) {}
111 // the number of bytes in the piece that has been hashed
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
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();
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
>
197 friend class invariant_access
;
198 friend struct disk_io_thread
;
202 boost::shared_ptr
<void> const& torrent
203 , boost::intrusive_ptr
<torrent_info
const> info
204 , fs::path
const& path
207 , storage_constructor_type sc
208 , storage_mode_t sm
);
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
);
224 peer_request
const& r
225 , boost::function
<void(int, disk_io_job
const&)> const& handler
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
);
255 // return values from check_fastresume and check_files
257 need_full_check
= -1,
258 fatal_disk_error
= -2,
259 disk_check_aborted
= -3
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
; }
298 std::string
name() const { return m_info
->name(); }
301 bool allocate_slots(int num_slots
, bool abort_on_disk
= false);
315 // -1=error 0=ok 1=skip
316 int check_one_piece(int& have_piece
);
318 const std::vector
<char>& piece_data
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
);
333 void check_invariant() const;
334 #ifdef TORRENT_STORAGE_DEBUG
335 void debug_log() const;
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
;
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
;
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
;
374 // the default initial state
376 // the file checking is complete
378 // checking the files
380 // move pieces to their final position
384 // used during check. If any piece is found
385 // that is not in its final position, this
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
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
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
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