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
pull/1/head
Tatsuhiro Tsujikawa 2007-11-05 15:13:55 +00:00
parent bcbadb3b6b
commit 52b43151c6
14 changed files with 119 additions and 31 deletions

View File

@ -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> 2007-11-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Now SleepCommand dispatches nextCommand when halt is requested. Now SleepCommand dispatches nextCommand when halt is requested.

2
TODO
View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@
/* copyright --> */ /* copyright --> */
#include "FileEntry.h" #include "FileEntry.h"
#include "File.h" #include "File.h"
#include "DlAbortEx.h" #include "Util.h"
#include <libgen.h> #include <libgen.h>
FileEntry::FileEntry(const string& path, FileEntry::FileEntry(const string& path,
@ -48,21 +48,7 @@ FileEntry::~FileEntry() {}
void FileEntry::setupDir(const string& parentDir) void FileEntry::setupDir(const string& parentDir)
{ {
string absPath = parentDir+"/"+path; Util::mkdirs(File(parentDir+"/"+path).getDirname());
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());
}
} }
FileEntry& FileEntry::operator=(const FileEntry& entry) FileEntry& FileEntry::operator=(const FileEntry& entry)

View File

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

View File

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

View File

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

View File

@ -763,3 +763,14 @@ int32_t Util::alphaToNum(const string& alphabets)
return num; 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));
}
}

View File

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

34
test/FileEntryTest.cc Normal file
View File

@ -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());
}

View File

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

View File

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

View File

@ -28,6 +28,7 @@ class UtilTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testIsLowercase); CPPUNIT_TEST(testIsLowercase);
CPPUNIT_TEST(testIsUppercase); CPPUNIT_TEST(testIsUppercase);
CPPUNIT_TEST(testAlphaToNum); CPPUNIT_TEST(testAlphaToNum);
CPPUNIT_TEST(testMkdirs);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
private: private:
@ -55,6 +56,7 @@ public:
void testIsLowercase(); void testIsLowercase();
void testIsUppercase(); void testIsUppercase();
void testAlphaToNum(); 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)675, Util::alphaToNum("ZZ")); // 25*26+25
CPPUNIT_ASSERT_EQUAL((int32_t)0, Util::alphaToNum("")); 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;
}
}