From 79d7ae36381c4bf4aa2cf7044a1cd89f31a9a51b Mon Sep 17 00:00:00 2001 From: arvidn Date: Tue, 11 Apr 2017 00:52:46 -0400 Subject: [PATCH] separate path and filesystem functions out into its own translation unit/header file pair, separating it from the file and directory class --- CMakeLists.txt | 1 + Jamfile | 1 + docs/gen_reference_doc.py | 1 - examples/make_torrent.cpp | 2 - include/libtorrent/Makefile.am | 1 + include/libtorrent/aux_/path.hpp | 195 +++++ include/libtorrent/block_cache.hpp | 2 +- include/libtorrent/create_torrent.hpp | 2 +- include/libtorrent/disk_buffer_pool.hpp | 6 +- include/libtorrent/file.hpp | 104 --- simulation/create_torrent.cpp | 2 +- simulation/setup_dht.cpp | 1 - simulation/setup_swarm.cpp | 2 +- simulation/test_file_pool.cpp | 1 - simulation/test_swarm.cpp | 2 +- simulation/test_web_seed.cpp | 1 + src/Makefile.am | 1 + src/create_torrent.cpp | 2 +- src/file.cpp | 821 +------------------- src/file_pool.cpp | 1 + src/file_storage.cpp | 2 +- src/part_file.cpp | 1 + src/path.cpp | 956 ++++++++++++++++++++++++ src/peer_connection.cpp | 1 - src/session_handle.cpp | 1 + src/session_impl.cpp | 1 - src/stat_cache.cpp | 2 +- src/storage.cpp | 2 +- src/storage_utils.cpp | 2 +- src/torrent.cpp | 1 + src/torrent_info.cpp | 2 + test/main.cpp | 2 +- test/setup_transfer.cpp | 1 + test/swarm_suite.cpp | 2 +- test/test_auto_unchoke.cpp | 2 +- test/test_checking.cpp | 1 + test/test_fast_extension.cpp | 2 +- test/test_file.cpp | 1 + test/test_file_storage.cpp | 2 +- test/test_gzip.cpp | 3 +- test/test_http_connection.cpp | 1 - test/test_lsd.cpp | 2 +- test/test_part_file.cpp | 2 +- test/test_peer_classes.cpp | 1 + test/test_pex.cpp | 2 +- test/test_priority.cpp | 2 +- test/test_privacy.cpp | 2 +- test/test_read_piece.cpp | 1 + test/test_recheck.cpp | 2 +- test/test_remap_files.cpp | 1 + test/test_resolve_links.cpp | 2 +- test/test_ssl.cpp | 2 +- test/test_storage.cpp | 1 + test/test_torrent.cpp | 2 +- test/test_torrent_info.cpp | 1 + test/test_tracker.cpp | 2 +- test/test_transfer.cpp | 2 +- test/test_upnp.cpp | 2 +- test/test_utf8.cpp | 2 +- test/test_utp.cpp | 2 +- test/web_seed_suite.cpp | 2 +- 61 files changed, 1206 insertions(+), 966 deletions(-) create mode 100644 include/libtorrent/aux_/path.hpp create mode 100644 src/path.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 201fe37c3..a0af8b741 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(sources escape_string string_util file + path fingerprint gzip hasher diff --git a/Jamfile b/Jamfile index 4d6aee5ff..6639afc2b 100644 --- a/Jamfile +++ b/Jamfile @@ -581,6 +581,7 @@ SOURCES = escape_string string_util file + path fingerprint gzip hasher diff --git a/docs/gen_reference_doc.py b/docs/gen_reference_doc.py index e04c9a45a..3e539d3fe 100644 --- a/docs/gen_reference_doc.py +++ b/docs/gen_reference_doc.py @@ -68,7 +68,6 @@ category_mapping = { 'add_torrent_params.hpp': 'Core', 'session_status.hpp': 'Core', 'error_code.hpp': 'Error Codes', - 'file.hpp': 'File', 'storage.hpp': 'Custom Storage', 'storage_defs.hpp': 'Storage', 'file_storage.hpp': 'Storage', diff --git a/examples/make_torrent.cpp b/examples/make_torrent.cpp index 578421031..c0aec0b4f 100644 --- a/examples/make_torrent.cpp +++ b/examples/make_torrent.cpp @@ -33,11 +33,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/torrent_info.hpp" -#include "libtorrent/file.hpp" #include "libtorrent/storage.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/create_torrent.hpp" -#include "libtorrent/file.hpp" #include "libtorrent/file_pool.hpp" #include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 38fe1667c..42634a9fa 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -172,6 +172,7 @@ nobase_include_HEADERS = \ aux_/escape_string.hpp \ aux_/io.hpp \ aux_/max_path.hpp \ + aux_/path.hpp \ aux_/merkle.hpp \ aux_/session_call.hpp \ aux_/session_impl.hpp \ diff --git a/include/libtorrent/aux_/path.hpp b/include/libtorrent/aux_/path.hpp new file mode 100644 index 000000000..720663b24 --- /dev/null +++ b/include/libtorrent/aux_/path.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 +#include +#include + +#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 + +#ifdef TORRENT_WINDOWS +// windows part +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#else +// posix part +#define _FILE_OFFSET_BITS 64 + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#include +#include +#include +#include +#include // 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 bufs); +} + +#endif // TORRENT_PATH_HPP_INCLUDED diff --git a/include/libtorrent/block_cache.hpp b/include/libtorrent/block_cache.hpp index ea0a5caa6..aee767236 100644 --- a/include/libtorrent/block_cache.hpp +++ b/include/libtorrent/block_cache.hpp @@ -46,7 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/tailqueue.hpp" #include "libtorrent/linked_list.hpp" #include "libtorrent/disk_buffer_pool.hpp" -#include "libtorrent/file.hpp" // for iovec_t +#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t #include "libtorrent/disk_io_job.hpp" #include "libtorrent/aux_/unique_ptr.hpp" #if TORRENT_USE_ASSERTS diff --git a/include/libtorrent/create_torrent.hpp b/include/libtorrent/create_torrent.hpp index 59549f044..feb2617ed 100644 --- a/include/libtorrent/create_torrent.hpp +++ b/include/libtorrent/create_torrent.hpp @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hasher.hpp" #include "libtorrent/string_view.hpp" #include "libtorrent/aux_/vector.hpp" -#include "libtorrent/file.hpp" // for combine_path etc. +#include "libtorrent/aux_/path.hpp" // for combine_path etc. #include #include diff --git a/include/libtorrent/disk_buffer_pool.hpp b/include/libtorrent/disk_buffer_pool.hpp index d9ed7bac1..ad6c925de 100644 --- a/include/libtorrent/disk_buffer_pool.hpp +++ b/include/libtorrent/disk_buffer_pool.hpp @@ -53,8 +53,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/io_service_fwd.hpp" -#include "libtorrent/file.hpp" // for iovec_t #include "libtorrent/span.hpp" +#include "libtorrent/aux_/storage_utils.hpp" // for iovec_t namespace libtorrent { @@ -62,10 +62,12 @@ namespace libtorrent class alert; struct disk_observer; - struct TORRENT_EXTRA_EXPORT disk_buffer_pool : boost::noncopyable + struct TORRENT_EXTRA_EXPORT disk_buffer_pool { disk_buffer_pool(int block_size, io_service& ios , std::function const& trigger_trim); + disk_buffer_pool(disk_buffer_pool const&) = delete; + disk_buffer_pool& operator=(disk_buffer_pool const&) = delete; ~disk_buffer_pool(); #if TORRENT_USE_ASSERTS diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 67f3138fe..5106cf8d7 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -92,110 +92,6 @@ namespace libtorrent using handle_type = int; #endif - struct file_status - { - std::int64_t file_size = 0; - std::uint64_t atime = 0; - std::uint64_t mtime = 0; - std::uint64_t ctime = 0; - enum { -#if defined TORRENT_WINDOWS - fifo = 0x1000, // named pipe (fifo) - character_special = 0x2000, // character special - directory = 0x4000, // directory - regular_file = 0x8000 // regular -#else - fifo = 0010000, // named pipe (fifo) - character_special = 0020000, // character special - directory = 0040000, // directory - block_special = 0060000, // block special - regular_file = 0100000, // regular - link = 0120000, // symbolic link - socket = 0140000 // socket -#endif - } modes_t; - int mode = 0; - }; - - // internal flags for stat_file - enum { dont_follow_links = 1 }; - TORRENT_EXTRA_EXPORT void stat_file(std::string const& f, file_status* s - , error_code& ec, int flags = 0); - TORRENT_EXTRA_EXPORT void rename(std::string const& f - , std::string const& newf, error_code& ec); - TORRENT_EXTRA_EXPORT void create_directories(std::string const& f - , error_code& ec); - TORRENT_EXTRA_EXPORT void create_directory(std::string const& f - , error_code& ec); - TORRENT_EXTRA_EXPORT void remove_all(std::string const& f - , error_code& ec); - TORRENT_EXTRA_EXPORT void remove(std::string const& f, error_code& ec); - TORRENT_EXTRA_EXPORT bool exists(std::string const& f, error_code& ec); - TORRENT_EXTRA_EXPORT bool exists(std::string const& f); - TORRENT_EXTRA_EXPORT std::int64_t file_size(std::string const& f); - TORRENT_EXTRA_EXPORT bool is_directory(std::string const& f - , error_code& ec); - TORRENT_EXTRA_EXPORT void recursive_copy(std::string const& old_path - , std::string const& new_path, error_code& ec); - TORRENT_EXTRA_EXPORT void copy_file(std::string const& f - , std::string const& newf, error_code& ec); - TORRENT_EXTRA_EXPORT void move_file(std::string const& f - , std::string const& newf, error_code& ec); - - // file is expected to exist, link will be created to point to it. If hard - // links are not supported by the filesystem or OS, the file will be copied. - TORRENT_EXTRA_EXPORT void hard_link(std::string const& file - , std::string const& link, error_code& ec); - - TORRENT_EXTRA_EXPORT std::string split_path(std::string const& f - , bool only_first_part = false); - TORRENT_EXTRA_EXPORT char const* next_path_element(char const* p); - TORRENT_EXTRA_EXPORT std::string extension(std::string const& f); - TORRENT_EXTRA_EXPORT std::string remove_extension(std::string const& f); - TORRENT_EXTRA_EXPORT void replace_extension(std::string& f, std::string const& ext); - TORRENT_EXTRA_EXPORT bool is_root_path(std::string const& f); - - - // internal used by create_torrent.hpp - TORRENT_EXTRA_EXPORT std::string parent_path(std::string const& f); - TORRENT_EXTRA_EXPORT bool has_parent_path(std::string const& f); - TORRENT_EXTRA_EXPORT char const* filename_cstr(char const* f); - - // internal used by create_torrent.hpp - TORRENT_EXTRA_EXPORT std::string filename(std::string const& f); - TORRENT_EXTRA_EXPORT std::string combine_path(string_view lhs - , string_view rhs); - TORRENT_EXTRA_EXPORT void append_path(std::string& branch - , string_view leaf); - - // internal used by create_torrent.hpp - TORRENT_EXTRA_EXPORT std::string complete(string_view f); - TORRENT_EXTRA_EXPORT bool is_complete(string_view f); - TORRENT_EXTRA_EXPORT std::string current_working_directory(); -#if TORRENT_USE_UNC_PATHS - TORRENT_EXTRA_EXPORT std::string canonicalize_path(string_view f); -#endif - -// internal type alias export should be used at unit tests only - using native_path_string = -#if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS - std::wstring; -#else - std::string; -#endif - -// internal export should be used at unit tests only - TORRENT_EXTRA_EXPORT native_path_string convert_to_native_path_string(std::string const& path); - -// internal export should be used at unit tests only - TORRENT_EXTRA_EXPORT std::string convert_from_native_path(char const* s); - -#if defined TORRENT_WINDOWS && TORRENT_USE_WSTRING -// internal export should be used at unit tests only - TORRENT_EXTRA_EXPORT std::string convert_from_native_path(wchar_t const* s); -#endif - - // TODO: move this into a separate header file, TU pair class TORRENT_EXTRA_EXPORT directory : public boost::noncopyable { public: diff --git a/simulation/create_torrent.cpp b/simulation/create_torrent.cpp index e33632b4d..2dce61fc5 100644 --- a/simulation/create_torrent.cpp +++ b/simulation/create_torrent.cpp @@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" // for ::create_torrent #include "libtorrent/add_torrent_params.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include namespace lt = libtorrent; diff --git a/simulation/setup_dht.cpp b/simulation/setup_dht.cpp index c504335cc..3e34af040 100644 --- a/simulation/setup_dht.cpp +++ b/simulation/setup_dht.cpp @@ -44,7 +44,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/random.hpp" #include "libtorrent/crc32c.hpp" #include "libtorrent/alert_types.hpp" // for dht_routing_bucket -#include "libtorrent/file.hpp" #include "setup_dht.hpp" diff --git a/simulation/setup_swarm.cpp b/simulation/setup_swarm.cpp index e36aebbf9..fa36185c1 100644 --- a/simulation/setup_swarm.cpp +++ b/simulation/setup_swarm.cpp @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/settings_pack.hpp" #include "libtorrent/ip_filter.hpp" #include "libtorrent/alert_types.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include "settings.hpp" diff --git a/simulation/test_file_pool.cpp b/simulation/test_file_pool.cpp index dded9a340..c7c5eac8b 100644 --- a/simulation/test_file_pool.cpp +++ b/simulation/test_file_pool.cpp @@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/session.hpp" #include "libtorrent/session_stats.hpp" -#include "libtorrent/file.hpp" #include "libtorrent/torrent_info.hpp" using namespace libtorrent; diff --git a/simulation/test_swarm.cpp b/simulation/test_swarm.cpp index 11ae295e7..da235cace 100644 --- a/simulation/test_swarm.cpp +++ b/simulation/test_swarm.cpp @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/session.hpp" #include "libtorrent/session_stats.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent_info.hpp" #include "settings.hpp" diff --git a/simulation/test_web_seed.cpp b/simulation/test_web_seed.cpp index 680cf00a7..8867f9bcf 100644 --- a/simulation/test_web_seed.cpp +++ b/simulation/test_web_seed.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/deadline_timer.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/alert_types.hpp" +#include "libtorrent/aux_/path.hpp" #include "simulator/http_server.hpp" #include "simulator/http_proxy.hpp" #include "settings.hpp" diff --git a/src/Makefile.am b/src/Makefile.am index e1f9c7bbe..f1a7ed145 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -74,6 +74,7 @@ libtorrent_rasterbar_la_SOURCES = \ error_code.cpp \ escape_string.cpp \ file.cpp \ + path.cpp \ file_pool.cpp \ file_storage.cpp \ fingerprint.cpp \ diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index 4eb588128..61d3d8f2a 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/announce_entry.hpp" #include "libtorrent/performance_counters.hpp" // for counters #include "libtorrent/alert_manager.hpp" -#include "libtorrent/file.hpp" // for combine_path etc. +#include "libtorrent/aux_/path.hpp" #include #include diff --git a/src/file.cpp b/src/file.cpp index 82dfcf863..b46914cc4 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -69,6 +69,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/aux_/alloca.hpp" #include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/string_util.hpp" #include "libtorrent/aux_/max_path.hpp" // for TORRENT_MAX_PATH #include @@ -329,832 +330,12 @@ static_assert((libtorrent::file::sparse & libtorrent::file::attribute_mask) == 0 namespace libtorrent { - int bufs_size(span 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 std::unique_ptr make_free_holder(T* ptr) { return std::unique_ptr(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(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(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::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(error_code(errno, generic_category())); - auto holder = make_free_holder(cwd); - return convert_from_native_path(cwd); -#undef GetCurrentDir_ - } - -#if TORRENT_USE_UNC_PATHS - std::string canonicalize_path(string_view f) - { - std::string ret; - ret.resize(f.size()); - char* write_cur = &ret[0]; - char* last_write_sep = write_cur; - - char const* read_cur = f.data(); - char const* last_read_sep = read_cur; - - // the last_*_sep pointers point to one past - // the last path separator encountered and is - // initialized to the first character in the path - for (int i = 0; i < int(f.size()); ++i) - { - if (*read_cur != '\\') - { - *write_cur++ = *read_cur++; - continue; - } - int element_len = int(read_cur - last_read_sep); - if (element_len == 1 && std::memcmp(last_read_sep, ".", 1) == 0) - { - --write_cur; - ++read_cur; - last_read_sep = read_cur; - continue; - } - if (element_len == 2 && std::memcmp(last_read_sep, "..", 2) == 0) - { - // find the previous path separator - if (last_write_sep > &ret[0]) - { - --last_write_sep; - while (last_write_sep > &ret[0] - && last_write_sep[-1] != '\\') - --last_write_sep; - } - write_cur = last_write_sep; - // find the previous path separator - if (last_write_sep > &ret[0]) - { - --last_write_sep; - while (last_write_sep > &ret[0] - && last_write_sep[-1] != '\\') - --last_write_sep; - } - ++read_cur; - last_read_sep = read_cur; - continue; - } - *write_cur++ = *read_cur++; - last_write_sep = write_cur; - last_read_sep = read_cur; - } - // terminate destination string - *write_cur = 0; - ret.resize(write_cur - &ret[0]); - return ret; - } -#endif - - std::int64_t file_size(std::string const& f) - { - error_code ec; - file_status s; - stat_file(f, &s, ec); - if (ec) return 0; - return s.file_size; - } - - bool exists(std::string const& f, error_code& ec) - { - file_status s; - stat_file(f, &s, ec); - if (ec) - { - if (ec == boost::system::errc::no_such_file_or_directory) - ec.clear(); - return false; - } - return true; - } - - bool exists(std::string const& f) - { - error_code ec; - return exists(f, ec); - } - - void remove(std::string const& inf, error_code& ec) - { - ec.clear(); - native_path_string f = convert_to_native_path_string(inf); - -#ifdef TORRENT_WINDOWS - // windows does not allow trailing / or \ in - // the path when removing files - while (!f.empty() && ( - f.back() == '/' || - f.back() == '\\' - )) f.pop_back(); -#if TORRENT_USE_WSTRING -#define DeleteFile_ DeleteFileW -#define RemoveDirectory_ RemoveDirectoryW -#else -#define DeleteFile_ DeleteFileA -#define RemoveDirectory_ RemoveDirectoryA -#endif - if (DeleteFile_(f.c_str()) == 0) - { - if (GetLastError() == ERROR_ACCESS_DENIED) - { - if (RemoveDirectory_(f.c_str()) != 0) - return; - } - ec.assign(GetLastError(), system_category()); - return; - } -#undef DeleteFile_ -#undef RemoveDirectory_ -#else // TORRENT_WINDOWS - if (::remove(f.c_str()) < 0) - { - ec.assign(errno, system_category()); - return; - } -#endif // TORRENT_WINDOWS - } - - void remove_all(std::string const& f, error_code& ec) - { - ec.clear(); - - file_status s; - stat_file(f, &s, ec); - if (ec) return; - - if (s.mode & file_status::directory) - { - for (directory i(f, ec); !i.done(); i.next(ec)) - { - if (ec) return; - std::string p = i.file(); - if (p == "." || p == "..") continue; - remove_all(combine_path(f, p), ec); - if (ec) return; - } - } - remove(f, ec); - } - - std::string complete(string_view f) - { - if (is_complete(f)) return f.to_string(); - if (f == ".") return current_working_directory(); - return combine_path(current_working_directory(), f); - } - - bool is_complete(string_view f) - { - if (f.empty()) return false; -#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2) - int i = 0; - // match the xx:\ or xx:/ form - while (f[i] && is_alpha(f[i])) ++i; - if (i < int(f.size()-1) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/')) - return true; - - // match the \\ form - if (int(f.size()) >= 2 && f[0] == '\\' && f[1] == '\\') - return true; - return false; -#else - if (f[0] == '/') return true; - return false; -#endif - } - directory::directory(std::string const& path, error_code& ec) : m_done(false) { diff --git a/src/file_pool.cpp b/src/file_pool.cpp index eaa3d2e16..d8d2bf099 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/units.hpp" #include "libtorrent/disk_interface.hpp" +#include "libtorrent/aux_/path.hpp" #ifdef TORRENT_WINDOWS #include "libtorrent/aux_/win_util.hpp" #endif diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 3e4e6734d..50b8d8d3c 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -32,8 +32,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/string_util.hpp" // for allocate_string_copy -#include "libtorrent/file.hpp" #include "libtorrent/utf8.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/aux_/numeric_cast.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp" diff --git a/src/part_file.cpp b/src/part_file.cpp index e65ef2771..672f6540c 100644 --- a/src/part_file.cpp +++ b/src/part_file.cpp @@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/io.hpp" #include "libtorrent/assert.hpp" #include "libtorrent/aux_/vector.hpp" +#include "libtorrent/aux_/path.hpp" namespace { diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 000000000..6a8a2d0bc --- /dev/null +++ b/src/path.cpp @@ -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 + +// 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 +#include // 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 +#include +#ifndef TORRENT_MINGW +#include // for _getcwd, _mkdir +#else +#include +#endif +#include +#else +// posix part + +#include +#include +#include +#include + +#ifdef TORRENT_LINUX +// linux specifics + +#include + +#elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 +// mac specifics + +#include + +#endif + +#endif // posix part + +#include "libtorrent/aux_/disable_warnings_pop.hpp" + +namespace libtorrent +{ + int bufs_size(span 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 + std::unique_ptr make_free_holder(T* ptr) + { + return std::unique_ptr(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(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(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::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(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 + } +} + diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index debeffbed..0db17ee59 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/io.hpp" -#include "libtorrent/file.hpp" #include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_interface.hpp" #include "libtorrent/peer_list.hpp" diff --git a/src/session_handle.cpp b/src/session_handle.cpp index 4fe1e269b..668f13a4d 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_call.hpp" #include "libtorrent/aux_/throw.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent.hpp" #include "libtorrent/lazy_entry.hpp" #include "libtorrent/peer_class.hpp" diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 655fe112c..580ddcc05 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -59,7 +59,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/fingerprint.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/invariant_check.hpp" -#include "libtorrent/file.hpp" #include "libtorrent/bt_peer_connection.hpp" #include "libtorrent/peer_connection_handle.hpp" #include "libtorrent/ip_filter.hpp" diff --git a/src/stat_cache.cpp b/src/stat_cache.cpp index 36bbc1e78..81f640ca2 100644 --- a/src/stat_cache.cpp +++ b/src/stat_cache.cpp @@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/stat_cache.hpp" #include "libtorrent/assert.hpp" #include "libtorrent/error_code.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" namespace libtorrent { diff --git a/src/storage.cpp b/src/storage.cpp index 313bd3bdc..72e0fb563 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -65,7 +65,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/storage.hpp" #include "libtorrent/torrent.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/file_pool.hpp" #include "libtorrent/aux_/session_impl.hpp" diff --git a/src/storage_utils.cpp b/src/storage_utils.cpp index 1040134d2..9b7af5421 100644 --- a/src/storage_utils.cpp +++ b/src/storage_utils.cpp @@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/storage_utils.hpp" #include "libtorrent/file_storage.hpp" #include "libtorrent/aux_/alloca.hpp" -#include "libtorrent/file.hpp" // for count_bufs +#include "libtorrent/aux_/path.hpp" // for count_bufs #include "libtorrent/part_file.hpp" #include "libtorrent/session.hpp" // for session::delete_files #include "libtorrent/stat_cache.hpp" diff --git a/src/torrent.cpp b/src/torrent.cpp index c02fe52aa..a300bad8a 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -97,6 +97,7 @@ POSSIBILITY OF SUCH DAMAGE. // TODO: factor out cache_status to its own header #include "libtorrent/disk_io_thread.hpp" // for cache_status #include "libtorrent/aux_/numeric_cast.hpp" +#include "libtorrent/aux_/path.hpp" #ifndef TORRENT_DISABLE_LOGGING #include "libtorrent/aux_/session_impl.hpp" // for tracker_logger diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 73f50b2d8..3d83970cc 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -37,7 +37,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/entry.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/utf8.hpp" #include "libtorrent/time.hpp" #include "libtorrent/random.hpp" diff --git a/test/main.cpp b/test/main.cpp index 276b20e2f..f30817d47 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/assert.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/random.hpp" #include "libtorrent/aux_/escape_string.hpp" #include diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 24fa7e785..1298be3e1 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6() #include "libtorrent/hex.hpp" // to_hex #include "libtorrent/aux_/vector.hpp" +#include "libtorrent/aux_/path.hpp" #include "test.hpp" #include "test_utils.hpp" diff --git a/test/swarm_suite.cpp b/test/swarm_suite.cpp index 9329e5688..386d323df 100644 --- a/test/swarm_suite.cpp +++ b/test/swarm_suite.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/time.hpp" #include "libtorrent/random.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include diff --git a/test/test_auto_unchoke.cpp b/test/test_auto_unchoke.cpp index d72b233cc..799084cf2 100644 --- a/test/test_auto_unchoke.cpp +++ b/test/test_auto_unchoke.cpp @@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hasher.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/ip_filter.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include diff --git a/test/test_checking.cpp b/test/test_checking.cpp index 06a19e27d..a5a73dd05 100644 --- a/test/test_checking.cpp +++ b/test/test_checking.cpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_status.hpp" #include "libtorrent/hex.hpp" // to_hex +#include "libtorrent/aux_/path.hpp" static const int file_sizes[] = { 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 diff --git a/test/test_fast_extension.cpp b/test/test_fast_extension.cpp index 4ab7054db..a6547028e 100644 --- a/test/test_fast_extension.cpp +++ b/test/test_fast_extension.cpp @@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/torrent_info.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include diff --git a/test/test_file.cpp b/test/test_file.cpp index 80a912d4d..ff721b213 100644 --- a/test/test_file.cpp +++ b/test/test_file.cpp @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/string_util.hpp" // for split_string #include "libtorrent/string_view.hpp" #include "test.hpp" diff --git a/test/test_file_storage.cpp b/test/test_file_storage.cpp index d92c502ac..3da4000d3 100644 --- a/test/test_file_storage.cpp +++ b/test/test_file_storage.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "setup_transfer.hpp" #include "libtorrent/file_storage.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" using namespace libtorrent; diff --git a/test/test_gzip.cpp b/test/test_gzip.cpp index 0f6c10e48..a38353304 100644 --- a/test/test_gzip.cpp +++ b/test/test_gzip.cpp @@ -30,11 +30,10 @@ POSSIBILITY OF SUCH DAMAGE. */ -#include "libtorrent/file.hpp" #include "test.hpp" #include "libtorrent/gzip.hpp" #include "setup_transfer.hpp" // for load_file -#include "libtorrent/file.hpp" // for combine_path +#include "libtorrent/aux_/path.hpp" // for combine_path using namespace libtorrent; diff --git a/test/test_http_connection.cpp b/test/test_http_connection.cpp index 7afe2e3c9..97dddbca8 100644 --- a/test/test_http_connection.cpp +++ b/test/test_http_connection.cpp @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_io.hpp" // print_endpoint #include "libtorrent/http_connection.hpp" #include "libtorrent/resolver.hpp" -#include "libtorrent/file.hpp" #include #include diff --git a/test/test_lsd.cpp b/test/test_lsd.cpp index 599008adb..1ecb59d8f 100644 --- a/test/test_lsd.cpp +++ b/test/test_lsd.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session_settings.hpp" #include "libtorrent/torrent_status.hpp" #include "libtorrent/hasher.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include "test.hpp" diff --git a/test/test_part_file.cpp b/test/test_part_file.cpp index c8ca71dbb..90a7dbc1c 100644 --- a/test/test_part_file.cpp +++ b/test/test_part_file.cpp @@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "test.hpp" #include "libtorrent/part_file.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/error_code.hpp" using namespace libtorrent; diff --git a/test/test_peer_classes.cpp b/test/test_peer_classes.cpp index d7cf8d856..17c5a2959 100644 --- a/test/test_peer_classes.cpp +++ b/test/test_peer_classes.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/peer_class.hpp" #include "libtorrent/peer_class_set.hpp" #include "libtorrent/peer_class_type_filter.hpp" +#include "libtorrent/aux_/path.hpp" using namespace libtorrent; diff --git a/test/test_pex.cpp b/test/test_pex.cpp index a4eeafb92..230d9e1ce 100644 --- a/test/test_pex.cpp +++ b/test/test_pex.cpp @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/extensions/ut_pex.hpp" #include "libtorrent/ip_filter.hpp" #include "libtorrent/torrent_status.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include "setup_transfer.hpp" diff --git a/test/test_priority.cpp b/test/test_priority.cpp index 38c70a94b..d8f1b6c05 100644 --- a/test/test_priority.cpp +++ b/test/test_priority.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/read_resume_data.hpp" #include "libtorrent/write_resume_data.hpp" diff --git a/test/test_privacy.cpp b/test/test_privacy.cpp index c3f785654..84f382117 100644 --- a/test/test_privacy.cpp +++ b/test/test_privacy.cpp @@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/random.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/torrent_info.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include diff --git a/test/test_read_piece.cpp b/test/test_read_piece.cpp index 51714ea9a..70c5844bf 100644 --- a/test/test_read_piece.cpp +++ b/test/test_read_piece.cpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/hex.hpp" // to_hex +#include "libtorrent/aux_/path.hpp" enum flags_t { diff --git a/test/test_recheck.cpp b/test/test_recheck.cpp index 9cf94d81c..153c50cfc 100644 --- a/test/test_recheck.cpp +++ b/test/test_recheck.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/error_code.hpp" #include #include diff --git a/test/test_remap_files.cpp b/test/test_remap_files.cpp index 05c9ffa5e..9fbac0637 100644 --- a/test/test_remap_files.cpp +++ b/test/test_remap_files.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/create_torrent.hpp" #include "libtorrent/torrent_info.hpp" +#include "libtorrent/aux_/path.hpp" #include "setup_transfer.hpp" #include "test.hpp" #include "settings.hpp" diff --git a/test/test_resolve_links.cpp b/test/test_resolve_links.cpp index c6b80fe3f..b9fb74644 100644 --- a/test/test_resolve_links.cpp +++ b/test/test_resolve_links.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" #include "libtorrent/resolve_links.hpp" -#include "libtorrent/file.hpp" // for combine_path +#include "libtorrent/aux_/path.hpp" // for combine_path #include "libtorrent/hex.hpp" // to_hex #include "libtorrent/create_torrent.hpp" diff --git a/test/test_ssl.cpp b/test/test_ssl.cpp index 32793434f..b1a217465 100644 --- a/test/test_ssl.cpp +++ b/test/test_ssl.cpp @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session.hpp" #include "libtorrent/alert_types.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/session_status.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/hex.hpp" // for to_hex diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 12459e64a..09848e846 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" #include "libtorrent/read_resume_data.hpp" #include "libtorrent/write_resume_data.hpp" +#include "libtorrent/aux_/path.hpp" #include #include diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index 6e4cd1943..326008db8 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/extensions.hpp" -#include "libtorrent/file.hpp" // for combine_path, current_working_directory +#include "libtorrent/aux_/path.hpp" // for combine_path, current_working_directory #include "libtorrent/magnet_uri.hpp" #include "settings.hpp" #include diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 96b0f4eb9..e376ea534 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "libtorrent/file_storage.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/create_torrent.hpp" #include "libtorrent/announce_entry.hpp" diff --git a/test/test_tracker.cpp b/test/test_tracker.cpp index 4fe8ccbd7..c7ad57b85 100644 --- a/test/test_tracker.cpp +++ b/test/test_tracker.cpp @@ -45,7 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" #include "libtorrent/announce_entry.hpp" #include "libtorrent/torrent.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include diff --git a/test/test_transfer.cpp b/test/test_transfer.cpp index 44090f28d..74e116aac 100644 --- a/test/test_transfer.cpp +++ b/test/test_transfer.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent_info.hpp" #include "test.hpp" diff --git a/test/test_upnp.cpp b/test/test_upnp.cpp index bbaef861a..0ba3ee987 100644 --- a/test/test_upnp.cpp +++ b/test/test_upnp.cpp @@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_io.hpp" // print_endpoint #include "test.hpp" #include "setup_transfer.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include #include #include diff --git a/test/test_utf8.cpp b/test/test_utf8.cpp index df5fb2c47..8e6a01a7b 100644 --- a/test/test_utf8.cpp +++ b/test/test_utf8.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/utf8.hpp" #include "libtorrent/ConvertUTF.h" #include "setup_transfer.hpp" // for load_file -#include "libtorrent/file.hpp" // for combine_path +#include "libtorrent/aux_/path.hpp" // for combine_path #include diff --git a/test/test_utp.cpp b/test/test_utp.cpp index a669cde37..1a684c40f 100644 --- a/test/test_utp.cpp +++ b/test/test_utp.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/utp_stream.hpp" #include #include diff --git a/test/web_seed_suite.cpp b/test/web_seed_suite.cpp index 7ad875bb7..d6475bdf7 100644 --- a/test/web_seed_suite.cpp +++ b/test/web_seed_suite.cpp @@ -33,7 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/file_pool.hpp" -#include "libtorrent/file.hpp" +#include "libtorrent/aux_/path.hpp" #include "libtorrent/storage.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/create_torrent.hpp"