Skip to content

Commit

Permalink
add function to truncate over-sized files part of a torrent
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Feb 14, 2022
1 parent c070e0a commit eda4baa
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ set(libtorrent_include_files
torrent_peer_allocator.hpp
torrent_status.hpp
tracker_manager.hpp
truncate.hpp
udp_socket.hpp
udp_tracker_connection.hpp
union_endpoint.hpp
Expand Down Expand Up @@ -402,6 +403,7 @@ set(sources
torrent_peer_allocator.cpp
torrent_status.cpp
tracker_manager.cpp
truncate.cpp
udp_socket.cpp
udp_tracker_connection.cpp
upnp.cpp
Expand Down
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* add function to truncate over-sized files part of a torrent
* fix directory creation on windows shared folders
* add flag to make add_files() not record file attributes
* deprecate (unused) allow_partial_disk_writes settings
Expand Down
1 change: 1 addition & 0 deletions Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ SOURCES =
posix_part_file
posix_storage
ssl
truncate

# -- extensions --
ut_pex
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ SOURCES = \
torrent_peer_allocator.cpp \
torrent_status.cpp \
tracker_manager.cpp \
truncate.cpp \
udp_socket.cpp \
udp_tracker_connection.cpp \
upnp.cpp \
Expand Down Expand Up @@ -544,6 +545,7 @@ HEADERS = \
torrent_peer_allocator.hpp \
torrent_status.hpp \
tracker_manager.hpp \
truncate.hpp \
udp_socket.hpp \
udp_tracker_connection.hpp \
union_endpoint.hpp \
Expand Down Expand Up @@ -915,6 +917,7 @@ TEST_SOURCES = \
test_torrent_info.cpp \
test_torrent_list.cpp \
test_tracker.cpp \
test_truncate.cpp \
test_transfer.cpp \
test_upnp.cpp \
test_url_seed.cpp \
Expand Down
48 changes: 48 additions & 0 deletions include/libtorrent/truncate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright (c) 2022, 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_TRUNCATE_HPP_INCLUDED
#define TORRENT_TRUNCATE_HPP_INCLUDED

#include "libtorrent/fwd.hpp"
#include "libtorrent/error_code.hpp"
#include <string>

namespace libtorrent {

// Truncates files larger than specified in the file_storage, saved under
// the specified save_path.
TORRENT_EXPORT void truncate_files(file_storage const& fs, std::string const& save_path, storage_error& ec);

}

#endif
177 changes: 177 additions & 0 deletions src/truncate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
Copyright (c) 2022, 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/truncate.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/aux_/path.hpp"
#include "libtorrent/operations.hpp"

#ifdef TORRENT_WINDOWS
#include "libtorrent/aux_/windows.hpp"
#else
#include <sys/stat.h>
#endif

namespace libtorrent {

#ifdef TORRENT_WINDOWS

void truncate_files(file_storage const& fs, std::string const& save_path, storage_error& ec)
{
for (auto i : fs.file_range())
{
if (fs.pad_file_at(i)) continue;
auto const fn = fs.file_path(i, save_path);
native_path_string const file_path = convert_to_native_path_string(fn);
#ifdef TORRENT_WINRT
HANDLE handle = CreateFile2(file_path.c_str()
, GENERIC_WRITE | GENERIC_READ
, FILE_SHARE_READ | FILE_SHARE_WRITE
, OPEN_EXISTING
, nullptr);
#else
HANDLE handle = CreateFileW(file_path.c_str()
, GENERIC_WRITE | GENERIC_READ
, FILE_SHARE_READ | FILE_SHARE_WRITE
, nullptr
, OPEN_EXISTING
, 0
, nullptr);
#endif
if (handle == INVALID_HANDLE_VALUE)
{
auto const error = ::GetLastError();
if (error != ERROR_FILE_NOT_FOUND)
{
ec.ec.assign(error, system_category());
ec.file(i);
ec.operation = operation_t::file_open;
return;
}
continue;
}

LARGE_INTEGER file_size;
if (GetFileSizeEx(handle, &file_size) == FALSE)
{
ec.ec.assign(::GetLastError(), system_category());
ec.file(i);
ec.operation = operation_t::file_stat;
::CloseHandle(handle);
return;
}

if (file_size.QuadPart < fs.file_size(i))
{
::CloseHandle(handle);
continue;
}

LARGE_INTEGER sz;
sz.QuadPart = fs.file_size(i);
if (SetFilePointerEx(handle, sz, nullptr, FILE_BEGIN) == FALSE)
{
ec.ec.assign(::GetLastError(), system_category());
ec.file(i);
ec.operation = operation_t::file_seek;
::CloseHandle(handle);
return;
}

if (::SetEndOfFile(handle) == FALSE)
{
ec.ec.assign(::GetLastError(), system_category());
ec.file(i);
ec.operation = operation_t::file_truncate;
::CloseHandle(handle);
return;
}
::CloseHandle(handle);
}
}

#else

void truncate_files(file_storage const& fs, std::string const& save_path, storage_error& ec)
{
for (auto i : fs.file_range())
{
if (fs.pad_file_at(i)) continue;
auto const fn = fs.file_path(i, save_path);
native_path_string const file_path = convert_to_native_path_string(fn);
int const fd = ::open(file_path.c_str(), O_RDWR);

if (fd < 0)
{
int const error = errno;
if (error != ENOENT)
{
ec.ec.assign(error, generic_category());
ec.file(i);
ec.operation = operation_t::file_open;
return;
}
continue;
}

struct ::stat st;
if (::fstat(fd, &st) != 0)
{
ec.ec.assign(errno, system_category());
ec.file(i);
ec.operation = operation_t::file_stat;
::close(fd);
return;
}

if (st.st_size < fs.file_size(i))
{
::close(fd);
continue;
}

if (::ftruncate(fd, static_cast<off_t>(fs.file_size(i))) < 0)
{
ec.ec.assign(errno, system_category());
ec.file(i);
ec.operation = operation_t::file_truncate;
::close(fd);
return;
}

::close(fd);
}
}

#endif

}
2 changes: 2 additions & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ run test_hash_picker.cpp ;
run test_torrent.cpp ;
run test_remap_files.cpp ;
run test_similar_torrent.cpp ;
run test_truncate.cpp ;

# turn these tests into simulations
run test_resume.cpp ;
Expand Down Expand Up @@ -314,4 +315,5 @@ alias deterministic-tests :
test_xml
test_store_buffer
test_similar_torrent
test_truncate
;
Loading

0 comments on commit eda4baa

Please sign in to comment.