From 52b43151c62f52cff557f126fcd7062559b09e0e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 5 Nov 2007 15:13:55 +0000 Subject: [PATCH] 2007-11-06 Tatsuhiro Tsujikawa 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 --- ChangeLog | 24 +++++++++++++++++++++++ TODO | 2 +- src/AbstractDiskWriter.cc | 5 +---- src/File.h | 5 +++++ src/FileEntry.cc | 18 ++--------------- src/HttpResponseCommand.cc | 2 -- src/Metalink2RequestGroup.cc | 4 ++-- src/SingleFileDownloadContext.h | 4 ++++ src/Util.cc | 11 +++++++++++ src/Util.h | 2 ++ test/FileEntryTest.cc | 34 +++++++++++++++++++++++++++++++++ test/Makefile.am | 1 + test/Makefile.in | 13 +++++++------ test/UtilTest.cc | 25 ++++++++++++++++++++++++ 14 files changed, 119 insertions(+), 31 deletions(-) create mode 100644 test/FileEntryTest.cc diff --git a/ChangeLog b/ChangeLog index 6878b1bc..38c2d52e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2007-11-06 Tatsuhiro Tsujikawa + + 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 Now SleepCommand dispatches nextCommand when halt is requested. diff --git a/TODO b/TODO index de39b6b4..69069328 100644 --- a/TODO +++ b/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 + diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index af509244..e70867d8 100644 --- a/src/AbstractDiskWriter.cc +++ b/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)); } diff --git a/src/File.h b/src/File.h index 36b93093..cecf66d5 100644 --- a/src/File.h +++ b/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); diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 14226b36..80b6cedc 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -34,7 +34,7 @@ /* copyright --> */ #include "FileEntry.h" #include "File.h" -#include "DlAbortEx.h" +#include "Util.h" #include 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) diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 9bc35758..fccaf648 100644 --- a/src/HttpResponseCommand.cc +++ b/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()); diff --git a/src/Metalink2RequestGroup.cc b/src/Metalink2RequestGroup.cc index 1b1f2653..e3001920 100644 --- a/src/Metalink2RequestGroup.cc +++ b/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) : diff --git a/src/SingleFileDownloadContext.h b/src/SingleFileDownloadContext.h index f980fb5e..43a9d403 100644 --- a/src/SingleFileDownloadContext.h +++ b/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; diff --git a/src/Util.cc b/src/Util.cc index 92fd7cce..8dd24f42 100644 --- a/src/Util.cc +++ b/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)); + } +} diff --git a/src/Util.h b/src/Util.h index ac3cfabd..dac5a148 100644 --- a/src/Util.h +++ b/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_ diff --git a/test/FileEntryTest.cc b/test/FileEntryTest.cc new file mode 100644 index 00000000..af1c3fd7 --- /dev/null +++ b/test/FileEntryTest.cc @@ -0,0 +1,34 @@ +#include "FileEntry.h" +#include + +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()); +} diff --git a/test/Makefile.am b/test/Makefile.am index 4fc2fa06..b9f8688d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,7 @@ TESTS = aria2c check_PROGRAMS = $(TESTS) aria2c_SOURCES = AllTest.cc\ + FileEntryTest.cc\ PieceTest.cc\ DefaultPieceStorageTest.cc\ SegmentTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index d29bf0a0..767f6869 100644 --- a/test/Makefile.in +++ b/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@ diff --git a/test/UtilTest.cc b/test/UtilTest.cc index dd12423e..0ad2c494 100644 --- a/test/UtilTest.cc +++ b/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; + } +}