separate path and filesystem functions out into its own translation unit/header file pair, separating it from the file and directory class
This commit is contained in:
parent
a1df74a404
commit
79d7ae3638
|
@ -35,6 +35,7 @@ set(sources
|
|||
escape_string
|
||||
string_util
|
||||
file
|
||||
path
|
||||
fingerprint
|
||||
gzip
|
||||
hasher
|
||||
|
|
1
Jamfile
1
Jamfile
|
@ -581,6 +581,7 @@ SOURCES =
|
|||
escape_string
|
||||
string_util
|
||||
file
|
||||
path
|
||||
fingerprint
|
||||
gzip
|
||||
hasher
|
||||
|
|
|
@ -68,7 +68,6 @@ category_mapping = {
|
|||
'add_torrent_params.hpp': 'Core',
|
||||
'session_status.hpp': 'Core',
|
||||
'error_code.hpp': 'Error Codes',
|
||||
'file.hpp': 'File',
|
||||
'storage.hpp': 'Custom Storage',
|
||||
'storage_defs.hpp': 'Storage',
|
||||
'file_storage.hpp': 'Storage',
|
||||
|
|
|
@ -33,11 +33,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ nobase_include_HEADERS = \
|
|||
aux_/escape_string.hpp \
|
||||
aux_/io.hpp \
|
||||
aux_/max_path.hpp \
|
||||
aux_/path.hpp \
|
||||
aux_/merkle.hpp \
|
||||
aux_/session_call.hpp \
|
||||
aux_/session_impl.hpp \
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003-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_PATH_HPP_INCLUDED
|
||||
#define TORRENT_PATH_HPP_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/string_view.hpp"
|
||||
#include "libtorrent/span.hpp"
|
||||
#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// windows part
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
// posix part
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h> // for DIR
|
||||
|
||||
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
||||
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
#endif
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
struct file_status
|
||||
{
|
||||
std::int64_t file_size = 0;
|
||||
std::uint64_t atime = 0;
|
||||
std::uint64_t mtime = 0;
|
||||
std::uint64_t ctime = 0;
|
||||
enum {
|
||||
#if defined TORRENT_WINDOWS
|
||||
fifo = 0x1000, // named pipe (fifo)
|
||||
character_special = 0x2000, // character special
|
||||
directory = 0x4000, // directory
|
||||
regular_file = 0x8000 // regular
|
||||
#else
|
||||
fifo = 0010000, // named pipe (fifo)
|
||||
character_special = 0020000, // character special
|
||||
directory = 0040000, // directory
|
||||
block_special = 0060000, // block special
|
||||
regular_file = 0100000, // regular
|
||||
link = 0120000, // symbolic link
|
||||
socket = 0140000 // socket
|
||||
#endif
|
||||
} modes_t;
|
||||
int mode = 0;
|
||||
};
|
||||
|
||||
// internal flags for stat_file
|
||||
enum { dont_follow_links = 1 };
|
||||
TORRENT_EXTRA_EXPORT void stat_file(std::string const& f, file_status* s
|
||||
, error_code& ec, int flags = 0);
|
||||
TORRENT_EXTRA_EXPORT void rename(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void create_directories(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void create_directory(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void remove_all(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void remove(std::string const& f, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT bool exists(std::string const& f, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT bool exists(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::int64_t file_size(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT bool is_directory(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void recursive_copy(std::string const& old_path
|
||||
, std::string const& new_path, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void copy_file(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void move_file(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
|
||||
// file is expected to exist, link will be created to point to it. If hard
|
||||
// links are not supported by the filesystem or OS, the file will be copied.
|
||||
TORRENT_EXTRA_EXPORT void hard_link(std::string const& file
|
||||
, std::string const& link, error_code& ec);
|
||||
|
||||
TORRENT_EXTRA_EXPORT std::string split_path(std::string const& f
|
||||
, bool only_first_part = false);
|
||||
TORRENT_EXTRA_EXPORT char const* next_path_element(char const* p);
|
||||
TORRENT_EXTRA_EXPORT std::string extension(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::string remove_extension(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT void replace_extension(std::string& f, std::string const& ext);
|
||||
TORRENT_EXTRA_EXPORT bool is_root_path(std::string const& f);
|
||||
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string parent_path(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT bool has_parent_path(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT char const* filename_cstr(char const* f);
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string filename(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::string combine_path(string_view lhs
|
||||
, string_view rhs);
|
||||
TORRENT_EXTRA_EXPORT void append_path(std::string& branch
|
||||
, string_view leaf);
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string complete(string_view f);
|
||||
TORRENT_EXTRA_EXPORT bool is_complete(string_view f);
|
||||
TORRENT_EXTRA_EXPORT std::string current_working_directory();
|
||||
#if TORRENT_USE_UNC_PATHS
|
||||
TORRENT_EXTRA_EXPORT std::string canonicalize_path(string_view f);
|
||||
#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
|
||||
|
||||
TORRENT_EXTRA_EXPORT int bufs_size(span<iovec_t const> bufs);
|
||||
}
|
||||
|
||||
#endif // TORRENT_PATH_HPP_INCLUDED
|
|
@ -46,7 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/tailqueue.hpp"
|
||||
#include "libtorrent/linked_list.hpp"
|
||||
#include "libtorrent/disk_buffer_pool.hpp"
|
||||
#include "libtorrent/file.hpp" // for iovec_t
|
||||
#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t
|
||||
#include "libtorrent/disk_io_job.hpp"
|
||||
#include "libtorrent/aux_/unique_ptr.hpp"
|
||||
#if TORRENT_USE_ASSERTS
|
||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/string_view.hpp"
|
||||
#include "libtorrent/aux_/vector.hpp"
|
||||
#include "libtorrent/file.hpp" // for combine_path etc.
|
||||
#include "libtorrent/aux_/path.hpp" // for combine_path etc.
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
|
@ -53,8 +53,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <memory>
|
||||
|
||||
#include "libtorrent/io_service_fwd.hpp"
|
||||
#include "libtorrent/file.hpp" // for iovec_t
|
||||
#include "libtorrent/span.hpp"
|
||||
#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -62,10 +62,12 @@ namespace libtorrent
|
|||
class alert;
|
||||
struct disk_observer;
|
||||
|
||||
struct TORRENT_EXTRA_EXPORT disk_buffer_pool : boost::noncopyable
|
||||
struct TORRENT_EXTRA_EXPORT disk_buffer_pool
|
||||
{
|
||||
disk_buffer_pool(int block_size, io_service& ios
|
||||
, std::function<void()> const& trigger_trim);
|
||||
disk_buffer_pool(disk_buffer_pool const&) = delete;
|
||||
disk_buffer_pool& operator=(disk_buffer_pool const&) = delete;
|
||||
~disk_buffer_pool();
|
||||
|
||||
#if TORRENT_USE_ASSERTS
|
||||
|
|
|
@ -92,110 +92,6 @@ namespace libtorrent
|
|||
using handle_type = int;
|
||||
#endif
|
||||
|
||||
struct file_status
|
||||
{
|
||||
std::int64_t file_size = 0;
|
||||
std::uint64_t atime = 0;
|
||||
std::uint64_t mtime = 0;
|
||||
std::uint64_t ctime = 0;
|
||||
enum {
|
||||
#if defined TORRENT_WINDOWS
|
||||
fifo = 0x1000, // named pipe (fifo)
|
||||
character_special = 0x2000, // character special
|
||||
directory = 0x4000, // directory
|
||||
regular_file = 0x8000 // regular
|
||||
#else
|
||||
fifo = 0010000, // named pipe (fifo)
|
||||
character_special = 0020000, // character special
|
||||
directory = 0040000, // directory
|
||||
block_special = 0060000, // block special
|
||||
regular_file = 0100000, // regular
|
||||
link = 0120000, // symbolic link
|
||||
socket = 0140000 // socket
|
||||
#endif
|
||||
} modes_t;
|
||||
int mode = 0;
|
||||
};
|
||||
|
||||
// internal flags for stat_file
|
||||
enum { dont_follow_links = 1 };
|
||||
TORRENT_EXTRA_EXPORT void stat_file(std::string const& f, file_status* s
|
||||
, error_code& ec, int flags = 0);
|
||||
TORRENT_EXTRA_EXPORT void rename(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void create_directories(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void create_directory(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void remove_all(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void remove(std::string const& f, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT bool exists(std::string const& f, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT bool exists(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::int64_t file_size(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT bool is_directory(std::string const& f
|
||||
, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void recursive_copy(std::string const& old_path
|
||||
, std::string const& new_path, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void copy_file(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
TORRENT_EXTRA_EXPORT void move_file(std::string const& f
|
||||
, std::string const& newf, error_code& ec);
|
||||
|
||||
// file is expected to exist, link will be created to point to it. If hard
|
||||
// links are not supported by the filesystem or OS, the file will be copied.
|
||||
TORRENT_EXTRA_EXPORT void hard_link(std::string const& file
|
||||
, std::string const& link, error_code& ec);
|
||||
|
||||
TORRENT_EXTRA_EXPORT std::string split_path(std::string const& f
|
||||
, bool only_first_part = false);
|
||||
TORRENT_EXTRA_EXPORT char const* next_path_element(char const* p);
|
||||
TORRENT_EXTRA_EXPORT std::string extension(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::string remove_extension(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT void replace_extension(std::string& f, std::string const& ext);
|
||||
TORRENT_EXTRA_EXPORT bool is_root_path(std::string const& f);
|
||||
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string parent_path(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT bool has_parent_path(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT char const* filename_cstr(char const* f);
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string filename(std::string const& f);
|
||||
TORRENT_EXTRA_EXPORT std::string combine_path(string_view lhs
|
||||
, string_view rhs);
|
||||
TORRENT_EXTRA_EXPORT void append_path(std::string& branch
|
||||
, string_view leaf);
|
||||
|
||||
// internal used by create_torrent.hpp
|
||||
TORRENT_EXTRA_EXPORT std::string complete(string_view f);
|
||||
TORRENT_EXTRA_EXPORT bool is_complete(string_view f);
|
||||
TORRENT_EXTRA_EXPORT std::string current_working_directory();
|
||||
#if TORRENT_USE_UNC_PATHS
|
||||
TORRENT_EXTRA_EXPORT std::string canonicalize_path(string_view f);
|
||||
#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
|
||||
class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "test.hpp"
|
||||
#include "setup_transfer.hpp" // for ::create_torrent
|
||||
#include "libtorrent/add_torrent_params.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <fstream>
|
||||
|
||||
namespace lt = libtorrent;
|
||||
|
|
|
@ -44,7 +44,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/random.hpp"
|
||||
#include "libtorrent/crc32c.hpp"
|
||||
#include "libtorrent/alert_types.hpp" // for dht_routing_bucket
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
#include "setup_dht.hpp"
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/settings_pack.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <fstream>
|
||||
|
||||
#include "settings.hpp"
|
||||
|
|
|
@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/session_stats.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
|
|
@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/session_stats.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/deadline_timer.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "simulator/http_server.hpp"
|
||||
#include "simulator/http_proxy.hpp"
|
||||
#include "settings.hpp"
|
||||
|
|
|
@ -74,6 +74,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
|||
error_code.cpp \
|
||||
escape_string.cpp \
|
||||
file.cpp \
|
||||
path.cpp \
|
||||
file_pool.cpp \
|
||||
file_storage.cpp \
|
||||
fingerprint.cpp \
|
||||
|
|
|
@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/announce_entry.hpp"
|
||||
#include "libtorrent/performance_counters.hpp" // for counters
|
||||
#include "libtorrent/alert_manager.hpp"
|
||||
#include "libtorrent/file.hpp" // for combine_path etc.
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
821
src/file.cpp
821
src/file.cpp
|
@ -69,6 +69,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/aux_/alloca.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/string_util.hpp"
|
||||
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
||||
#include <cstring>
|
||||
|
@ -329,832 +330,12 @@ static_assert((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
int bufs_size(span<iovec_t const> bufs)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for (auto buf : bufs)
|
||||
size += buf.iov_len;
|
||||
return int(size);
|
||||
}
|
||||
|
||||
std::string convert_from_native_path(char const* s) { return convert_from_native(s); }
|
||||
|
||||
#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)
|
||||
{
|
||||
return std::unique_ptr<T, decltype(&std::free)>(ptr, &std::free);
|
||||
}
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
time_t file_time_to_posix(FILETIME f)
|
||||
{
|
||||
const std::uint64_t posix_time_offset = 11644473600LL;
|
||||
std::uint64_t ft = (std::uint64_t(f.dwHighDateTime) << 32)
|
||||
| f.dwLowDateTime;
|
||||
|
||||
// windows filetime is specified in 100 nanoseconds resolution.
|
||||
// convert to seconds
|
||||
return time_t(ft / 10000000 - posix_time_offset);
|
||||
}
|
||||
#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
|
||||
, error_code& ec, int const flags)
|
||||
{
|
||||
ec.clear();
|
||||
native_path_string f = convert_to_native_path_string(inf);
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
||||
TORRENT_UNUSED(flags);
|
||||
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateFile_ CreateFileW
|
||||
#else
|
||||
#define CreateFile_ CreateFileA
|
||||
#endif
|
||||
|
||||
// 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
|
||||
| FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
#undef CreateFile_
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ec.assign(GetLastError(), system_category());
|
||||
TORRENT_ASSERT(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION data;
|
||||
if (!GetFileInformationByHandle(h, &data))
|
||||
{
|
||||
ec.assign(GetLastError(), system_category());
|
||||
TORRENT_ASSERT(ec);
|
||||
CloseHandle(h);
|
||||
return;
|
||||
}
|
||||
|
||||
s->file_size = (std::uint64_t(data.nFileSizeHigh) << 32) | data.nFileSizeLow;
|
||||
s->ctime = file_time_to_posix(data.ftCreationTime);
|
||||
s->atime = file_time_to_posix(data.ftLastAccessTime);
|
||||
s->mtime = file_time_to_posix(data.ftLastWriteTime);
|
||||
|
||||
s->mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? file_status::directory
|
||||
: (data.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
|
||||
? file_status::character_special : file_status::regular_file;
|
||||
CloseHandle(h);
|
||||
#else
|
||||
|
||||
// posix version
|
||||
|
||||
struct stat ret;
|
||||
int retval;
|
||||
if (flags & dont_follow_links)
|
||||
retval = ::lstat(f.c_str(), &ret);
|
||||
else
|
||||
retval = ::stat(f.c_str(), &ret);
|
||||
if (retval < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
s->file_size = ret.st_size;
|
||||
s->atime = std::uint64_t(ret.st_atime);
|
||||
s->mtime = std::uint64_t(ret.st_mtime);
|
||||
s->ctime = std::uint64_t(ret.st_ctime);
|
||||
|
||||
s->mode = (S_ISREG(ret.st_mode) ? file_status::regular_file : 0)
|
||||
| (S_ISDIR(ret.st_mode) ? file_status::directory : 0)
|
||||
| (S_ISLNK(ret.st_mode) ? file_status::link : 0)
|
||||
| (S_ISFIFO(ret.st_mode) ? file_status::fifo : 0)
|
||||
| (S_ISCHR(ret.st_mode) ? file_status::character_special : 0)
|
||||
| (S_ISBLK(ret.st_mode) ? file_status::block_special : 0)
|
||||
| (S_ISSOCK(ret.st_mode) ? file_status::socket : 0);
|
||||
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void rename(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
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
|
||||
#define RenameFunction_ _wrename
|
||||
#else
|
||||
#define RenameFunction_ ::rename
|
||||
#endif
|
||||
|
||||
if (RenameFunction_(f1.c_str(), f2.c_str()) < 0)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
}
|
||||
#undef RenameFunction_
|
||||
}
|
||||
|
||||
void create_directories(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
if (is_directory(f, ec)) return;
|
||||
if (ec != boost::system::errc::no_such_file_or_directory)
|
||||
return;
|
||||
ec.clear();
|
||||
if (is_root_path(f)) return;
|
||||
if (has_parent_path(f))
|
||||
{
|
||||
create_directories(parent_path(f), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
create_directory(f, ec);
|
||||
}
|
||||
|
||||
void create_directory(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
native_path_string n = convert_to_native_path_string(f);
|
||||
#ifdef TORRENT_WINDOWS
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateDirectory_ CreateDirectoryW
|
||||
#else
|
||||
#define CreateDirectory_ CreateDirectoryA
|
||||
#endif // TORRENT_USE_WSTRING
|
||||
|
||||
if (CreateDirectory_(n.c_str(), 0) == 0
|
||||
&& GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
ec.assign(GetLastError(), system_category());
|
||||
#undef CreateDirectory_
|
||||
#else
|
||||
int ret = ::mkdir(n.c_str(), 0777);
|
||||
if (ret < 0 && errno != EEXIST)
|
||||
ec.assign(errno, system_category());
|
||||
#endif
|
||||
}
|
||||
|
||||
void hard_link(std::string const& file, std::string const& link
|
||||
, 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
|
||||
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateHardLink_ CreateHardLinkW
|
||||
#else
|
||||
#define CreateHardLink_ CreateHardLinkA
|
||||
#endif
|
||||
BOOL ret = CreateHardLink_(n_link.c_str(), n_exist.c_str(), nullptr);
|
||||
if (ret)
|
||||
{
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
#undef CreateHardLink_
|
||||
// something failed. Does the filesystem not support hard links?
|
||||
// TODO: 3 find out what error code is reported when the filesystem
|
||||
// does not support hard links.
|
||||
DWORD const error = GetLastError();
|
||||
if (error != ERROR_NOT_SUPPORTED && error != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
// it's possible CreateHardLink will copy the file internally too,
|
||||
// if the filesystem does not support it.
|
||||
ec.assign(GetLastError(), system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// fall back to making a copy
|
||||
|
||||
#else
|
||||
// assume posix's link() function exists
|
||||
int ret = ::link(n_exist.c_str(), n_link.c_str());
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// most errors are passed through, except for the ones that indicate that
|
||||
// hard links are not supported and require a copy.
|
||||
// TODO: 2 test this on a FAT volume to see what error we get!
|
||||
if (errno != EMLINK || errno != EXDEV)
|
||||
{
|
||||
// some error happened, report up to the caller
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// fall back to making a copy
|
||||
|
||||
#endif
|
||||
|
||||
// if we get here, we should copy the file
|
||||
copy_file(file, link, ec);
|
||||
}
|
||||
|
||||
bool is_directory(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
error_code e;
|
||||
file_status s;
|
||||
stat_file(f, &s, e);
|
||||
if (!e && s.mode & file_status::directory) return true;
|
||||
ec = e;
|
||||
return false;
|
||||
}
|
||||
|
||||
void recursive_copy(std::string const& old_path, std::string const& new_path, error_code& ec)
|
||||
{
|
||||
TORRENT_ASSERT(!ec);
|
||||
if (is_directory(old_path, ec))
|
||||
{
|
||||
create_directory(new_path, ec);
|
||||
if (ec) return;
|
||||
for (directory i(old_path, ec); !i.done(); i.next(ec))
|
||||
{
|
||||
std::string f = i.file();
|
||||
if (f == ".." || f == ".") continue;
|
||||
recursive_copy(combine_path(old_path, f), combine_path(new_path, f), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
}
|
||||
else if (!ec)
|
||||
{
|
||||
copy_file(old_path, new_path, ec);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_file(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
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
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CopyFile_ CopyFileW
|
||||
#else
|
||||
#define CopyFile_ CopyFileA
|
||||
#endif
|
||||
|
||||
if (CopyFile_(f1.c_str(), f2.c_str(), false) == 0)
|
||||
ec.assign(GetLastError(), system_category());
|
||||
#undef CopyFile_
|
||||
|
||||
#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
// this only works on 10.5
|
||||
copyfile_state_t state = copyfile_state_alloc();
|
||||
if (copyfile(f1.c_str(), f2.c_str(), state, COPYFILE_ALL) < 0)
|
||||
ec.assign(errno, system_category());
|
||||
copyfile_state_free(state);
|
||||
#else
|
||||
int const infd = ::open(f1.c_str(), O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// rely on default umask to filter x and w permissions
|
||||
// for group and others
|
||||
int const permissions = S_IRUSR | S_IWUSR
|
||||
| S_IRGRP | S_IWGRP
|
||||
| S_IROTH | S_IWOTH;
|
||||
|
||||
int const outfd = ::open(f2.c_str(), O_WRONLY | O_CREAT, permissions);
|
||||
if (outfd < 0)
|
||||
{
|
||||
close(infd);
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
char buffer[4096];
|
||||
for (;;)
|
||||
{
|
||||
int const num_read = int(read(infd, buffer, sizeof(buffer)));
|
||||
if (num_read == 0) break;
|
||||
if (num_read < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
break;
|
||||
}
|
||||
int const num_written = int(write(outfd, buffer, std::size_t(num_read)));
|
||||
if (num_written < num_read)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
break;
|
||||
}
|
||||
if (num_read < int(sizeof(buffer))) break;
|
||||
}
|
||||
close(infd);
|
||||
close(outfd);
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void move_file(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
file_status s;
|
||||
stat_file(inf, &s, ec);
|
||||
if (ec) return;
|
||||
|
||||
if (has_parent_path(newf))
|
||||
{
|
||||
create_directories(parent_path(newf), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
|
||||
rename(inf, newf, ec);
|
||||
}
|
||||
|
||||
std::string split_path(std::string const& f, bool only_first_part)
|
||||
{
|
||||
if (f.empty()) return f;
|
||||
|
||||
std::string ret;
|
||||
char const* start = f.c_str();
|
||||
char const* p = start;
|
||||
while (*start != 0)
|
||||
{
|
||||
while (*p != '/'
|
||||
&& *p != '\0'
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
&& *p != '\\'
|
||||
#endif
|
||||
) ++p;
|
||||
if (p - start > 0)
|
||||
{
|
||||
ret.append(start, aux::numeric_cast<std::size_t>(p - start));
|
||||
if (only_first_part) return ret;
|
||||
ret.append(1, '\0');
|
||||
}
|
||||
if (*p != 0) ++p;
|
||||
start = p;
|
||||
}
|
||||
if (only_first_part) return ret;
|
||||
ret.append(1, '\0');
|
||||
return ret;
|
||||
}
|
||||
|
||||
char const* next_path_element(char const* p)
|
||||
{
|
||||
p += strlen(p) + 1;
|
||||
if (*p == 0) return nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string extension(std::string const& f)
|
||||
{
|
||||
for (int i = int(f.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
std::size_t const idx = std::size_t(i);
|
||||
if (f[idx] == '/') break;
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f[idx] == '\\') break;
|
||||
#endif
|
||||
if (f[idx] != '.') continue;
|
||||
return f.substr(idx);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string remove_extension(std::string const& f)
|
||||
{
|
||||
char const* slash = std::strrchr(f.c_str(), '/');
|
||||
#ifdef TORRENT_WINDOWS
|
||||
slash = (std::max)((char const*)std::strrchr(f.c_str(), '\\'), slash);
|
||||
#endif
|
||||
char const* ext = std::strrchr(f.c_str(), '.');
|
||||
// if we don't have an extension, just return f
|
||||
if (ext == nullptr || ext == &f[0] || (slash != nullptr && ext < slash)) return f;
|
||||
return f.substr(0, aux::numeric_cast<std::size_t>(ext - &f[0]));
|
||||
}
|
||||
|
||||
void replace_extension(std::string& f, std::string const& ext)
|
||||
{
|
||||
for (int i = int(f.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
std::size_t const idx = std::size_t(i);
|
||||
if (f[idx] == '/') break;
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f[idx] == '\\') break;
|
||||
#endif
|
||||
|
||||
if (f[idx] != '.') continue;
|
||||
|
||||
f.resize(idx);
|
||||
break;
|
||||
}
|
||||
f += '.';
|
||||
f += ext;
|
||||
}
|
||||
|
||||
bool is_root_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
// match \\ form
|
||||
if (f == "\\\\") return true;
|
||||
int i = 0;
|
||||
// match the xx:\ or xx:/ form
|
||||
while (f[i] && is_alpha(f[i])) ++i;
|
||||
if (i == int(f.size()-2) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/'))
|
||||
return true;
|
||||
// match network paths \\computer_name\ form
|
||||
if (f.size() > 2 && f[0] == '\\' && f[1] == '\\')
|
||||
{
|
||||
// we don't care about the last character, since it's OK for it
|
||||
// to be a slash or a back slash
|
||||
bool found = false;
|
||||
for (int j = 2; j < int(f.size()) - 1; ++j)
|
||||
{
|
||||
if (f[j] != '\\' && f[j] != '/') continue;
|
||||
// there is a directory separator in here,
|
||||
// i.e. this is not the root
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) return true;
|
||||
}
|
||||
#else
|
||||
// as well as parent_path("/") should be "/".
|
||||
if (f == "/") return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_parent_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
if (is_root_path(f)) return false;
|
||||
|
||||
int len = int(f.size()) - 1;
|
||||
// if the last character is / or \ ignore it
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\') --len;
|
||||
while (len >= 0)
|
||||
{
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\')
|
||||
break;
|
||||
--len;
|
||||
}
|
||||
|
||||
return len >= 0;
|
||||
}
|
||||
|
||||
std::string parent_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return f;
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f == "\\\\") return "";
|
||||
#endif
|
||||
if (f == "/") return "";
|
||||
|
||||
int len = int(f.size());
|
||||
// if the last character is / or \ ignore it
|
||||
if (f[std::size_t(len - 1)] == '/' || f[std::size_t(len - 1)] == '\\') --len;
|
||||
while (len > 0)
|
||||
{
|
||||
--len;
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\')
|
||||
break;
|
||||
}
|
||||
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\') ++len;
|
||||
return std::string(f.c_str(), std::size_t(len));
|
||||
}
|
||||
|
||||
char const* filename_cstr(char const* f)
|
||||
{
|
||||
if (f == nullptr) return f;
|
||||
|
||||
char const* sep = std::strrchr(f, '/');
|
||||
#ifdef TORRENT_WINDOWS
|
||||
char const* altsep = std::strrchr(f, '\\');
|
||||
if (sep == 0 || altsep > sep) sep = altsep;
|
||||
#endif
|
||||
if (sep == nullptr) return f;
|
||||
return sep+1;
|
||||
}
|
||||
|
||||
std::string filename(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return "";
|
||||
char const* first = f.c_str();
|
||||
char const* sep = std::strrchr(first, '/');
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
char const* altsep = std::strrchr(first, '\\');
|
||||
if (sep == 0 || altsep > sep) sep = altsep;
|
||||
#endif
|
||||
if (sep == nullptr) return f;
|
||||
|
||||
if (sep - first == int(f.size()) - 1)
|
||||
{
|
||||
// if the last character is a / (or \)
|
||||
// ignore it
|
||||
int len = 0;
|
||||
while (sep > first)
|
||||
{
|
||||
--sep;
|
||||
if (*sep == '/'
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
|| *sep == '\\'
|
||||
#endif
|
||||
)
|
||||
return std::string(sep + 1, std::size_t(len));
|
||||
++len;
|
||||
}
|
||||
return std::string(first, std::size_t(len));
|
||||
|
||||
}
|
||||
return std::string(sep + 1);
|
||||
}
|
||||
|
||||
void append_path(std::string& branch, string_view leaf)
|
||||
{
|
||||
TORRENT_ASSERT(!is_complete(leaf));
|
||||
if (branch.empty() || branch == ".")
|
||||
{
|
||||
branch.assign(leaf.data(), leaf.size());
|
||||
return;
|
||||
}
|
||||
if (leaf.size() == 0) return;
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
#define TORRENT_SEPARATOR_CHAR '\\'
|
||||
bool const need_sep = branch[branch.size()-1] != '\\'
|
||||
&& branch[branch.size()-1] != '/';
|
||||
#else
|
||||
#define TORRENT_SEPARATOR_CHAR '/'
|
||||
bool const need_sep = branch[branch.size()-1] != '/';
|
||||
#endif
|
||||
|
||||
if (need_sep) branch += TORRENT_SEPARATOR_CHAR;
|
||||
branch.append(leaf.data(), leaf.size());
|
||||
}
|
||||
|
||||
std::string combine_path(string_view lhs, string_view rhs)
|
||||
{
|
||||
TORRENT_ASSERT(!is_complete(rhs));
|
||||
if (lhs.empty() || lhs == ".") return rhs.to_string();
|
||||
if (rhs.empty() || rhs == ".") return lhs.to_string();
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
#define TORRENT_SEPARATOR "\\"
|
||||
bool const need_sep = lhs[lhs.size() - 1] != '\\' && lhs[lhs.size() - 1] != '/';
|
||||
#else
|
||||
#define TORRENT_SEPARATOR "/"
|
||||
bool const need_sep = lhs[lhs.size() - 1] != '/';
|
||||
#endif
|
||||
std::string ret;
|
||||
std::size_t target_size = lhs.size() + rhs.size() + 2;
|
||||
ret.resize(target_size);
|
||||
target_size = aux::numeric_cast<std::size_t>(std::snprintf(&ret[0], target_size, "%*s%s%*s"
|
||||
, int(lhs.size()), lhs.data()
|
||||
, (need_sep ? TORRENT_SEPARATOR : "")
|
||||
, int(rhs.size()), rhs.data()));
|
||||
ret.resize(target_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string current_working_directory()
|
||||
{
|
||||
#if defined TORRENT_WINDOWS
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define GetCurrentDir_ ::_wgetcwd
|
||||
#else
|
||||
#define GetCurrentDir_ ::_getcwd
|
||||
#endif // TORRENT_USE_WSTRING
|
||||
#else
|
||||
#define GetCurrentDir_ ::getcwd
|
||||
#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
|
||||
std::string canonicalize_path(string_view f)
|
||||
{
|
||||
std::string ret;
|
||||
ret.resize(f.size());
|
||||
char* write_cur = &ret[0];
|
||||
char* last_write_sep = write_cur;
|
||||
|
||||
char const* read_cur = f.data();
|
||||
char const* last_read_sep = read_cur;
|
||||
|
||||
// the last_*_sep pointers point to one past
|
||||
// the last path separator encountered and is
|
||||
// initialized to the first character in the path
|
||||
for (int i = 0; i < int(f.size()); ++i)
|
||||
{
|
||||
if (*read_cur != '\\')
|
||||
{
|
||||
*write_cur++ = *read_cur++;
|
||||
continue;
|
||||
}
|
||||
int element_len = int(read_cur - last_read_sep);
|
||||
if (element_len == 1 && std::memcmp(last_read_sep, ".", 1) == 0)
|
||||
{
|
||||
--write_cur;
|
||||
++read_cur;
|
||||
last_read_sep = read_cur;
|
||||
continue;
|
||||
}
|
||||
if (element_len == 2 && std::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
|
||||
|
||||
std::int64_t file_size(std::string const& f)
|
||||
{
|
||||
error_code ec;
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec) return 0;
|
||||
return s.file_size;
|
||||
}
|
||||
|
||||
bool exists(std::string const& f, error_code& ec)
|
||||
{
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec)
|
||||
{
|
||||
if (ec == boost::system::errc::no_such_file_or_directory)
|
||||
ec.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exists(std::string const& f)
|
||||
{
|
||||
error_code ec;
|
||||
return exists(f, ec);
|
||||
}
|
||||
|
||||
void remove(std::string const& inf, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
native_path_string f = convert_to_native_path_string(inf);
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// windows does not allow trailing / or \ in
|
||||
// the path when removing files
|
||||
while (!f.empty() && (
|
||||
f.back() == '/' ||
|
||||
f.back() == '\\'
|
||||
)) f.pop_back();
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define DeleteFile_ DeleteFileW
|
||||
#define RemoveDirectory_ RemoveDirectoryW
|
||||
#else
|
||||
#define DeleteFile_ DeleteFileA
|
||||
#define RemoveDirectory_ RemoveDirectoryA
|
||||
#endif
|
||||
if (DeleteFile_(f.c_str()) == 0)
|
||||
{
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
if (RemoveDirectory_(f.c_str()) != 0)
|
||||
return;
|
||||
}
|
||||
ec.assign(GetLastError(), system_category());
|
||||
return;
|
||||
}
|
||||
#undef DeleteFile_
|
||||
#undef RemoveDirectory_
|
||||
#else // TORRENT_WINDOWS
|
||||
if (::remove(f.c_str()) < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void remove_all(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec) return;
|
||||
|
||||
if (s.mode & file_status::directory)
|
||||
{
|
||||
for (directory i(f, ec); !i.done(); i.next(ec))
|
||||
{
|
||||
if (ec) return;
|
||||
std::string p = i.file();
|
||||
if (p == "." || p == "..") continue;
|
||||
remove_all(combine_path(f, p), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
}
|
||||
remove(f, ec);
|
||||
}
|
||||
|
||||
std::string complete(string_view f)
|
||||
{
|
||||
if (is_complete(f)) return f.to_string();
|
||||
if (f == ".") return current_working_directory();
|
||||
return combine_path(current_working_directory(), f);
|
||||
}
|
||||
|
||||
bool is_complete(string_view f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
int i = 0;
|
||||
// match the xx:\ or xx:/ form
|
||||
while (f[i] && is_alpha(f[i])) ++i;
|
||||
if (i < int(f.size()-1) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/'))
|
||||
return true;
|
||||
|
||||
// match the \\ form
|
||||
if (int(f.size()) >= 2 && f[0] == '\\' && f[1] == '\\')
|
||||
return true;
|
||||
return false;
|
||||
#else
|
||||
if (f[0] == '/') return true;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
directory::directory(std::string const& path, error_code& ec)
|
||||
: m_done(false)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/units.hpp"
|
||||
#include "libtorrent/disk_interface.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#ifdef TORRENT_WINDOWS
|
||||
#include "libtorrent/aux_/win_util.hpp"
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/string_util.hpp" // for allocate_string_copy
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/utf8.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/aux_/numeric_cast.hpp"
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
|
|
@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/aux_/vector.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
|
@ -0,0 +1,956 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003-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.
|
||||
|
||||
*/
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wunused-macros"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif
|
||||
|
||||
// these defines are just in case the system we're on needs them for 64 bit file
|
||||
// support
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _LARGE_FILES 1
|
||||
|
||||
// on mingw this is necessary to enable 64-bit time_t, specifically used for
|
||||
// the stat struct. Without this, modification times returned by stat may be
|
||||
// incorrect and consistently fail resume data
|
||||
#ifndef __MINGW_USE_VC2005_COMPAT
|
||||
# define __MINGW_USE_VC2005_COMPAT
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/aux_/alloca.hpp"
|
||||
#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/assert.hpp"
|
||||
#include "libtorrent/aux_/throw.hpp"
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <climits> // for IOV_MAX
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// windows part
|
||||
|
||||
#include "libtorrent/utf8.hpp"
|
||||
#include "libtorrent/aux_/win_util.hpp"
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#ifndef TORRENT_MINGW
|
||||
#include <direct.h> // for _getcwd, _mkdir
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
// posix part
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <cerrno>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef TORRENT_LINUX
|
||||
// linux specifics
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
// mac specifics
|
||||
|
||||
#include <copyfile.h>
|
||||
|
||||
#endif
|
||||
|
||||
#endif // posix part
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
int bufs_size(span<iovec_t const> bufs)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for (auto buf : bufs)
|
||||
size += buf.iov_len;
|
||||
return int(size);
|
||||
}
|
||||
|
||||
std::string convert_from_native_path(char const* s) { return convert_from_native(s); }
|
||||
|
||||
#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)
|
||||
{
|
||||
return std::unique_ptr<T, decltype(&std::free)>(ptr, &std::free);
|
||||
}
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
time_t file_time_to_posix(FILETIME f)
|
||||
{
|
||||
const std::uint64_t posix_time_offset = 11644473600LL;
|
||||
std::uint64_t ft = (std::uint64_t(f.dwHighDateTime) << 32)
|
||||
| f.dwLowDateTime;
|
||||
|
||||
// windows filetime is specified in 100 nanoseconds resolution.
|
||||
// convert to seconds
|
||||
return time_t(ft / 10000000 - posix_time_offset);
|
||||
}
|
||||
#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
|
||||
, error_code& ec, int const flags)
|
||||
{
|
||||
ec.clear();
|
||||
native_path_string f = convert_to_native_path_string(inf);
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
||||
TORRENT_UNUSED(flags);
|
||||
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateFile_ CreateFileW
|
||||
#else
|
||||
#define CreateFile_ CreateFileA
|
||||
#endif
|
||||
|
||||
// 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
|
||||
| FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
#undef CreateFile_
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ec.assign(GetLastError(), system_category());
|
||||
TORRENT_ASSERT(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION data;
|
||||
if (!GetFileInformationByHandle(h, &data))
|
||||
{
|
||||
ec.assign(GetLastError(), system_category());
|
||||
TORRENT_ASSERT(ec);
|
||||
CloseHandle(h);
|
||||
return;
|
||||
}
|
||||
|
||||
s->file_size = (std::uint64_t(data.nFileSizeHigh) << 32) | data.nFileSizeLow;
|
||||
s->ctime = file_time_to_posix(data.ftCreationTime);
|
||||
s->atime = file_time_to_posix(data.ftLastAccessTime);
|
||||
s->mtime = file_time_to_posix(data.ftLastWriteTime);
|
||||
|
||||
s->mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? file_status::directory
|
||||
: (data.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
|
||||
? file_status::character_special : file_status::regular_file;
|
||||
CloseHandle(h);
|
||||
#else
|
||||
|
||||
// posix version
|
||||
|
||||
struct stat ret;
|
||||
int retval;
|
||||
if (flags & dont_follow_links)
|
||||
retval = ::lstat(f.c_str(), &ret);
|
||||
else
|
||||
retval = ::stat(f.c_str(), &ret);
|
||||
if (retval < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
s->file_size = ret.st_size;
|
||||
s->atime = std::uint64_t(ret.st_atime);
|
||||
s->mtime = std::uint64_t(ret.st_mtime);
|
||||
s->ctime = std::uint64_t(ret.st_ctime);
|
||||
|
||||
s->mode = (S_ISREG(ret.st_mode) ? file_status::regular_file : 0)
|
||||
| (S_ISDIR(ret.st_mode) ? file_status::directory : 0)
|
||||
| (S_ISLNK(ret.st_mode) ? file_status::link : 0)
|
||||
| (S_ISFIFO(ret.st_mode) ? file_status::fifo : 0)
|
||||
| (S_ISCHR(ret.st_mode) ? file_status::character_special : 0)
|
||||
| (S_ISBLK(ret.st_mode) ? file_status::block_special : 0)
|
||||
| (S_ISSOCK(ret.st_mode) ? file_status::socket : 0);
|
||||
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void rename(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
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
|
||||
#define RenameFunction_ _wrename
|
||||
#else
|
||||
#define RenameFunction_ ::rename
|
||||
#endif
|
||||
|
||||
if (RenameFunction_(f1.c_str(), f2.c_str()) < 0)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
}
|
||||
#undef RenameFunction_
|
||||
}
|
||||
|
||||
void create_directories(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
if (is_directory(f, ec)) return;
|
||||
if (ec != boost::system::errc::no_such_file_or_directory)
|
||||
return;
|
||||
ec.clear();
|
||||
if (is_root_path(f)) return;
|
||||
if (has_parent_path(f))
|
||||
{
|
||||
create_directories(parent_path(f), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
create_directory(f, ec);
|
||||
}
|
||||
|
||||
void create_directory(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
native_path_string n = convert_to_native_path_string(f);
|
||||
#ifdef TORRENT_WINDOWS
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateDirectory_ CreateDirectoryW
|
||||
#else
|
||||
#define CreateDirectory_ CreateDirectoryA
|
||||
#endif // TORRENT_USE_WSTRING
|
||||
|
||||
if (CreateDirectory_(n.c_str(), 0) == 0
|
||||
&& GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
ec.assign(GetLastError(), system_category());
|
||||
#undef CreateDirectory_
|
||||
#else
|
||||
int ret = ::mkdir(n.c_str(), 0777);
|
||||
if (ret < 0 && errno != EEXIST)
|
||||
ec.assign(errno, system_category());
|
||||
#endif
|
||||
}
|
||||
|
||||
void hard_link(std::string const& file, std::string const& link
|
||||
, 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
|
||||
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CreateHardLink_ CreateHardLinkW
|
||||
#else
|
||||
#define CreateHardLink_ CreateHardLinkA
|
||||
#endif
|
||||
BOOL ret = CreateHardLink_(n_link.c_str(), n_exist.c_str(), nullptr);
|
||||
if (ret)
|
||||
{
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
#undef CreateHardLink_
|
||||
// something failed. Does the filesystem not support hard links?
|
||||
// TODO: 3 find out what error code is reported when the filesystem
|
||||
// does not support hard links.
|
||||
DWORD const error = GetLastError();
|
||||
if (error != ERROR_NOT_SUPPORTED && error != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
// it's possible CreateHardLink will copy the file internally too,
|
||||
// if the filesystem does not support it.
|
||||
ec.assign(GetLastError(), system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// fall back to making a copy
|
||||
|
||||
#else
|
||||
// assume posix's link() function exists
|
||||
int ret = ::link(n_exist.c_str(), n_link.c_str());
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// most errors are passed through, except for the ones that indicate that
|
||||
// hard links are not supported and require a copy.
|
||||
// TODO: 2 test this on a FAT volume to see what error we get!
|
||||
if (errno != EMLINK || errno != EXDEV)
|
||||
{
|
||||
// some error happened, report up to the caller
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// fall back to making a copy
|
||||
|
||||
#endif
|
||||
|
||||
// if we get here, we should copy the file
|
||||
copy_file(file, link, ec);
|
||||
}
|
||||
|
||||
bool is_directory(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
error_code e;
|
||||
file_status s;
|
||||
stat_file(f, &s, e);
|
||||
if (!e && s.mode & file_status::directory) return true;
|
||||
ec = e;
|
||||
return false;
|
||||
}
|
||||
|
||||
void recursive_copy(std::string const& old_path, std::string const& new_path, error_code& ec)
|
||||
{
|
||||
TORRENT_ASSERT(!ec);
|
||||
if (is_directory(old_path, ec))
|
||||
{
|
||||
create_directory(new_path, ec);
|
||||
if (ec) return;
|
||||
for (directory i(old_path, ec); !i.done(); i.next(ec))
|
||||
{
|
||||
std::string f = i.file();
|
||||
if (f == ".." || f == ".") continue;
|
||||
recursive_copy(combine_path(old_path, f), combine_path(new_path, f), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
}
|
||||
else if (!ec)
|
||||
{
|
||||
copy_file(old_path, new_path, ec);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_file(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
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
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define CopyFile_ CopyFileW
|
||||
#else
|
||||
#define CopyFile_ CopyFileA
|
||||
#endif
|
||||
|
||||
if (CopyFile_(f1.c_str(), f2.c_str(), false) == 0)
|
||||
ec.assign(GetLastError(), system_category());
|
||||
#undef CopyFile_
|
||||
|
||||
#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
// this only works on 10.5
|
||||
copyfile_state_t state = copyfile_state_alloc();
|
||||
if (copyfile(f1.c_str(), f2.c_str(), state, COPYFILE_ALL) < 0)
|
||||
ec.assign(errno, system_category());
|
||||
copyfile_state_free(state);
|
||||
#else
|
||||
int const infd = ::open(f1.c_str(), O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
|
||||
// rely on default umask to filter x and w permissions
|
||||
// for group and others
|
||||
int const permissions = S_IRUSR | S_IWUSR
|
||||
| S_IRGRP | S_IWGRP
|
||||
| S_IROTH | S_IWOTH;
|
||||
|
||||
int const outfd = ::open(f2.c_str(), O_WRONLY | O_CREAT, permissions);
|
||||
if (outfd < 0)
|
||||
{
|
||||
close(infd);
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
char buffer[4096];
|
||||
for (;;)
|
||||
{
|
||||
int const num_read = int(read(infd, buffer, sizeof(buffer)));
|
||||
if (num_read == 0) break;
|
||||
if (num_read < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
break;
|
||||
}
|
||||
int const num_written = int(write(outfd, buffer, std::size_t(num_read)));
|
||||
if (num_written < num_read)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
break;
|
||||
}
|
||||
if (num_read < int(sizeof(buffer))) break;
|
||||
}
|
||||
close(infd);
|
||||
close(outfd);
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void move_file(std::string const& inf, std::string const& newf, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
file_status s;
|
||||
stat_file(inf, &s, ec);
|
||||
if (ec) return;
|
||||
|
||||
if (has_parent_path(newf))
|
||||
{
|
||||
create_directories(parent_path(newf), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
|
||||
rename(inf, newf, ec);
|
||||
}
|
||||
|
||||
std::string split_path(std::string const& f, bool only_first_part)
|
||||
{
|
||||
if (f.empty()) return f;
|
||||
|
||||
std::string ret;
|
||||
char const* start = f.c_str();
|
||||
char const* p = start;
|
||||
while (*start != 0)
|
||||
{
|
||||
while (*p != '/'
|
||||
&& *p != '\0'
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
&& *p != '\\'
|
||||
#endif
|
||||
) ++p;
|
||||
if (p - start > 0)
|
||||
{
|
||||
ret.append(start, aux::numeric_cast<std::size_t>(p - start));
|
||||
if (only_first_part) return ret;
|
||||
ret.append(1, '\0');
|
||||
}
|
||||
if (*p != 0) ++p;
|
||||
start = p;
|
||||
}
|
||||
if (only_first_part) return ret;
|
||||
ret.append(1, '\0');
|
||||
return ret;
|
||||
}
|
||||
|
||||
char const* next_path_element(char const* p)
|
||||
{
|
||||
p += strlen(p) + 1;
|
||||
if (*p == 0) return nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string extension(std::string const& f)
|
||||
{
|
||||
for (int i = int(f.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
std::size_t const idx = std::size_t(i);
|
||||
if (f[idx] == '/') break;
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f[idx] == '\\') break;
|
||||
#endif
|
||||
if (f[idx] != '.') continue;
|
||||
return f.substr(idx);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string remove_extension(std::string const& f)
|
||||
{
|
||||
char const* slash = std::strrchr(f.c_str(), '/');
|
||||
#ifdef TORRENT_WINDOWS
|
||||
slash = (std::max)((char const*)std::strrchr(f.c_str(), '\\'), slash);
|
||||
#endif
|
||||
char const* ext = std::strrchr(f.c_str(), '.');
|
||||
// if we don't have an extension, just return f
|
||||
if (ext == nullptr || ext == &f[0] || (slash != nullptr && ext < slash)) return f;
|
||||
return f.substr(0, aux::numeric_cast<std::size_t>(ext - &f[0]));
|
||||
}
|
||||
|
||||
void replace_extension(std::string& f, std::string const& ext)
|
||||
{
|
||||
for (int i = int(f.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
std::size_t const idx = std::size_t(i);
|
||||
if (f[idx] == '/') break;
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f[idx] == '\\') break;
|
||||
#endif
|
||||
|
||||
if (f[idx] != '.') continue;
|
||||
|
||||
f.resize(idx);
|
||||
break;
|
||||
}
|
||||
f += '.';
|
||||
f += ext;
|
||||
}
|
||||
|
||||
bool is_root_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
// match \\ form
|
||||
if (f == "\\\\") return true;
|
||||
int i = 0;
|
||||
// match the xx:\ or xx:/ form
|
||||
while (f[i] && is_alpha(f[i])) ++i;
|
||||
if (i == int(f.size()-2) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/'))
|
||||
return true;
|
||||
// match network paths \\computer_name\ form
|
||||
if (f.size() > 2 && f[0] == '\\' && f[1] == '\\')
|
||||
{
|
||||
// we don't care about the last character, since it's OK for it
|
||||
// to be a slash or a back slash
|
||||
bool found = false;
|
||||
for (int j = 2; j < int(f.size()) - 1; ++j)
|
||||
{
|
||||
if (f[j] != '\\' && f[j] != '/') continue;
|
||||
// there is a directory separator in here,
|
||||
// i.e. this is not the root
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) return true;
|
||||
}
|
||||
#else
|
||||
// as well as parent_path("/") should be "/".
|
||||
if (f == "/") return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_parent_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
if (is_root_path(f)) return false;
|
||||
|
||||
int len = int(f.size()) - 1;
|
||||
// if the last character is / or \ ignore it
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\') --len;
|
||||
while (len >= 0)
|
||||
{
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\')
|
||||
break;
|
||||
--len;
|
||||
}
|
||||
|
||||
return len >= 0;
|
||||
}
|
||||
|
||||
std::string parent_path(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return f;
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
if (f == "\\\\") return "";
|
||||
#endif
|
||||
if (f == "/") return "";
|
||||
|
||||
int len = int(f.size());
|
||||
// if the last character is / or \ ignore it
|
||||
if (f[std::size_t(len - 1)] == '/' || f[std::size_t(len - 1)] == '\\') --len;
|
||||
while (len > 0)
|
||||
{
|
||||
--len;
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\')
|
||||
break;
|
||||
}
|
||||
|
||||
if (f[std::size_t(len)] == '/' || f[std::size_t(len)] == '\\') ++len;
|
||||
return std::string(f.c_str(), std::size_t(len));
|
||||
}
|
||||
|
||||
char const* filename_cstr(char const* f)
|
||||
{
|
||||
if (f == nullptr) return f;
|
||||
|
||||
char const* sep = std::strrchr(f, '/');
|
||||
#ifdef TORRENT_WINDOWS
|
||||
char const* altsep = std::strrchr(f, '\\');
|
||||
if (sep == 0 || altsep > sep) sep = altsep;
|
||||
#endif
|
||||
if (sep == nullptr) return f;
|
||||
return sep+1;
|
||||
}
|
||||
|
||||
std::string filename(std::string const& f)
|
||||
{
|
||||
if (f.empty()) return "";
|
||||
char const* first = f.c_str();
|
||||
char const* sep = std::strrchr(first, '/');
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
char const* altsep = std::strrchr(first, '\\');
|
||||
if (sep == 0 || altsep > sep) sep = altsep;
|
||||
#endif
|
||||
if (sep == nullptr) return f;
|
||||
|
||||
if (sep - first == int(f.size()) - 1)
|
||||
{
|
||||
// if the last character is a / (or \)
|
||||
// ignore it
|
||||
int len = 0;
|
||||
while (sep > first)
|
||||
{
|
||||
--sep;
|
||||
if (*sep == '/'
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
|| *sep == '\\'
|
||||
#endif
|
||||
)
|
||||
return std::string(sep + 1, std::size_t(len));
|
||||
++len;
|
||||
}
|
||||
return std::string(first, std::size_t(len));
|
||||
|
||||
}
|
||||
return std::string(sep + 1);
|
||||
}
|
||||
|
||||
void append_path(std::string& branch, string_view leaf)
|
||||
{
|
||||
TORRENT_ASSERT(!is_complete(leaf));
|
||||
if (branch.empty() || branch == ".")
|
||||
{
|
||||
branch.assign(leaf.data(), leaf.size());
|
||||
return;
|
||||
}
|
||||
if (leaf.size() == 0) return;
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
#define TORRENT_SEPARATOR_CHAR '\\'
|
||||
bool const need_sep = branch[branch.size()-1] != '\\'
|
||||
&& branch[branch.size()-1] != '/';
|
||||
#else
|
||||
#define TORRENT_SEPARATOR_CHAR '/'
|
||||
bool const need_sep = branch[branch.size()-1] != '/';
|
||||
#endif
|
||||
|
||||
if (need_sep) branch += TORRENT_SEPARATOR_CHAR;
|
||||
branch.append(leaf.data(), leaf.size());
|
||||
}
|
||||
|
||||
std::string combine_path(string_view lhs, string_view rhs)
|
||||
{
|
||||
TORRENT_ASSERT(!is_complete(rhs));
|
||||
if (lhs.empty() || lhs == ".") return rhs.to_string();
|
||||
if (rhs.empty() || rhs == ".") return lhs.to_string();
|
||||
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
#define TORRENT_SEPARATOR "\\"
|
||||
bool const need_sep = lhs[lhs.size() - 1] != '\\' && lhs[lhs.size() - 1] != '/';
|
||||
#else
|
||||
#define TORRENT_SEPARATOR "/"
|
||||
bool const need_sep = lhs[lhs.size() - 1] != '/';
|
||||
#endif
|
||||
std::string ret;
|
||||
std::size_t target_size = lhs.size() + rhs.size() + 2;
|
||||
ret.resize(target_size);
|
||||
target_size = aux::numeric_cast<std::size_t>(std::snprintf(&ret[0], target_size, "%*s%s%*s"
|
||||
, int(lhs.size()), lhs.data()
|
||||
, (need_sep ? TORRENT_SEPARATOR : "")
|
||||
, int(rhs.size()), rhs.data()));
|
||||
ret.resize(target_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string current_working_directory()
|
||||
{
|
||||
#if defined TORRENT_WINDOWS
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define GetCurrentDir_ ::_wgetcwd
|
||||
#else
|
||||
#define GetCurrentDir_ ::_getcwd
|
||||
#endif // TORRENT_USE_WSTRING
|
||||
#else
|
||||
#define GetCurrentDir_ ::getcwd
|
||||
#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
|
||||
std::string canonicalize_path(string_view f)
|
||||
{
|
||||
std::string ret;
|
||||
ret.resize(f.size());
|
||||
char* write_cur = &ret[0];
|
||||
char* last_write_sep = write_cur;
|
||||
|
||||
char const* read_cur = f.data();
|
||||
char const* last_read_sep = read_cur;
|
||||
|
||||
// the last_*_sep pointers point to one past
|
||||
// the last path separator encountered and is
|
||||
// initialized to the first character in the path
|
||||
for (int i = 0; i < int(f.size()); ++i)
|
||||
{
|
||||
if (*read_cur != '\\')
|
||||
{
|
||||
*write_cur++ = *read_cur++;
|
||||
continue;
|
||||
}
|
||||
int element_len = int(read_cur - last_read_sep);
|
||||
if (element_len == 1 && std::memcmp(last_read_sep, ".", 1) == 0)
|
||||
{
|
||||
--write_cur;
|
||||
++read_cur;
|
||||
last_read_sep = read_cur;
|
||||
continue;
|
||||
}
|
||||
if (element_len == 2 && std::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
|
||||
|
||||
std::int64_t file_size(std::string const& f)
|
||||
{
|
||||
error_code ec;
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec) return 0;
|
||||
return s.file_size;
|
||||
}
|
||||
|
||||
bool exists(std::string const& f, error_code& ec)
|
||||
{
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec)
|
||||
{
|
||||
if (ec == boost::system::errc::no_such_file_or_directory)
|
||||
ec.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exists(std::string const& f)
|
||||
{
|
||||
error_code ec;
|
||||
return exists(f, ec);
|
||||
}
|
||||
|
||||
void remove(std::string const& inf, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
native_path_string f = convert_to_native_path_string(inf);
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// windows does not allow trailing / or \ in
|
||||
// the path when removing files
|
||||
while (!f.empty() && (
|
||||
f.back() == '/' ||
|
||||
f.back() == '\\'
|
||||
)) f.pop_back();
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define DeleteFile_ DeleteFileW
|
||||
#define RemoveDirectory_ RemoveDirectoryW
|
||||
#else
|
||||
#define DeleteFile_ DeleteFileA
|
||||
#define RemoveDirectory_ RemoveDirectoryA
|
||||
#endif
|
||||
if (DeleteFile_(f.c_str()) == 0)
|
||||
{
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
if (RemoveDirectory_(f.c_str()) != 0)
|
||||
return;
|
||||
}
|
||||
ec.assign(GetLastError(), system_category());
|
||||
return;
|
||||
}
|
||||
#undef DeleteFile_
|
||||
#undef RemoveDirectory_
|
||||
#else // TORRENT_WINDOWS
|
||||
if (::remove(f.c_str()) < 0)
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
return;
|
||||
}
|
||||
#endif // TORRENT_WINDOWS
|
||||
}
|
||||
|
||||
void remove_all(std::string const& f, error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
file_status s;
|
||||
stat_file(f, &s, ec);
|
||||
if (ec) return;
|
||||
|
||||
if (s.mode & file_status::directory)
|
||||
{
|
||||
for (directory i(f, ec); !i.done(); i.next(ec))
|
||||
{
|
||||
if (ec) return;
|
||||
std::string p = i.file();
|
||||
if (p == "." || p == "..") continue;
|
||||
remove_all(combine_path(f, p), ec);
|
||||
if (ec) return;
|
||||
}
|
||||
}
|
||||
remove(f, ec);
|
||||
}
|
||||
|
||||
std::string complete(string_view f)
|
||||
{
|
||||
if (is_complete(f)) return f.to_string();
|
||||
if (f == ".") return current_working_directory();
|
||||
return combine_path(current_working_directory(), f);
|
||||
}
|
||||
|
||||
bool is_complete(string_view f)
|
||||
{
|
||||
if (f.empty()) return false;
|
||||
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
int i = 0;
|
||||
// match the xx:\ or xx:/ form
|
||||
while (f[i] && is_alpha(f[i])) ++i;
|
||||
if (i < int(f.size()-1) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/'))
|
||||
return true;
|
||||
|
||||
// match the \\ form
|
||||
if (int(f.size()) >= 2 && f[0] == '\\' && f[1] == '\\')
|
||||
return true;
|
||||
return false;
|
||||
#else
|
||||
if (f[0] == '/') return true;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/aux_/session_interface.hpp"
|
||||
#include "libtorrent/peer_list.hpp"
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/aux_/session_call.hpp"
|
||||
#include "libtorrent/aux_/throw.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/lazy_entry.hpp"
|
||||
#include "libtorrent/peer_class.hpp"
|
||||
|
|
|
@ -59,7 +59,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/fingerprint.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/bt_peer_connection.hpp"
|
||||
#include "libtorrent/peer_connection_handle.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/stat_cache.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/storage_utils.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/aux_/alloca.hpp"
|
||||
#include "libtorrent/file.hpp" // for count_bufs
|
||||
#include "libtorrent/aux_/path.hpp" // for count_bufs
|
||||
#include "libtorrent/part_file.hpp"
|
||||
#include "libtorrent/session.hpp" // for session::delete_files
|
||||
#include "libtorrent/stat_cache.hpp"
|
||||
|
|
|
@ -97,6 +97,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// TODO: factor out cache_status to its own header
|
||||
#include "libtorrent/disk_io_thread.hpp" // for cache_status
|
||||
#include "libtorrent/aux_/numeric_cast.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
#include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
|
||||
|
|
|
@ -37,7 +37,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/utf8.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/random.hpp"
|
||||
|
|
|
@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/system/system_error.hpp>
|
||||
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/random.hpp"
|
||||
#include "libtorrent/aux_/escape_string.hpp"
|
||||
#include <csignal>
|
||||
|
|
|
@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6()
|
||||
#include "libtorrent/hex.hpp" // to_hex
|
||||
#include "libtorrent/aux_/vector.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include "test.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/random.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/torrent_status.hpp"
|
||||
#include "libtorrent/hex.hpp" // to_hex
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
static const int file_sizes[] =
|
||||
{ 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
|
||||
|
|
|
@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
|
|
@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/string_util.hpp" // for split_string
|
||||
#include "libtorrent/string_view.hpp"
|
||||
#include "test.hpp"
|
||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "setup_transfer.hpp"
|
||||
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
|
|
|
@ -30,11 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "test.hpp"
|
||||
#include "libtorrent/gzip.hpp"
|
||||
#include "setup_transfer.hpp" // for load_file
|
||||
#include "libtorrent/file.hpp" // for combine_path
|
||||
#include "libtorrent/aux_/path.hpp" // for combine_path
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/socket_io.hpp" // print_endpoint
|
||||
#include "libtorrent/http_connection.hpp"
|
||||
#include "libtorrent/resolver.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/session_settings.hpp"
|
||||
#include "libtorrent/torrent_status.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <tuple>
|
||||
|
||||
#include "test.hpp"
|
||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <cstring>
|
||||
#include "test.hpp"
|
||||
#include "libtorrent/part_file.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/peer_class.hpp"
|
||||
#include "libtorrent/peer_class_set.hpp"
|
||||
#include "libtorrent/peer_class_type_filter.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/extensions/ut_pex.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/torrent_status.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <tuple>
|
||||
|
||||
#include "setup_transfer.hpp"
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/read_resume_data.hpp"
|
||||
#include "libtorrent/write_resume_data.hpp"
|
||||
|
|
|
@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/random.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/hex.hpp" // to_hex
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
enum flags_t
|
||||
{
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "setup_transfer.hpp"
|
||||
#include "test.hpp"
|
||||
#include "settings.hpp"
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/resolve_links.hpp"
|
||||
#include "libtorrent/file.hpp" // for combine_path
|
||||
#include "libtorrent/aux_/path.hpp" // for combine_path
|
||||
#include "libtorrent/hex.hpp" // to_hex
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/session_status.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/hex.hpp" // for to_hex
|
||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/read_resume_data.hpp"
|
||||
#include "libtorrent/write_resume_data.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
|
|
@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/peer_info.hpp"
|
||||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/file.hpp" // for combine_path, current_working_directory
|
||||
#include "libtorrent/aux_/path.hpp" // for combine_path, current_working_directory
|
||||
#include "libtorrent/magnet_uri.hpp"
|
||||
#include "settings.hpp"
|
||||
#include <tuple>
|
||||
|
|
|
@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "test.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/announce_entry.hpp"
|
||||
|
|
|
@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/announce_entry.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
|
||||
#include "test.hpp"
|
||||
|
|
|
@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/socket_io.hpp" // print_endpoint
|
||||
#include "test.hpp"
|
||||
#include "setup_transfer.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/utf8.hpp"
|
||||
#include "libtorrent/ConvertUTF.h"
|
||||
#include "setup_transfer.hpp" // for load_file
|
||||
#include "libtorrent/file.hpp" // for combine_path
|
||||
#include "libtorrent/aux_/path.hpp" // for combine_path
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/utp_stream.hpp"
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/aux_/path.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
|
|
Loading…
Reference in New Issue