From f8aab322fc33194e8886eb630a01acda6c19e76b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 28 Aug 2007 15:46:49 +0000 Subject: [PATCH] 2007-08-28 Tatsuhiro Tsujikawa 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. --- ChangeLog | 16 ++++++++++++++ src/FtpNegotiationCommand.cc | 5 ----- src/HttpResponseCommand.cc | 4 ---- src/OptionHandlerFactory.cc | 1 + src/RequestGroup.cc | 41 ++++++++++++++++++++++++++++++------ src/RequestGroup.h | 2 ++ src/SegmentMan.cc | 5 ----- src/SegmentMan.h | 2 -- src/main.cc | 31 ++++++++++++++++++++++----- src/prefs.h | 2 ++ test/Makefile.am | 1 + test/Makefile.in | 27 ++++++++++++------------ 12 files changed, 97 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2c1cb9f2..cd5c7af2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,22 @@ Added '\n' after the error message * 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 diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index bd497228..4b5c3008 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -196,11 +196,6 @@ bool FtpNegotiationCommand::recvSize() { // TODO validate filename and totalsize against hintFilename and hintTotalSize if these are provided. _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) { _requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved. sequence = SEQ_HEAD_OK; diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 3f5f5bcc..8a29619a 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -100,10 +100,6 @@ bool HttpResponseCommand::executeInternal() _requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength()); _requestGroup->getSegmentMan()->filename = httpResponse->determinFilename(); - if(e->_requestGroupMan->isSameFileBeingDownloaded(_requestGroup)) { - throw new FatalException(EX_DUPLICATE_FILE_DOWNLOAD, _requestGroup->getFilePath().c_str()); - } - if(httpResponse->isTransferEncodingSpecified()) { return handleOtherEncoding(httpResponse); } else { diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index c3d466d5..527df1dd 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -95,6 +95,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() handlers.push_back(new DefaultOptionHandler(PREF_LOAD_COOKIES)); handlers.push_back(new DefaultOptionHandler(PREF_PEER_ID_PREFIX)); handlers.push_back(new BooleanOptionHandler(PREF_FORCE_SEQUENTIAL)); + handlers.push_back(new BooleanOptionHandler(PREF_AUTO_FILE_RENAMING)); return handlers; } diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index ca4e850c..01e95a40 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -115,12 +115,22 @@ void RequestGroup::markPieceDone(int64_t length) void RequestGroup::shouldCancelDownloadForSafety() { - if(_segmentMan->shouldCancelDownloadForSafety()) { - logger->notice(MSG_FILE_ALREADY_EXISTS, - _segmentMan->getFilePath().c_str(), - _segmentMan->getSegmentFilePath().c_str()); - - throw new FatalException(EX_DOWNLOAD_ABORTED); + if(fileExists() && !segmentFileExists()) { + if(_option->get(PREF_AUTO_FILE_RENAMING) == V_TRUE) { + if(tryAutoFileRenaming()) { + logger->notice("File already exists. Renamed to %s.", + getFilePath().c_str()); + } 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(); } + +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; +} diff --git a/src/RequestGroup.h b/src/RequestGroup.h index ff7f31cc..83317786 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -312,6 +312,8 @@ public: { return _segmentMan->calculateDownloadSpeed(); } + + bool tryAutoFileRenaming(); }; typedef SharedHandle RequestGroupHandle; diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 7ad4f984..9b88585a 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -431,11 +431,6 @@ bool SegmentMan::fileExists() const { return File(getFilePath()).exists(); } -bool SegmentMan::shouldCancelDownloadForSafety() const { - return fileExists() && !segmentFileExists() && - option->get(PREF_ALLOW_OVERWRITE) != V_TRUE; -} - void SegmentMan::markAllPiecesDone() { if(bitfield) { diff --git a/src/SegmentMan.h b/src/SegmentMan.h index 7e877e6a..fc67214a 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -282,8 +282,6 @@ public: bool fileExists() const; - bool shouldCancelDownloadForSafety() const; - void markAllPiecesDone(); void markPieceDone(int64_t length); diff --git a/src/main.cc b/src/main.cc index 4b79ce2c..2838a2f6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -196,10 +196,15 @@ void showUsage() { " already exists but the corresponding .aria2 file\n" " doesn't exist.\n" " 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" - " 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 cout << _(" --check-integrity=true|false Check file integrity by validating piece hash.\n" " This option only affects in BitTorrent downloads\n" @@ -358,6 +363,17 @@ Strings unfoldURI(const Strings& args) 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[]) { #ifdef HAVE_WINSOCK2_H Platform platform; @@ -425,6 +441,7 @@ int main(int argc, char* argv[]) { op->put(PREF_MAX_CONCURRENT_DOWNLOADS, "5"); op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15"); op->put(PREF_FORCE_SEQUENTIAL, V_FALSE); + op->put(PREF_AUTO_FILE_RENAMING, V_TRUE); while(1) { int optIndex = 0; int lopt; @@ -457,7 +474,6 @@ int main(int argc, char* argv[]) { { "max-download-limit", required_argument, &lopt, 201 }, { "file-allocation", required_argument, 0, 'a' }, { "allow-overwrite", required_argument, &lopt, 202 }, - { "force-sequential", no_argument, 0, 'Z' }, #ifdef ENABLE_MESSAGE_DIGEST { "check-integrity", required_argument, &lopt, 203 }, { "realtime-chunk-checksum", required_argument, &lopt, 204 }, @@ -468,6 +484,8 @@ int main(int argc, char* argv[]) { { "input-file", required_argument, 0, 'i' }, { "max-concurrent-downloads", required_argument, 0, 'j' }, { "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 { "show-files", no_argument, NULL, 'S' }, { "select-file", required_argument, &lopt, 21 }, @@ -606,6 +624,9 @@ int main(int argc, char* argv[]) { case 205: cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n"; break; + case 206: + cmdstream << PREF_AUTO_FILE_RENAMING << "=" << toBoolArg(optarg) << "\n"; + break; } break; } @@ -666,7 +687,7 @@ int main(int argc, char* argv[]) { cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n"; break; case 'Z': - cmdstream << PREF_FORCE_SEQUENTIAL << "=" << V_TRUE << "\n"; + cmdstream << PREF_FORCE_SEQUENTIAL << "=" << toBoolArg(optarg) << "\n"; break; case 'v': showVersion(); diff --git a/src/prefs.h b/src/prefs.h index 4ad48643..68d4a983 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -109,6 +109,8 @@ #define PREF_DIRECT_DOWNLOAD_TIMEOUT "direct-download-timeout" // value: #define PREF_FORCE_SEQUENTIAL "force-sequential" +// value: +#define PREF_AUTO_FILE_RENAMING "auto-file-renaming" /** * FTP related preferences diff --git a/test/Makefile.am b/test/Makefile.am index 4d88f52c..16308915 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,7 @@ TESTS = aria2c check_PROGRAMS = $(TESTS) aria2c_SOURCES = AllTest.cc\ + RequestGroupTest.cc\ PStringBuildVisitorTest.cc\ ParameterizedStringParserTest.cc\ UtilTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index 84b59c80..4346d2f2 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -110,12 +110,12 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__EXEEXT_1 = aria2c$(EXEEXT) -am__aria2c_SOURCES_DIST = AllTest.cc PStringBuildVisitorTest.cc \ - ParameterizedStringParserTest.cc UtilTest.cc \ - AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ - StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ - CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ - HttpRequestTest.cc CookieBoxFactoryTest.cc \ +am__aria2c_SOURCES_DIST = AllTest.cc RequestGroupTest.cc \ + PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ + UtilTest.cc AlphaNumberDecoratorTest.cc \ + FileUriListParserTest.cc StreamUriListParserTest.cc \ + HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \ + CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.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@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Xml2MetalinkProcessorTest.$(OBJEXT) -am_aria2c_OBJECTS = AllTest.$(OBJEXT) \ +am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestGroupTest.$(OBJEXT) \ PStringBuildVisitorTest.$(OBJEXT) \ ParameterizedStringParserTest.$(OBJEXT) UtilTest.$(OBJEXT) \ AlphaNumberDecoratorTest.$(OBJEXT) \ @@ -403,12 +403,12 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ TESTS = aria2c -aria2c_SOURCES = AllTest.cc PStringBuildVisitorTest.cc \ - ParameterizedStringParserTest.cc UtilTest.cc \ - AlphaNumberDecoratorTest.cc FileUriListParserTest.cc \ - StreamUriListParserTest.cc HttpHeaderProcessorTest.cc \ - CookieBoxTest.cc RequestTest.cc CookieParserTest.cc \ - HttpRequestTest.cc CookieBoxFactoryTest.cc \ +aria2c_SOURCES = AllTest.cc RequestGroupTest.cc \ + PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \ + UtilTest.cc AlphaNumberDecoratorTest.cc \ + FileUriListParserTest.cc StreamUriListParserTest.cc \ + HttpHeaderProcessorTest.cc CookieBoxTest.cc RequestTest.cc \ + CookieParserTest.cc HttpRequestTest.cc CookieBoxFactoryTest.cc \ RequestGroupManTest.cc RequestFactoryTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.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)/RequestFactoryTest.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)/SegmentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@