Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resume download from control file #2179

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ compile
main.log
main.trs
test-suite.log
.vscode/
4 changes: 2 additions & 2 deletions doc/manual-src/en/aria2c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ aria2c(1)

SYNOPSIS
--------
**aria2c** [<OPTIONS>] [<URI>|<MAGNET>|<TORRENT_FILE>|<METALINK_FILE>] ...
**aria2c** [<OPTIONS>] [<URI>|<MAGNET>|<TORRENT_FILE>|<METALINK_FILE>|<ARIA2_CONTROL_FILE>] ...

DESCRIPTION
-----------
Expand Down Expand Up @@ -1736,7 +1736,7 @@ Some options takes ``K`` and ``M`` to conveniently represent 1024 and
case-insensitive way. In other words, ``k`` and ``m`` can be used as
well as ``K`` and ``M`` respectively.

URI, MAGNET, TORRENT_FILE, METALINK_FILE
URI, MAGNET, TORRENT_FILE, METALINK_FILE, ARIA2_CONTROL_FILE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can specify multiple URIs in command-line. Unless you specify
Expand Down
2 changes: 1 addition & 1 deletion doc/manual-src/pt/aria2c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1482,7 +1482,7 @@ Algumas opções usam ``K`` e ``M`` para convenientemente representar
transparente (maiúsculas e minúsculas), portanto podem ser usados
`k`` ou ``K`` e ``m`` ou ``M``.

URI, MAGNET, TORRENT_FILE, METALINK_FILE
URI, MAGNET, TORRENT_FILE, METALINK_FILE, ARIA2_CONTROL_FILE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Podemos especificar múltiplas URIs em uma linha de comando. A menos que seja
Expand Down
2 changes: 1 addition & 1 deletion doc/manual-src/ru/aria2c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1836,7 +1836,7 @@ URI, и это не то, что обычно вы ожидаете.
регистра. Другими словами, ``k`` и ``m`` могут быть использованы также как
``K`` и ``M`` соответственно.

URI, MAGNET-ССЫЛКА, TORRENT-ФАЙЛ, METALINK-ФАЙЛ
URI, MAGNET-ССЫЛКА, TORRENT-ФАЙЛ, METALINK-ФАЙЛ, ARIA2_CONTROL_FILE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вы можете перечислить несколько URI в командной строке. Пока вы не указали
Expand Down
67 changes: 53 additions & 14 deletions src/DefaultBtProgressInfoFile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@
#include "fmt.h"
#include "array_fun.h"
#include "DownloadContext.h"
#include "BufferedFile.h"
#include "SHA1IOFile.h"
#include "BtConstants.h"
#ifdef ENABLE_BITTORRENT
# include "PeerStorage.h"
# include "BtRuntime.h"
Expand Down Expand Up @@ -223,23 +221,17 @@ void DefaultBtProgressInfoFile::save()
}
}

#define READ_CHECK(fp, ptr, count) \
#define READ_CHECK_STATIC(fp, ptr, count, filename) \
if (fp.read((ptr), (count)) != (count)) { \
throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str())); \
throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename.c_str())); \
}

// It is assumed that integers are saved as:
// 1) host byte order if version == 0000
// 2) network byte order if version == 0001
void DefaultBtProgressInfoFile::load()
#define READ_CHECK(fp, ptr, count) READ_CHECK_STATIC(fp, ptr, count, filename_)

uint DefaultBtProgressInfoFile::getControlFileVersion(BufferedFile& fp, const std::string& filename)
{
A2_LOG_INFO(fmt(MSG_LOADING_SEGMENT_FILE, filename_.c_str()));
BufferedFile fp(filename_.c_str(), BufferedFile::READ);
if (!fp) {
throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str()));
}
unsigned char versionBuf[2];
READ_CHECK(fp, versionBuf, sizeof(versionBuf));
READ_CHECK_STATIC(fp, versionBuf, sizeof(versionBuf), filename);
std::string versionHex = util::toHex(versionBuf, sizeof(versionBuf));
int version;
if ("0000" == versionHex) {
Expand All @@ -252,6 +244,53 @@ void DefaultBtProgressInfoFile::load()
throw DL_ABORT_EX(
fmt("Unsupported ctrl file version: %s", versionHex.c_str()));
}

return version;
}

std::array<unsigned char, INFO_HASH_LENGTH> DefaultBtProgressInfoFile::getInfoHash(const std::string& control_file)
{
A2_LOG_INFO(fmt(MSG_LOADING_SEGMENT_FILE, control_file.c_str()));
BufferedFile fp(control_file.c_str(), BufferedFile::READ);
if (!fp) {
throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, control_file.c_str()));
}

const auto version = getControlFileVersion(fp, control_file);

unsigned char extension[4];
READ_CHECK_STATIC(fp, extension, sizeof(extension), control_file);

uint32_t infoHashLength;
READ_CHECK_STATIC(fp, &infoHashLength, sizeof(infoHashLength), control_file);
if (version >= 1) {
infoHashLength = ntohl(infoHashLength);
}
if (infoHashLength != INFO_HASH_LENGTH) {
throw DL_ABORT_EX(fmt("Invalid info hash length: %d", infoHashLength));
}

std::array<unsigned char, INFO_HASH_LENGTH> savedInfoHash;
if (infoHashLength > 0) {
READ_CHECK_STATIC(fp, savedInfoHash.data(), infoHashLength, control_file);
}

return savedInfoHash;
}

// It is assumed that integers are saved as:
// 1) host byte order if version == 0000
// 2) network byte order if version == 0001
void DefaultBtProgressInfoFile::load()
{
A2_LOG_INFO(fmt(MSG_LOADING_SEGMENT_FILE, filename_.c_str()));
BufferedFile fp(filename_.c_str(), BufferedFile::READ);
if (!fp) {
throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str()));
}

const auto version = getControlFileVersion(fp, filename_);

unsigned char extension[4];
READ_CHECK(fp, extension, sizeof(extension));
bool infoHashCheckEnabled = false;
Expand Down
7 changes: 7 additions & 0 deletions src/DefaultBtProgressInfoFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#define D_DEFAULT_BT_PROGRESS_INFO_FILE_H

#include "BtProgressInfoFile.h"
#include "BufferedFile.h"
#include "BtConstants.h"

#include <memory>

Expand Down Expand Up @@ -93,6 +95,11 @@ class DefaultBtProgressInfoFile : public BtProgressInfoFile {
void setBtRuntime(const std::shared_ptr<BtRuntime>& btRuntime);
#endif // ENABLE_BITTORRENT

// Assume getting pointer to the start of the file
static uint getControlFileVersion(BufferedFile& fp, const std::string& filename);

static std::array<unsigned char, INFO_HASH_LENGTH> getInfoHash(const std::string& control_file);

static const std::string& getSuffix()
{
static std::string suffix = ".aria2";
Expand Down
5 changes: 5 additions & 0 deletions src/File.cc
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ Time File::getModifiedTime()
return Time(fstat.st_mtime);
}

std::string File::getExtension() const
{
return name_.substr(name_.find_last_of("."));
}

std::string File::getCurrentDir()
{
#ifdef __MINGW32__
Expand Down
2 changes: 2 additions & 0 deletions src/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ class File {

Time getModifiedTime();

std::string getExtension() const;

// Returns the current working directory. If the current working
// directory cannot be retrieved or its length is larger than 2048,
// returns ".".
Expand Down
19 changes: 19 additions & 0 deletions src/ProtocolDetector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
#ifdef ENABLE_BITTORRENT
# include "bittorrent_helper.h"
#endif // ENABLE_BITTORRENT
#ifdef ENABLE_CONTROL_FILE
# include "DefaultBtProgressInfoFile.h"
#endif // ENABLE_CONTROL_FILE

namespace aria2 {

Expand Down Expand Up @@ -90,6 +93,22 @@ bool ProtocolDetector::guessTorrentMagnet(const std::string& uri) const
#endif // !ENABLE_BITTORRENT
}

bool ProtocolDetector::guessAria2ControlFile(const std::string& uri) const
{
#ifdef ENABLE_CONTROL_FILE
File control_file(uri);

if(!control_file.isFile())
{
return false;
}

return control_file.getExtension() == DefaultBtProgressInfoFile::getSuffix();
#else // !ENABLE_CONTROL_FILE
return false;
#endif // !ENABLE_CONTROL_FILE
}

bool ProtocolDetector::guessMetalinkFile(const std::string& uri) const
{
BufferedFile fp(uri.c_str(), BufferedFile::READ);
Expand Down
4 changes: 4 additions & 0 deletions src/ProtocolDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class ProtocolDetector {
// Returns true if ProtocolDetector thinks uri is a path of Metalink XML
// file, otherwise return false.
bool guessMetalinkFile(const std::string& uri) const;

// Returns true if ProtocolDetector thinks uri is a path to aria2 control
// file, otherwise return false
bool guessAria2ControlFile(const std::string& uri) const;
};

} // namespace aria2
Expand Down
18 changes: 18 additions & 0 deletions src/download_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
# include "BtConstants.h"
# include "ValueBaseBencodeParser.h"
#endif // ENABLE_BITTORRENT
#ifdef ENABLE_CONTROL_FILE
# include "TorrentAttribute.h"
# include "DefaultBtProgressInfoFile.h"
#endif // ENABLE_CONTROL_FILE

namespace aria2 {

Expand Down Expand Up @@ -445,7 +449,20 @@ class AccRequestGroup {
}
}
}

#endif // ENABLE_METALINK
#ifdef ENABLE_CONTROL_FILE
else if (!ignoreLocalPath_ && detector_.guessAria2ControlFile(uri))
{
// Extract hash and construct a magnet to feed into createBtMagentRequestGroup
const auto infoHash = DefaultBtProgressInfoFile::getInfoHash(uri);

auto torrent_attribute = std::make_unique<TorrentAttribute>();
torrent_attribute->infoHash = std::string(std::begin(infoHash), std::end(infoHash));
const auto magent = aria2::bittorrent::torrent2Magnet(torrent_attribute.get());

requestGroups_.push_back(createBtMagnetRequestGroup(magent, option_));
}
else {
if (throwOnError_) {
throw DL_ABORT_EX(fmt(MSG_UNRECOGNIZED_URI, uri.c_str()));
Expand All @@ -455,6 +472,7 @@ class AccRequestGroup {
}
}
}
#endif // ENABLE_CONTROL_FILE
};
} // namespace

Expand Down
4 changes: 2 additions & 2 deletions src/version_usage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void showUsage(const std::string& keyword,
const std::shared_ptr<OptionParser>& oparser, const Console& out)
{
out->printf(_("Usage: aria2c [OPTIONS] [URI | MAGNET | TORRENT_FILE |"
" METALINK_FILE]..."));
" METALINK_FILE | ARIA2_CONTROL_FILE]..."));
out->printf("\n");
if (keyword.empty()) {
// Very short version of usage.
Expand Down Expand Up @@ -139,7 +139,7 @@ void showUsage(const std::string& keyword,
}
}
if (keyword == strHelpTag(TAG_BASIC)) {
out->printf("URI, MAGNET, TORRENT_FILE, METALINK_FILE:\n");
out->printf("URI, MAGNET, TORRENT_FILE, METALINK_FILE, ARIA2_CONTROL_FILE:\n");
out->printf(
_(" You can specify multiple HTTP(S)/FTP URIs. Unless you specify -Z "
"option, all\n"
Expand Down
10 changes: 10 additions & 0 deletions test/ProtocolDetectorTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ProtocolDetectorTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testGuessTorrentFile);
CPPUNIT_TEST(testGuessTorrentMagnet);
CPPUNIT_TEST(testGuessMetalinkFile);
CPPUNIT_TEST(testGuessAria2ControlFile);
CPPUNIT_TEST_SUITE_END();

public:
Expand All @@ -25,6 +26,7 @@ class ProtocolDetectorTest : public CppUnit::TestFixture {
void testGuessTorrentFile();
void testGuessTorrentMagnet();
void testGuessMetalinkFile();
void testGuessAria2ControlFile();
};

CPPUNIT_TEST_SUITE_REGISTRATION(ProtocolDetectorTest);
Expand Down Expand Up @@ -66,4 +68,12 @@ void ProtocolDetectorTest::testGuessMetalinkFile()
CPPUNIT_ASSERT(!detector.guessMetalinkFile(A2_TEST_DIR "/test.torrent"));
}

void ProtocolDetectorTest::testGuessAria2ControlFile()
{
const ProtocolDetector detector;
CPPUNIT_ASSERT(detector.guessAria2ControlFile(A2_TEST_DIR "/control_file.aria2"));
CPPUNIT_ASSERT(!detector.guessAria2ControlFile(A2_TEST_DIR));
CPPUNIT_ASSERT(!detector.guessAria2ControlFile(A2_TEST_DIR "/control_file.aria"));
}

} // namespace aria2
Binary file added test/control_file.aria
Binary file not shown.
Binary file added test/control_file.aria2
Binary file not shown.