1 /*
2 
3 Copyright (c) 2003-2018, Arvid Norberg, Daniel Wallin
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 #include "libtorrent/config.hpp"
34 #include "libtorrent/error_code.hpp"
35 #include "libtorrent/aux_/storage_utils.hpp"
36 
37 #include <ctime>
38 #include <algorithm>
39 #include <numeric>
40 #include <set>
41 #include <functional>
42 #include <cstdio>
43 
44 #include "libtorrent/aux_/disable_warnings_push.hpp"
45 
46 #if defined(__APPLE__)
47 // for getattrlist()
48 #include <sys/attr.h>
49 #include <unistd.h>
50 // for statfs()
51 #include <sys/param.h>
52 #include <sys/mount.h>
53 #endif
54 
55 #if defined(__linux__)
56 #include <sys/statfs.h>
57 #endif
58 
59 #if defined(__FreeBSD__) || defined(__DragonFly__)
60 // for statfs()
61 #include <sys/param.h>
62 #include <sys/mount.h>
63 #endif
64 
65 #if TORRENT_HAS_SYMLINK
66 #include <unistd.h> // for symlink()
67 #endif
68 
69 #include "libtorrent/aux_/disable_warnings_pop.hpp"
70 
71 #include "libtorrent/storage.hpp"
72 #include "libtorrent/torrent.hpp"
73 #include "libtorrent/aux_/path.hpp"
74 #include "libtorrent/invariant_check.hpp"
75 #include "libtorrent/file_pool.hpp"
76 #include "libtorrent/aux_/session_impl.hpp"
77 #include "libtorrent/disk_buffer_holder.hpp"
78 #include "libtorrent/stat_cache.hpp"
79 #include "libtorrent/hex.hpp" // to_hex
80 //#include "libtorrent/aux_/escape_string.hpp"
81 
82 namespace libtorrent {
83 
default_storage(storage_params const & params,file_pool & pool)84 	default_storage::default_storage(storage_params const& params
85 		, file_pool& pool)
86 		: storage_interface(params.files)
87 		, m_file_priority(params.priorities)
88 		, m_pool(pool)
89 		, m_allocate_files(params.mode == storage_mode_allocate)
90 	{
91 		if (params.mapped_files) m_mapped_files.reset(new file_storage(*params.mapped_files));
92 
93 		TORRENT_ASSERT(files().num_files() > 0);
94 		m_save_path = complete(params.path);
95 		m_part_file_name = "." + aux::to_hex(params.info_hash) + ".parts";
96 	}
97 
~default_storage()98 	default_storage::~default_storage()
99 	{
100 		error_code ec;
101 		if (m_part_file) m_part_file->flush_metadata(ec);
102 
103 		// this may be called from a different
104 		// thread than the disk thread
105 		m_pool.release(storage_index());
106 	}
107 
need_partfile()108 	void default_storage::need_partfile()
109 	{
110 		if (m_part_file) return;
111 
112 		m_part_file.reset(new part_file(
113 			m_save_path, m_part_file_name
114 			, files().num_pieces(), files().piece_length()));
115 	}
116 
set_file_priority(aux::vector<download_priority_t,file_index_t> & prio,storage_error & ec)117 	void default_storage::set_file_priority(
118 		aux::vector<download_priority_t, file_index_t>& prio
119 		, storage_error& ec)
120 	{
121 		// extend our file priorities in case it's truncated
122 		// the default assumed priority is 4 (the default)
123 		if (prio.size() > m_file_priority.size())
124 			m_file_priority.resize(prio.size(), default_priority);
125 
126 		file_storage const& fs = files();
127 		for (file_index_t i(0); i < prio.end_index(); ++i)
128 		{
129 			// pad files always have priority 0.
130 			if (fs.pad_file_at(i)) continue;
131 
132 			download_priority_t const old_prio = m_file_priority[i];
133 			download_priority_t new_prio = prio[i];
134 			if (old_prio == dont_download && new_prio != dont_download)
135 			{
136 				// move stuff out of the part file
137 				file_handle f = open_file(i, open_mode::read_write, ec);
138 				if (ec)
139 				{
140 					prio = m_file_priority;
141 					return;
142 				}
143 
144 				if (m_part_file && use_partfile(i))
145 				{
146 					m_part_file->export_file([&f, &ec](std::int64_t file_offset, span<char> buf)
147 					{
148 						iovec_t const v = {buf.data(), buf.size()};
149 						std::int64_t const ret = f->writev(file_offset, v, ec.ec);
150 						TORRENT_UNUSED(ret);
151 						TORRENT_ASSERT(ec || ret == std::int64_t(v.size()));
152 					}, fs.file_offset(i), fs.file_size(i), ec.ec);
153 
154 					if (ec)
155 					{
156 						ec.file(i);
157 						ec.operation = operation_t::partfile_write;
158 						prio = m_file_priority;
159 						return;
160 					}
161 				}
162 			}
163 			else if (old_prio != dont_download && new_prio == dont_download)
164 			{
165 				// move stuff into the part file
166 				// this is not implemented yet.
167 				// so we just don't use a partfile for this file
168 
169 				std::string const fp = fs.file_path(i, m_save_path);
170 				if (exists(fp)) use_partfile(i, false);
171 /*
172 				file_handle f = open_file(i, open_mode::read_only, ec);
173 				if (ec.ec != boost::system::errc::no_such_file_or_directory)
174 				{
175 					if (ec)
176 					{
177 						prio = m_file_priority;
178 						return;
179 					}
180 
181 					need_partfile();
182 
183 					m_part_file->import_file(*f, fs.file_offset(i), fs.file_size(i), ec.ec);
184 					if (ec)
185 					{
186 						ec.file(i);
187 						ec.operation = operation_t::partfile_read;
188 						prio = m_file_priority;
189 						return;
190 					}
191 					// remove the file
192 					std::string p = fs.file_path(i, m_save_path);
193 					delete_one_file(p, ec.ec);
194 					if (ec)
195 					{
196 						ec.file(i);
197 						ec.operation = operation_t::file_remove;
198 						prio = m_file_priority;
199 						return;
200 					}
201 				}
202 */
203 			}
204 			ec.ec.clear();
205 			m_file_priority[i] = new_prio;
206 
207 			if (m_file_priority[i] == dont_download && use_partfile(i))
208 			{
209 				need_partfile();
210 			}
211 		}
212 		if (m_part_file) m_part_file->flush_metadata(ec.ec);
213 		if (ec)
214 		{
215 			ec.file(torrent_status::error_file_partfile);
216 			ec.operation = operation_t::partfile_write;
217 		}
218 	}
219 
use_partfile(file_index_t const index) const220 	bool default_storage::use_partfile(file_index_t const index) const
221 	{
222 		TORRENT_ASSERT_VAL(index >= file_index_t{}, index);
223 		if (index >= m_use_partfile.end_index()) return true;
224 		return m_use_partfile[index];
225 	}
226 
use_partfile(file_index_t const index,bool const b)227 	void default_storage::use_partfile(file_index_t const index, bool const b)
228 	{
229 		if (index >= m_use_partfile.end_index()) m_use_partfile.resize(static_cast<int>(index) + 1, true);
230 		m_use_partfile[index] = b;
231 	}
232 
initialize(storage_error & ec)233 	void default_storage::initialize(storage_error& ec)
234 	{
235 		m_stat_cache.reserve(files().num_files());
236 
237 #ifdef TORRENT_WINDOWS
238 		// don't do full file allocations on network drives
239 		auto const file_name = convert_to_native_path_string(m_save_path);
240 		int const drive_type = GetDriveTypeW(file_name.c_str());
241 
242 		if (drive_type == DRIVE_REMOTE)
243 			m_allocate_files = false;
244 #endif
245 
246 		{
247 			std::unique_lock<std::mutex> l(m_file_created_mutex);
248 			m_file_created.resize(files().num_files(), false);
249 		}
250 
251 		file_storage const& fs = files();
252 		// if some files have priority 0, we need to check if they exist on the
253 		// filesystem, in which case we won't use a partfile for them.
254 		// this is to be backwards compatible with previous versions of
255 		// libtorrent, when part files were not supported.
256 		for (file_index_t i(0); i < m_file_priority.end_index(); ++i)
257 		{
258 			if (m_file_priority[i] != dont_download || fs.pad_file_at(i))
259 				continue;
260 
261 			file_status s;
262 			std::string const file_path = fs.file_path(i, m_save_path);
263 			error_code err;
264 			stat_file(file_path, &s, err);
265 			if (!err)
266 			{
267 				use_partfile(i, false);
268 			}
269 			else
270 			{
271 				need_partfile();
272 			}
273 		}
274 
275 		// first, create all missing directories
276 		std::string last_path;
277 		for (auto const file_index : fs.file_range())
278 		{
279 			// ignore files that have priority 0
280 			if (m_file_priority.end_index() > file_index
281 				&& m_file_priority[file_index] == dont_download)
282 			{
283 				continue;
284 			}
285 
286 			// ignore pad files
287 			if (fs.pad_file_at(file_index)) continue;
288 
289 			// this is just to see if the file exists
290 			error_code err;
291 			m_stat_cache.get_filesize(file_index, fs, m_save_path, err);
292 
293 			if (err && err != boost::system::errc::no_such_file_or_directory)
294 			{
295 				ec.file(file_index);
296 				ec.operation = operation_t::file_stat;
297 				ec.ec = err;
298 				break;
299 			}
300 
301 			// if the file is empty and doesn't already exist, create it
302 			// deliberately don't truncate files that already exist
303 			// if a file is supposed to have size 0, but already exists, we will
304 			// never truncate it to 0.
305 			if (fs.file_size(file_index) == 0
306 				&& err == boost::system::errc::no_such_file_or_directory)
307 			{
308 				std::string dir = parent_path(fs.file_path(file_index, m_save_path));
309 
310 				if (dir != last_path)
311 				{
312 					last_path = dir;
313 
314 					create_directories(last_path, ec.ec);
315 					if (ec.ec)
316 					{
317 						ec.file(file_index);
318 						ec.operation = operation_t::mkdir;
319 						break;
320 					}
321 				}
322 				ec.ec.clear();
323 
324 #if TORRENT_HAS_SYMLINK
325 				// create symlinks
326 				if (fs.file_flags(file_index) & file_storage::flag_symlink)
327 				{
328 					// we make the symlink target relative to the link itself
329 					std::string const target = lexically_relative(
330 						parent_path(fs.file_path(file_index)), fs.symlink(file_index));
331 					std::string const link = fs.file_path(file_index, m_save_path);
332 					if (::symlink(target.c_str(), link.c_str()) != 0)
333 					{
334 						int const error = errno;
335 						if (error == EEXIST)
336 						{
337 							// if the file exist, it may be a symlink already. if so,
338 							// just verify the link target is what it's supposed to be
339 							// note that readlink() does not null terminate the buffer
340 							char buffer[512];
341 							auto const ret = ::readlink(link.c_str(), buffer, sizeof(buffer));
342 							if (ret <= 0 || target != string_view(buffer, std::size_t(ret)))
343 							{
344 								ec.ec = error_code(error, generic_category());
345 								ec.file(file_index);
346 								ec.operation = operation_t::symlink;
347 								return;
348 							}
349 						}
350 						else
351 						{
352 							ec.ec = error_code(error, generic_category());
353 							ec.file(file_index);
354 							ec.operation = operation_t::symlink;
355 							return;
356 						}
357 					}
358 				}
359 				else
360 #endif
361 				{
362 					// just creating the file is enough to make it zero-sized. If
363 					// there's a race here and some other process truncates the file,
364 					// it's not a problem, we won't access empty files ever again
365 					file_handle f = open_file(file_index, open_mode::read_write
366 						| open_mode::random_access, ec);
367 					if (ec) return;
368 				}
369 			}
370 			ec.ec.clear();
371 		}
372 
373 		// close files that were opened in write mode
374 		m_pool.release(storage_index());
375 	}
376 
has_any_file(storage_error & ec)377 	bool default_storage::has_any_file(storage_error& ec)
378 	{
379 		m_stat_cache.reserve(files().num_files());
380 
381 		if (aux::has_any_file(files(), m_save_path, m_stat_cache, ec))
382 			return true;
383 
384 		if (ec) return false;
385 
386 		file_status s;
387 		stat_file(combine_path(m_save_path, m_part_file_name), &s, ec.ec);
388 		if (!ec) return true;
389 
390 		// the part file not existing is expected
391 		if (ec && ec.ec == boost::system::errc::no_such_file_or_directory)
392 			ec.ec.clear();
393 
394 		if (ec)
395 		{
396 			ec.file(torrent_status::error_file_partfile);
397 			ec.operation = operation_t::file_stat;
398 			return false;
399 		}
400 		return false;
401 	}
402 
rename_file(file_index_t const index,std::string const & new_filename,storage_error & ec)403 	void default_storage::rename_file(file_index_t const index, std::string const& new_filename
404 		, storage_error& ec)
405 	{
406 		if (index < file_index_t(0) || index >= files().end_file()) return;
407 		std::string old_name = files().file_path(index, m_save_path);
408 		m_pool.release(storage_index(), index);
409 
410 		// if the old file doesn't exist, just succeed and change the filename
411 		// that will be created. This shortcut is important because the
412 		// destination directory may not exist yet, which would cause a failure
413 		// even though we're not moving a file (yet). It's better for it to
414 		// fail later when we try to write to the file the first time, because
415 		// the user then will have had a chance to make the destination directory
416 		// valid.
417 		if (exists(old_name, ec.ec))
418 		{
419 			std::string new_path;
420 			if (is_complete(new_filename)) new_path = new_filename;
421 			else new_path = combine_path(m_save_path, new_filename);
422 			std::string new_dir = parent_path(new_path);
423 
424 			// create any missing directories that the new filename
425 			// lands in
426 			create_directories(new_dir, ec.ec);
427 			if (ec.ec)
428 			{
429 				ec.file(index);
430 				ec.operation = operation_t::file_rename;
431 				return;
432 			}
433 
434 			rename(old_name, new_path, ec.ec);
435 
436 			// if old_name doesn't exist, that's not an error
437 			// here. Once we start writing to the file, it will
438 			// be written to the new filename
439 			if (ec.ec == boost::system::errc::no_such_file_or_directory)
440 				ec.ec.clear();
441 
442 			if (ec)
443 			{
444 				ec.ec.clear();
445 				copy_file(old_name, new_path, ec.ec);
446 
447 				if (ec)
448 				{
449 					ec.file(index);
450 					ec.operation = operation_t::file_rename;
451 					return;
452 				}
453 
454 				error_code ignore;
455 				remove(old_name, ignore);
456 			}
457 		}
458 		else if (ec.ec)
459 		{
460 			// if exists fails, report that error
461 			ec.file(index);
462 			ec.operation = operation_t::file_rename;
463 			return;
464 		}
465 
466 		// if old path doesn't exist, just rename the file
467 		// in our file_storage, so that when it is created
468 		// it will get the new name
469 		if (!m_mapped_files)
470 		{ m_mapped_files.reset(new file_storage(files())); }
471 		m_mapped_files->rename_file(index, new_filename);
472 	}
473 
release_files(storage_error &)474 	void default_storage::release_files(storage_error&)
475 	{
476 		if (m_part_file)
477 		{
478 			error_code ignore;
479 			m_part_file->flush_metadata(ignore);
480 		}
481 
482 		// make sure we don't have the files open
483 		m_pool.release(storage_index());
484 
485 		// make sure we can pick up new files added to the download directory when
486 		// we start the torrent again
487 		m_stat_cache.clear();
488 	}
489 
delete_files(remove_flags_t const options,storage_error & ec)490 	void default_storage::delete_files(remove_flags_t const options, storage_error& ec)
491 	{
492 		// make sure we don't have the files open
493 		m_pool.release(storage_index());
494 
495 		// if there's a part file open, make sure to destruct it to have it
496 		// release the underlying part file. Otherwise we may not be able to
497 		// delete it
498 		if (m_part_file) m_part_file.reset();
499 
500 		aux::delete_files(files(), m_save_path, m_part_file_name, options, ec);
501 	}
502 
verify_resume_data(add_torrent_params const & rd,aux::vector<std::string,file_index_t> const & links,storage_error & ec)503 	bool default_storage::verify_resume_data(add_torrent_params const& rd
504 		, aux::vector<std::string, file_index_t> const& links
505 		, storage_error& ec)
506 	{
507 		return aux::verify_resume_data(rd, links, files()
508 			, m_file_priority, m_stat_cache, m_save_path, ec);
509 	}
510 
move_storage(std::string const & sp,move_flags_t const flags,storage_error & ec)511 	status_t default_storage::move_storage(std::string const& sp
512 		, move_flags_t const flags, storage_error& ec)
513 	{
514 		m_pool.release(storage_index());
515 
516 		status_t ret;
517 		std::tie(ret, m_save_path) = aux::move_storage(files(), m_save_path, sp
518 			, m_part_file.get(), flags, ec);
519 
520 		// clear the stat cache in case the new location has new files
521 		m_stat_cache.clear();
522 
523 		return ret;
524 	}
525 
readv(span<iovec_t const> bufs,piece_index_t const piece,int const offset,open_mode_t const flags,storage_error & error)526 	int default_storage::readv(span<iovec_t const> bufs
527 		, piece_index_t const piece, int const offset
528 		, open_mode_t const flags, storage_error& error)
529 	{
530 #ifdef TORRENT_SIMULATE_SLOW_READ
531 		std::this_thread::sleep_for(seconds(1));
532 #endif
533 		return readwritev(files(), bufs, piece, offset, error
534 			, [this, flags](file_index_t const file_index
535 				, std::int64_t const file_offset
536 				, span<iovec_t const> vec, storage_error& ec)
537 		{
538 			if (files().pad_file_at(file_index))
539 			{
540 				// reading from a pad file yields zeroes
541 				aux::clear_bufs(vec);
542 				return bufs_size(vec);
543 			}
544 
545 			if (file_index < m_file_priority.end_index()
546 				&& m_file_priority[file_index] == dont_download
547 				&& use_partfile(file_index))
548 			{
549 				TORRENT_ASSERT(m_part_file);
550 
551 				error_code e;
552 				peer_request map = files().map_file(file_index
553 					, file_offset, 0);
554 				int const ret = m_part_file->readv(vec
555 					, map.piece, map.start, e);
556 
557 				if (e)
558 				{
559 					ec.ec = e;
560 					ec.file(file_index);
561 					ec.operation = operation_t::partfile_read;
562 					return -1;
563 				}
564 				return ret;
565 			}
566 
567 			file_handle handle = open_file(file_index
568 				, open_mode::read_only | flags, ec);
569 			if (ec) return -1;
570 
571 			error_code e;
572 			int const ret = int(handle->readv(file_offset
573 				, vec, e, flags));
574 
575 			// set this unconditionally in case the upper layer would like to treat
576 			// short reads as errors
577 			ec.operation = operation_t::file_read;
578 
579 			// we either get an error or 0 or more bytes read
580 			TORRENT_ASSERT(e || ret >= 0);
581 			TORRENT_ASSERT(ret <= bufs_size(vec));
582 
583 			if (e)
584 			{
585 				ec.ec = e;
586 				ec.file(file_index);
587 				return -1;
588 			}
589 
590 			return ret;
591 		});
592 	}
593 
writev(span<iovec_t const> bufs,piece_index_t const piece,int const offset,open_mode_t const flags,storage_error & error)594 	int default_storage::writev(span<iovec_t const> bufs
595 		, piece_index_t const piece, int const offset
596 		, open_mode_t const flags, storage_error& error)
597 	{
598 		return readwritev(files(), bufs, piece, offset, error
599 			, [this, flags](file_index_t const file_index
600 				, std::int64_t const file_offset
601 				, span<iovec_t const> vec, storage_error& ec)
602 		{
603 			if (files().pad_file_at(file_index))
604 			{
605 				// writing to a pad-file is a no-op
606 				return bufs_size(vec);
607 			}
608 
609 			if (file_index < m_file_priority.end_index()
610 				&& m_file_priority[file_index] == dont_download
611 				&& use_partfile(file_index))
612 			{
613 				TORRENT_ASSERT(m_part_file);
614 
615 				error_code e;
616 				peer_request map = files().map_file(file_index
617 					, file_offset, 0);
618 				int const ret = m_part_file->writev(vec
619 					, map.piece, map.start, e);
620 
621 				if (e)
622 				{
623 					ec.ec = e;
624 					ec.file(file_index);
625 					ec.operation = operation_t::partfile_write;
626 					return -1;
627 				}
628 				return ret;
629 			}
630 
631 			// invalidate our stat cache for this file, since
632 			// we're writing to it
633 			m_stat_cache.set_dirty(file_index);
634 
635 			file_handle handle = open_file(file_index
636 				, open_mode::read_write, ec);
637 			if (ec) return -1;
638 
639 			error_code e;
640 			int const ret = int(handle->writev(file_offset
641 				, vec, e, flags));
642 
643 			// set this unconditionally in case the upper layer would like to treat
644 			// short reads as errors
645 			ec.operation = operation_t::file_write;
646 
647 			// we either get an error or 0 or more bytes read
648 			TORRENT_ASSERT(e || ret >= 0);
649 			TORRENT_ASSERT(ret <= bufs_size(vec));
650 
651 			if (e)
652 			{
653 				ec.ec = e;
654 				ec.file(file_index);
655 				return -1;
656 			}
657 
658 			return ret;
659 		});
660 	}
661 
open_file(file_index_t const file,open_mode_t mode,storage_error & ec) const662 	file_handle default_storage::open_file(file_index_t const file
663 		, open_mode_t mode, storage_error& ec) const
664 	{
665 		file_handle h = open_file_impl(file, mode, ec.ec);
666 		if (((mode & open_mode::rw_mask) != open_mode::read_only)
667 			&& ec.ec == boost::system::errc::no_such_file_or_directory)
668 		{
669 			// this means the directory the file is in doesn't exist.
670 			// so create it
671 			ec.ec.clear();
672 			std::string path = files().file_path(file, m_save_path);
673 			create_directories(parent_path(path), ec.ec);
674 
675 			if (ec.ec)
676 			{
677 				ec.file(file);
678 				ec.operation = operation_t::mkdir;
679 				return file_handle();
680 			}
681 
682 			// if the directory creation failed, don't try to open the file again
683 			// but actually just fail
684 			h = open_file_impl(file, mode, ec.ec);
685 		}
686 		if (ec.ec)
687 		{
688 			ec.file(file);
689 			ec.operation = operation_t::file_open;
690 			return file_handle();
691 		}
692 		TORRENT_ASSERT(h);
693 
694 		if ((mode & open_mode::rw_mask) != open_mode::read_only)
695 		{
696 			std::unique_lock<std::mutex> l(m_file_created_mutex);
697 			if (m_file_created.size() != files().num_files())
698 				m_file_created.resize(files().num_files(), false);
699 
700 			TORRENT_ASSERT(int(m_file_created.size()) == files().num_files());
701 			TORRENT_ASSERT(file < m_file_created.end_index());
702 			// if this is the first time we open this file for writing,
703 			// and we have m_allocate_files enabled, set the final size of
704 			// the file right away, to allocate it on the filesystem.
705 			if (m_file_created[file] == false)
706 			{
707 				m_file_created.set_bit(file);
708 				l.unlock();
709 
710 				// if we're allocating files or if the file exists and is greater
711 				// than what it's supposed to be, truncate it to its correct size
712 				std::int64_t const size = files().file_size(file);
713 				error_code e;
714 				bool const need_truncate = h->get_size(e) > size;
715 				if (e)
716 				{
717 					ec.ec = e;
718 					ec.file(file);
719 					ec.operation = operation_t::file_stat;
720 					return h;
721 				}
722 
723 				if (m_allocate_files || need_truncate)
724 				{
725 					h->set_size(size, e);
726 					if (e)
727 					{
728 						ec.ec = e;
729 						ec.file(file);
730 						ec.operation = operation_t::file_fallocate;
731 						return h;
732 					}
733 					m_stat_cache.set_dirty(file);
734 				}
735 			}
736 		}
737 		return h;
738 	}
739 
open_file_impl(file_index_t file,open_mode_t mode,error_code & ec) const740 	file_handle default_storage::open_file_impl(file_index_t file, open_mode_t mode
741 		, error_code& ec) const
742 	{
743 		if (!m_allocate_files) mode |= open_mode::sparse;
744 
745 		// files with priority 0 should always be sparse
746 		if (m_file_priority.end_index() > file
747 			&& m_file_priority[file] == dont_download)
748 		{
749 			mode |= open_mode::sparse;
750 		}
751 
752 		if (m_settings.load() && settings().get_bool(settings_pack::no_atime_storage)) mode |= open_mode::no_atime;
753 
754 		// if we have a cache already, don't store the data twice by leaving it in the OS cache as well
755 		if (m_settings.load()
756 			&& settings().get_int(settings_pack::disk_io_write_mode)
757 			== settings_pack::disable_os_cache)
758 		{
759 			mode |= open_mode::no_cache;
760 		}
761 
762 		file_handle ret = m_pool.open_file(storage_index(), m_save_path, file
763 			, files(), mode, ec);
764 		return ret;
765 	}
766 
tick()767 	bool default_storage::tick()
768 	{
769 		error_code ec;
770 		if (m_part_file) m_part_file->flush_metadata(ec);
771 
772 		return false;
773 	}
774 
default_storage_constructor(storage_params const & params,file_pool & pool)775 	storage_interface* default_storage_constructor(storage_params const& params
776 		, file_pool& pool)
777 	{
778 		return new default_storage(params, pool);
779 	}
780 
781 	// -- disabled_storage --------------------------------------------------
782 
783 namespace {
784 
785 		// this storage implementation does not write anything to disk
786 		// and it pretends to read, and just leaves garbage in the buffers
787 		// this is useful when simulating many clients on the same machine
788 		// or when running stress tests and want to take the cost of the
789 		// disk I/O out of the picture. This cannot be used for any kind
790 		// of normal bittorrent operation, since it will just send garbage
791 		// to peers and throw away all the data it downloads. It would end
792 		// up being banned immediately
793 		class disabled_storage final : public storage_interface
794 		{
795 		public:
disabled_storage(file_storage const & fs)796 			explicit disabled_storage(file_storage const& fs) : storage_interface(fs) {}
797 
has_any_file(storage_error &)798 			bool has_any_file(storage_error&) override { return false; }
set_file_priority(aux::vector<download_priority_t,file_index_t> &,storage_error &)799 			void set_file_priority(aux::vector<download_priority_t, file_index_t>&
800 				, storage_error&) override {}
rename_file(file_index_t,std::string const &,storage_error &)801 			void rename_file(file_index_t, std::string const&, storage_error&) override {}
release_files(storage_error &)802 			void release_files(storage_error&) override {}
delete_files(remove_flags_t,storage_error &)803 			void delete_files(remove_flags_t, storage_error&) override {}
initialize(storage_error &)804 			void initialize(storage_error&) override {}
move_storage(std::string const &,move_flags_t,storage_error &)805 			status_t move_storage(std::string const&, move_flags_t, storage_error&) override { return status_t::no_error; }
806 
readv(span<iovec_t const> bufs,piece_index_t,int,open_mode_t,storage_error &)807 			int readv(span<iovec_t const> bufs
808 				, piece_index_t, int, open_mode_t, storage_error&) override
809 			{
810 				return bufs_size(bufs);
811 			}
writev(span<iovec_t const> bufs,piece_index_t,int,open_mode_t,storage_error &)812 			int writev(span<iovec_t const> bufs
813 				, piece_index_t, int, open_mode_t, storage_error&) override
814 			{
815 				return bufs_size(bufs);
816 			}
817 
verify_resume_data(add_torrent_params const &,aux::vector<std::string,file_index_t> const &,storage_error &)818 			bool verify_resume_data(add_torrent_params const&
819 				, aux::vector<std::string, file_index_t> const&
820 				, storage_error&) override { return false; }
821 		};
822 	}
823 
disabled_storage_constructor(storage_params const & params,file_pool &)824 	storage_interface* disabled_storage_constructor(storage_params const& params, file_pool&)
825 	{
826 		return new disabled_storage(params.files);
827 	}
828 
829 	// -- zero_storage ------------------------------------------------------
830 
831 namespace {
832 
833 		// this storage implementation always reads zeroes, and always discards
834 		// anything written to it
835 		struct zero_storage final : storage_interface
836 		{
zero_storagelibtorrent::__anon023f1a3b0511::zero_storage837 			explicit zero_storage(file_storage const& fs) : storage_interface(fs) {}
initializelibtorrent::__anon023f1a3b0511::zero_storage838 			void initialize(storage_error&) override {}
839 
readvlibtorrent::__anon023f1a3b0511::zero_storage840 			int readv(span<iovec_t const> bufs
841 				, piece_index_t, int, open_mode_t, storage_error&) override
842 			{
843 				int ret = 0;
844 				for (auto const& b : bufs)
845 				{
846 					std::memset(b.data(), 0, std::size_t(b.size()));
847 					ret += int(b.size());
848 				}
849 				return ret;
850 			}
writevlibtorrent::__anon023f1a3b0511::zero_storage851 			int writev(span<iovec_t const> bufs
852 				, piece_index_t, int, open_mode_t, storage_error&) override
853 			{
854 				return std::accumulate(bufs.begin(), bufs.end(), 0
855 					, [](int const acc, iovec_t const& b) { return acc + int(b.size()); });
856 			}
857 
has_any_filelibtorrent::__anon023f1a3b0511::zero_storage858 			bool has_any_file(storage_error&) override { return false; }
set_file_prioritylibtorrent::__anon023f1a3b0511::zero_storage859 			void set_file_priority(aux::vector<download_priority_t, file_index_t>& /* prio */
860 				, storage_error&) override {}
move_storagelibtorrent::__anon023f1a3b0511::zero_storage861 			status_t move_storage(std::string const& /* save_path */
862 				, move_flags_t, storage_error&) override { return status_t::no_error; }
verify_resume_datalibtorrent::__anon023f1a3b0511::zero_storage863 			bool verify_resume_data(add_torrent_params const& /* rd */
864 				, aux::vector<std::string, file_index_t> const& /* links */
865 				, storage_error&) override
866 			{ return false; }
release_fileslibtorrent::__anon023f1a3b0511::zero_storage867 			void release_files(storage_error&) override {}
rename_filelibtorrent::__anon023f1a3b0511::zero_storage868 			void rename_file(file_index_t
869 				, std::string const& /* new_filename */, storage_error&) override {}
delete_fileslibtorrent::__anon023f1a3b0511::zero_storage870 			void delete_files(remove_flags_t, storage_error&) override {}
871 		};
872 	}
873 
zero_storage_constructor(storage_params const & params,file_pool &)874 	storage_interface* zero_storage_constructor(storage_params const& params, file_pool&)
875 	{
876 		return new zero_storage(params.files);
877 	}
878 
879 } // namespace libtorrent
880