support renaming files to absolute paths

This commit is contained in:
Arvid Norberg 2013-06-09 22:30:02 +00:00
parent 91f8c32937
commit 8f3723cdef
7 changed files with 135 additions and 57 deletions

View File

@ -1,3 +1,4 @@
* allow moving files to absolute paths, out of the download directory
* make move_storage more generic to allow both overwriting files as well as taking existing ones
* fix choking issue at high upload rates
* optimized rate limiter

View File

@ -1914,6 +1914,12 @@ If you want to rename the base name of the torrent (for a multifile torrent), yo
can copy the ``file_storage`` (see `files() orig_files()`_), change the name, and
then use `remap_files()`_.
The ``new_filename`` can both be a relative path, in which case the file name
is relative to the ``save_path`` of the torrent. If the ``new_filename`` is
an absolute path (i.e. ``is_complete(new_filename) == true``), then the file
is detached from the ``save_path`` of the torrent. In this case the file is
not moved when move_storage_ is invoked.
begin_files() end_files() rbegin_files() rend_files()
-----------------------------------------------------
@ -2660,6 +2666,11 @@ of the other modes.
``dont_replace`` always takes the existing file in the target directory, if there is
one. The source files will still be removed in that case.
Files that have been renamed to have absolute pahts are not moved by this function.
Keep in mind that files that don't belong to the torrent but are stored in the torrent's
directory may be moved as well. This goes for files that have been renamed to
absolute paths that still end up inside the save path.
rename_file()
-------------

View File

@ -149,6 +149,10 @@ namespace libtorrent
// the full path to this file, concatenate the path
// from that array with the 'name' field in
// this struct
// if path_index == -2, it means the filename
// in this field contains the full, absolute path
// to the file
// -1 means no path (i.e. single file torrent)
int path_index;
};
@ -251,7 +255,7 @@ namespace libtorrent
time_t mtime(int index) const;
size_type file_base(int index) const;
void set_file_base(int index, size_type off);
std::string file_path(int index) const;
std::string file_path(int index, std::string const& save_path = "") const;
std::string file_name(int index) const;
size_type file_size(int index) const;
bool pad_file_at(int index) const;
@ -263,7 +267,7 @@ namespace libtorrent
int file_index(internal_file_entry const& fe) const;
size_type file_base(internal_file_entry const& fe) const;
void set_file_base(internal_file_entry const& fe, size_type off);
std::string file_path(internal_file_entry const& fe) const;
std::string file_path(internal_file_entry const& fe, std::string const& save_path = "") const;
std::string file_name(internal_file_entry const& fe) const;
size_type file_size(internal_file_entry const& fe) const;
bool pad_file_at(internal_file_entry const& fe) const;

View File

@ -71,7 +71,13 @@ namespace libtorrent
void file_storage::update_path_index(internal_file_entry& e)
{
std::string parent = parent_path(e.filename());
std::string fname = e.filename();
if (is_complete(fname))
{
e.path_index = -2;
return;
}
std::string parent = parent_path(fname);
if (parent.empty())
{
e.path_index = -1;
@ -431,13 +437,18 @@ namespace libtorrent
return m_file_base[index];
}
std::string file_storage::file_path(int index) const
std::string file_storage::file_path(int index, std::string const& save_path) const
{
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
internal_file_entry const& fe = m_files[index];
TORRENT_ASSERT(fe.path_index >= -1 && fe.path_index < int(m_paths.size()));
if (fe.path_index == -1) return fe.filename();
return combine_path(m_paths[fe.path_index], fe.filename());
TORRENT_ASSERT(fe.path_index >= -2 && fe.path_index < int(m_paths.size()));
// -2 means this is an absolute path filename
if (fe.path_index == -2) return fe.filename();
// -1 means no path
if (fe.path_index == -1) return combine_path(save_path, fe.filename());
return combine_path(save_path, combine_path(m_paths[fe.path_index], fe.filename()));
}
std::string file_storage::file_name(int index) const
@ -507,11 +518,16 @@ namespace libtorrent
return m_file_base[index];
}
std::string file_storage::file_path(internal_file_entry const& fe) const
std::string file_storage::file_path(internal_file_entry const& fe, std::string const& save_path) const
{
TORRENT_ASSERT(fe.path_index >= -1 && fe.path_index < int(m_paths.size()));
if (fe.path_index == -1) return fe.filename();
return combine_path(m_paths[fe.path_index], fe.filename());
TORRENT_ASSERT(fe.path_index >= -2 && fe.path_index < int(m_paths.size()));
// -2 means this is an absolute path filename
if (fe.path_index == -2) return fe.filename();
// -1 means no path
if (fe.path_index == -1) return combine_path(save_path, fe.filename());
return combine_path(save_path, combine_path(m_paths[fe.path_index], fe.filename()));
}
std::string file_storage::file_name(internal_file_entry const& fe) const

View File

@ -110,7 +110,7 @@ namespace libtorrent
{
file_status s;
error_code ec;
stat_file(combine_path(save_path, storage.file_path(*i)), &s, ec);
stat_file(storage.file_path(*i, save_path), &s, ec);
if (!ec)
{
@ -160,7 +160,7 @@ namespace libtorrent
file_status s;
error_code ec;
stat_file(combine_path(p, fs.file_path(*i)), &s, ec);
stat_file(fs.file_path(*i, p), &s, ec);
if (!ec)
{
@ -417,7 +417,7 @@ namespace libtorrent
// ignore pad files
if (file_iter->pad_file) continue;
std::string file_path = combine_path(m_save_path, files().file_path(*file_iter));
std::string file_path = files().file_path(*file_iter, m_save_path);
file_status s;
stat_file(file_path, &s, ec);
@ -482,7 +482,7 @@ namespace libtorrent
{
error_code ec;
file_status s;
stat_file(combine_path(m_save_path, files().file_path(*i)), &s, ec);
stat_file(files().file_path(*i, m_save_path), &s, ec);
if (ec) continue;
if (s.mode & file_status::regular_file && i->size > 0)
return true;
@ -493,11 +493,13 @@ namespace libtorrent
bool default_storage::rename_file(int index, std::string const& new_filename)
{
if (index < 0 || index >= files().num_files()) return true;
std::string old_name = combine_path(m_save_path, files().file_path(files().at(index)));
std::string old_name = files().file_path(index, m_save_path);
m_pool.release(this, index);
error_code ec;
std::string new_path = combine_path(m_save_path, new_filename);
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
@ -556,7 +558,10 @@ namespace libtorrent
, end(files().end()); i != end; ++i)
{
std::string fp = files().file_path(*i);
std::string p = combine_path(m_save_path, fp);
bool complete = is_complete(fp);
std::string p = complete ? fp : combine_path(m_save_path, fp);
if (!complete)
{
std::string bp = parent_path(fp);
std::pair<iter_t, bool> ret;
ret.second = true;
@ -565,6 +570,7 @@ namespace libtorrent
ret = directories.insert(combine_path(m_save_path, bp));
bp = parent_path(bp);
}
}
delete_one_file(p);
}
@ -768,7 +774,10 @@ namespace libtorrent
for (file_storage::iterator i = f.begin()
, end(f.end()); i != end; ++i)
{
std::string new_path = combine_path(save_path, f.file_path(*i));
// files moved out to absolute paths are ignored
if (is_complete(f.file_path(*i))) continue;
std::string new_path = f.file_path(*i, save_path);
stat_file(new_path, &s, ec);
if (ec != boost::system::errc::no_such_file_or_directory)
return piece_manager::file_exist;
@ -783,6 +792,9 @@ namespace libtorrent
for (file_storage::iterator i = f.begin()
, end(f.end()); i != end; ++i)
{
// files moved out to absolute paths are not moved
if (is_complete(f.file_path(*i))) continue;
std::string split = split_path(f.file_path(*i));
to_move.insert(to_move.begin(), split);
}
@ -1199,7 +1211,7 @@ ret:
// this means the directory the file is in doesn't exist.
// so create it
ec.clear();
std::string path = combine_path(m_save_path, files().file_path(*file_iter));
std::string path = files().file_path(*file_iter, m_save_path);
create_directories(parent_path(path), ec);
// if the directory creation failed, don't try to open the file again
// but actually just fail
@ -1208,7 +1220,7 @@ ret:
if (!file_handle || ec)
{
std::string path = combine_path(m_save_path, files().file_path(*file_iter));
std::string path = files().file_path(*file_iter, m_save_path);
TORRENT_ASSERT(ec);
set_error(path, ec);
return -1;
@ -1253,7 +1265,7 @@ ret:
if (ec)
{
set_error(combine_path(m_save_path, files().file_path(*file_iter)), ec);
set_error(files().file_path(*file_iter, m_save_path), ec);
return -1;
}

View File

@ -77,9 +77,51 @@ void setup_test_storage(file_storage& st)
int test_main()
{
{
file_storage a;
setup_test_storage(a);
file_storage st;
setup_test_storage(st);
st.rename_file(0, "test/c/d");
TEST_EQUAL(st.file_path(0, "./"), "./test/c/d");
st.rename_file(0, "/tmp/a");
TEST_EQUAL(st.file_path(0, "./"), "/tmp/a");
}
{
file_storage st;
st.add_file("a", 10000);
st.rename_file(0, "test/c/d");
TEST_EQUAL(st.file_path(0, "./"), "./test/c/d");
st.rename_file(0, "/tmp/a");
TEST_EQUAL(st.file_path(0, "./"), "/tmp/a");
}
{
file_storage fs;
fs.set_piece_length(512);
fs.add_file("temp_storage/test1.tmp", 17);
fs.add_file("temp_storage/test2.tmp", 612);
fs.add_file("temp_storage/test3.tmp", 0);
fs.add_file("temp_storage/test4.tmp", 0);
fs.add_file("temp_storage/test5.tmp", 3253);
// size: 3882
fs.add_file("temp_storage/test6.tmp", 841);
// size: 4723
peer_request rq = fs.map_file(0, 0, 10);
TEST_EQUAL(rq.piece, 0);
TEST_EQUAL(rq.start, 0);
TEST_EQUAL(rq.length, 10);
rq = fs.map_file(5, 0, 10);
TEST_EQUAL(rq.piece, 7);
TEST_EQUAL(rq.start, 298);
TEST_EQUAL(rq.length, 10);
rq = fs.map_file(5, 0, 1000);
TEST_EQUAL(rq.piece, 7);
TEST_EQUAL(rq.start, 298);
TEST_EQUAL(rq.length, 841);
}
return 0;

View File

@ -901,6 +901,8 @@ void test_fastresume(std::string const& test_path)
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file);
file.close();
TEST_CHECK(exists(combine_path(test_path, "tmp1/temporary")));
if (!exists(combine_path(test_path, "tmp1/temporary")))
return;
entry resume;
{
@ -914,23 +916,37 @@ void test_fastresume(std::string const& test_path)
p.save_path = combine_path(test_path, "tmp1");
p.storage_mode = storage_mode_compact;
torrent_handle h = ses.add_torrent(p, ec);
TEST_CHECK(exists(combine_path(p.save_path, "temporary")));
if (!exists(combine_path(p.save_path, "temporary")))
return;
for (int i = 0; i < 10; ++i)
torrent_status s;
for (int i = 0; i < 5; ++i)
{
print_alerts(ses, "ses");
test_sleep(1000);
torrent_status s = h.status();
s = h.status();
if (s.progress == 1.0f)
{
std::cout << "progress: 1.0f" << std::endl;
break;
}
}
// the whole point of the test is to have a resume
// data which expects the file to exist in full. If
// we failed to do that, we might as well abort
TEST_EQUAL(s.progress, 1.0f);
if (s.progress != 1.0f)
return;
// TODO: 3 don't use this deprecated function
resume = h.write_resume_data();
ses.remove_torrent(h, session::delete_files);
}
TEST_CHECK(!exists(combine_path(test_path, "tmp1/temporary")));
if (exists(combine_path(test_path, "tmp1/temporary")))
return;
#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM
resume.print(std::cout);
#endif
@ -962,6 +978,7 @@ void test_fastresume(std::string const& test_path)
assert(a.get());
std::cerr << a->message() << std::endl;
}
// we expect the fast resume to be rejected because the files were removed
TEST_CHECK(dynamic_cast<fastresume_rejected_alert*>(a.get()) != 0);
}
remove_all(combine_path(test_path, "tmp1"), ec);
@ -1094,31 +1111,6 @@ int test_main()
std::for_each(test_paths.begin(), test_paths.end(), boost::bind(&run_test, _1, true));
std::for_each(test_paths.begin(), test_paths.end(), boost::bind(&run_test, _1, false));
file_storage fs;
fs.set_piece_length(512);
fs.add_file("temp_storage/test1.tmp", 17);
fs.add_file("temp_storage/test2.tmp", 612);
fs.add_file("temp_storage/test3.tmp", 0);
fs.add_file("temp_storage/test4.tmp", 0);
fs.add_file("temp_storage/test5.tmp", 3253);
// size: 3882
fs.add_file("temp_storage/test6.tmp", 841);
// size: 4723
peer_request rq = fs.map_file(0, 0, 10);
TEST_EQUAL(rq.piece, 0);
TEST_EQUAL(rq.start, 0);
TEST_EQUAL(rq.length, 10);
rq = fs.map_file(5, 0, 10);
TEST_EQUAL(rq.piece, 7);
TEST_EQUAL(rq.start, 298);
TEST_EQUAL(rq.length, 10);
rq = fs.map_file(5, 0, 1000);
TEST_EQUAL(rq.piece, 7);
TEST_EQUAL(rq.start, 298);
TEST_EQUAL(rq.length, 841);
return 0;
}