2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2003-2016, Arvid Norberg, Daniel Wallin
|
2003-10-23 01:00:57 +02:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2015-06-06 08:10:53 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
|
|
|
#include "libtorrent/error_code.hpp"
|
2017-01-11 06:42:10 +01:00
|
|
|
#include "libtorrent/aux_/storage_utils.hpp"
|
2015-06-06 08:10:53 +02:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <ctime>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
2004-12-21 13:30:09 +01:00
|
|
|
#include <functional>
|
2016-05-23 14:15:39 +02:00
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
// for getattrlist()
|
|
|
|
#include <sys/attr.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
// for statfs()
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__linux__)
|
|
|
|
#include <sys/statfs.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
// for statfs()
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mount.h>
|
2004-01-25 19:18:36 +01:00
|
|
|
#endif
|
|
|
|
|
2015-04-21 03:16:28 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
2015-04-18 04:33:39 +02:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/storage.hpp"
|
|
|
|
#include "libtorrent/torrent.hpp"
|
2017-04-11 06:52:46 +02:00
|
|
|
#include "libtorrent/aux_/path.hpp"
|
2004-01-25 19:18:36 +01:00
|
|
|
#include "libtorrent/invariant_check.hpp"
|
2006-11-14 14:36:10 +01:00
|
|
|
#include "libtorrent/file_pool.hpp"
|
2006-10-11 16:02:21 +02:00
|
|
|
#include "libtorrent/aux_/session_impl.hpp"
|
2008-04-10 12:03:23 +02:00
|
|
|
#include "libtorrent/disk_buffer_holder.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/stat_cache.hpp"
|
2016-06-04 16:01:43 +02:00
|
|
|
#include "libtorrent/hex.hpp" // to_hex
|
2009-03-01 01:02:33 +01:00
|
|
|
// for convert_to_wstring and convert_to_native
|
2015-03-15 00:10:20 +01:00
|
|
|
#include "libtorrent/aux_/escape_string.hpp"
|
2005-08-16 20:39:38 +02:00
|
|
|
|
2017-04-12 19:00:57 +02:00
|
|
|
namespace libtorrent {
|
|
|
|
|
2017-01-11 06:42:10 +01:00
|
|
|
void clear_bufs(span<iovec_t const> bufs)
|
2009-01-03 09:11:31 +01:00
|
|
|
{
|
2016-10-27 02:40:56 +02:00
|
|
|
for (auto buf : bufs)
|
2017-04-29 06:27:55 +02:00
|
|
|
std::memset(buf.data(), 0, buf.size());
|
2009-01-03 09:11:31 +01:00
|
|
|
}
|
|
|
|
|
2017-04-07 00:11:24 +02:00
|
|
|
default_storage::default_storage(storage_params const& params
|
|
|
|
, file_pool& pool)
|
|
|
|
: storage_interface(*params.files)
|
|
|
|
, m_pool(pool)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_allocate_files(params.mode == storage_mode_allocate)
|
|
|
|
{
|
|
|
|
if (params.mapped_files) m_mapped_files.reset(new file_storage(*params.mapped_files));
|
|
|
|
if (params.priorities) m_file_priority = *params.priorities;
|
|
|
|
|
2017-04-07 00:11:24 +02:00
|
|
|
TORRENT_ASSERT(files().num_files() > 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
m_save_path = complete(params.path);
|
|
|
|
m_part_file_name = "." + (params.info
|
2016-07-29 08:36:15 +02:00
|
|
|
? aux::to_hex(params.info->info_hash())
|
2014-07-06 21:18:00 +02:00
|
|
|
: params.files->name()) + ".parts";
|
|
|
|
}
|
|
|
|
|
|
|
|
default_storage::~default_storage()
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
if (m_part_file) m_part_file->flush_metadata(ec);
|
|
|
|
|
|
|
|
// this may be called from a different
|
|
|
|
// thread than the disk thread
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index());
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void default_storage::need_partfile()
|
2007-06-10 22:46:09 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_part_file) return;
|
|
|
|
|
|
|
|
m_part_file.reset(new part_file(
|
|
|
|
m_save_path, m_part_file_name
|
2017-04-07 00:11:24 +02:00
|
|
|
, files().num_pieces(), files().piece_length()));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void default_storage::set_file_priority(
|
|
|
|
aux::vector<std::uint8_t, file_index_t> const& prio
|
|
|
|
, storage_error& ec)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// extend our file priorities in case it's truncated
|
2017-02-11 20:58:02 +01:00
|
|
|
// the default assumed priority is 4 (the default)
|
2014-07-06 21:18:00 +02:00
|
|
|
if (prio.size() > m_file_priority.size())
|
2017-02-11 20:58:02 +01:00
|
|
|
m_file_priority.resize(prio.size(), default_piece_priority);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
file_storage const& fs = files();
|
2016-12-22 16:42:33 +01:00
|
|
|
for (file_index_t i(0); i < prio.end_index(); ++i)
|
2007-09-19 21:55:11 +02:00
|
|
|
{
|
2016-03-03 00:38:13 +01:00
|
|
|
int const old_prio = m_file_priority[i];
|
2014-07-06 21:18:00 +02:00
|
|
|
int new_prio = prio[i];
|
|
|
|
if (old_prio == 0 && new_prio != 0)
|
2009-01-11 03:02:34 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// move stuff out of the part file
|
2017-05-26 20:49:21 +02:00
|
|
|
file_handle f = open_file(i, open_mode_t::read_write, ec);
|
2015-01-03 17:57:21 +01:00
|
|
|
if (ec) return;
|
2009-05-03 21:09:06 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
need_partfile();
|
|
|
|
|
2017-04-15 02:25:24 +02:00
|
|
|
m_part_file->export_file([&f, &ec](std::int64_t file_offset, span<char> buf)
|
|
|
|
{
|
|
|
|
iovec_t const v = {buf.data(), buf.size()};
|
|
|
|
std::int64_t const ret = f->writev(file_offset, v, ec.ec);
|
2017-04-23 03:33:38 +02:00
|
|
|
TORRENT_UNUSED(ret);
|
2017-04-29 06:27:55 +02:00
|
|
|
TORRENT_ASSERT(ec || ret == std::int64_t(v.size()));
|
2017-04-15 02:25:24 +02:00
|
|
|
}, fs.file_offset(i), fs.file_size(i), ec.ec);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec)
|
2009-05-03 21:09:06 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::partfile_write;
|
|
|
|
return;
|
2009-05-03 21:09:06 +02:00
|
|
|
}
|
2009-01-11 03:02:34 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
else if (old_prio != 0 && new_prio == 0)
|
2009-01-11 03:02:34 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// move stuff into the part file
|
|
|
|
// this is not implemented yet.
|
|
|
|
// pretend that we didn't set the priority to 0.
|
|
|
|
|
|
|
|
std::string fp = fs.file_path(i, m_save_path);
|
|
|
|
if (exists(fp))
|
|
|
|
new_prio = 1;
|
|
|
|
/*
|
2017-05-26 20:49:21 +02:00
|
|
|
file_handle f = open_file(i, open_mode_t::read_only, ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec.ec != boost::system::errc::no_such_file_or_directory)
|
2009-05-03 21:09:06 +02:00
|
|
|
{
|
2015-01-03 17:57:21 +01:00
|
|
|
if (ec) return;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
need_partfile();
|
2009-05-21 18:15:05 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_part_file->import_file(*f, fs.file_offset(i), fs.file_size(i), ec.ec);
|
|
|
|
if (ec)
|
2009-05-21 18:15:05 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::partfile_read;
|
|
|
|
return;
|
2009-05-21 18:15:05 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
// remove the file
|
|
|
|
std::string p = fs.file_path(i, m_save_path);
|
|
|
|
delete_one_file(p, ec.ec);
|
|
|
|
if (ec)
|
2009-05-21 18:15:05 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::remove;
|
2009-05-21 18:15:05 +02:00
|
|
|
}
|
2009-05-03 21:09:06 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
*/
|
2009-01-11 03:02:34 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.ec.clear();
|
2016-11-21 16:08:26 +01:00
|
|
|
m_file_priority[i] = std::uint8_t(new_prio);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
if (m_part_file) m_part_file->flush_metadata(ec.ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index_t(-1));
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::partfile_write;
|
2007-09-19 21:55:11 +02:00
|
|
|
}
|
2014-02-28 11:19:29 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void default_storage::initialize(storage_error& ec)
|
2007-04-19 05:06:15 +02:00
|
|
|
{
|
2015-12-11 07:08:57 +01:00
|
|
|
m_stat_cache.reserve(files().num_files());
|
2014-06-07 04:57:24 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
// don't do full file allocations on network drives
|
2014-06-09 06:08:41 +02:00
|
|
|
#if TORRENT_USE_WSTRING
|
2016-04-17 22:56:07 +02:00
|
|
|
std::wstring file_name = convert_to_wstring(m_save_path);
|
2016-10-27 05:30:58 +02:00
|
|
|
int const drive_type = GetDriveTypeW(file_name.c_str());
|
2014-06-09 06:08:41 +02:00
|
|
|
#else
|
2016-10-24 04:01:09 +02:00
|
|
|
int const drive_type = GetDriveTypeA(m_save_path.c_str());
|
2014-06-09 06:08:41 +02:00
|
|
|
#endif
|
|
|
|
|
2014-06-07 04:57:24 +02:00
|
|
|
if (drive_type == DRIVE_REMOTE)
|
|
|
|
m_allocate_files = false;
|
|
|
|
#endif
|
|
|
|
|
2017-05-07 17:01:42 +02:00
|
|
|
{
|
2017-05-08 13:48:42 +02:00
|
|
|
std::unique_lock<std::mutex> l(m_file_created_mutex);
|
2017-05-07 17:01:42 +02:00
|
|
|
m_file_created.resize(files().num_files(), false);
|
|
|
|
}
|
2013-12-30 03:50:29 +01:00
|
|
|
|
2007-04-19 05:06:15 +02:00
|
|
|
// first, create all missing directories
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string last_path;
|
2016-12-22 16:42:33 +01:00
|
|
|
file_storage const& fs = files();
|
|
|
|
for (file_index_t file_index(0); file_index < fs.end_file(); ++file_index)
|
2007-04-19 05:06:15 +02:00
|
|
|
{
|
2008-10-30 07:09:23 +01:00
|
|
|
// ignore files that have priority 0
|
2016-12-22 16:42:33 +01:00
|
|
|
if (m_file_priority.end_index() > file_index
|
2014-07-06 21:18:00 +02:00
|
|
|
&& m_file_priority[file_index] == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2008-10-30 07:09:23 +01:00
|
|
|
|
|
|
|
// ignore pad files
|
2013-08-12 09:30:57 +02:00
|
|
|
if (files().pad_file_at(file_index)) continue;
|
2007-04-19 05:06:15 +02:00
|
|
|
|
2015-12-11 07:08:57 +01:00
|
|
|
error_code err;
|
2016-06-18 20:01:38 +02:00
|
|
|
std::int64_t size = m_stat_cache.get_filesize(file_index, files()
|
2015-12-11 07:08:57 +01:00
|
|
|
, m_save_path, err);
|
|
|
|
|
|
|
|
if (err && err != boost::system::errc::no_such_file_or_directory)
|
2007-04-19 05:06:15 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index);
|
2015-12-11 07:08:57 +01:00
|
|
|
ec.operation = storage_error::stat;
|
|
|
|
ec.ec = err;
|
|
|
|
break;
|
2009-10-26 02:29:39 +01:00
|
|
|
}
|
|
|
|
|
2011-01-19 08:39:55 +01:00
|
|
|
// if the file already exists, but is larger than what
|
2013-12-30 03:50:29 +01:00
|
|
|
// it's supposed to be, truncate it
|
2011-01-19 08:39:55 +01:00
|
|
|
// if the file is empty, just create it either way.
|
2015-12-11 07:08:57 +01:00
|
|
|
if ((!err && size > files().file_size(file_index))
|
2014-07-06 21:18:00 +02:00
|
|
|
|| files().file_size(file_index) == 0)
|
2009-10-26 02:29:39 +01:00
|
|
|
{
|
2015-02-18 04:32:49 +01:00
|
|
|
std::string file_path = files().file_path(file_index, m_save_path);
|
2011-08-01 02:22:54 +02:00
|
|
|
std::string dir = parent_path(file_path);
|
|
|
|
|
|
|
|
if (dir != last_path)
|
|
|
|
{
|
|
|
|
last_path = dir;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
create_directories(last_path, ec.ec);
|
|
|
|
if (ec.ec)
|
2011-08-01 02:22:54 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::mkdir;
|
2011-08-01 02:22:54 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.ec.clear();
|
2017-05-26 20:49:21 +02:00
|
|
|
file_handle f = open_file(file_index, open_mode_t::read_write
|
|
|
|
| open_mode_t::random_access, ec);
|
2015-12-11 07:08:57 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index);
|
2015-12-11 07:08:57 +01:00
|
|
|
ec.operation = storage_error::fallocate;
|
|
|
|
return;
|
|
|
|
}
|
2015-01-03 17:57:21 +01:00
|
|
|
|
2015-12-11 07:08:57 +01:00
|
|
|
size = files().file_size(file_index);
|
2015-02-18 04:32:49 +01:00
|
|
|
f->set_size(size, ec.ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec)
|
2008-07-18 01:41:46 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::fallocate;
|
|
|
|
break;
|
2008-07-18 01:41:46 +02:00
|
|
|
}
|
2007-04-19 05:06:15 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.ec.clear();
|
2007-04-19 05:06:15 +02:00
|
|
|
}
|
2009-10-26 02:29:39 +01:00
|
|
|
|
2007-10-07 03:29:38 +02:00
|
|
|
// close files that were opened in write mode
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index());
|
2008-05-28 10:44:40 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool default_storage::has_any_file(storage_error& ec)
|
2009-04-10 09:22:27 +02:00
|
|
|
{
|
2015-12-11 07:08:57 +01:00
|
|
|
m_stat_cache.reserve(files().num_files());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
file_storage const& fs = files();
|
|
|
|
for (file_index_t i(0); i < fs.end_file(); ++i)
|
2009-04-10 09:22:27 +02:00
|
|
|
{
|
2016-09-23 22:51:20 +02:00
|
|
|
std::int64_t const sz = m_stat_cache.get_filesize(
|
2015-12-11 07:08:57 +01:00
|
|
|
i, files(), m_save_path, ec.ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-12-11 07:08:57 +01:00
|
|
|
if (sz < 0)
|
|
|
|
{
|
|
|
|
if (ec && ec.ec != boost::system::errc::no_such_file_or_directory)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::stat;
|
|
|
|
m_stat_cache.clear();
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-11 07:08:57 +01:00
|
|
|
// some files not existing is expected and not an error
|
|
|
|
ec.ec.clear();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-06-06 08:10:53 +02:00
|
|
|
|
2015-12-11 07:08:57 +01:00
|
|
|
if (sz > 0) return true;
|
2009-04-10 09:22:27 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
file_status s;
|
|
|
|
stat_file(combine_path(m_save_path, m_part_file_name), &s, ec.ec);
|
|
|
|
if (!ec) return true;
|
|
|
|
|
2015-12-11 07:08:57 +01:00
|
|
|
// the part file not existing is expected
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec && ec.ec == boost::system::errc::no_such_file_or_directory)
|
|
|
|
ec.ec.clear();
|
2015-12-11 07:08:57 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file_index_t(-1));
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::stat;
|
|
|
|
return false;
|
|
|
|
}
|
2009-04-10 09:22:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void default_storage::rename_file(file_index_t const index, std::string const& new_filename
|
2014-12-26 22:25:37 +01:00
|
|
|
, storage_error& ec)
|
2008-05-28 10:44:40 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
if (index < file_index_t(0) || index >= files().end_file()) return;
|
2013-06-10 00:30:02 +02:00
|
|
|
std::string old_name = files().file_path(index, m_save_path);
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index(), index);
|
2008-05-28 10:44:40 +02:00
|
|
|
|
2014-12-26 22:25:37 +01:00
|
|
|
// if the old file doesn't exist, just succeed and change the filename
|
|
|
|
// that will be created. This shortcut is important because the
|
|
|
|
// destination directory may not exist yet, which would cause a failure
|
|
|
|
// even though we're not moving a file (yet). It's better for it to
|
|
|
|
// fail later when we try to write to the file the first time, because
|
|
|
|
// the user then will have had a chance to make the destination directory
|
|
|
|
// valid.
|
2015-01-13 19:28:06 +01:00
|
|
|
if (exists(old_name, ec.ec))
|
2014-12-26 22:25:37 +01:00
|
|
|
{
|
2015-01-13 19:28:06 +01:00
|
|
|
std::string new_path;
|
|
|
|
if (is_complete(new_filename)) new_path = new_filename;
|
|
|
|
else new_path = combine_path(m_save_path, new_filename);
|
|
|
|
std::string new_dir = parent_path(new_path);
|
|
|
|
|
|
|
|
// create any missing directories that the new filename
|
|
|
|
// lands in
|
|
|
|
create_directories(new_dir, ec.ec);
|
|
|
|
if (ec.ec)
|
2014-12-26 22:25:37 +01:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(index);
|
2015-01-13 19:28:06 +01:00
|
|
|
ec.operation = storage_error::rename;
|
2014-12-26 22:25:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-13 19:28:06 +01:00
|
|
|
rename(old_name, new_path, ec.ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-01-13 19:28:06 +01:00
|
|
|
// if old_name doesn't exist, that's not an error
|
|
|
|
// here. Once we start writing to the file, it will
|
|
|
|
// be written to the new filename
|
|
|
|
if (ec.ec == boost::system::errc::no_such_file_or_directory)
|
|
|
|
ec.ec.clear();
|
2013-02-09 22:50:22 +01:00
|
|
|
|
2015-01-13 19:28:06 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(index);
|
2015-01-13 19:28:06 +01:00
|
|
|
ec.operation = storage_error::rename;
|
|
|
|
return;
|
|
|
|
}
|
2013-02-09 22:50:22 +01:00
|
|
|
}
|
2015-01-13 19:28:06 +01:00
|
|
|
else if (ec.ec)
|
2008-05-28 10:44:40 +02:00
|
|
|
{
|
2015-01-13 19:28:06 +01:00
|
|
|
// if exists fails, report that error
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(index);
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.operation = storage_error::rename;
|
|
|
|
return;
|
2008-05-28 10:44:40 +02:00
|
|
|
}
|
2009-10-26 02:29:39 +01:00
|
|
|
|
|
|
|
// if old path doesn't exist, just rename the file
|
|
|
|
// in our file_storage, so that when it is created
|
|
|
|
// it will get the new name
|
|
|
|
if (!m_mapped_files)
|
2017-04-07 00:11:24 +02:00
|
|
|
{ m_mapped_files.reset(new file_storage(files())); }
|
2009-10-26 02:29:39 +01:00
|
|
|
m_mapped_files->rename_file(index, new_filename);
|
2007-04-19 05:06:15 +02:00
|
|
|
}
|
|
|
|
|
2015-04-19 08:28:21 +02:00
|
|
|
void default_storage::release_files(storage_error&)
|
2004-12-21 13:30:09 +01:00
|
|
|
{
|
2015-10-24 21:35:42 +02:00
|
|
|
if (m_part_file)
|
|
|
|
{
|
|
|
|
error_code ignore;
|
|
|
|
m_part_file->flush_metadata(ignore);
|
|
|
|
m_part_file.reset();
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// make sure we don't have the files open
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2017-01-28 20:36:23 +01:00
|
|
|
// make sure we can pick up new files added to the download directory when
|
|
|
|
// we start the torrent again
|
|
|
|
m_stat_cache.clear();
|
2003-12-07 17:26:16 +01:00
|
|
|
}
|
|
|
|
|
2016-03-13 08:50:37 +01:00
|
|
|
void default_storage::delete_files(int const options, storage_error& ec)
|
2007-10-13 05:33:33 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
// this is a fence job, we expect no other
|
|
|
|
// threads to hold any references to any files
|
2015-06-06 08:10:53 +02:00
|
|
|
// in this file storage. Assert that that's the
|
2014-07-06 21:18:00 +02:00
|
|
|
// case
|
2016-12-31 18:35:10 +01:00
|
|
|
if (!m_pool.assert_idle_files(storage_index()))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-05-02 18:36:21 +02:00
|
|
|
TORRENT_ASSERT_FAIL();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-10-13 05:33:33 +02:00
|
|
|
// make sure we don't have the files open
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index());
|
2007-10-13 05:33:33 +02:00
|
|
|
|
2016-03-13 08:50:37 +01:00
|
|
|
// if there's a part file open, make sure to destruct it to have it
|
|
|
|
// release the underlying part file. Otherwise we may not be able to
|
|
|
|
// delete it
|
|
|
|
if (m_part_file) m_part_file.reset();
|
|
|
|
|
2017-01-20 06:01:00 +01:00
|
|
|
aux::delete_files(files(), m_save_path, m_part_file_name, options, ec);
|
2007-10-13 05:33:33 +02:00
|
|
|
}
|
|
|
|
|
2016-02-15 00:17:32 +01:00
|
|
|
bool default_storage::verify_resume_data(add_torrent_params const& rd
|
2016-12-22 16:42:33 +01:00
|
|
|
, aux::vector<std::string, file_index_t> const& links
|
2015-03-21 01:12:40 +01:00
|
|
|
, storage_error& ec)
|
2007-03-28 01:49:05 +02:00
|
|
|
{
|
2017-01-20 06:01:00 +01:00
|
|
|
return aux::verify_resume_data(rd, links, files()
|
|
|
|
, m_file_priority, m_stat_cache, m_save_path, ec);
|
2007-03-28 01:49:05 +02:00
|
|
|
}
|
|
|
|
|
2017-06-01 10:15:15 +02:00
|
|
|
status_t default_storage::move_storage(std::string const& sp
|
|
|
|
, move_flags_t const flags, storage_error& ec)
|
2004-07-18 02:39:58 +02:00
|
|
|
{
|
2016-12-31 18:35:10 +01:00
|
|
|
m_pool.release(storage_index());
|
2013-05-09 04:50:16 +02:00
|
|
|
|
2017-01-17 14:02:44 +01:00
|
|
|
status_t ret;
|
2017-01-20 06:01:00 +01:00
|
|
|
std::tie(ret, m_save_path) = aux::move_storage(files(), m_save_path, sp
|
2017-01-17 14:02:44 +01:00
|
|
|
, m_part_file.get(), flags, ec);
|
2016-05-01 04:18:38 +02:00
|
|
|
|
2017-01-28 20:36:23 +01:00
|
|
|
// clear the stat cache in case the new location has new files
|
|
|
|
m_stat_cache.clear();
|
2016-05-01 04:18:38 +02:00
|
|
|
|
2009-09-05 09:21:10 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-01-11 06:42:10 +01:00
|
|
|
int default_storage::readv(span<iovec_t const> bufs
|
2017-04-09 07:28:46 +02:00
|
|
|
, piece_index_t const piece, int const offset
|
2017-05-26 20:49:21 +02:00
|
|
|
, open_mode_t const flags, storage_error& error)
|
2009-01-17 09:35:48 +01:00
|
|
|
{
|
2009-09-05 09:21:10 +02:00
|
|
|
#ifdef TORRENT_SIMULATE_SLOW_READ
|
2016-09-27 02:05:04 +02:00
|
|
|
std::this_thread::sleep_for(seconds(1));
|
2009-09-05 09:21:10 +02:00
|
|
|
#endif
|
2017-05-02 06:07:50 +02:00
|
|
|
return readwritev(files(), bufs, piece, offset, error
|
|
|
|
, [this, flags](file_index_t const file_index
|
|
|
|
, std::int64_t const file_offset
|
|
|
|
, span<iovec_t const> vec, storage_error& ec)
|
|
|
|
{
|
|
|
|
if (files().pad_file_at(file_index))
|
|
|
|
{
|
|
|
|
// reading from a pad file yields zeroes
|
|
|
|
clear_bufs(vec);
|
|
|
|
return bufs_size(vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file_index < m_file_priority.end_index()
|
|
|
|
&& m_file_priority[file_index] == 0)
|
|
|
|
{
|
|
|
|
need_partfile();
|
|
|
|
|
|
|
|
error_code e;
|
|
|
|
peer_request map = files().map_file(file_index
|
|
|
|
, file_offset, 0);
|
|
|
|
int const ret = m_part_file->readv(vec
|
|
|
|
, map.piece, map.start, e);
|
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
ec.ec = e;
|
|
|
|
ec.file(file_index);
|
|
|
|
ec.operation = storage_error::partfile_read;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_handle handle = open_file(file_index
|
2017-05-26 20:49:21 +02:00
|
|
|
, open_mode_t::read_only | flags, ec);
|
2017-05-02 06:07:50 +02:00
|
|
|
if (ec) return -1;
|
|
|
|
|
|
|
|
error_code e;
|
2017-05-04 15:22:17 +02:00
|
|
|
int const ret = int(handle->readv(file_offset
|
2017-05-02 06:07:50 +02:00
|
|
|
, vec, e, flags));
|
|
|
|
|
|
|
|
// set this unconditionally in case the upper layer would like to treat
|
|
|
|
// short reads as errors
|
|
|
|
ec.operation = storage_error::read;
|
|
|
|
|
2017-05-03 01:44:07 +02:00
|
|
|
// we either get an error or 0 or more bytes read
|
2017-05-02 06:07:50 +02:00
|
|
|
TORRENT_ASSERT(e || ret >= 0);
|
|
|
|
TORRENT_ASSERT(ret <= bufs_size(vec));
|
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
ec.ec = e;
|
|
|
|
ec.file(file_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
});
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2017-01-11 06:42:10 +01:00
|
|
|
int default_storage::writev(span<iovec_t const> bufs
|
2017-04-09 07:28:46 +02:00
|
|
|
, piece_index_t const piece, int const offset
|
2017-05-26 20:49:21 +02:00
|
|
|
, open_mode_t const flags, storage_error& error)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-05-02 06:07:50 +02:00
|
|
|
return readwritev(files(), bufs, piece, offset, error
|
|
|
|
, [this, flags](file_index_t const file_index
|
|
|
|
, std::int64_t const file_offset
|
|
|
|
, span<iovec_t const> vec, storage_error& ec)
|
|
|
|
{
|
|
|
|
if (files().pad_file_at(file_index))
|
|
|
|
{
|
|
|
|
// writing to a pad-file is a no-op
|
|
|
|
return bufs_size(vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file_index < m_file_priority.end_index()
|
|
|
|
&& m_file_priority[file_index] == 0)
|
|
|
|
{
|
|
|
|
need_partfile();
|
|
|
|
|
|
|
|
error_code e;
|
|
|
|
peer_request map = files().map_file(file_index
|
|
|
|
, file_offset, 0);
|
|
|
|
int const ret = m_part_file->writev(vec
|
|
|
|
, map.piece, map.start, e);
|
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
ec.ec = e;
|
|
|
|
ec.file(file_index);
|
|
|
|
ec.operation = storage_error::partfile_write;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// invalidate our stat cache for this file, since
|
|
|
|
// we're writing to it
|
|
|
|
m_stat_cache.set_dirty(file_index);
|
|
|
|
|
|
|
|
file_handle handle = open_file(file_index
|
2017-05-26 20:49:21 +02:00
|
|
|
, open_mode_t::read_write, ec);
|
2017-05-02 06:07:50 +02:00
|
|
|
if (ec) return -1;
|
|
|
|
|
|
|
|
error_code e;
|
2017-05-04 15:22:17 +02:00
|
|
|
int const ret = int(handle->writev(file_offset
|
2017-05-02 06:07:50 +02:00
|
|
|
, vec, e, flags));
|
|
|
|
|
|
|
|
// set this unconditionally in case the upper layer would like to treat
|
|
|
|
// short reads as errors
|
|
|
|
ec.operation = storage_error::write;
|
|
|
|
|
2017-05-03 01:44:07 +02:00
|
|
|
// we either get an error or 0 or more bytes read
|
2017-05-02 06:07:50 +02:00
|
|
|
TORRENT_ASSERT(e || ret >= 0);
|
|
|
|
TORRENT_ASSERT(ret <= bufs_size(vec));
|
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
ec.ec = e;
|
|
|
|
ec.file(file_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
});
|
2009-01-17 09:35:48 +01:00
|
|
|
}
|
|
|
|
|
2017-04-09 00:24:50 +02:00
|
|
|
file_handle default_storage::open_file(file_index_t const file
|
2017-05-26 20:49:21 +02:00
|
|
|
, open_mode_t mode, storage_error& ec) const
|
2015-01-03 17:57:21 +01:00
|
|
|
{
|
|
|
|
file_handle h = open_file_impl(file, mode, ec.ec);
|
2017-05-26 20:49:21 +02:00
|
|
|
if (((mode & open_mode_t::rw_mask) != open_mode_t::read_only)
|
2015-01-03 17:57:21 +01:00
|
|
|
&& ec.ec == boost::system::errc::no_such_file_or_directory)
|
|
|
|
{
|
|
|
|
// this means the directory the file is in doesn't exist.
|
|
|
|
// so create it
|
|
|
|
ec.ec.clear();
|
|
|
|
std::string path = files().file_path(file, m_save_path);
|
|
|
|
create_directories(parent_path(path), ec.ec);
|
|
|
|
|
|
|
|
if (ec.ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file);
|
2015-01-03 17:57:21 +01:00
|
|
|
ec.operation = storage_error::mkdir;
|
|
|
|
return file_handle();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the directory creation failed, don't try to open the file again
|
|
|
|
// but actually just fail
|
|
|
|
h = open_file_impl(file, mode, ec.ec);
|
|
|
|
}
|
|
|
|
if (ec.ec)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file);
|
2015-01-03 17:57:21 +01:00
|
|
|
ec.operation = storage_error::open;
|
|
|
|
return file_handle();
|
|
|
|
}
|
|
|
|
TORRENT_ASSERT(h);
|
2015-11-16 04:36:55 +01:00
|
|
|
|
2017-05-26 20:49:21 +02:00
|
|
|
if (m_allocate_files && (mode & open_mode_t::rw_mask) != open_mode_t::read_only)
|
2015-11-16 04:36:55 +01:00
|
|
|
{
|
2017-05-08 13:48:42 +02:00
|
|
|
std::unique_lock<std::mutex> l(m_file_created_mutex);
|
2015-11-16 04:36:55 +01:00
|
|
|
if (m_file_created.size() != files().num_files())
|
|
|
|
m_file_created.resize(files().num_files(), false);
|
|
|
|
|
|
|
|
TORRENT_ASSERT(int(m_file_created.size()) == files().num_files());
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(file < m_file_created.end_index());
|
2015-11-16 04:36:55 +01:00
|
|
|
// if this is the first time we open this file for writing,
|
|
|
|
// and we have m_allocate_files enabled, set the final size of
|
|
|
|
// the file right away, to allocate it on the filesystem.
|
|
|
|
if (m_file_created[file] == false)
|
|
|
|
{
|
2017-05-07 17:01:42 +02:00
|
|
|
m_file_created.set_bit(file);
|
|
|
|
l.unlock();
|
2015-11-16 04:36:55 +01:00
|
|
|
error_code e;
|
2016-11-13 02:03:53 +01:00
|
|
|
std::int64_t const size = files().file_size(file);
|
2016-10-24 04:01:09 +02:00
|
|
|
h->set_size(size, e);
|
2015-11-16 04:36:55 +01:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
ec.ec = e;
|
2016-12-22 16:42:33 +01:00
|
|
|
ec.file(file);
|
2015-11-16 04:36:55 +01:00
|
|
|
ec.operation = storage_error::fallocate;
|
|
|
|
return h;
|
|
|
|
}
|
2016-10-24 04:01:09 +02:00
|
|
|
m_stat_cache.set_dirty(file);
|
2015-11-16 04:36:55 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-03 17:57:21 +01:00
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2017-05-26 20:49:21 +02:00
|
|
|
file_handle default_storage::open_file_impl(file_index_t file, open_mode_t mode
|
2014-07-06 21:18:00 +02:00
|
|
|
, error_code& ec) const
|
2009-01-17 09:35:48 +01:00
|
|
|
{
|
2017-04-09 00:24:50 +02:00
|
|
|
bool const lock_files = m_settings ? settings().get_bool(settings_pack::lock_files) : false;
|
2017-05-26 20:49:21 +02:00
|
|
|
if (lock_files) mode |= open_mode_t::lock_file;
|
2015-03-09 07:09:50 +01:00
|
|
|
|
2017-05-26 20:49:21 +02:00
|
|
|
if (!m_allocate_files) mode |= open_mode_t::sparse;
|
2011-02-22 03:53:26 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// files with priority 0 should always be sparse
|
2016-12-22 16:42:33 +01:00
|
|
|
if (m_file_priority.end_index() > file && m_file_priority[file] == 0)
|
2017-05-26 20:49:21 +02:00
|
|
|
mode |= open_mode_t::sparse;
|
2011-11-02 05:45:22 +01:00
|
|
|
|
2017-05-26 20:49:21 +02:00
|
|
|
if (m_settings && settings().get_bool(settings_pack::no_atime_storage)) mode |= open_mode_t::no_atime;
|
2011-02-22 03:53:26 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if we have a cache already, don't store the data twice by leaving it in the OS cache as well
|
|
|
|
if (m_settings
|
|
|
|
&& settings().get_int(settings_pack::disk_io_write_mode)
|
|
|
|
== settings_pack::disable_os_cache)
|
2011-02-22 03:53:26 +01:00
|
|
|
{
|
2017-05-26 20:49:21 +02:00
|
|
|
mode |= open_mode_t::no_cache;
|
2011-02-22 03:53:26 +01:00
|
|
|
}
|
|
|
|
|
2016-12-31 18:35:10 +01:00
|
|
|
file_handle ret = m_pool.open_file(storage_index(), m_save_path, file
|
|
|
|
, files(), mode, ec);
|
2017-05-26 20:49:21 +02:00
|
|
|
if (ec && test(mode & open_mode_t::lock_file))
|
2015-03-09 07:09:50 +01:00
|
|
|
{
|
|
|
|
// we failed to open the file and we're trying to lock it. It's
|
|
|
|
// possible we're failing because we have another handle to this
|
|
|
|
// file in use (but waiting to be closed). Just retry to open it
|
|
|
|
// without locking.
|
2017-05-26 20:49:21 +02:00
|
|
|
mode &= ~open_mode_t::lock_file;
|
2016-12-31 18:35:10 +01:00
|
|
|
ret = m_pool.open_file(storage_index(), m_save_path, file, files()
|
|
|
|
, mode, ec);
|
2015-03-09 07:09:50 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2003-12-07 02:26:57 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool default_storage::tick()
|
2003-12-07 02:26:57 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code ec;
|
|
|
|
if (m_part_file) m_part_file->flush_metadata(ec);
|
2015-06-06 08:10:53 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
return false;
|
2009-01-03 09:11:31 +01:00
|
|
|
}
|
|
|
|
|
2017-04-07 00:11:24 +02:00
|
|
|
storage_interface* default_storage_constructor(storage_params const& params
|
|
|
|
, file_pool& pool)
|
2009-01-03 09:11:31 +01:00
|
|
|
{
|
2017-04-07 00:11:24 +02:00
|
|
|
return new default_storage(params, pool);
|
2009-01-03 09:11:31 +01:00
|
|
|
}
|
|
|
|
|
2016-05-02 05:16:00 +02:00
|
|
|
// -- disabled_storage --------------------------------------------------
|
2010-01-09 19:40:05 +01:00
|
|
|
|
2017-04-12 19:00:57 +02:00
|
|
|
namespace {
|
|
|
|
|
2016-05-02 05:16:00 +02:00
|
|
|
// this storage implementation does not write anything to disk
|
|
|
|
// and it pretends to read, and just leaves garbage in the buffers
|
|
|
|
// this is useful when simulating many clients on the same machine
|
|
|
|
// or when running stress tests and want to take the cost of the
|
|
|
|
// disk I/O out of the picture. This cannot be used for any kind
|
|
|
|
// of normal bittorrent operation, since it will just send garbage
|
|
|
|
// to peers and throw away all the data it downloads. It would end
|
|
|
|
// up being banned immediately
|
2016-11-13 03:45:30 +01:00
|
|
|
class disabled_storage final : public storage_interface
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
|
|
|
public:
|
2017-04-07 00:11:24 +02:00
|
|
|
explicit disabled_storage(file_storage const& fs) : storage_interface(fs) {}
|
|
|
|
|
2016-07-10 02:10:38 +02:00
|
|
|
bool has_any_file(storage_error&) override { return false; }
|
2016-12-22 16:42:33 +01:00
|
|
|
void set_file_priority(aux::vector<std::uint8_t, file_index_t> const&
|
2016-05-02 05:16:00 +02:00
|
|
|
, storage_error&) override {}
|
2016-12-22 16:42:33 +01:00
|
|
|
void rename_file(file_index_t, std::string const&, storage_error&) override {}
|
2016-07-10 02:10:38 +02:00
|
|
|
void release_files(storage_error&) override {}
|
|
|
|
void delete_files(int, storage_error&) override {}
|
|
|
|
void initialize(storage_error&) override {}
|
2017-06-01 10:15:15 +02:00
|
|
|
status_t move_storage(std::string const&, move_flags_t, storage_error&) override { return status_t::no_error; }
|
2016-05-02 05:16:00 +02:00
|
|
|
|
2017-01-11 06:42:10 +01:00
|
|
|
int readv(span<iovec_t const> bufs
|
2017-05-26 20:49:21 +02:00
|
|
|
, piece_index_t, int, open_mode_t, storage_error&) override
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
2016-10-27 02:40:56 +02:00
|
|
|
return bufs_size(bufs);
|
2016-05-02 05:16:00 +02:00
|
|
|
}
|
2017-01-11 06:42:10 +01:00
|
|
|
int writev(span<iovec_t const> bufs
|
2017-05-26 20:49:21 +02:00
|
|
|
, piece_index_t, int, open_mode_t, storage_error&) override
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
2016-10-27 02:40:56 +02:00
|
|
|
return bufs_size(bufs);
|
2016-05-02 05:16:00 +02:00
|
|
|
}
|
|
|
|
|
2016-07-10 02:10:38 +02:00
|
|
|
bool verify_resume_data(add_torrent_params const&
|
2016-12-22 16:42:33 +01:00
|
|
|
, aux::vector<std::string, file_index_t> const&
|
2016-05-02 05:16:00 +02:00
|
|
|
, storage_error&) override { return false; }
|
|
|
|
};
|
2010-01-09 19:40:05 +01:00
|
|
|
}
|
|
|
|
|
2017-04-07 00:11:24 +02:00
|
|
|
storage_interface* disabled_storage_constructor(storage_params const& params, file_pool&)
|
2007-03-16 06:29:23 +01:00
|
|
|
{
|
2017-04-07 00:11:24 +02:00
|
|
|
return new disabled_storage(*params.files);
|
2007-03-16 06:29:23 +01:00
|
|
|
}
|
2003-12-09 09:49:49 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// -- zero_storage ------------------------------------------------------
|
|
|
|
|
2017-04-12 19:00:57 +02:00
|
|
|
namespace {
|
|
|
|
|
2016-05-02 05:16:00 +02:00
|
|
|
// this storage implementation always reads zeroes, and always discards
|
|
|
|
// anything written to it
|
|
|
|
struct zero_storage final : storage_interface
|
2009-08-02 08:40:45 +02:00
|
|
|
{
|
2017-04-07 00:11:24 +02:00
|
|
|
explicit zero_storage(file_storage const& fs) : storage_interface(fs) {}
|
2016-07-10 02:10:38 +02:00
|
|
|
void initialize(storage_error&) override {}
|
2011-04-17 00:58:11 +02:00
|
|
|
|
2017-01-11 06:42:10 +01:00
|
|
|
int readv(span<iovec_t const> bufs
|
2017-05-26 20:49:21 +02:00
|
|
|
, piece_index_t, int, open_mode_t, storage_error&) override
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
|
|
|
int ret = 0;
|
2017-01-17 03:51:49 +01:00
|
|
|
for (auto const& b : bufs)
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
2017-04-29 06:27:55 +02:00
|
|
|
std::memset(b.data(), 0, b.size());
|
|
|
|
ret += int(b.size());
|
2016-05-02 05:16:00 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-01-11 06:42:10 +01:00
|
|
|
int writev(span<iovec_t const> bufs
|
2017-05-26 20:49:21 +02:00
|
|
|
, piece_index_t, int, open_mode_t, storage_error&) override
|
2016-05-02 05:16:00 +02:00
|
|
|
{
|
|
|
|
int ret = 0;
|
2017-01-17 03:51:49 +01:00
|
|
|
for (auto const& b : bufs)
|
2017-04-29 06:27:55 +02:00
|
|
|
ret += int(b.size());
|
2016-05-02 05:16:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-10 02:10:38 +02:00
|
|
|
bool has_any_file(storage_error&) override { return false; }
|
2016-12-22 16:42:33 +01:00
|
|
|
void set_file_priority(aux::vector<std::uint8_t, file_index_t> const& /* prio */
|
2016-05-02 05:16:00 +02:00
|
|
|
, storage_error&) override {}
|
2016-11-26 07:51:47 +01:00
|
|
|
status_t move_storage(std::string const& /* save_path */
|
2017-06-01 10:15:15 +02:00
|
|
|
, move_flags_t, storage_error&) override { return status_t::no_error; }
|
2016-07-10 02:10:38 +02:00
|
|
|
bool verify_resume_data(add_torrent_params const& /* rd */
|
2016-12-22 16:42:33 +01:00
|
|
|
, aux::vector<std::string, file_index_t> const& /* links */
|
2016-05-02 05:16:00 +02:00
|
|
|
, storage_error&) override
|
|
|
|
{ return false; }
|
2016-07-10 02:10:38 +02:00
|
|
|
void release_files(storage_error&) override {}
|
2016-12-22 16:42:33 +01:00
|
|
|
void rename_file(file_index_t
|
2016-08-18 17:57:50 +02:00
|
|
|
, std::string const& /* new_filename */, storage_error&) override {}
|
2016-07-10 02:10:38 +02:00
|
|
|
void delete_files(int, storage_error&) override {}
|
2016-05-02 05:16:00 +02:00
|
|
|
};
|
2011-04-17 00:58:11 +02:00
|
|
|
}
|
2009-08-02 08:40:45 +02:00
|
|
|
|
2017-04-07 00:11:24 +02:00
|
|
|
storage_interface* zero_storage_constructor(storage_params const& params, file_pool&)
|
2009-08-02 08:40:45 +02:00
|
|
|
{
|
2017-04-07 00:11:24 +02:00
|
|
|
return new zero_storage(*params.files);
|
2009-08-02 08:40:45 +02:00
|
|
|
}
|
|
|
|
|
2003-12-07 02:26:57 +01:00
|
|
|
} // namespace libtorrent
|