Ver código fonte

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.
Tatsuhiro Tsujikawa 18 anos atrás
pai
commit
f8aab322fc

+ 16 - 0
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  <tujikawa at rednoah dot com>
 

+ 0 - 5
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;

+ 0 - 4
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 {

+ 1 - 0
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;
 }

+ 35 - 6
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;
+}

+ 2 - 0
src/RequestGroup.h

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

+ 0 - 5
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) {

+ 0 - 2
src/SegmentMan.h

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

+ 26 - 5
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();

+ 2 - 0
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

+ 1 - 0
test/Makefile.am

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

+ 14 - 13
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@