diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 4fb9c6489..84d42c088 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -140,6 +140,9 @@ namespace libtorrent TORRENT_EXPORT std::string complete(std::string const& f); TORRENT_EXPORT bool is_complete(std::string const& f); TORRENT_EXPORT std::string current_working_directory(); +#if TORRENT_USE_UNC_PATHS + TORRENT_EXTRA_EXPORT std::string canonicalize_path(std::string const& f); +#endif class TORRENT_EXPORT directory : public boost::noncopyable { diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index 1cff5a739..bf31719ff 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -167,6 +167,9 @@ namespace libtorrent file_pool fp; std::string utf8; wchar_utf8(p, utf8); +#if TORRENT_USE_UNC_PATHS + p = canonicalize_path(p); +#endif boost::scoped_ptr st( default_storage_constructor(const_cast(t.files()), 0, utf8, fp , std::vector())); @@ -195,6 +198,9 @@ namespace libtorrent , boost::function f, error_code& ec) { file_pool fp; +#if TORRENT_USE_UNC_PATHS + p = canonicalize_path(p); +#endif boost::scoped_ptr st( default_storage_constructor(const_cast(t.files()), 0, p, fp , std::vector())); diff --git a/src/file.cpp b/src/file.cpp index 227c01cce..24fa0c77b 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -536,6 +536,69 @@ namespace libtorrent #endif } +#if TORRENT_USE_UNC_PATHS + std::string canonicalize_path(std::string const& f) + { + std::string ret; + ret.resize(f.size()); + char* write_cur = &ret[0]; + char* last_write_sep = write_cur; + + char const* read_cur = f.c_str(); + char const* last_read_sep = read_cur; + + // the last_*_sep pointers point to one past + // the last path separator encountered and is + // initializes to the first character in the path + while (*read_cur) + { + if (*read_cur != '\\') + { + *write_cur++ = *read_cur++; + continue; + } + int element_len = read_cur - last_read_sep; + if (element_len == 1 && memcmp(last_read_sep, ".", 1) == 0) + { + --write_cur; + ++read_cur; + last_read_sep = read_cur; + continue; + } + if (element_len == 2 && memcmp(last_read_sep, "..", 2) == 0) + { + // find the previous path separator + if (last_write_sep > &ret[0]) + { + --last_write_sep; + while (last_write_sep > &ret[0] + && last_write_sep[-1] != '\\') + --last_write_sep; + } + write_cur = last_write_sep; + // find the previous path separator + if (last_write_sep > &ret[0]) + { + --last_write_sep; + while (last_write_sep > &ret[0] + && last_write_sep[-1] != '\\') + --last_write_sep; + } + ++read_cur; + last_read_sep = read_cur; + continue; + } + *write_cur++ = *read_cur++; + last_write_sep = write_cur; + last_read_sep = read_cur; + } + // terminate destination string + *write_cur = 0; + ret.resize(write_cur - &ret[0]); + return ret; + } +#endif + size_type file_size(std::string const& f) { error_code ec; @@ -811,14 +874,12 @@ namespace libtorrent FILE_SHARE_READ, }; + std::string p = convert_separators(path); #if TORRENT_USE_UNC_PATHS // UNC paths must be absolute - std::string p = convert_separators(path); - // network paths are not supported by UNC paths + // network paths are already UNC paths if (path.substr(0,2) == "\\\\") p = path; else p = "\\\\?\\" + (is_complete(p) ? p : combine_path(current_working_directory(), p)); -#else - std::string p = convert_separators(path); #endif #if TORRENT_USE_WSTRING diff --git a/src/torrent.cpp b/src/torrent.cpp index cf49b3278..4713211bd 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -433,6 +433,10 @@ namespace libtorrent #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS m_resume_data_loaded = false; #endif +#if TORRENT_USE_UNC_PATHS + m_save_path = canonicalize_path(m_save_path); +#endif + if (!m_apply_ip_filter) ++m_ses.m_non_filtered_torrents; if (!p.ti || !p.ti->is_valid()) diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 841cf3df2..79fd9f733 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -871,6 +871,15 @@ int test_main() TEST_EQUAL(combine_path("test1", "test2"), "test1/test2"); #endif +#if TORRENT_USE_UNC_PATHS + TEST_EQUAL(canonicalize_path("c:\\a\\..\\b"), "c:\\b"); + TEST_EQUAL(canonicalize_path("a\\..\\b"), "b"); + TEST_EQUAL(canonicalize_path("a\\..\\.\\b"), "b"); + TEST_EQUAL(canonicalize_path("\\.\\a"), "\\a"); + TEST_EQUAL(canonicalize_path("\\\\bla\\.\\a"), "\\\\bla\\a"); + TEST_EQUAL(canonicalize_path("c:\\bla\\a"), "c:\\bla\\a"); +#endif + TEST_EQUAL(extension("blah"), ""); TEST_EQUAL(extension("blah.exe"), ".exe"); TEST_EQUAL(extension("blah.foo.bar"), ".bar");