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