use UNC paths pervasively on windows

This commit is contained in:
arvidn 2017-07-02 11:39:06 -04:00 committed by Arvid Norberg
parent 3a1e546a6c
commit f4f1425115
18 changed files with 130 additions and 179 deletions

View File

@ -234,7 +234,6 @@ set(libtorrent_aux_include_files
ip_notifier
listen_socket_handle
lsd
max_path
merkle
noexcept_movable
numeric_cast

View File

@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/create_torrent.hpp"
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
#include <functional>
#include <cstdio>
@ -259,17 +258,24 @@ int main(int argc_, char const* argv_[]) try
if (full_path[0] != '/')
#endif
{
char cwd[TORRENT_MAX_PATH];
char cwd[2048];
#ifdef TORRENT_WINDOWS
_getcwd(cwd, sizeof(cwd));
full_path = cwd + ("\\" + full_path);
#define getcwd_ _getcwd
#else
char const* ret = getcwd(cwd, sizeof(cwd));
#define getcwd_ getcwd
#endif
char const* ret = getcwd_(cwd, sizeof(cwd));
if (ret == nullptr) {
std::cerr << "failed to get current working directory: "
<< strerror(errno) << "\n";
return 1;
}
#undef getcwd_
#ifdef TORRENT_WINDOWS
full_path = cwd + ("\\" + full_path);
#else
full_path = cwd + ("/" + full_path);
#endif
}

View File

@ -178,7 +178,6 @@ nobase_include_HEADERS = \
aux_/generate_peer_id.hpp \
aux_/io.hpp \
aux_/listen_socket_handle.hpp \
aux_/max_path.hpp \
aux_/path.hpp \
aux_/merkle.hpp \
aux_/session_call.hpp \

View File

@ -64,7 +64,8 @@ namespace libtorrent {
TORRENT_EXTRA_EXPORT std::string maybe_url_encode(std::string const& url);
TORRENT_EXTRA_EXPORT string_view trim(string_view);
TORRENT_EXTRA_EXPORT string_view::size_type find(string_view haystack, string_view needle, string_view::size_type pos);
TORRENT_EXTRA_EXPORT string_view::size_type find(string_view haystack
, string_view needle, string_view::size_type pos);
#if TORRENT_ABI_VERSION == 1
// deprecated in 1.2

View File

@ -1,67 +0,0 @@
/*
Copyright (c) 2016, Arvid Norberg
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.
*/
#ifndef TORRENT_MAX_PATH_HPP_INCLUDED
#define TORRENT_MAX_PATH_HPP_INCLUDED
// on windows, NAME_MAX refers to Unicode characters
// on linux it refers to bytes (utf-8 encoded)
// TODO: Make this count Unicode characters instead of bytes on windows
// windows
#if defined FILENAME_MAX
#define TORRENT_MAX_PATH FILENAME_MAX
// beos
#elif defined B_PATH_NAME_LENGTH
#define TORRENT_MAX_PATH B_PATH_NAME_LENGTH
// solaris
#elif defined MAXPATH
#define TORRENT_MAX_PATH MAXPATH
// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows and also on many filesystems commonly used
// on linux
#define TORRENT_MAX_PATH 255
#ifdef _MSC_VER
#pragma message ( "unknown platform, assuming the longest path is 255" )
#else
#warning "unknown platform, assuming the longest path is 255"
#endif
#endif // FILENAME_MAX
#endif // TORRENT_MAX_PATH_HPP_INCLUDED

View File

@ -69,8 +69,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/types.h>
#include <dirent.h> // for DIR
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
#undef _FILE_OFFSET_BITS
#endif

View File

@ -229,9 +229,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_USE_GETADAPTERSADDRESSES 1
#define TORRENT_HAS_SALEN 0
#define TORRENT_USE_GETIPFORWARDTABLE 1
#ifndef TORRENT_USE_UNC_PATHS
# define TORRENT_USE_UNC_PATHS 1
#endif
#define TORRENT_USE_UNC_PATHS 1
// these are emulated on windows
#define TORRENT_USE_PREADV 1
#define TORRENT_USE_PWRITEV 1
@ -273,9 +271,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#define TORRENT_USE_RLIMIT 0
#define TORRENT_HAS_FALLOCATE 0
#ifndef TORRENT_USE_UNC_PATHS
# define TORRENT_USE_UNC_PATHS 1
#endif
#define TORRENT_USE_UNC_PATHS 1
// these are emulated on windows
#define TORRENT_USE_PREADV 1
#define TORRENT_USE_PWRITEV 1

View File

@ -70,8 +70,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/types.h>
#include <dirent.h> // for DIR
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
#undef _FILE_OFFSET_BITS
#endif

View File

@ -51,7 +51,6 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#include "libtorrent/aux_/escape_string.hpp" // for convert_from_native
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
namespace libtorrent {

View File

@ -32,7 +32,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/create_torrent.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/aux_/escape_string.hpp" // for convert_to_wstring
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/aux_/merkle.hpp" // for merkle_*()
#include "libtorrent/torrent_info.hpp"
@ -69,16 +68,17 @@ namespace {
file_flags_t get_file_attributes(std::string const& p)
{
auto const path = convert_to_native_path_string(p);
#ifdef TORRENT_WINDOWS
WIN32_FILE_ATTRIBUTE_DATA attr;
std::wstring path = convert_to_wstring(p);
GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &attr);
if (attr.dwFileAttributes == INVALID_FILE_ATTRIBUTES) return {};
if (attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) return file_storage::flag_hidden;
return {};
#else
struct ::stat s;
if (::lstat(convert_to_native(p).c_str(), &s) < 0) return {};
if (::lstat(path.c_str(), &s) < 0) return {};
file_flags_t file_attr = {};
if (s.st_mode & S_IXUSR)
file_attr |= file_storage::flag_executable;
@ -94,12 +94,12 @@ namespace {
constexpr int MAX_SYMLINK_PATH = 200;
char buf[MAX_SYMLINK_PATH];
std::string f = convert_to_native(path);
std::string f = convert_to_native_path_string(path);
int char_read = int(readlink(f.c_str(), buf, MAX_SYMLINK_PATH));
if (char_read < 0) return "";
if (char_read < MAX_SYMLINK_PATH) buf[char_read] = 0;
else buf[0] = 0;
return convert_from_native(buf);
return convert_from_native_path(buf);
}
#endif

View File

@ -84,13 +84,10 @@ struct iovec
#include "libtorrent/aux_/alloca.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/aux_/path.hpp"
#include "libtorrent/aux_/path.hpp" // for convert_to_native_path_string
#include "libtorrent/string_util.hpp"
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
#include <cstring>
// for convert_to_wstring and convert_to_native
#include "libtorrent/aux_/escape_string.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/aux_/throw.hpp"
@ -391,7 +388,7 @@ static_assert(!(open_mode::sparse & open_mode::attribute_mask), "internal flags
#ifdef TORRENT_WINDOWS
return convert_from_native_path(m_fd.cFileName);
#else
return convert_from_native(m_name);
return convert_from_native_path(m_name.c_str());
#endif
}

View File

@ -71,11 +71,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/path.hpp"
#include "libtorrent/file.hpp" // for directory
#include "libtorrent/string_util.hpp"
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
#include <cstring>
// for convert_to_wstring and convert_to_native
#include "libtorrent/aux_/escape_string.hpp"
#include "libtorrent/aux_/escape_string.hpp" // for convert_to_native
#include "libtorrent/assert.hpp"
#include "libtorrent/aux_/throw.hpp"
@ -132,7 +130,11 @@ namespace libtorrent {
}
#if defined TORRENT_WINDOWS
std::string convert_from_native_path(wchar_t const* s) { return convert_from_wstring(s); }
std::string convert_from_native_path(wchar_t const* s)
{
if (s[0] == L'\\' && s[1] == L'\\' && s[2] == L'?' && s[3] == L'\\') s += 4;
return convert_from_wstring(s);
}
#else
std::string convert_from_native_path(char const* s) { return convert_from_native(s); }
#endif
@ -165,23 +167,13 @@ namespace {
native_path_string convert_to_native_path_string(std::string const& path)
{
#ifdef TORRENT_WINDOWS
#if TORRENT_USE_UNC_PATHS
std::string prepared_path;
// UNC paths must be absolute
// network paths are already UNC paths
if (path.substr(0,2) == "\\\\")
prepared_path = path;
else
{
std::string sep_path = path;
std::replace(sep_path.begin(), sep_path.end(), '/', '\\');
prepared_path = "\\\\?\\" + (is_complete(sep_path) ? sep_path : complete(sep_path));
}
#else
std::string prepared_path = path;
std::string prepared_path = complete(path);
if (prepared_path.substr(0,2) != "\\\\")
prepared_path = "\\\\?\\" + prepared_path;
std::replace(prepared_path.begin(), prepared_path.end(), '/', '\\');
#endif
return convert_to_wstring(prepared_path);
#else // TORRENT_WINDOWS

View File

@ -73,8 +73,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/disk_buffer_holder.hpp"
#include "libtorrent/stat_cache.hpp"
#include "libtorrent/hex.hpp" // to_hex
// for convert_to_wstring and convert_to_native
#include "libtorrent/aux_/escape_string.hpp"
//#include "libtorrent/aux_/escape_string.hpp"
namespace libtorrent {
@ -233,7 +232,7 @@ namespace libtorrent {
#ifdef TORRENT_WINDOWS
// don't do full file allocations on network drives
std::wstring file_name = convert_to_wstring(m_save_path);
auto const file_name = convert_to_native_path_string(m_save_path);
int const drive_type = GetDriveTypeW(file_name.c_str());
if (drive_type == DRIVE_REMOTE)

View File

@ -8155,7 +8155,7 @@ bool is_downloading_state(int const st)
if (m_storage && file >= file_index_t(0))
{
file_storage const& st = m_torrent_file->files();
return combine_path(m_save_path, st.file_path(file));
return st.file_path(file, m_save_path);
}
else
{

View File

@ -192,6 +192,8 @@ namespace libtorrent {
}
#if !TORRENT_USE_UNC_PATHS && defined TORRENT_WINDOWS
#pragma message ("building for windows without UNC paths is deprecated")
// if we're not using UNC paths on windows, there
// are certain filenames we're not allowed to use
static const char const* reserved_names[] =

View File

@ -230,12 +230,12 @@ void change_directory(std::string const& f, error_code& ec)
{
ec.clear();
native_path_string const n = convert_to_native_path_string(f);
#ifdef TORRENT_WINDOWS
native_path_string const n = convert_to_wstring(f);
if (SetCurrentDirectoryW(n.c_str()) == 0)
ec.assign(GetLastError(), system_category());
#else
native_path_string const n = convert_to_native_path_string(f);
int ret = ::chdir(n.c_str());
if (ret != 0)
ec.assign(errno, system_category());
@ -430,6 +430,7 @@ int EXPORT main(int argc, char const* argv[])
return 1;
}
std::printf("cwd: %s\n", unit_dir.c_str());
unit_test_t& t = _g_unit_tests[i];
if (redirect_stdout || redirect_stderr)

View File

@ -810,7 +810,8 @@ setup_transfer(lt::session* ses1, lt::session* ses2, lt::session* ses3
{
error_code ec;
create_directory("tmp1" + suffix, ec);
std::ofstream file(combine_path("tmp1" + suffix, "temporary").c_str());
std::string const file_path = combine_path("tmp1" + suffix, "temporary");
std::ofstream file(file_path.c_str());
t = ::create_torrent(&file, "temporary", piece_size, 9, false);
file.close();
if (clear_files)
@ -818,7 +819,7 @@ setup_transfer(lt::session* ses1, lt::session* ses2, lt::session* ses3
remove_all(combine_path("tmp2" + suffix, "temporary"), ec);
remove_all(combine_path("tmp3" + suffix, "temporary"), ec);
}
std::printf("generated torrent: %s tmp1%s/temporary\n", aux::to_hex(t->info_hash()).c_str(), suffix.c_str());
std::printf("generated torrent: %s %s\n", aux::to_hex(t->info_hash()).c_str(), file_path.c_str());
}
else
{

View File

@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include <set>
#include <thread>
#include <iostream>
using namespace lt;
@ -56,11 +57,13 @@ int touch_file(std::string const& filename, int size)
file f;
error_code ec;
if (!f.open(filename, open_mode::write_only, ec)) return -1;
TEST_EQUAL(ec, error_code());
if (ec) return -1;
iovec_t b = {v};
std::int64_t written = f.writev(0, b, ec);
if (written != int(v.size())) return -3;
if (ec) return -3;
TEST_EQUAL(ec, error_code());
return 0;
}
@ -447,31 +450,31 @@ TORRENT_TEST(stat_file)
TEST_EQUAL(ec, boost::system::errc::no_such_file_or_directory);
}
// specificaly UNC tests
// UNC tests
#if TORRENT_USE_UNC_PATHS
namespace {
std::tuple<int, bool> fill_current_directory_caps()
std::tuple<int, bool> current_directory_caps()
{
#ifdef TORRENT_WINDOWS
error_code ec;
DWORD dw_maximum_component_length;
DWORD dw_file_system_flags;
if (!GetVolumeInformationA(nullptr, nullptr, 0, nullptr, &dw_maximum_component_length, &dw_file_system_flags, nullptr, 0))
DWORD maximum_component_length = FILENAME_MAX;
DWORD file_system_flags = 0;
if (GetVolumeInformation(nullptr
, nullptr, 0, nullptr
, &maximum_component_length, &file_system_flags, nullptr, 0) == 0)
{
ec.assign(GetLastError(), system_category());
std::printf("GetVolumeInformation: [%s] %s\n"
, ec.category().name(), ec.message().c_str());
return std::make_tuple(0, false);
error_code ec(GetLastError(), system_category());
std::printf("GetVolumeInformation: [%s : %d] %s\n"
, ec.category().name(), ec.value(), ec.message().c_str());
// ignore errors, this is best-effort
}
int maximum_component_length = int(dw_maximum_component_length);
bool support_hard_links = ((dw_file_system_flags & FILE_SUPPORTS_HARD_LINKS) != 0);
return std::make_tuple(maximum_component_length, support_hard_links);
bool const support_hard_links = ((file_system_flags & FILE_SUPPORTS_HARD_LINKS) != 0);
return std::make_tuple(int(maximum_component_length), support_hard_links);
#else
return std::make_tuple(TORRENT_MAX_PATH, true);
return std::make_tuple(255, true);
#endif
}
}
} // anonymous namespace
TORRENT_TEST(unc_tests)
{
@ -497,7 +500,7 @@ TORRENT_TEST(unc_tests)
for (std::string special_name : special_names)
{
TEST_EQUAL(touch_file(special_name, 10), 0);
touch_file(special_name, 10);
TEST_CHECK(lt::exists(special_name));
lt::remove(special_name, ec);
TEST_EQUAL(ec, error_code());
@ -506,61 +509,88 @@ TORRENT_TEST(unc_tests)
int maximum_component_length;
bool support_hard_links;
std::tie(maximum_component_length, support_hard_links) = fill_current_directory_caps();
std::tie(maximum_component_length, support_hard_links) = current_directory_caps();
if (maximum_component_length > 0)
std::cout << "max file path component length: " << maximum_component_length << "\n"
<< "support hard links: " << (support_hard_links?"yes":"no") << "\n";
std::string long_dir_name;
maximum_component_length -= 12;
long_dir_name.resize(size_t(maximum_component_length));
for (int i = 0; i < maximum_component_length; ++i)
long_dir_name[i] = static_cast<char>((i % 26) + 'A');
std::string long_file_name1 = combine_path(long_dir_name, long_dir_name);
long_file_name1.back() = '1';
std::string long_file_name2 = long_file_name1;
long_file_name2.back() = '2';
lt::create_directory(long_dir_name, ec);
TEST_EQUAL(ec, error_code());
if (ec)
{
std::string long_component_name;
long_component_name.resize(size_t(maximum_component_length));
for (int i = 0; i < maximum_component_length; ++i)
long_component_name[i] = static_cast<char>((i % 26) + 'A');
std::cout << "create_directory \"" << long_dir_name << "\" failed: " << ec.message() << "\n";
std::wcout << convert_to_native_path_string(long_dir_name) << L"\n";
}
TEST_CHECK(lt::exists(long_dir_name));
TEST_CHECK(lt::is_directory(long_dir_name, ec));
TEST_EQUAL(ec, error_code());
if (ec)
{
std::cout << "is_directory \"" << long_dir_name << "\" failed " << ec.message() << "\n";
std::wcout << convert_to_native_path_string(long_dir_name) << L"\n";
}
std::string long_file_name1 = combine_path(long_component_name, long_component_name);
long_file_name1.back() = '1';
std::string long_file_name2 { long_file_name1 };
long_file_name2.back() = '2';
touch_file(long_file_name1, 10);
TEST_CHECK(lt::exists(long_file_name1));
lt::create_directory(long_component_name, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(lt::exists(long_component_name));
TEST_CHECK(lt::is_directory(long_component_name, ec));
lt::rename(long_file_name1, long_file_name2, ec);
TEST_EQUAL(ec, error_code());
if (ec)
{
std::cout << "rename \"" << long_file_name1 << "\" failed " << ec.message() << "\n";
std::wcout << convert_to_native_path_string(long_file_name1) << L"\n";
}
TEST_CHECK(!lt::exists(long_file_name1));
TEST_CHECK(lt::exists(long_file_name2));
TEST_EQUAL(touch_file(long_file_name1, 10), 0);
TEST_CHECK(lt::exists(long_file_name1));
lt::copy_file(long_file_name2, long_file_name1, ec);
TEST_EQUAL(ec, error_code());
if (ec)
{
std::cout << "copy_file \"" << long_file_name2 << "\" failed " << ec.message() << "\n";
std::wcout << convert_to_native_path_string(long_file_name2) << L"\n";
}
TEST_CHECK(lt::exists(long_file_name1));
lt::rename(long_file_name1, long_file_name2, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(!lt::exists(long_file_name1));
TEST_CHECK(lt::exists(long_file_name2));
std::set<std::string> files;
lt::copy_file(long_file_name2, long_file_name1, ec);
for (lt::directory i(long_dir_name, ec); !i.done(); i.next(ec))
{
std::string f = i.file();
files.insert(f);
}
TEST_EQUAL(files.size(), 4);
lt::remove(long_file_name1, ec);
TEST_EQUAL(ec, error_code());
if (ec)
{
std::cout << "remove \"" << long_file_name1 << "\" failed " << ec.message() << "\n";
std::wcout << convert_to_native_path_string(long_file_name1) << L"\n";
}
TEST_CHECK(!lt::exists(long_file_name1));
if (support_hard_links)
{
lt::hard_link(long_file_name2, long_file_name1, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(lt::exists(long_file_name1));
std::set<std::string> files;
for (lt::directory i(long_component_name, ec); !i.done(); i.next(ec))
{
std::string f = i.file();
files.insert(f);
}
TEST_EQUAL(files.size(), 4);
lt::remove(long_file_name1, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(!lt::exists(long_file_name1));
if (support_hard_links)
{
lt::hard_link(long_file_name2, long_file_name1, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(lt::exists(long_file_name1));
lt::remove(long_file_name1, ec);
TEST_EQUAL(ec, error_code());
TEST_CHECK(!lt::exists(long_file_name1));
}
}
}