Browse Source

2007-11-06 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Now a file is stored in the directory specified in .metalnk file
	(file[@name]).
	* src/Metalink2RequestGroup.cc

	Create the directory structure when opening the file if it 
doesn't
	exist.
	* src/AbstractDiskWriter.cc
	* src/Util.{h, cc}
	* src/File.h
	* test/UtilTest.cc
	
	Removed file name comparison
	* src/Metalink2RequestGroup.cc
	* src/HttpResponseCommand.cc

	Rewritten using Util::mkdirs()
	* src/FileEntry.cc (setupDir)
	* test/FileEntryTest.cc
	
	Updated doc
	* src/SingleFileDownloadContext.h
Tatsuhiro Tsujikawa 18 years ago
parent
commit
52b43151c6

+ 24 - 0
ChangeLog

@@ -1,3 +1,27 @@
+2007-11-06  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Now a file is stored in the directory specified in .metalnk file
+	(file[@name]).
+	* src/Metalink2RequestGroup.cc
+
+	Create the directory structure when opening the file if it doesn't
+	exist.
+	* src/AbstractDiskWriter.cc
+	* src/Util.{h, cc}
+	* src/File.h
+	* test/UtilTest.cc
+	
+	Removed file name comparison
+	* src/Metalink2RequestGroup.cc
+	* src/HttpResponseCommand.cc
+
+	Rewritten using Util::mkdirs()
+	* src/FileEntry.cc (setupDir)
+	* test/FileEntryTest.cc
+	
+	Updated doc
+	* src/SingleFileDownloadContext.h
+	
 2007-11-05  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Now SleepCommand dispatches nextCommand when halt is requested.

+ 1 - 1
TODO

@@ -53,4 +53,4 @@
 * Implement duplicate download checking in Bt
 * improve --metalink-location field
 * Use content-type for PostDownloadHandler
-* Fix SleepCommand to catch halt signal
+

+ 1 - 4
src/AbstractDiskWriter.cc

@@ -92,11 +92,8 @@ void AbstractDiskWriter::createFile(const string& filename, int32_t addFlags)
   throw(DlAbortEx*)
 {
   this->filename = filename;
-  // TODO proper filename handling needed
   assert(filename.size());
-//   if(filename.empty()) {
-//     filename = "index.html";
-//   }
+  Util::mkdirs(File(filename).getDirname());
   if((fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags, OPEN_MODE)) < 0) {
     throw new DlAbortEx(EX_FILE_OPEN, filename.c_str(), strerror(errno));
   }  

+ 5 - 0
src/File.h

@@ -95,6 +95,11 @@ public:
 
   string getDirname() const;
 
+  const string& getPath() const
+  {
+    return name;
+  }
+
   static bool isDir(const string& filename);
 
   bool renameTo(const string& dest);

+ 2 - 16
src/FileEntry.cc

@@ -34,7 +34,7 @@
 /* copyright --> */
 #include "FileEntry.h"
 #include "File.h"
-#include "DlAbortEx.h"
+#include "Util.h"
 #include <libgen.h>
 
 FileEntry::FileEntry(const string& path,
@@ -48,21 +48,7 @@ FileEntry::~FileEntry() {}
 
 void FileEntry::setupDir(const string& parentDir)
 {
-  string absPath = parentDir+"/"+path;
-  char* temp = strdup(absPath.c_str());
-  string dir = string(dirname(temp));
-  free(temp);
-  if(!dir.size()) {
-    return;
-  }
-  File f(dir);
-  if(f.isDir()) {
-    // nothing to do
-  } else if(f.exists()) {
-    throw new DlAbortEx("%s is not a directory.", dir.c_str());
-  } else if(!f.mkdirs()) {
-    throw new DlAbortEx("Failed to create directory %s.", dir.c_str());
-  }  
+  Util::mkdirs(File(parentDir+"/"+path).getDirname());
 }
 
 FileEntry& FileEntry::operator=(const FileEntry& entry)

+ 0 - 2
src/HttpResponseCommand.cc

@@ -91,14 +91,12 @@ bool HttpResponseCommand::executeInternal()
   }
   if(!_requestGroup->getPieceStorage().isNull()) {
     // validate totalsize
-    _requestGroup->validateFilename(httpResponse->determinFilename());
     _requestGroup->validateTotalLength(httpResponse->getEntityLength());
 
     e->commands.push_back(createHttpDownloadCommand(httpResponse));
     return true;
   } else {
     // validate totalsize against hintTotalSize if it is provided.
-    _requestGroup->validateFilenameByHint(httpResponse->determinFilename());
     _requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength());
 
     SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setFilename(httpResponse->determinFilename());

+ 2 - 2
src/Metalink2RequestGroup.cc

@@ -159,7 +159,8 @@ RequestGroups Metalink2RequestGroup::generate(const string& metalinkFile)
     SingleFileDownloadContextHandle dctx =
       new SingleFileDownloadContext(pieceLength,
 				    0,
-				    "");
+				    "",
+				    entry->file->getPath());
     dctx->setDir(_option->get(PREF_DIR));
     if(!entry->chunkChecksum.isNull()) {
       dctx->setPieceHashes(entry->chunkChecksum->getChecksums());
@@ -169,7 +170,6 @@ RequestGroups Metalink2RequestGroup::generate(const string& metalinkFile)
     // * hash and hash algorithm
 
     rg->setDownloadContext(dctx);
-    rg->setHintFilename(entry->file->getBasename());
     rg->setHintTotalLength(entry->getLength());
     rg->setNumConcurrentCommand(entry->maxConnections < 0 ?
 				_option->getAsInt(PREF_METALINK_SERVERS) :

+ 4 - 0
src/SingleFileDownloadContext.h

@@ -46,6 +46,10 @@ private:
    * If _ufilename is not zero-length string, then _dir + _ufilename.
    */
   FileEntryHandle _fileEntry;
+  /**
+   * _filename and _ufilename may contains directory path name.
+   * So usr/local/aria2c is acceptable here.
+   */
   string _filename;
   string _ufilename;
 

+ 11 - 0
src/Util.cc

@@ -763,3 +763,14 @@ int32_t Util::alphaToNum(const string& alphabets)
   return num;
 }
 
+void Util::mkdirs(const string& dirpath)
+{
+  File dir(dirpath);
+  if(dir.isDir()) {
+    // do nothing
+  } else if(dir.exists()) {
+    throw new DlAbortEx(EX_MAKE_DIR, dir.getPath().c_str(), "File already exists.");
+  } else if(!dir.mkdirs()) {
+    throw new DlAbortEx(EX_MAKE_DIR, dir.getPath().c_str(), strerror(errno));
+  }
+}

+ 2 - 0
src/Util.h

@@ -150,6 +150,8 @@ public:
   static bool isUppercase(const string& what);
 
   static int32_t alphaToNum(const string& alphabets);
+
+  static void mkdirs(const string& dirpath);
 };
 
 #endif // _D_UTIL_H_

+ 34 - 0
test/FileEntryTest.cc

@@ -0,0 +1,34 @@
+#include "FileEntry.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+class FileEntryTest : public CppUnit::TestFixture {
+  
+  CPPUNIT_TEST_SUITE(FileEntryTest);
+  CPPUNIT_TEST(testSetupDir);
+  CPPUNIT_TEST_SUITE_END();
+public:
+  void setUp() {}
+  
+  void testSetupDir();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( FileEntryTest );
+
+void FileEntryTest::testSetupDir()
+{
+  string topDir = "/tmp";
+  string dir = "aria2-FileEntryTest-testSetupDir";
+  string filename = "filename";
+  string path = topDir+"/"+dir+"/"+filename;
+  File d(topDir+"/"+dir);
+  if(d.exists()) {
+    CPPUNIT_ASSERT(d.remove());
+  }
+  CPPUNIT_ASSERT(!d.exists());
+  FileEntry fileEntry(dir+"/"+filename, 0, 0);
+  fileEntry.setupDir(topDir);
+  CPPUNIT_ASSERT(d.isDir());
+  File f(path);
+  CPPUNIT_ASSERT(!f.exists());
+}

+ 1 - 0
test/Makefile.am

@@ -1,6 +1,7 @@
 TESTS = aria2c
 check_PROGRAMS = $(TESTS)
 aria2c_SOURCES = AllTest.cc\
+	FileEntryTest.cc\
 	PieceTest.cc\
 	DefaultPieceStorageTest.cc\
 	SegmentTest.cc\

+ 7 - 6
test/Makefile.in

@@ -112,7 +112,7 @@ 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 PieceTest.cc \
+am__aria2c_SOURCES_DIST = AllTest.cc FileEntryTest.cc PieceTest.cc \
 	DefaultPieceStorageTest.cc SegmentTest.cc GrowSegmentTest.cc \
 	SingleFileAllocationIteratorTest.cc \
 	DefaultBtProgressInfoFileTest.cc \
@@ -203,9 +203,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc PieceTest.cc \
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroupTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkPostDownloadHandlerTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkHelperTest.$(OBJEXT)
-am_aria2c_OBJECTS = AllTest.$(OBJEXT) PieceTest.$(OBJEXT) \
-	DefaultPieceStorageTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
-	GrowSegmentTest.$(OBJEXT) \
+am_aria2c_OBJECTS = AllTest.$(OBJEXT) FileEntryTest.$(OBJEXT) \
+	PieceTest.$(OBJEXT) DefaultPieceStorageTest.$(OBJEXT) \
+	SegmentTest.$(OBJEXT) GrowSegmentTest.$(OBJEXT) \
 	SingleFileAllocationIteratorTest.$(OBJEXT) \
 	DefaultBtProgressInfoFileTest.$(OBJEXT) \
 	SingleFileDownloadContextTest.$(OBJEXT) \
@@ -414,8 +414,8 @@ target_cpu = @target_cpu@
 target_os = @target_os@
 target_vendor = @target_vendor@
 TESTS = aria2c
-aria2c_SOURCES = AllTest.cc PieceTest.cc DefaultPieceStorageTest.cc \
-	SegmentTest.cc GrowSegmentTest.cc \
+aria2c_SOURCES = AllTest.cc FileEntryTest.cc PieceTest.cc \
+	DefaultPieceStorageTest.cc SegmentTest.cc GrowSegmentTest.cc \
 	SingleFileAllocationIteratorTest.cc \
 	DefaultBtProgressInfoFileTest.cc \
 	SingleFileDownloadContextTest.cc RequestGroupTest.cc \
@@ -540,6 +540,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DictionaryTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfigTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntryTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileUriListParserTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegmentTest.Po@am__quote@

+ 25 - 0
test/UtilTest.cc

@@ -28,6 +28,7 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testIsLowercase);
   CPPUNIT_TEST(testIsUppercase);
   CPPUNIT_TEST(testAlphaToNum);
+  CPPUNIT_TEST(testMkdirs);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -55,6 +56,7 @@ public:
   void testIsLowercase();
   void testIsUppercase();
   void testAlphaToNum();
+  void testMkdirs();
 };
 
 
@@ -364,3 +366,26 @@ void UtilTest::testAlphaToNum()
   CPPUNIT_ASSERT_EQUAL((int32_t)675, Util::alphaToNum("ZZ")); // 25*26+25
   CPPUNIT_ASSERT_EQUAL((int32_t)0, Util::alphaToNum(""));
 }
+
+void UtilTest::testMkdirs()
+{
+  string dir = "/tmp/aria2-UtilTest-testMkdirs";
+  File d(dir);
+  if(d.exists()) {
+    CPPUNIT_ASSERT(d.remove());
+  }
+  CPPUNIT_ASSERT(!d.exists());
+  Util::mkdirs(dir);
+  CPPUNIT_ASSERT(d.isDir());
+
+  string file = "./UtilTest.cc";
+  File f(file);
+  CPPUNIT_ASSERT(f.isFile());
+  try {
+    Util::mkdirs(file);
+    CPPUNIT_FAIL("exception must be thrown.");
+  } catch(DlAbortEx* ex) {
+    cerr << ex->getMsg() << endl;
+    delete ex;
+  }
+}