add support for creating symlinks, for torrents with symlinks in them
This commit is contained in:
parent
57e56d5070
commit
381d5a3c5d
|
@ -1,3 +1,4 @@
|
|||
* support creating symlinks, for torrents with symlinks in them
|
||||
* fix error in seed_mode flag
|
||||
* support magnet link parameters with number siffixes
|
||||
* consistently use "lt" namespace in examples and documentation
|
||||
|
|
|
@ -345,6 +345,7 @@ void bind_alert()
|
|||
.value("partfile_read", operation_t::partfile_read)
|
||||
.value("partfile_write", operation_t::partfile_write)
|
||||
.value("hostname_lookup", operation_t::hostname_lookup)
|
||||
.value("symlink", operation_t::symlink)
|
||||
;
|
||||
|
||||
def("operation_name", static_cast<char const*(*)(operation_t)>(<::operation_name));
|
||||
|
|
|
@ -166,6 +166,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
#endif // __APPLE__
|
||||
|
||||
#define TORRENT_HAS_SYMLINK 1
|
||||
#define TORRENT_USE_DEV_RANDOM 1
|
||||
#define TORRENT_HAVE_MMAP 1
|
||||
|
||||
|
@ -188,6 +189,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
# define TORRENT_USE_PREAD 1
|
||||
#endif
|
||||
|
||||
#define TORRENT_HAS_SYMLINK 1
|
||||
#define TORRENT_HAVE_MMAP 1
|
||||
#define TORRENT_USE_NETLINK 1
|
||||
#define TORRENT_USE_IFADDRS 0
|
||||
|
@ -308,6 +310,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_HAS_SALEN 0
|
||||
#define TORRENT_HAS_SEM_RELTIMEDWAIT 1
|
||||
#define TORRENT_HAVE_MMAP 1
|
||||
#define TORRENT_HAS_SYMLINK 1
|
||||
|
||||
// ==== BEOS ===
|
||||
#elif defined __BEOS__ || defined __HAIKU__
|
||||
|
@ -323,6 +326,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_HURD
|
||||
#define TORRENT_USE_IFADDRS 1
|
||||
#define TORRENT_USE_IFCONF 1
|
||||
#define TORRENT_HAS_SYMLINK 1
|
||||
|
||||
// ==== eCS(OS/2) ===
|
||||
#elif defined __OS2__
|
||||
|
@ -505,6 +509,10 @@ constexpr std::size_t TORRENT_WRITE_HANDLER_MAX_SIZE = 342;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_HAS_SYMLINK
|
||||
#define TORRENT_HAS_SYMLINK 0
|
||||
#endif
|
||||
|
||||
// debug builds have asserts enabled by default, release
|
||||
// builds have asserts if they are explicitly enabled by
|
||||
// the release_asserts macro.
|
||||
|
|
|
@ -465,6 +465,8 @@ namespace detail {
|
|||
}
|
||||
#endif // TORRENT_ABI_VERSION
|
||||
|
||||
TORRENT_EXTRA_EXPORT file_flags_t get_file_attributes(std::string const& p);
|
||||
TORRENT_EXTRA_EXPORT std::string get_symlink_path(std::string const& p);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -134,6 +134,7 @@ namespace libtorrent {
|
|||
partfile_read,
|
||||
partfile_write,
|
||||
hostname_lookup,
|
||||
symlink,
|
||||
};
|
||||
|
||||
// maps an operation id (from peer_error_alert and peer_disconnected_alert)
|
||||
|
|
|
@ -894,6 +894,7 @@ namespace {
|
|||
case o::partfile_read: return -1;
|
||||
case o::partfile_write: return -1;
|
||||
case o::hostname_lookup: return -1;
|
||||
case o::symlink: return -1;
|
||||
};
|
||||
return -1;
|
||||
}
|
||||
|
@ -1558,7 +1559,8 @@ namespace {
|
|||
"partfile_move",
|
||||
"partfile_read",
|
||||
"partfile_write",
|
||||
"hostname_lookup"
|
||||
"hostname_lookup",
|
||||
"symlink"
|
||||
};
|
||||
|
||||
int const idx = static_cast<int>(op);
|
||||
|
|
|
@ -66,28 +66,6 @@ namespace {
|
|||
bool ignore_subdir(std::string const& leaf)
|
||||
{ return leaf == ".." || leaf == "."; }
|
||||
|
||||
file_flags_t get_file_attributes(std::string const& p)
|
||||
{
|
||||
auto const path = convert_to_native_path_string(p);
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &attr);
|
||||
if (attr.dwFileAttributes == INVALID_FILE_ATTRIBUTES) return {};
|
||||
if (attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) return file_storage::flag_hidden;
|
||||
return {};
|
||||
#else
|
||||
struct ::stat s;
|
||||
if (::lstat(path.c_str(), &s) < 0) return {};
|
||||
file_flags_t file_attr = {};
|
||||
if (s.st_mode & S_IXUSR)
|
||||
file_attr |= file_storage::flag_executable;
|
||||
if (S_ISLNK(s.st_mode))
|
||||
file_attr |= file_storage::flag_symlink;
|
||||
return file_attr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TORRENT_WINDOWS
|
||||
std::string get_symlink_path_impl(char const* path)
|
||||
{
|
||||
|
@ -103,16 +81,6 @@ namespace {
|
|||
}
|
||||
#endif
|
||||
|
||||
std::string get_symlink_path(std::string const& p)
|
||||
{
|
||||
#if defined TORRENT_WINDOWS
|
||||
TORRENT_UNUSED(p);
|
||||
return "";
|
||||
#else
|
||||
return get_symlink_path_impl(p.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void add_files_impl(file_storage& fs, std::string const& p
|
||||
, std::string const& l, std::function<bool(std::string)> const& pred
|
||||
, create_flags_t const flags)
|
||||
|
@ -202,6 +170,39 @@ namespace {
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
file_flags_t get_file_attributes(std::string const& p)
|
||||
{
|
||||
auto const path = convert_to_native_path_string(p);
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &attr);
|
||||
if (attr.dwFileAttributes == INVALID_FILE_ATTRIBUTES) return {};
|
||||
if (attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) return file_storage::flag_hidden;
|
||||
return {};
|
||||
#else
|
||||
struct ::stat s;
|
||||
if (::lstat(path.c_str(), &s) < 0) return {};
|
||||
file_flags_t file_attr = {};
|
||||
if (s.st_mode & S_IXUSR)
|
||||
file_attr |= file_storage::flag_executable;
|
||||
if (S_ISLNK(s.st_mode))
|
||||
file_attr |= file_storage::flag_symlink;
|
||||
return file_attr;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string get_symlink_path(std::string const& p)
|
||||
{
|
||||
#if defined TORRENT_WINDOWS
|
||||
TORRENT_UNUSED(p);
|
||||
return "";
|
||||
#else
|
||||
return get_symlink_path_impl(p.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if TORRENT_ABI_VERSION == 1
|
||||
|
||||
void add_files(file_storage& fs, std::wstring const& wfile
|
||||
|
|
|
@ -62,6 +62,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
#if TORRENT_HAS_SYMLINK
|
||||
#include <unistd.h> // for symlink()
|
||||
#endif
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
@ -294,6 +298,7 @@ namespace libtorrent {
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
// if the file is empty and doesn't already exist, create it
|
||||
// deliberately don't truncate files that already exist
|
||||
// if a file is supposed to have size 0, but already exists, we will
|
||||
|
@ -301,8 +306,7 @@ namespace libtorrent {
|
|||
if (fs.file_size(file_index) == 0
|
||||
&& err == boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
std::string file_path = fs.file_path(file_index, m_save_path);
|
||||
std::string dir = parent_path(file_path);
|
||||
std::string dir = parent_path(fs.file_path(file_index, m_save_path));
|
||||
|
||||
if (dir != last_path)
|
||||
{
|
||||
|
@ -317,12 +321,30 @@ namespace libtorrent {
|
|||
}
|
||||
}
|
||||
ec.ec.clear();
|
||||
// just creating the file is enough to make it zero-sized. If
|
||||
// there's a race here and some other process truncates the file,
|
||||
// it's not a problem, we won't access empty files ever again
|
||||
file_handle f = open_file(file_index, open_mode::read_write
|
||||
| open_mode::random_access, ec);
|
||||
if (ec) return;
|
||||
|
||||
#if TORRENT_HAS_SYMLINK
|
||||
// create symlinks
|
||||
if (fs.file_flags(file_index) & file_storage::flag_symlink)
|
||||
{
|
||||
if (::symlink(fs.symlink(file_index).c_str()
|
||||
, fs.file_path(file_index, m_save_path).c_str()) != 0)
|
||||
{
|
||||
ec.ec = error_code(errno, generic_category());
|
||||
ec.file(file_index);
|
||||
ec.operation = operation_t::symlink;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// just creating the file is enough to make it zero-sized. If
|
||||
// there's a race here and some other process truncates the file,
|
||||
// it's not a problem, we won't access empty files ever again
|
||||
file_handle f = open_file(file_index, open_mode::read_write
|
||||
| open_mode::random_access, ec);
|
||||
if (ec) return;
|
||||
}
|
||||
}
|
||||
ec.ec.clear();
|
||||
}
|
||||
|
|
|
@ -739,3 +739,26 @@ TORRENT_TEST(test_calc_bytes_all_pieces_two_pad)
|
|||
auto const fs = test_fs();
|
||||
TEST_EQUAL(calc_bytes(fs, piece_count{fs.num_pieces(), 2, true}), fs.total_size() - 2 * 0x4000);
|
||||
}
|
||||
|
||||
#if TORRENT_HAS_SYMLINK
|
||||
TORRENT_TEST(symlinks_restore)
|
||||
{
|
||||
// downloading test torrent with symlinks
|
||||
std::string const work_dir = current_working_directory();
|
||||
lt::add_torrent_params p;
|
||||
p.ti = std::make_shared<lt::torrent_info>(combine_path(
|
||||
combine_path(parent_path(work_dir), "test_torrents"), "symlink2.torrent"));
|
||||
p.flags &= ~lt::torrent_flags::paused;
|
||||
p.save_path = work_dir;
|
||||
settings_pack pack = settings();
|
||||
pack.set_int(libtorrent::settings_pack::alert_mask, libtorrent::alert::status_notification | libtorrent::alert::error_notification);
|
||||
lt::session ses(std::move(pack));
|
||||
ses.add_torrent(p);
|
||||
|
||||
wait_for_alert(ses, torrent_checked_alert::alert_type, "torrent_checked_alert");
|
||||
|
||||
std::string const f = combine_path(combine_path(work_dir, "Some.framework"), "SDL2");
|
||||
TEST_CHECK(get_file_attributes(f) & file_storage::flag_symlink);
|
||||
TEST_CHECK(get_symlink_path(f) == "Versions/A/SDL2");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
d7:comment13:Symlinks test4:infod5:filesld4:attr2:xl6:lengthi0e4:pathl4:SDL2e12:symlink pathl8:Versions1:A4:SDL2eed6:lengthi2514e4:pathl8:Versions1:A14:_CodeSignature13:CodeResourceseed6:lengthi1310e4:pathl8:Versions1:A9:Resources10:Info.plisteed6:lengthi0e4:pathl8:Versions1:A4:SDL2eed4:attr2:xl6:lengthi0e4:pathl8:Versions7:Currente12:symlink pathl1:Aeee4:name14:Some.framework12:piece lengthi16384e6:pieces20:¤ÎIÝ¡Ú‹<eõîÌ[›×“Íee
|
Loading…
Reference in New Issue