forked from premiere/premiere-libtorrent
complete UNC path support (#1689)
complete UNC path support. all internal file api functions handle long size paths (> MAX_PATH) and special names (CON,PRN ...) with unit test
This commit is contained in:
parent
6819823f1f
commit
9bee2146d0
|
@ -1,3 +1,4 @@
|
||||||
|
* complete UNC path support
|
||||||
* add packets pool allocator
|
* add packets pool allocator
|
||||||
* fix last_upload and last_download overflow after 9 hours in past
|
* fix last_upload and last_download overflow after 9 hours in past
|
||||||
* python binding add more add_torrent_params fields and an invalid key check
|
* python binding add more add_torrent_params fields and an invalid key check
|
||||||
|
|
|
@ -176,6 +176,25 @@ namespace libtorrent
|
||||||
TORRENT_EXTRA_EXPORT std::string canonicalize_path(string_view f);
|
TORRENT_EXTRA_EXPORT std::string canonicalize_path(string_view f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// internal type alias export should be used at unit tests only
|
||||||
|
using native_path_string =
|
||||||
|
#if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS
|
||||||
|
std::wstring;
|
||||||
|
#else
|
||||||
|
std::string;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// internal export should be used at unit tests only
|
||||||
|
TORRENT_EXTRA_EXPORT native_path_string convert_to_native_path_string(std::string const& path);
|
||||||
|
|
||||||
|
// internal export should be used at unit tests only
|
||||||
|
TORRENT_EXTRA_EXPORT std::string convert_from_native_path(char const* s);
|
||||||
|
|
||||||
|
#if defined TORRENT_WINDOWS && TORRENT_USE_WSTRING
|
||||||
|
// internal export should be used at unit tests only
|
||||||
|
TORRENT_EXTRA_EXPORT std::string convert_from_native_path(wchar_t const* s);
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: move this into a separate header file, TU pair
|
// TODO: move this into a separate header file, TU pair
|
||||||
class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable
|
class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable
|
||||||
{
|
{
|
||||||
|
|
|
@ -177,10 +177,12 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string file_completed_alert::message() const
|
std::string file_completed_alert::message() const
|
||||||
{
|
{
|
||||||
char msg[200 + TORRENT_MAX_PATH];
|
std::string ret { torrent_alert::message() };
|
||||||
std::snprintf(msg, sizeof(msg), "%s: file %d finished downloading"
|
char msg[200];
|
||||||
, torrent_alert::message().c_str(), static_cast<int>(index));
|
std::snprintf(msg, sizeof(msg), ": file %d finished downloading"
|
||||||
return msg;
|
, static_cast<int>(index));
|
||||||
|
ret.append(msg);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_renamed_alert::file_renamed_alert(aux::stack_allocator& alloc
|
file_renamed_alert::file_renamed_alert(aux::stack_allocator& alloc
|
||||||
|
@ -200,10 +202,13 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string file_renamed_alert::message() const
|
std::string file_renamed_alert::message() const
|
||||||
{
|
{
|
||||||
char msg[200 + TORRENT_MAX_PATH * 2];
|
std::string ret { torrent_alert::message() };
|
||||||
std::snprintf(msg, sizeof(msg), "%s: file %d renamed to %s"
|
char msg[200];
|
||||||
, torrent_alert::message().c_str(), static_cast<int>(index), new_name());
|
std::snprintf(msg, sizeof(msg), ": file %d renamed to "
|
||||||
return msg;
|
, static_cast<int>(index));
|
||||||
|
ret.append(msg);
|
||||||
|
ret.append(new_name());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_rename_failed_alert::file_rename_failed_alert(aux::stack_allocator& alloc
|
file_rename_failed_alert::file_rename_failed_alert(aux::stack_allocator& alloc
|
||||||
|
@ -217,10 +222,12 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string file_rename_failed_alert::message() const
|
std::string file_rename_failed_alert::message() const
|
||||||
{
|
{
|
||||||
char ret[200 + TORRENT_MAX_PATH * 2];
|
std::string ret { torrent_alert::message() };
|
||||||
std::snprintf(ret, sizeof(ret), "%s: failed to rename file %d: %s"
|
char msg[200];
|
||||||
, torrent_alert::message().c_str(), static_cast<int>(index)
|
std::snprintf(msg, sizeof(msg), ": failed to rename file %d: "
|
||||||
, convert_from_native(error.message()).c_str());
|
, static_cast<int>(index));
|
||||||
|
ret.append(msg);
|
||||||
|
ret.append(convert_from_native(error.message()));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,12 +231,30 @@ namespace libtorrent
|
||||||
if (!need_encoding(path.c_str(), int(path.size())))
|
if (!need_encoding(path.c_str(), int(path.size())))
|
||||||
return url;
|
return url;
|
||||||
|
|
||||||
char msg[TORRENT_MAX_PATH*4];
|
std::string msg;
|
||||||
std::snprintf(msg, sizeof(msg), "%s://%s%s%s%s%s%s", protocol.c_str(), auth.c_str()
|
std::string escaped_path { escape_path(path) };
|
||||||
, auth.empty() ? "" : "@", host.c_str()
|
// reserve enough space so further append will
|
||||||
, port == -1 ? "" : ":"
|
// only copy values to existing location
|
||||||
, port == -1 ? "" : to_string(port).data()
|
msg.reserve(protocol.size() + 3 + // protocol part
|
||||||
, escape_path(path).c_str());
|
auth.size() + 1 + // auth part
|
||||||
|
host.size() + // host part
|
||||||
|
1 + 5 + // port part
|
||||||
|
escaped_path.size());
|
||||||
|
msg.append(protocol);
|
||||||
|
msg.append("://");
|
||||||
|
if (!auth.empty())
|
||||||
|
{
|
||||||
|
msg.append(auth);
|
||||||
|
msg.append("@");
|
||||||
|
}
|
||||||
|
msg.append(host);
|
||||||
|
if (port != -1)
|
||||||
|
{
|
||||||
|
msg.append(":");
|
||||||
|
msg.append(to_string(port).data());
|
||||||
|
}
|
||||||
|
msg.append(escaped_path);
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
203
src/file.cpp
203
src/file.cpp
|
@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
// for convert_to_wstring and convert_to_native
|
// for convert_to_wstring and convert_to_native
|
||||||
#include "libtorrent/aux_/escape_string.hpp"
|
#include "libtorrent/aux_/escape_string.hpp"
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
|
#include "libtorrent/aux_/throw.hpp"
|
||||||
|
|
||||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
||||||
|
@ -336,14 +337,19 @@ namespace libtorrent
|
||||||
return int(size);
|
return int(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
std::string convert_from_native_path(char const* s) { return convert_from_native(s); }
|
||||||
std::string convert_separators(std::string p)
|
|
||||||
|
#if defined TORRENT_WINDOWS && TORRENT_USE_WSTRING
|
||||||
|
std::string convert_from_native_path(wchar_t const* s) { return convert_from_wstring(s); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::unique_ptr<T, decltype(&std::free)> make_free_holder(T* ptr)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < int(p.size()); ++i)
|
return std::unique_ptr<T, decltype(&std::free)>(ptr, &std::free);
|
||||||
if (p[i] == '/') p[i] = '\\';
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
time_t file_time_to_posix(FILETIME f)
|
time_t file_time_to_posix(FILETIME f)
|
||||||
{
|
{
|
||||||
const std::uint64_t posix_time_offset = 11644473600LL;
|
const std::uint64_t posix_time_offset = 11644473600LL;
|
||||||
|
@ -356,34 +362,55 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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 : combine_path(current_working_directory(), sep_path));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::string prepared_path { path };
|
||||||
|
std::replace(prepared_path.begin(), prepared_path.end(), '/', '\\');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TORRENT_USE_WSTRING
|
||||||
|
return convert_to_wstring(prepared_path);
|
||||||
|
#else
|
||||||
|
return convert_to_native(prepared_path);
|
||||||
|
#endif
|
||||||
|
#else // TORRENT_WINDOWS
|
||||||
|
return convert_to_native(path);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void stat_file(std::string const& inf, file_status* s
|
void stat_file(std::string const& inf, file_status* s
|
||||||
, error_code& ec, int const flags)
|
, error_code& ec, int const flags)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
native_path_string f = convert_to_native_path_string(inf);
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
TORRENT_UNUSED(flags);
|
TORRENT_UNUSED(flags);
|
||||||
|
|
||||||
std::string p = convert_separators(inf);
|
|
||||||
#if TORRENT_USE_UNC_PATHS
|
|
||||||
// UNC paths must be absolute
|
|
||||||
// network paths are already UNC paths
|
|
||||||
if (inf.substr(0,2) == "\\\\") p = inf;
|
|
||||||
else p = "\\\\?\\" + (is_complete(p) ? p : combine_path(current_working_directory(), p));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define CreateFile_ CreateFileW
|
#define CreateFile_ CreateFileW
|
||||||
std::wstring f = convert_to_wstring(p);
|
|
||||||
#else
|
#else
|
||||||
#define CreateFile_ CreateFileA
|
#define CreateFile_ CreateFileA
|
||||||
std::string f = convert_to_native(p);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// in order to open a directory, we need the FILE_FLAG_BACKUP_SEMANTICS
|
// in order to open a directory, we need the FILE_FLAG_BACKUP_SEMANTICS
|
||||||
HANDLE h = CreateFile_(f.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ
|
HANDLE h = CreateFile_(f.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ
|
||||||
| FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
| FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
|
#undef CreateFile_
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
|
@ -414,8 +441,6 @@ namespace libtorrent
|
||||||
|
|
||||||
// posix version
|
// posix version
|
||||||
|
|
||||||
std::string const& f = convert_to_native(inf);
|
|
||||||
|
|
||||||
struct stat ret;
|
struct stat ret;
|
||||||
int retval;
|
int retval;
|
||||||
if (flags & dont_follow_links)
|
if (flags & dont_follow_links)
|
||||||
|
@ -448,19 +473,20 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
|
||||||
|
native_path_string f1 = convert_to_native_path_string(inf);
|
||||||
|
native_path_string f2 = convert_to_native_path_string(newf);
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS
|
#if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS
|
||||||
std::wstring f1 = convert_to_wstring(inf);
|
#define RenameFunction_ _wrename
|
||||||
std::wstring f2 = convert_to_wstring(newf);
|
|
||||||
if (_wrename(f1.c_str(), f2.c_str()) < 0)
|
|
||||||
#else
|
#else
|
||||||
std::string const& f1 = convert_to_native(inf);
|
#define RenameFunction_ ::rename
|
||||||
std::string const& f2 = convert_to_native(newf);
|
|
||||||
if (::rename(f1.c_str(), f2.c_str()) < 0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (RenameFunction_(f1.c_str(), f2.c_str()) < 0)
|
||||||
{
|
{
|
||||||
ec.assign(errno, generic_category());
|
ec.assign(errno, generic_category());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
#undef RenameFunction_
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_directories(std::string const& f, error_code& ec)
|
void create_directories(std::string const& f, error_code& ec)
|
||||||
|
@ -483,20 +509,19 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
|
||||||
|
native_path_string n = convert_to_native_path_string(f);
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define CreateDirectory_ CreateDirectoryW
|
#define CreateDirectory_ CreateDirectoryW
|
||||||
std::wstring n = convert_to_wstring(f);
|
|
||||||
#else
|
#else
|
||||||
#define CreateDirectory_ CreateDirectoryA
|
#define CreateDirectory_ CreateDirectoryA
|
||||||
std::string const& n = convert_to_native(f);
|
|
||||||
#endif // TORRENT_USE_WSTRING
|
#endif // TORRENT_USE_WSTRING
|
||||||
|
|
||||||
if (CreateDirectory_(n.c_str(), 0) == 0
|
if (CreateDirectory_(n.c_str(), 0) == 0
|
||||||
&& GetLastError() != ERROR_ALREADY_EXISTS)
|
&& GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
|
#undef CreateDirectory_
|
||||||
#else
|
#else
|
||||||
std::string n = convert_to_native(f);
|
|
||||||
int ret = ::mkdir(n.c_str(), 0777);
|
int ret = ::mkdir(n.c_str(), 0777);
|
||||||
if (ret < 0 && errno != EEXIST)
|
if (ret < 0 && errno != EEXIST)
|
||||||
ec.assign(errno, system_category());
|
ec.assign(errno, system_category());
|
||||||
|
@ -506,16 +531,14 @@ namespace libtorrent
|
||||||
void hard_link(std::string const& file, std::string const& link
|
void hard_link(std::string const& file, std::string const& link
|
||||||
, error_code& ec)
|
, error_code& ec)
|
||||||
{
|
{
|
||||||
|
native_path_string n_exist = convert_to_native_path_string(file);
|
||||||
|
native_path_string n_link = convert_to_native_path_string(link);
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define CreateHardLink_ CreateHardLinkW
|
#define CreateHardLink_ CreateHardLinkW
|
||||||
std::wstring n_exist = convert_to_wstring(file);
|
|
||||||
std::wstring n_link = convert_to_wstring(link);
|
|
||||||
#else
|
#else
|
||||||
#define CreateHardLink_ CreateHardLinkA
|
#define CreateHardLink_ CreateHardLinkA
|
||||||
std::string n_exist = convert_to_native(file);
|
|
||||||
std::string n_link = convert_to_native(link);
|
|
||||||
#endif
|
#endif
|
||||||
BOOL ret = CreateHardLink_(n_link.c_str(), n_exist.c_str(), nullptr);
|
BOOL ret = CreateHardLink_(n_link.c_str(), n_exist.c_str(), nullptr);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -523,7 +546,7 @@ namespace libtorrent
|
||||||
ec.clear();
|
ec.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#undef CreateHardLink_
|
||||||
// something failed. Does the filesystem not support hard links?
|
// something failed. Does the filesystem not support hard links?
|
||||||
// TODO: 3 find out what error code is reported when the filesystem
|
// TODO: 3 find out what error code is reported when the filesystem
|
||||||
// does not support hard links.
|
// does not support hard links.
|
||||||
|
@ -539,10 +562,6 @@ namespace libtorrent
|
||||||
// fall back to making a copy
|
// fall back to making a copy
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
std::string n_exist = convert_to_native(file);
|
|
||||||
std::string n_link = convert_to_native(link);
|
|
||||||
|
|
||||||
// assume posix's link() function exists
|
// assume posix's link() function exists
|
||||||
int ret = ::link(n_exist.c_str(), n_link.c_str());
|
int ret = ::link(n_exist.c_str(), n_link.c_str());
|
||||||
|
|
||||||
|
@ -605,32 +624,27 @@ namespace libtorrent
|
||||||
void copy_file(std::string const& inf, std::string const& newf, error_code& ec)
|
void copy_file(std::string const& inf, std::string const& newf, error_code& ec)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
native_path_string f1 = convert_to_native_path_string(inf);
|
||||||
|
native_path_string f2 = convert_to_native_path_string(newf);
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define CopyFile_ CopyFileW
|
#define CopyFile_ CopyFileW
|
||||||
std::wstring f1 = convert_to_wstring(inf);
|
|
||||||
std::wstring f2 = convert_to_wstring(newf);
|
|
||||||
#else
|
#else
|
||||||
#define CopyFile_ CopyFileA
|
#define CopyFile_ CopyFileA
|
||||||
std::string const& f1 = convert_to_native(inf);
|
|
||||||
std::string const& f2 = convert_to_native(newf);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (CopyFile_(f1.c_str(), f2.c_str(), false) == 0)
|
if (CopyFile_(f1.c_str(), f2.c_str(), false) == 0)
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
#undef CopyFile_
|
||||||
std::string f1 = convert_to_native(inf);
|
|
||||||
std::string f2 = convert_to_native(newf);
|
|
||||||
|
|
||||||
|
#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||||
// this only works on 10.5
|
// this only works on 10.5
|
||||||
copyfile_state_t state = copyfile_state_alloc();
|
copyfile_state_t state = copyfile_state_alloc();
|
||||||
if (copyfile(f1.c_str(), f2.c_str(), state, COPYFILE_ALL) < 0)
|
if (copyfile(f1.c_str(), f2.c_str(), state, COPYFILE_ALL) < 0)
|
||||||
ec.assign(errno, system_category());
|
ec.assign(errno, system_category());
|
||||||
copyfile_state_free(state);
|
copyfile_state_free(state);
|
||||||
#else
|
#else
|
||||||
std::string const f1 = convert_to_native(inf);
|
|
||||||
std::string const f2 = convert_to_native(newf);
|
|
||||||
|
|
||||||
int const infd = ::open(f1.c_str(), O_RDONLY);
|
int const infd = ::open(f1.c_str(), O_RDONLY);
|
||||||
if (infd < 0)
|
if (infd < 0)
|
||||||
{
|
{
|
||||||
|
@ -944,23 +958,21 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string current_working_directory()
|
std::string current_working_directory()
|
||||||
{
|
{
|
||||||
#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW
|
#if defined TORRENT_WINDOWS
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
wchar_t cwd[TORRENT_MAX_PATH];
|
#define GetCurrentDir_ ::_wgetcwd
|
||||||
_wgetcwd(cwd, sizeof(cwd) / sizeof(wchar_t));
|
|
||||||
#else
|
#else
|
||||||
char cwd[TORRENT_MAX_PATH];
|
#define GetCurrentDir_ ::_getcwd
|
||||||
_getcwd(cwd, sizeof(cwd));
|
|
||||||
#endif // TORRENT_USE_WSTRING
|
#endif // TORRENT_USE_WSTRING
|
||||||
#else
|
#else
|
||||||
char cwd[TORRENT_MAX_PATH];
|
#define GetCurrentDir_ ::getcwd
|
||||||
if (getcwd(cwd, sizeof(cwd)) == nullptr) return "/";
|
|
||||||
#endif
|
|
||||||
#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW && TORRENT_USE_WSTRING
|
|
||||||
return convert_from_wstring(cwd);
|
|
||||||
#else
|
|
||||||
return convert_from_native(cwd);
|
|
||||||
#endif
|
#endif
|
||||||
|
auto cwd = GetCurrentDir_(nullptr, 0);
|
||||||
|
if (cwd == nullptr)
|
||||||
|
aux::throw_ex<system_error>(error_code(errno, generic_category()));
|
||||||
|
auto holder = make_free_holder(cwd);
|
||||||
|
return convert_from_native_path(cwd);
|
||||||
|
#undef GetCurrentDir_
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_UNC_PATHS
|
#if TORRENT_USE_UNC_PATHS
|
||||||
|
@ -1057,24 +1069,21 @@ namespace libtorrent
|
||||||
void remove(std::string const& inf, error_code& ec)
|
void remove(std::string const& inf, error_code& ec)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
native_path_string f = convert_to_native_path_string(inf);
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
// windows does not allow trailing / or \ in
|
// windows does not allow trailing / or \ in
|
||||||
// the path when removing files
|
// the path when removing files
|
||||||
std::string pruned;
|
while (!f.empty() && (
|
||||||
if (inf[inf.size() - 1] == '/'
|
f.back() == '/' ||
|
||||||
|| inf[inf.size() - 1] == '\\')
|
f.back() == '\\'
|
||||||
pruned = inf.substr(0, inf.size() - 1);
|
)) f.pop_back();
|
||||||
else
|
|
||||||
pruned = inf;
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define DeleteFile_ DeleteFileW
|
#define DeleteFile_ DeleteFileW
|
||||||
#define RemoveDirectory_ RemoveDirectoryW
|
#define RemoveDirectory_ RemoveDirectoryW
|
||||||
std::wstring f = convert_to_wstring(pruned);
|
|
||||||
#else
|
#else
|
||||||
#define DeleteFile_ DeleteFileA
|
#define DeleteFile_ DeleteFileA
|
||||||
#define RemoveDirectory_ RemoveDirectoryA
|
#define RemoveDirectory_ RemoveDirectoryA
|
||||||
std::string f = convert_to_native(pruned);
|
|
||||||
#endif
|
#endif
|
||||||
if (DeleteFile_(f.c_str()) == 0)
|
if (DeleteFile_(f.c_str()) == 0)
|
||||||
{
|
{
|
||||||
|
@ -1086,8 +1095,9 @@ namespace libtorrent
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#undef DeleteFile_
|
||||||
|
#undef RemoveDirectory_
|
||||||
#else // TORRENT_WINDOWS
|
#else // TORRENT_WINDOWS
|
||||||
std::string const& f = convert_to_native(inf);
|
|
||||||
if (::remove(f.c_str()) < 0)
|
if (::remove(f.c_str()) < 0)
|
||||||
{
|
{
|
||||||
ec.assign(errno, system_category());
|
ec.assign(errno, system_category());
|
||||||
|
@ -1149,40 +1159,43 @@ namespace libtorrent
|
||||||
: m_done(false)
|
: m_done(false)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
std::string p{ path };
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
m_inode = 0;
|
|
||||||
// the path passed to FindFirstFile() must be
|
// the path passed to FindFirstFile() must be
|
||||||
// a pattern
|
// a pattern
|
||||||
std::string f = convert_separators(path);
|
p.append((!p.empty() && p.back() != '\\') ? "\\*" : "*");
|
||||||
if (!f.empty() && f[f.size()-1] != '\\') f += "\\*";
|
#else
|
||||||
else f += "*";
|
// the path passed to opendir() may not
|
||||||
|
// end with a /
|
||||||
|
if (!p.empty() && p.back() == '/')
|
||||||
|
p.pop_back();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
native_path_string f = convert_to_native_path_string(p);
|
||||||
|
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
m_inode = 0;
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define FindFirstFile_ FindFirstFileW
|
#define FindFirstFile_ FindFirstFileW
|
||||||
std::wstring p = convert_to_wstring(f);
|
|
||||||
#else
|
#else
|
||||||
#define FindFirstFile_ FindFirstFileA
|
#define FindFirstFile_ FindFirstFileA
|
||||||
std::string p = convert_to_native(f);
|
|
||||||
#endif
|
#endif
|
||||||
m_handle = FindFirstFile_(p.c_str(), &m_fd);
|
m_handle = FindFirstFile_(f.c_str(), &m_fd);
|
||||||
if (m_handle == INVALID_HANDLE_VALUE)
|
if (m_handle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
m_done = true;
|
m_done = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#undef FindFirstFile_
|
||||||
#else
|
#else
|
||||||
|
|
||||||
std::memset(&m_dirent, 0, sizeof(dirent));
|
std::memset(&m_dirent, 0, sizeof(dirent));
|
||||||
m_name[0] = 0;
|
m_name[0] = 0;
|
||||||
|
|
||||||
// the path passed to opendir() may not
|
m_handle = ::opendir(f.c_str());
|
||||||
// end with a /
|
|
||||||
std::string p = path;
|
|
||||||
if (!path.empty() && path[path.size()-1] == '/')
|
|
||||||
p.resize(path.size()-1);
|
|
||||||
|
|
||||||
p = convert_to_native(p);
|
|
||||||
m_handle = ::opendir(p.c_str());
|
|
||||||
if (m_handle == nullptr)
|
if (m_handle == nullptr)
|
||||||
{
|
{
|
||||||
ec.assign(errno, system_category());
|
ec.assign(errno, system_category());
|
||||||
|
@ -1216,11 +1229,7 @@ namespace libtorrent
|
||||||
std::string directory::file() const
|
std::string directory::file() const
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
#if TORRENT_USE_WSTRING
|
return convert_from_native_path(m_fd.cFileName);
|
||||||
return convert_from_wstring(m_fd.cFileName);
|
|
||||||
#else
|
|
||||||
return convert_from_native(m_fd.cFileName);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
return convert_from_native(m_dirent.d_name);
|
return convert_from_native(m_dirent.d_name);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1242,6 +1251,7 @@ namespace libtorrent
|
||||||
if (err != ERROR_NO_MORE_FILES)
|
if (err != ERROR_NO_MORE_FILES)
|
||||||
ec.assign(err, system_category());
|
ec.assign(err, system_category());
|
||||||
}
|
}
|
||||||
|
#undef FindNextFile_
|
||||||
++m_inode;
|
++m_inode;
|
||||||
#else
|
#else
|
||||||
dirent* dummy;
|
dirent* dummy;
|
||||||
|
@ -1330,6 +1340,7 @@ namespace libtorrent
|
||||||
bool file::open(std::string const& path, int mode, error_code& ec)
|
bool file::open(std::string const& path, int mode, error_code& ec)
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
native_path_string file_path = convert_to_native_path_string(path);
|
||||||
|
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
||||||
|
@ -1357,20 +1368,10 @@ namespace libtorrent
|
||||||
FILE_ATTRIBUTE_HIDDEN, // hidden + executable
|
FILE_ATTRIBUTE_HIDDEN, // hidden + executable
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string p = convert_separators(path);
|
|
||||||
#if TORRENT_USE_UNC_PATHS
|
|
||||||
// UNC paths must be absolute
|
|
||||||
// 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));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
#define CreateFile_ CreateFileW
|
#define CreateFile_ CreateFileW
|
||||||
std::wstring file_path = convert_to_wstring(p);
|
|
||||||
#else
|
#else
|
||||||
#define CreateFile_ CreateFileA
|
#define CreateFile_ CreateFileA
|
||||||
std::string file_path = convert_to_native(p);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TORRENT_ASSERT((mode & rw_mask) < sizeof(mode_array)/sizeof(mode_array[0]));
|
TORRENT_ASSERT((mode & rw_mask) < sizeof(mode_array)/sizeof(mode_array[0]));
|
||||||
|
@ -1390,6 +1391,8 @@ namespace libtorrent
|
||||||
, (mode & lock_file) ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE
|
, (mode & lock_file) ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE
|
||||||
, 0, m.create_mode, flags, 0);
|
, 0, m.create_mode, flags, 0);
|
||||||
|
|
||||||
|
#undef CreateFile_
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
ec.assign(GetLastError(), system_category());
|
ec.assign(GetLastError(), system_category());
|
||||||
|
@ -1436,7 +1439,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
handle_type handle = ::open(convert_to_native(path).c_str()
|
handle_type handle = ::open(file_path.c_str()
|
||||||
, mode_array[mode & rw_mask] | open_mode
|
, mode_array[mode & rw_mask] | open_mode
|
||||||
, permissions);
|
, permissions);
|
||||||
|
|
||||||
|
@ -1448,7 +1451,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
mode &= ~no_atime;
|
mode &= ~no_atime;
|
||||||
open_mode &= ~O_NOATIME;
|
open_mode &= ~O_NOATIME;
|
||||||
handle = ::open(convert_to_native(path).c_str(), mode_array[mode & rw_mask] | open_mode
|
handle = ::open(file_path.c_str(), mode_array[mode & rw_mask] | open_mode
|
||||||
, permissions);
|
, permissions);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -170,15 +170,6 @@ TORRENT_TEST(paths)
|
||||||
TEST_EQUAL(combine_path("test1", "test2"), "test1/test2");
|
TEST_EQUAL(combine_path("test1", "test2"), "test1/test2");
|
||||||
#endif
|
#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"), "");
|
||||||
TEST_EQUAL(extension("blah.exe"), ".exe");
|
TEST_EQUAL(extension("blah.exe"), ".exe");
|
||||||
TEST_EQUAL(extension("blah.foo.bar"), ".bar");
|
TEST_EQUAL(extension("blah.foo.bar"), ".bar");
|
||||||
|
@ -408,3 +399,121 @@ TORRENT_TEST(stat_file)
|
||||||
TEST_CHECK(ec);
|
TEST_CHECK(ec);
|
||||||
TEST_EQUAL(ec, boost::system::errc::no_such_file_or_directory);
|
TEST_EQUAL(ec, boost::system::errc::no_such_file_or_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specificaly UNC tests
|
||||||
|
#if TORRENT_USE_UNC_PATHS
|
||||||
|
|
||||||
|
std::tuple<int, bool> fill_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))
|
||||||
|
{
|
||||||
|
ec.assign(GetLastError(), system_category());
|
||||||
|
std::printf("GetVolumeInformation: [%s] %s\n"
|
||||||
|
, ec.category().name(), ec.message().c_str());
|
||||||
|
return std::make_tuple(0, false);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
#else
|
||||||
|
return std::make_tuple(TORRENT_MAX_PATH, true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(unc_tests)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
std::vector<std::string> special_names
|
||||||
|
{
|
||||||
|
"CON", "PRN", "AUX", "NUL",
|
||||||
|
"COM1", "COM2", "COM3", "COM4",
|
||||||
|
"COM5", "COM6", "COM7", "COM8",
|
||||||
|
"COM9", "LPT1", "LPT2", "LPT3",
|
||||||
|
"LPT4", "LPT5", "LPT6", "LPT7",
|
||||||
|
"LPT8", "LPT9"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::string special_name : special_names)
|
||||||
|
{
|
||||||
|
TEST_EQUAL(touch_file(special_name, 10), 0);
|
||||||
|
TEST_CHECK(lt::exists(special_name));
|
||||||
|
lt::remove(special_name, ec);
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_CHECK(!lt::exists(special_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
int maximum_component_length;
|
||||||
|
bool support_hard_links;
|
||||||
|
std::tie(maximum_component_length, support_hard_links) = fill_current_directory_caps();
|
||||||
|
|
||||||
|
if (maximum_component_length > 0)
|
||||||
|
{
|
||||||
|
std::string long_component_name;
|
||||||
|
long_component_name.resize(maximum_component_length);
|
||||||
|
for (int i = 0; i < maximum_component_length; ++i)
|
||||||
|
long_component_name[i] = static_cast<char>((i % 26) + 'A');
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
TEST_EQUAL(touch_file(long_file_name1, 10), 0);
|
||||||
|
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));
|
||||||
|
|
||||||
|
lt::copy_file(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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue