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
|
escape_string
|
||||||
string_util
|
string_util
|
||||||
file
|
file
|
||||||
|
path
|
||||||
fingerprint
|
fingerprint
|
||||||
gzip
|
gzip
|
||||||
hasher
|
hasher
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -581,6 +581,7 @@ SOURCES =
|
||||||
escape_string
|
escape_string
|
||||||
string_util
|
string_util
|
||||||
file
|
file
|
||||||
|
path
|
||||||
fingerprint
|
fingerprint
|
||||||
gzip
|
gzip
|
||||||
hasher
|
hasher
|
||||||
|
|
|
@ -68,7 +68,6 @@ category_mapping = {
|
||||||
'add_torrent_params.hpp': 'Core',
|
'add_torrent_params.hpp': 'Core',
|
||||||
'session_status.hpp': 'Core',
|
'session_status.hpp': 'Core',
|
||||||
'error_code.hpp': 'Error Codes',
|
'error_code.hpp': 'Error Codes',
|
||||||
'file.hpp': 'File',
|
|
||||||
'storage.hpp': 'Custom Storage',
|
'storage.hpp': 'Custom Storage',
|
||||||
'storage_defs.hpp': 'Storage',
|
'storage_defs.hpp': 'Storage',
|
||||||
'file_storage.hpp': 'Storage',
|
'file_storage.hpp': 'Storage',
|
||||||
|
|
|
@ -33,11 +33,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/storage.hpp"
|
#include "libtorrent/storage.hpp"
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/create_torrent.hpp"
|
#include "libtorrent/create_torrent.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/file_pool.hpp"
|
#include "libtorrent/file_pool.hpp"
|
||||||
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,7 @@ nobase_include_HEADERS = \
|
||||||
aux_/escape_string.hpp \
|
aux_/escape_string.hpp \
|
||||||
aux_/io.hpp \
|
aux_/io.hpp \
|
||||||
aux_/max_path.hpp \
|
aux_/max_path.hpp \
|
||||||
|
aux_/path.hpp \
|
||||||
aux_/merkle.hpp \
|
aux_/merkle.hpp \
|
||||||
aux_/session_call.hpp \
|
aux_/session_call.hpp \
|
||||||
aux_/session_impl.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/tailqueue.hpp"
|
||||||
#include "libtorrent/linked_list.hpp"
|
#include "libtorrent/linked_list.hpp"
|
||||||
#include "libtorrent/disk_buffer_pool.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/disk_io_job.hpp"
|
||||||
#include "libtorrent/aux_/unique_ptr.hpp"
|
#include "libtorrent/aux_/unique_ptr.hpp"
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/string_view.hpp"
|
#include "libtorrent/string_view.hpp"
|
||||||
#include "libtorrent/aux_/vector.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 <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -53,8 +53,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "libtorrent/io_service_fwd.hpp"
|
#include "libtorrent/io_service_fwd.hpp"
|
||||||
#include "libtorrent/file.hpp" // for iovec_t
|
|
||||||
#include "libtorrent/span.hpp"
|
#include "libtorrent/span.hpp"
|
||||||
|
#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -62,10 +62,12 @@ namespace libtorrent
|
||||||
class alert;
|
class alert;
|
||||||
struct disk_observer;
|
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
|
disk_buffer_pool(int block_size, io_service& ios
|
||||||
, std::function<void()> const& trigger_trim);
|
, 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();
|
~disk_buffer_pool();
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
|
|
|
@ -92,110 +92,6 @@ namespace libtorrent
|
||||||
using handle_type = int;
|
using handle_type = int;
|
||||||
#endif
|
#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
|
class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "setup_transfer.hpp" // for ::create_torrent
|
#include "setup_transfer.hpp" // for ::create_torrent
|
||||||
#include "libtorrent/add_torrent_params.hpp"
|
#include "libtorrent/add_torrent_params.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace lt = libtorrent;
|
namespace lt = libtorrent;
|
||||||
|
|
|
@ -44,7 +44,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/random.hpp"
|
#include "libtorrent/random.hpp"
|
||||||
#include "libtorrent/crc32c.hpp"
|
#include "libtorrent/crc32c.hpp"
|
||||||
#include "libtorrent/alert_types.hpp" // for dht_routing_bucket
|
#include "libtorrent/alert_types.hpp" // for dht_routing_bucket
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
|
|
||||||
#include "setup_dht.hpp"
|
#include "setup_dht.hpp"
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/settings_pack.hpp"
|
#include "libtorrent/settings_pack.hpp"
|
||||||
#include "libtorrent/ip_filter.hpp"
|
#include "libtorrent/ip_filter.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
|
@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/session_stats.hpp"
|
#include "libtorrent/session_stats.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
|
@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/session_stats.hpp"
|
#include "libtorrent/session_stats.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/deadline_timer.hpp"
|
#include "libtorrent/deadline_timer.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "simulator/http_server.hpp"
|
#include "simulator/http_server.hpp"
|
||||||
#include "simulator/http_proxy.hpp"
|
#include "simulator/http_proxy.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
|
@ -74,6 +74,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
||||||
error_code.cpp \
|
error_code.cpp \
|
||||||
escape_string.cpp \
|
escape_string.cpp \
|
||||||
file.cpp \
|
file.cpp \
|
||||||
|
path.cpp \
|
||||||
file_pool.cpp \
|
file_pool.cpp \
|
||||||
file_storage.cpp \
|
file_storage.cpp \
|
||||||
fingerprint.cpp \
|
fingerprint.cpp \
|
||||||
|
|
|
@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/announce_entry.hpp"
|
#include "libtorrent/announce_entry.hpp"
|
||||||
#include "libtorrent/performance_counters.hpp" // for counters
|
#include "libtorrent/performance_counters.hpp" // for counters
|
||||||
#include "libtorrent/alert_manager.hpp"
|
#include "libtorrent/alert_manager.hpp"
|
||||||
#include "libtorrent/file.hpp" // for combine_path etc.
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.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/config.hpp"
|
||||||
#include "libtorrent/aux_/alloca.hpp"
|
#include "libtorrent/aux_/alloca.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/file.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/string_util.hpp"
|
#include "libtorrent/string_util.hpp"
|
||||||
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
#include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -329,832 +330,12 @@ static_assert((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0
|
||||||
|
|
||||||
namespace libtorrent
|
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>
|
template <typename T>
|
||||||
std::unique_ptr<T, decltype(&std::free)> make_free_holder(T* ptr)
|
std::unique_ptr<T, decltype(&std::free)> make_free_holder(T* ptr)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<T, decltype(&std::free)>(ptr, &std::free);
|
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)
|
directory::directory(std::string const& path, error_code& ec)
|
||||||
: m_done(false)
|
: m_done(false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/file_storage.hpp"
|
#include "libtorrent/file_storage.hpp"
|
||||||
#include "libtorrent/units.hpp"
|
#include "libtorrent/units.hpp"
|
||||||
#include "libtorrent/disk_interface.hpp"
|
#include "libtorrent/disk_interface.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
#include "libtorrent/aux_/win_util.hpp"
|
#include "libtorrent/aux_/win_util.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,8 +32,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/file_storage.hpp"
|
#include "libtorrent/file_storage.hpp"
|
||||||
#include "libtorrent/string_util.hpp" // for allocate_string_copy
|
#include "libtorrent/string_util.hpp" // for allocate_string_copy
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/utf8.hpp"
|
#include "libtorrent/utf8.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/aux_/numeric_cast.hpp"
|
#include "libtorrent/aux_/numeric_cast.hpp"
|
||||||
|
|
||||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
|
@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/aux_/vector.hpp"
|
#include "libtorrent/aux_/vector.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
namespace
|
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/alert_types.hpp"
|
||||||
#include "libtorrent/invariant_check.hpp"
|
#include "libtorrent/invariant_check.hpp"
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/extensions.hpp"
|
#include "libtorrent/extensions.hpp"
|
||||||
#include "libtorrent/aux_/session_interface.hpp"
|
#include "libtorrent/aux_/session_interface.hpp"
|
||||||
#include "libtorrent/peer_list.hpp"
|
#include "libtorrent/peer_list.hpp"
|
||||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
#include "libtorrent/aux_/session_call.hpp"
|
#include "libtorrent/aux_/session_call.hpp"
|
||||||
#include "libtorrent/aux_/throw.hpp"
|
#include "libtorrent/aux_/throw.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/lazy_entry.hpp"
|
#include "libtorrent/lazy_entry.hpp"
|
||||||
#include "libtorrent/peer_class.hpp"
|
#include "libtorrent/peer_class.hpp"
|
||||||
|
|
|
@ -59,7 +59,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/fingerprint.hpp"
|
#include "libtorrent/fingerprint.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/invariant_check.hpp"
|
#include "libtorrent/invariant_check.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "libtorrent/bt_peer_connection.hpp"
|
#include "libtorrent/bt_peer_connection.hpp"
|
||||||
#include "libtorrent/peer_connection_handle.hpp"
|
#include "libtorrent/peer_connection_handle.hpp"
|
||||||
#include "libtorrent/ip_filter.hpp"
|
#include "libtorrent/ip_filter.hpp"
|
||||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/stat_cache.hpp"
|
#include "libtorrent/stat_cache.hpp"
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/storage.hpp"
|
#include "libtorrent/storage.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/invariant_check.hpp"
|
#include "libtorrent/invariant_check.hpp"
|
||||||
#include "libtorrent/file_pool.hpp"
|
#include "libtorrent/file_pool.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/aux_/storage_utils.hpp"
|
#include "libtorrent/aux_/storage_utils.hpp"
|
||||||
#include "libtorrent/file_storage.hpp"
|
#include "libtorrent/file_storage.hpp"
|
||||||
#include "libtorrent/aux_/alloca.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/part_file.hpp"
|
||||||
#include "libtorrent/session.hpp" // for session::delete_files
|
#include "libtorrent/session.hpp" // for session::delete_files
|
||||||
#include "libtorrent/stat_cache.hpp"
|
#include "libtorrent/stat_cache.hpp"
|
||||||
|
|
|
@ -97,6 +97,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
// TODO: factor out cache_status to its own header
|
// TODO: factor out cache_status to its own header
|
||||||
#include "libtorrent/disk_io_thread.hpp" // for cache_status
|
#include "libtorrent/disk_io_thread.hpp" // for cache_status
|
||||||
#include "libtorrent/aux_/numeric_cast.hpp"
|
#include "libtorrent/aux_/numeric_cast.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
#include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
|
#include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
|
||||||
|
|
|
@ -37,7 +37,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/file.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/utf8.hpp"
|
#include "libtorrent/utf8.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/random.hpp"
|
#include "libtorrent/random.hpp"
|
||||||
|
|
|
@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <boost/system/system_error.hpp>
|
#include <boost/system/system_error.hpp>
|
||||||
|
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/random.hpp"
|
#include "libtorrent/random.hpp"
|
||||||
#include "libtorrent/aux_/escape_string.hpp"
|
#include "libtorrent/aux_/escape_string.hpp"
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
|
|
@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6()
|
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6()
|
||||||
#include "libtorrent/hex.hpp" // to_hex
|
#include "libtorrent/hex.hpp" // to_hex
|
||||||
#include "libtorrent/aux_/vector.hpp"
|
#include "libtorrent/aux_/vector.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "test_utils.hpp"
|
#include "test_utils.hpp"
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/random.hpp"
|
#include "libtorrent/random.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/ip_filter.hpp"
|
#include "libtorrent/ip_filter.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/torrent_status.hpp"
|
#include "libtorrent/torrent_status.hpp"
|
||||||
#include "libtorrent/hex.hpp" // to_hex
|
#include "libtorrent/hex.hpp" // to_hex
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
static const int file_sizes[] =
|
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
|
{ 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/bencode.hpp"
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
|
@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/file.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/string_util.hpp" // for split_string
|
#include "libtorrent/string_util.hpp" // for split_string
|
||||||
#include "libtorrent/string_view.hpp"
|
#include "libtorrent/string_view.hpp"
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "setup_transfer.hpp"
|
#include "setup_transfer.hpp"
|
||||||
|
|
||||||
#include "libtorrent/file_storage.hpp"
|
#include "libtorrent/file_storage.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "libtorrent/gzip.hpp"
|
#include "libtorrent/gzip.hpp"
|
||||||
#include "setup_transfer.hpp" // for load_file
|
#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;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/socket_io.hpp" // print_endpoint
|
#include "libtorrent/socket_io.hpp" // print_endpoint
|
||||||
#include "libtorrent/http_connection.hpp"
|
#include "libtorrent/http_connection.hpp"
|
||||||
#include "libtorrent/resolver.hpp"
|
#include "libtorrent/resolver.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/session_settings.hpp"
|
#include "libtorrent/session_settings.hpp"
|
||||||
#include "libtorrent/torrent_status.hpp"
|
#include "libtorrent/torrent_status.hpp"
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "libtorrent/part_file.hpp"
|
#include "libtorrent/part_file.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/peer_class.hpp"
|
#include "libtorrent/peer_class.hpp"
|
||||||
#include "libtorrent/peer_class_set.hpp"
|
#include "libtorrent/peer_class_set.hpp"
|
||||||
#include "libtorrent/peer_class_type_filter.hpp"
|
#include "libtorrent/peer_class_type_filter.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/extensions/ut_pex.hpp"
|
#include "libtorrent/extensions/ut_pex.hpp"
|
||||||
#include "libtorrent/ip_filter.hpp"
|
#include "libtorrent/ip_filter.hpp"
|
||||||
#include "libtorrent/torrent_status.hpp"
|
#include "libtorrent/torrent_status.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "setup_transfer.hpp"
|
#include "setup_transfer.hpp"
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/read_resume_data.hpp"
|
#include "libtorrent/read_resume_data.hpp"
|
||||||
#include "libtorrent/write_resume_data.hpp"
|
#include "libtorrent/write_resume_data.hpp"
|
||||||
|
|
|
@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/random.hpp"
|
#include "libtorrent/random.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/hex.hpp" // to_hex
|
#include "libtorrent/hex.hpp" // to_hex
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
enum flags_t
|
enum flags_t
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/create_torrent.hpp"
|
#include "libtorrent/create_torrent.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "setup_transfer.hpp"
|
#include "setup_transfer.hpp"
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/resolve_links.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/hex.hpp" // to_hex
|
||||||
#include "libtorrent/create_torrent.hpp"
|
#include "libtorrent/create_torrent.hpp"
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/session_status.hpp"
|
#include "libtorrent/session_status.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/hex.hpp" // for to_hex
|
#include "libtorrent/hex.hpp" // for to_hex
|
||||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/read_resume_data.hpp"
|
#include "libtorrent/read_resume_data.hpp"
|
||||||
#include "libtorrent/write_resume_data.hpp"
|
#include "libtorrent/write_resume_data.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/peer_info.hpp"
|
#include "libtorrent/peer_info.hpp"
|
||||||
#include "libtorrent/extensions.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 "libtorrent/magnet_uri.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
|
@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "libtorrent/file_storage.hpp"
|
#include "libtorrent/file_storage.hpp"
|
||||||
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/create_torrent.hpp"
|
#include "libtorrent/create_torrent.hpp"
|
||||||
#include "libtorrent/announce_entry.hpp"
|
#include "libtorrent/announce_entry.hpp"
|
||||||
|
|
|
@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/announce_entry.hpp"
|
#include "libtorrent/announce_entry.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
|
@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/socket_io.hpp" // print_endpoint
|
#include "libtorrent/socket_io.hpp" // print_endpoint
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
#include "setup_transfer.hpp"
|
#include "setup_transfer.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/utf8.hpp"
|
#include "libtorrent/utf8.hpp"
|
||||||
#include "libtorrent/ConvertUTF.h"
|
#include "libtorrent/ConvertUTF.h"
|
||||||
#include "setup_transfer.hpp" // for load_file
|
#include "setup_transfer.hpp" // for load_file
|
||||||
#include "libtorrent/file.hpp" // for combine_path
|
#include "libtorrent/aux_/path.hpp" // for combine_path
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/utp_stream.hpp"
|
#include "libtorrent/utp_stream.hpp"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
|
@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/hasher.hpp"
|
#include "libtorrent/hasher.hpp"
|
||||||
#include "libtorrent/file_pool.hpp"
|
#include "libtorrent/file_pool.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/aux_/path.hpp"
|
||||||
#include "libtorrent/storage.hpp"
|
#include "libtorrent/storage.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/create_torrent.hpp"
|
#include "libtorrent/create_torrent.hpp"
|
||||||
|
|
Loading…
Reference in New Issue