1 /* 2 3 Copyright (c) 2012-2018, Arvid Norberg 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 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. 18 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. 30 31 */ 32 33 #ifndef TORRENT_PART_FILE_HPP_INCLUDE 34 #define TORRENT_PART_FILE_HPP_INCLUDE 35 36 #include <string> 37 #include <vector> 38 #include <mutex> 39 #include <unordered_map> 40 #include <cstdint> 41 #include <memory> 42 43 #include "libtorrent/config.hpp" 44 #include "libtorrent/file.hpp" 45 #include "libtorrent/error_code.hpp" 46 #include "libtorrent/units.hpp" 47 48 namespace libtorrent { 49 50 using slot_index_t = aux::strong_typedef<int, struct slot_index_tag_t>; 51 52 struct TORRENT_EXTRA_EXPORT part_file 53 { 54 // create a part file at ``path``, that can hold ``num_pieces`` pieces. 55 // each piece being ``piece_size`` number of bytes 56 part_file(std::string const& path, std::string const& name, int num_pieces, int piece_size); 57 ~part_file(); 58 59 int writev(span<iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec); 60 int readv(span<iovec_t const> bufs, piece_index_t piece, int offset, error_code& ec); 61 62 // free the slot the given piece is stored in. We no longer need to store this 63 // piece in the part file 64 void free_piece(piece_index_t piece); 65 66 void move_partfile(std::string const& path, error_code& ec); 67 68 // the function is called for every block of data belonging to the 69 // specified range that's in the part_file. The first parameter is the 70 // offset within the range 71 void export_file(std::function<void(std::int64_t, span<char>)> f 72 , std::int64_t offset, std::int64_t size, error_code& ec); 73 74 // flush the metadata 75 void flush_metadata(error_code& ec); 76 77 private: 78 79 file open_file(open_mode_t mode, error_code& ec); 80 void flush_metadata_impl(error_code& ec); 81 slot_offsetlibtorrent::part_file82 std::int64_t slot_offset(slot_index_t const slot) const 83 { 84 return static_cast<int>(slot) * static_cast<std::int64_t>(m_piece_size) 85 + m_header_size; 86 } 87 88 std::string m_path; 89 std::string const m_name; 90 91 // allocate a slot and return the slot index 92 slot_index_t allocate_slot(piece_index_t piece); 93 94 // this mutex must be held while accessing the data 95 // structure. Not while reading or writing from the file though! 96 // it's important to support multithreading 97 std::mutex m_mutex; 98 99 // this is a list of unallocated slots in the part file 100 // within the m_num_allocated range 101 std::vector<slot_index_t> m_free_slots; 102 103 // this is the number of slots allocated 104 slot_index_t m_num_allocated{0}; 105 106 // the max number of pieces in the torrent this part file is 107 // backing 108 int const m_max_pieces; 109 110 // number of bytes each piece contains 111 int const m_piece_size; 112 113 // this is the size of the part_file header, it is added 114 // to offsets when calculating the offset to read and write 115 // payload data from 116 int const m_header_size; 117 118 // if this is true, the metadata in memory has changed since 119 // we last saved or read it from disk. It means that we 120 // need to flush the metadata before closing the file 121 bool m_dirty_metadata = false; 122 123 // maps a piece index to the part-file slot it is stored in 124 std::unordered_map<piece_index_t, slot_index_t> m_piece_map; 125 }; 126 } 127 128 #endif 129