2007-08-28 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Added auto file renaming feature in http(s)/ftp download.
	* src/main.cc: Added --auto-file-renaming command-line option.
	* src/OptionHandlerFactory.cc
	* src/prefs.h: Added PREF_AUTO_FILE_RENAMING
	* src/RequestGroup.{h, cc}
	(shouldCancelDownloadForSafety): Rewritten
	(tryAutoFileRenaming): New function.
	* src/SegmentMan.{h, cc} (shouldCancelDownloadForSafety): 
Removed.
	* src/HttpResponseCommand.cc
	(executeInternal): Removed the call to RequestGroupMan::
	isSameFileBeingDownloaded()
	* src/FtpNegotiateCommand.cc
	(recvSize): Removed the call to RequestGroupMan::
	isSameFileBeingDownloaded()
	* test/RequestGroupTest.cc: New class.
pull/1/head
Tatsuhiro Tsujikawa 2007-08-28 15:46:49 +00:00
parent 7fb4336d5e
commit f8aab322fc
12 changed files with 97 additions and 40 deletions

View File

@ -30,6 +30,22 @@
Added '\n' after the error message Added '\n' after the error message
* src/RequestInfo.h (printDownloadAbortMessage) * src/RequestInfo.h (printDownloadAbortMessage)
Added auto file renaming feature in http(s)/ftp download.
* src/main.cc: Added --auto-file-renaming command-line option.
* src/OptionHandlerFactory.cc
* src/prefs.h: Added PREF_AUTO_FILE_RENAMING
* src/RequestGroup.{h, cc}
(shouldCancelDownloadForSafety): Rewritten
(tryAutoFileRenaming): New function.
* src/SegmentMan.{h, cc} (shouldCancelDownloadForSafety): Removed.
* src/HttpResponseCommand.cc
(executeInternal): Removed the call to RequestGroupMan::
isSameFileBeingDownloaded()
* src/FtpNegotiateCommand.cc
(recvSize): Removed the call to RequestGroupMan::
isSameFileBeingDownloaded()
* test/RequestGroupTest.cc: New class.
2007-08-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com> 2007-08-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

View File

@ -196,11 +196,6 @@ bool FtpNegotiationCommand::recvSize() {
// TODO validate filename and totalsize against hintFilename and hintTotalSize if these are provided. // TODO validate filename and totalsize against hintFilename and hintTotalSize if these are provided.
_requestGroup->validateTotalLengthByHint(size); _requestGroup->validateTotalLengthByHint(size);
if(e->_requestGroupMan->isSameFileBeingDownloaded(_requestGroup)) {
throw new FatalException(EX_DUPLICATE_FILE_DOWNLOAD, _requestGroup->getFilePath().c_str());
}
if(req->getMethod() == Request::METHOD_HEAD) { if(req->getMethod() == Request::METHOD_HEAD) {
_requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved. _requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved.
sequence = SEQ_HEAD_OK; sequence = SEQ_HEAD_OK;

View File

@ -100,10 +100,6 @@ bool HttpResponseCommand::executeInternal()
_requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength()); _requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength());
_requestGroup->getSegmentMan()->filename = httpResponse->determinFilename(); _requestGroup->getSegmentMan()->filename = httpResponse->determinFilename();
if(e->_requestGroupMan->isSameFileBeingDownloaded(_requestGroup)) {
throw new FatalException(EX_DUPLICATE_FILE_DOWNLOAD, _requestGroup->getFilePath().c_str());
}
if(httpResponse->isTransferEncodingSpecified()) { if(httpResponse->isTransferEncodingSpecified()) {
return handleOtherEncoding(httpResponse); return handleOtherEncoding(httpResponse);
} else { } else {

View File

@ -95,6 +95,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
handlers.push_back(new DefaultOptionHandler(PREF_LOAD_COOKIES)); handlers.push_back(new DefaultOptionHandler(PREF_LOAD_COOKIES));
handlers.push_back(new DefaultOptionHandler(PREF_PEER_ID_PREFIX)); handlers.push_back(new DefaultOptionHandler(PREF_PEER_ID_PREFIX));
handlers.push_back(new BooleanOptionHandler(PREF_FORCE_SEQUENTIAL)); handlers.push_back(new BooleanOptionHandler(PREF_FORCE_SEQUENTIAL));
handlers.push_back(new BooleanOptionHandler(PREF_AUTO_FILE_RENAMING));
return handlers; return handlers;
} }

View File

@ -115,12 +115,22 @@ void RequestGroup::markPieceDone(int64_t length)
void RequestGroup::shouldCancelDownloadForSafety() void RequestGroup::shouldCancelDownloadForSafety()
{ {
if(_segmentMan->shouldCancelDownloadForSafety()) { if(fileExists() && !segmentFileExists()) {
logger->notice(MSG_FILE_ALREADY_EXISTS, if(_option->get(PREF_AUTO_FILE_RENAMING) == V_TRUE) {
_segmentMan->getFilePath().c_str(), if(tryAutoFileRenaming()) {
_segmentMan->getSegmentFilePath().c_str()); logger->notice("File already exists. Renamed to %s.",
getFilePath().c_str());
throw new FatalException(EX_DOWNLOAD_ABORTED); } else {
logger->notice("File renaming failed: %s",
_segmentMan->getFilePath().c_str());
throw new FatalException(EX_DOWNLOAD_ABORTED);
}
} else if(_option->get(PREF_ALLOW_OVERWRITE) != V_TRUE) {
logger->notice(MSG_FILE_ALREADY_EXISTS,
_segmentMan->getFilePath().c_str(),
_segmentMan->getSegmentFilePath().c_str());
throw new FatalException(EX_DOWNLOAD_ABORTED);
}
} }
} }
@ -303,3 +313,22 @@ int64_t RequestGroup::getExistingFileLength() const
{ {
return File(getFilePath()).size(); return File(getFilePath()).size();
} }
bool RequestGroup::tryAutoFileRenaming()
{
string filepath = getFilePath();
if(filepath.empty()) {
return false;
}
for(int32_t i = 1; i < 10000; ++i) {
File newfile(filepath+"."+Util::itos(i));
if(!newfile.exists()) {
_ufilename = newfile.getBasename();
if(!_segmentMan.isNull()) {
_segmentMan->ufilename = _ufilename;
}
return true;
}
}
return false;
}

View File

@ -312,6 +312,8 @@ public:
{ {
return _segmentMan->calculateDownloadSpeed(); return _segmentMan->calculateDownloadSpeed();
} }
bool tryAutoFileRenaming();
}; };
typedef SharedHandle<RequestGroup> RequestGroupHandle; typedef SharedHandle<RequestGroup> RequestGroupHandle;

View File

@ -431,11 +431,6 @@ bool SegmentMan::fileExists() const {
return File(getFilePath()).exists(); return File(getFilePath()).exists();
} }
bool SegmentMan::shouldCancelDownloadForSafety() const {
return fileExists() && !segmentFileExists() &&
option->get(PREF_ALLOW_OVERWRITE) != V_TRUE;
}
void SegmentMan::markAllPiecesDone() void SegmentMan::markAllPiecesDone()
{ {
if(bitfield) { if(bitfield) {

View File

@ -282,8 +282,6 @@ public:
bool fileExists() const; bool fileExists() const;
bool shouldCancelDownloadForSafety() const;
void markAllPiecesDone(); void markAllPiecesDone();
void markPieceDone(int64_t length); void markPieceDone(int64_t length);

View File

@ -196,10 +196,15 @@ void showUsage() {
" already exists but the corresponding .aria2 file\n" " already exists but the corresponding .aria2 file\n"
" doesn't exist.\n" " doesn't exist.\n"
" Default: false") << endl; " Default: false") << endl;
cout << _(" -Z, --force-sequential Fetch URIs in the command-line sequentially and\n" cout << _(" -Z, --force-sequential[=true|false] Fetch URIs in the command-line sequentially and\n"
" download each URI in a separate session, like\n" " download each URI in a separate session, like\n"
" the usual command-line download utilities.") << endl; " the usual command-line download utilities.\n"
" Default: false") << endl;
cout << _(" --auto-file-renaming[=true|false] Rename file name if the same file already\n"
" exists. This option works only in http(s)/ftp\n"
" download.\n"
" The new file name has a dot and a number(1..9999)\n"
" appended. Default: true") << endl;
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
cout << _(" --check-integrity=true|false Check file integrity by validating piece hash.\n" cout << _(" --check-integrity=true|false Check file integrity by validating piece hash.\n"
" This option only affects in BitTorrent downloads\n" " This option only affects in BitTorrent downloads\n"
@ -358,6 +363,17 @@ Strings unfoldURI(const Strings& args)
return nargs; return nargs;
} }
string toBoolArg(const char* optarg)
{
string arg;
if(!optarg || string(optarg) == "") {
arg = V_TRUE;
} else {
arg = optarg;
}
return arg;
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
#ifdef HAVE_WINSOCK2_H #ifdef HAVE_WINSOCK2_H
Platform platform; Platform platform;
@ -425,6 +441,7 @@ int main(int argc, char* argv[]) {
op->put(PREF_MAX_CONCURRENT_DOWNLOADS, "5"); op->put(PREF_MAX_CONCURRENT_DOWNLOADS, "5");
op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15"); op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15");
op->put(PREF_FORCE_SEQUENTIAL, V_FALSE); op->put(PREF_FORCE_SEQUENTIAL, V_FALSE);
op->put(PREF_AUTO_FILE_RENAMING, V_TRUE);
while(1) { while(1) {
int optIndex = 0; int optIndex = 0;
int lopt; int lopt;
@ -457,7 +474,6 @@ int main(int argc, char* argv[]) {
{ "max-download-limit", required_argument, &lopt, 201 }, { "max-download-limit", required_argument, &lopt, 201 },
{ "file-allocation", required_argument, 0, 'a' }, { "file-allocation", required_argument, 0, 'a' },
{ "allow-overwrite", required_argument, &lopt, 202 }, { "allow-overwrite", required_argument, &lopt, 202 },
{ "force-sequential", no_argument, 0, 'Z' },
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
{ "check-integrity", required_argument, &lopt, 203 }, { "check-integrity", required_argument, &lopt, 203 },
{ "realtime-chunk-checksum", required_argument, &lopt, 204 }, { "realtime-chunk-checksum", required_argument, &lopt, 204 },
@ -468,6 +484,8 @@ int main(int argc, char* argv[]) {
{ "input-file", required_argument, 0, 'i' }, { "input-file", required_argument, 0, 'i' },
{ "max-concurrent-downloads", required_argument, 0, 'j' }, { "max-concurrent-downloads", required_argument, 0, 'j' },
{ "load-cookies", required_argument, &lopt, 205 }, { "load-cookies", required_argument, &lopt, 205 },
{ "force-sequential", optional_argument, 0, 'Z' },
{ "auto-file-renaming", optional_argument, &lopt, 206 },
#if defined ENABLE_BITTORRENT || ENABLE_METALINK #if defined ENABLE_BITTORRENT || ENABLE_METALINK
{ "show-files", no_argument, NULL, 'S' }, { "show-files", no_argument, NULL, 'S' },
{ "select-file", required_argument, &lopt, 21 }, { "select-file", required_argument, &lopt, 21 },
@ -606,6 +624,9 @@ int main(int argc, char* argv[]) {
case 205: case 205:
cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n"; cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n";
break; break;
case 206:
cmdstream << PREF_AUTO_FILE_RENAMING << "=" << toBoolArg(optarg) << "\n";
break;
} }
break; break;
} }
@ -666,7 +687,7 @@ int main(int argc, char* argv[]) {
cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n"; cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n";
break; break;
case 'Z': case 'Z':
cmdstream << PREF_FORCE_SEQUENTIAL << "=" << V_TRUE << "\n"; cmdstream << PREF_FORCE_SEQUENTIAL << "=" << toBoolArg(optarg) << "\n";
break; break;
case 'v': case 'v':
showVersion(); showVersion();

View File

@ -109,6 +109,8 @@
#define PREF_DIRECT_DOWNLOAD_TIMEOUT "direct-download-timeout" #define PREF_DIRECT_DOWNLOAD_TIMEOUT "direct-download-timeout"
// value: // value:
#define PREF_FORCE_SEQUENTIAL "force-sequential" #define PREF_FORCE_SEQUENTIAL "force-sequential"
// value:
#define PREF_AUTO_FILE_RENAMING "auto-file-renaming"
/** /**
* FTP related preferences * FTP related preferences

View File

@ -1,6 +1,7 @@
TESTS = aria2c TESTS = aria2c
check_PROGRAMS = $(TESTS) check_PROGRAMS = $(TESTS)
aria2c_SOURCES = AllTest.cc\ aria2c_SOURCES = AllTest.cc\
RequestGroupTest.cc\
PStringBuildVisitorTest.cc\ PStringBuildVisitorTest.cc\
ParameterizedStringParserTest.cc\ ParameterizedStringParserTest.cc\
UtilTest.cc\ UtilTest.cc\

View File

@ -110,12 +110,12 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES = CONFIG_CLEAN_FILES =
am__EXEEXT_1 = aria2c$(EXEEXT) am__EXEEXT_1 = aria2c$(EXEEXT)
am__aria2c_SOURCES_DIST = AllTest.cc PStringBuildVisitorTest.cc \ am__aria2c_SOURCES_DIST = AllTest.cc RequestGroupTest.cc \
ParameterizedStringParserTest.cc UtilTest.cc \ PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \
AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ UtilTest.cc AlphaNumberDecoratorTest.cc \
StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ FileUriListParserTest.cc StreamUriListParserTest.cc \
CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \
HttpRequestTest.cc CookieBoxFactoryTest.cc \ CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \
RequestGroupManTest.cc RequestFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \
NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \
OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
@ -195,7 +195,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc PStringBuildVisitorTest.cc \
@ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \
@ENABLE_METALINK_TRUE@ Xml2MetalinkProcessorTest.$(OBJEXT) @ENABLE_METALINK_TRUE@ Xml2MetalinkProcessorTest.$(OBJEXT)
am_aria2c_OBJECTS = AllTest.$(OBJEXT) \ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestGroupTest.$(OBJEXT) \
PStringBuildVisitorTest.$(OBJEXT) \ PStringBuildVisitorTest.$(OBJEXT) \
ParameterizedStringParserTest.$(OBJEXT) UtilTest.$(OBJEXT) \ ParameterizedStringParserTest.$(OBJEXT) UtilTest.$(OBJEXT) \
AlphaNumberDecoratorTest.$(OBJEXT) \ AlphaNumberDecoratorTest.$(OBJEXT) \
@ -403,12 +403,12 @@ target_cpu = @target_cpu@
target_os = @target_os@ target_os = @target_os@
target_vendor = @target_vendor@ target_vendor = @target_vendor@
TESTS = aria2c TESTS = aria2c
aria2c_SOURCES = AllTest.cc PStringBuildVisitorTest.cc \ aria2c_SOURCES = AllTest.cc RequestGroupTest.cc \
ParameterizedStringParserTest.cc UtilTest.cc \ PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \
AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ UtilTest.cc AlphaNumberDecoratorTest.cc \
StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ FileUriListParserTest.cc StreamUriListParserTest.cc \
CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \
HttpRequestTest.cc CookieBoxFactoryTest.cc \ CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \
RequestGroupManTest.cc RequestFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \
NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \
OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
@ -548,6 +548,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestFactoryTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupManTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentManTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@