diff --git a/ChangeLog b/ChangeLog index bef852bb..ba27795c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2008-09-07 Tatsuhiro Tsujikawa + + Implemented the ability to get timestamp from remote HTTP server and + apply it to local file. To enable this feature, --remote-time option + is added. No usage text has been written yet. + If several servers returns difference timestamp, then aria2 uses latest + one. + * src/CopyDiskAdaptor.cc + * src/CopyDiskAdaptor.h + * src/DirectDiskAdaptor.cc + * src/DirectDiskAdaptor.h + * src/DiskAdaptor.h + * src/File.cc + * src/File.h + * src/HttpHeader.cc + * src/HttpHeader.h + * src/HttpResponse.cc + * src/HttpResponse.h + * src/HttpResponseCommand.cc + * src/HttpResponseCommand.h + * src/MultiDiskAdaptor.cc + * src/MultiDiskAdaptor.h + * src/OptionHandlerFactory.cc + * src/RequestGroup.cc + * src/RequestGroup.h + * src/RequestGroupMan.cc + * src/option_processing.cc + * src/prefs.cc + * src/prefs.h + * test/CopyDiskAdaptorTest.cc + * test/FileTest.cc + * test/Makefile.am + * test/Makefile.in + * test/MultiDiskAdaptorTest.cc + * test/TestUtil.cc + 2008-09-07 Tatsuhiro Tsujikawa Fixed the bug that DiskWriterEntry is not created when its diff --git a/src/CopyDiskAdaptor.cc b/src/CopyDiskAdaptor.cc index 081be967..333b53da 100644 --- a/src/CopyDiskAdaptor.cc +++ b/src/CopyDiskAdaptor.cc @@ -37,6 +37,7 @@ #include "Logger.h" #include "Util.h" #include "message.h" +#include "File.h" namespace aria2 { @@ -70,4 +71,20 @@ std::string CopyDiskAdaptor::getFilePath() return storeDir+"/"+tempFilename; } +size_t CopyDiskAdaptor::utime(const Time& actime, const Time& modtime) +{ + size_t numOK = 0; + std::string topDirPath = storeDir+"/"+topDir; + for(std::deque >::const_iterator i = + fileEntries.begin(); i != fileEntries.end(); ++i) { + if((*i)->isExtracted() && (*i)->isRequested()) { + File f(topDirPath+"/"+(*i)->getPath()); + if(f.isFile() && f.utime(actime, modtime)) { + ++numOK; + } + } + } + return numOK; +} + } // namespace aria2 diff --git a/src/CopyDiskAdaptor.h b/src/CopyDiskAdaptor.h index 80d3f130..0a01abf3 100644 --- a/src/CopyDiskAdaptor.h +++ b/src/CopyDiskAdaptor.h @@ -54,6 +54,8 @@ public: virtual void onDownloadComplete(); + virtual size_t utime(const Time& actime, const Time& modtime); + // tempFilename is relative to storeDir void setTempFilename(const std::string& tempFilename) { this->tempFilename = tempFilename; diff --git a/src/DirectDiskAdaptor.cc b/src/DirectDiskAdaptor.cc index 8fb8a123..9362db73 100644 --- a/src/DirectDiskAdaptor.cc +++ b/src/DirectDiskAdaptor.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "DirectDiskAdaptor.h" #include "FileEntry.h" +#include "File.h" namespace aria2 { @@ -48,4 +49,15 @@ void DirectDiskAdaptor::onDownloadComplete() openFile(); } +size_t DirectDiskAdaptor::utime(const Time& actime, const Time& modtime) +{ + File f(getFilePath()); + if(f.isFile() && f.utime(actime, modtime)) { + return 1; + } else { + return 0; + } +} + + } // namespace aria2 diff --git a/src/DirectDiskAdaptor.h b/src/DirectDiskAdaptor.h index f8458a4d..e215c243 100644 --- a/src/DirectDiskAdaptor.h +++ b/src/DirectDiskAdaptor.h @@ -47,6 +47,8 @@ public: virtual std::string getFilePath(); virtual void onDownloadComplete(); + + virtual size_t utime(const Time& actime, const Time& modtime); }; typedef SharedHandle DirectDiskAdaptorHandle; diff --git a/src/DiskAdaptor.h b/src/DiskAdaptor.h index 031b588c..012eb48b 100644 --- a/src/DiskAdaptor.h +++ b/src/DiskAdaptor.h @@ -36,6 +36,7 @@ #define _D_DISK_ADAPTOR_H_ #include "BinaryStream.h" +#include "TimeA2.h" #include #include @@ -103,6 +104,10 @@ public: // Call one of openFile/openExistingFile/initAndOpenFile before calling this // function. virtual void cutTrailingGarbage() = 0; + + // Returns the number of files, the actime and modtime of which are + // successfully changed. + virtual size_t utime(const Time& actime, const Time& modtime) = 0; }; typedef SharedHandle DiskAdaptorHandle; diff --git a/src/File.cc b/src/File.cc index ed41b450..e4ca5b69 100644 --- a/src/File.cc +++ b/src/File.cc @@ -38,6 +38,8 @@ #include #include #include +#include +#include namespace aria2 { @@ -178,4 +180,21 @@ bool File::renameTo(const std::string& dest) } } +bool File::utime(const Time& actime, const Time& modtime) const +{ + struct utimbuf ub; + ub.actime = actime.getTime(); + ub.modtime = modtime.getTime(); + return ::utime(name.c_str(), &ub) == 0; +} + +Time File::getModifiedTime() +{ + a2_struct_stat fstat; + if(fillStat(fstat) < 0) { + return 0; + } + return Time(fstat.st_mtime); +} + } // namespace aria2 diff --git a/src/File.h b/src/File.h index 4a06ef0c..ab75f123 100644 --- a/src/File.h +++ b/src/File.h @@ -37,6 +37,7 @@ #include "common.h" #include "a2io.h" +#include "TimeA2.h" #include namespace aria2 { @@ -102,6 +103,10 @@ public: static bool isDir(const std::string& filename); bool renameTo(const std::string& dest); + + bool utime(const Time& actime, const Time& modtime) const; + + Time getModifiedTime(); }; } // namespace aria2 diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 6fea1009..d7557e87 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -68,6 +68,8 @@ const std::string HttpHeader::CONTENT_LENGTH("Content-Length"); const std::string HttpHeader::CONTENT_RANGE("Content-Range"); +const std::string HttpHeader::LAST_MODIFIED("Last-Modified"); + const std::string HttpHeader::HTTP_1_1("HTTP/1.1"); const std::string HttpHeader::S200("200"); diff --git a/src/HttpHeader.h b/src/HttpHeader.h index 4bbec4c4..7e5c43a4 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -110,6 +110,8 @@ public: static const std::string CONTENT_RANGE; + static const std::string LAST_MODIFIED; + static const std::string HTTP_1_1; static const std::string S200; diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index 6588d339..98468b54 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -249,4 +249,9 @@ time_t HttpResponse::getRetryAfter() const return httpHeader->getFirstAsUInt(HttpHeader::RETRY_AFTER); } +Time HttpResponse::getLastModifiedTime() const +{ + return Time::parseHTTPDate(httpHeader->getFirst(HttpHeader::LAST_MODIFIED)); +} + } // namespace aria2 diff --git a/src/HttpResponse.h b/src/HttpResponse.h index aaef9a97..8d156768 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -37,7 +37,7 @@ #include "common.h" #include "SharedHandle.h" -#include "a2time.h" +#include "TimeA2.h" #include namespace aria2 { @@ -115,6 +115,8 @@ public: bool hasRetryAfter() const; time_t getRetryAfter() const; + + Time getLastModifiedTime() const; }; typedef SharedHandle HttpResponseHandle; diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 9033ef02..847a2d8f 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -120,6 +120,9 @@ bool HttpResponseCommand::executeInternal() (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, _requestGroup->getFilePath().c_str()).str()); } + // update last modified time + updateLastModifiedTime(httpResponse->getLastModifiedTime()); + if(totalLength == 0 || httpResponse->isTransferEncodingSpecified() || shouldInflateContentEncoding(httpResponse)) { // we ignore content-length when transfer-encoding is set @@ -131,11 +134,21 @@ bool HttpResponseCommand::executeInternal() } else { // validate totalsize _requestGroup->validateTotalLength(httpResponse->getEntityLength()); + // update last modified time + updateLastModifiedTime(httpResponse->getLastModifiedTime()); + e->commands.push_back(createHttpDownloadCommand(httpResponse)); return true; } } +void HttpResponseCommand::updateLastModifiedTime(const Time& lastModified) +{ + if(e->option->getAsBool(PREF_REMOTE_TIME)) { + _requestGroup->updateLastModifiedTime(lastModified); + } +} + static bool fileIsGzipped(const SharedHandle& httpResponse) { std::string filename = diff --git a/src/HttpResponseCommand.h b/src/HttpResponseCommand.h index 6162b2ca..0a622c16 100644 --- a/src/HttpResponseCommand.h +++ b/src/HttpResponseCommand.h @@ -37,6 +37,7 @@ #include "AbstractCommand.h" #include "Decoder.h" +#include "TimeA2.h" namespace aria2 { @@ -59,6 +60,8 @@ private: = SharedHandle(), const SharedHandle& contentEncodingDecoder = SharedHandle()); + + void updateLastModifiedTime(const Time& lastModified); protected: bool executeInternal(); diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index a2377ace..7edad19a 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -480,4 +480,19 @@ void MultiDiskAdaptor::setMaxOpenFiles(size_t maxOpenFiles) _maxOpenFiles = maxOpenFiles; } +size_t MultiDiskAdaptor::utime(const Time& actime, const Time& modtime) +{ + size_t numOK = 0; + for(std::deque >::const_iterator i = + fileEntries.begin(); i != fileEntries.end(); ++i) { + if((*i)->isRequested()) { + File f(getTopDirPath()+"/"+(*i)->getPath()); + if(f.isFile() && f.utime(actime, modtime)) { + ++numOK; + } + } + } + return numOK; +} + } // namespace aria2 diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h index 4533b7ce..6a759bea 100644 --- a/src/MultiDiskAdaptor.h +++ b/src/MultiDiskAdaptor.h @@ -189,6 +189,8 @@ public: virtual void cutTrailingGarbage(); void setMaxOpenFiles(size_t maxOpenFiles); + + virtual size_t utime(const Time& actime, const Time& modtime); }; typedef SharedHandle MultiDiskAdaptorHandle; diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 4c106fb2..0aabe532 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -154,6 +154,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() 0, INT32_MAX))); handlers.push_back(SH(new DefaultOptionHandler(PREF_SERVER_STAT_IF))); handlers.push_back(SH(new DefaultOptionHandler(PREF_SERVER_STAT_OF))); + handlers.push_back(SH(new BooleanOptionHandler(PREF_REMOTE_TIME))); return handlers; } diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 2b560b57..81a33c00 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -123,6 +123,7 @@ RequestGroup::RequestGroup(const Option* option, _forceHaltRequested(false), _singleHostMultiConnectionEnabled(true), _uriSelector(new InOrderURISelector()), + _lastModifiedTime(-1), _option(option), _logger(LogFactory::getInstance()) { @@ -1025,4 +1026,21 @@ void RequestGroup::setURISelector(const SharedHandle& uriSelector) _uriSelector = uriSelector; } +void RequestGroup::applyLastModifiedTimeToLocalFiles() +{ + if(!_pieceStorage.isNull() && _lastModifiedTime.good()) { + time_t t = _lastModifiedTime.getTime(); + _logger->info("Applying Last-Modified time: %s", ctime(&t)); + size_t n = + _pieceStorage->getDiskAdaptor()->utime(Time(), _lastModifiedTime); + _logger->info("Last-Modified attrs of %zu files were updated.", n); + } +} +void RequestGroup::updateLastModifiedTime(const Time& time) +{ + if(time.good() && _lastModifiedTime < time) { + _lastModifiedTime = time; + } +} + } // namespace aria2 diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 2101520c..1b2c213d 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -38,6 +38,7 @@ #include "common.h" #include "SharedHandle.h" #include "TransferStat.h" +#include "TimeA2.h" #include #include @@ -115,6 +116,8 @@ private: SharedHandle _uriSelector; + Time _lastModifiedTime; + const Option* _option; Logger* _logger; @@ -361,6 +364,10 @@ public: static const std::string ACCEPT_METALINK; void setURISelector(const SharedHandle& uriSelector); + + void applyLastModifiedTimeToLocalFiles(); + + void updateLastModifiedTime(const Time& time); }; typedef SharedHandle RequestGroupHandle; diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index fc9a61f5..1b041b69 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -153,8 +153,9 @@ public: { if(group->getNumCommand() == 0) { try { - group->closeFile(); + group->closeFile(); if(group->downloadFinished()) { + group->applyLastModifiedTimeToLocalFiles(); group->reportDownloadFinished(); if(group->allDownloadFinished()) { group->getProgressInfoFile()->removeFile(); diff --git a/src/option_processing.cc b/src/option_processing.cc index ce594448..8041f6c1 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -158,6 +158,7 @@ Option* createDefaultOption() op->put(PREF_LOG_LEVEL, V_DEBUG); op->put(PREF_URI_SELECTOR, V_INORDER); op->put(PREF_SERVER_STAT_TIMEOUT, "86400");// 1day + op->put(PREF_REMOTE_TIME, V_FALSE); return op; } @@ -239,6 +240,7 @@ Option* option_processing(int argc, char* const argv[]) { PREF_SERVER_STAT_IF.c_str(), required_argument, &lopt, 221 }, { PREF_SERVER_STAT_OF.c_str(), required_argument, &lopt, 222 }, { PREF_SERVER_STAT_TIMEOUT.c_str(), required_argument, &lopt, 223 }, + { PREF_REMOTE_TIME.c_str(), optional_argument, 0, 'R' }, #if defined ENABLE_BITTORRENT || defined ENABLE_METALINK { PREF_SHOW_FILES.c_str(), no_argument, NULL, 'S' }, { PREF_SELECT_FILE.c_str(), required_argument, &lopt, 21 }, @@ -280,7 +282,9 @@ Option* option_processing(int argc, char* const argv[]) { "help", optional_argument, NULL, 'h' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vh::ST:M:C:a:cU:ni:j:Z::P::q::", longOpts, &optIndex); + c = getopt_long(argc, argv, + "Dd:o:l:s:pt:m:vh::ST:M:C:a:cU:ni:j:Z::P::q::R::", + longOpts, &optIndex); if(c == -1) { break; } @@ -547,6 +551,9 @@ Option* option_processing(int argc, char* const argv[]) case 'q': cmdstream << PREF_QUIET << "=" << toBoolArg(optarg) << "\n"; break; + case 'R': + cmdstream << PREF_REMOTE_TIME << "=" << toBoolArg(optarg) << "\n"; + break; case 'v': showVersion(); exit(EXIT_SUCCESS); diff --git a/src/prefs.cc b/src/prefs.cc index 44205fa8..8b36e4b8 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -145,6 +145,8 @@ const std::string PREF_SERVER_STAT_TIMEOUT("server-stat-timeout"); const std::string PREF_SERVER_STAT_IF("server-stat-if"); // value: string that your file system recognizes as a file name. const std::string PREF_SERVER_STAT_OF("server-stat-of"); +// value: true | false +const std::string PREF_REMOTE_TIME("remote-time"); /** * FTP related preferences diff --git a/src/prefs.h b/src/prefs.h index 63304c0f..7d9314a4 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -149,6 +149,8 @@ extern const std::string PREF_SERVER_STAT_TIMEOUT; extern const std::string PREF_SERVER_STAT_IF; // value: string that your file system recognizes as a file name. extern const std::string PREF_SERVER_STAT_OF; +// value: true | false +extern const std::string PREF_REMOTE_TIME; /** * FTP related preferences diff --git a/test/CopyDiskAdaptorTest.cc b/test/CopyDiskAdaptorTest.cc new file mode 100644 index 00000000..28fea025 --- /dev/null +++ b/test/CopyDiskAdaptorTest.cc @@ -0,0 +1,81 @@ +#include "CopyDiskAdaptor.h" +#include "FileEntry.h" +#include "Exception.h" +#include "a2io.h" +#include "array_fun.h" +#include "TestUtil.h" +#include +#include +#include +#include + +namespace aria2 { + +class CopyDiskAdaptorTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(CopyDiskAdaptorTest); + CPPUNIT_TEST(testUtime); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() {} + + void testUtime(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( CopyDiskAdaptorTest ); + +void CopyDiskAdaptorTest::testUtime() +{ + std::string storeDir = "/tmp"; + std::string topDir = "aria2_CopyDiskAdaptorTest_testUtime"; + std::string prefix = storeDir+"/"+topDir; + SharedHandle entries[] = { + SharedHandle(new FileEntry("requested", 10, 0)), + SharedHandle(new FileEntry("notFound", 10, 10)), + SharedHandle(new FileEntry("notRequested", 10, 20)), + SharedHandle(new FileEntry("notExtracted", 10, 30)), + SharedHandle(new FileEntry("anotherRequested", 10, 40)), + }; + + std::deque > fileEntries + (&entries[0], &entries[arrayLength(entries)]); + CopyDiskAdaptor adaptor; + adaptor.setStoreDir(storeDir); + adaptor.setTopDir(topDir); + adaptor.setFileEntries(fileEntries); + + entries[0]->setExtracted(true); + entries[1]->setExtracted(true); + entries[2]->setExtracted(true); + entries[4]->setExtracted(true); + + entries[2]->setRequested(false); + + createFile(prefix+"/"+entries[0]->getPath(), entries[0]->getLength()); + File(prefix+"/"+entries[1]->getPath()).remove(); + createFile(prefix+"/"+entries[2]->getPath(), entries[2]->getLength()); + createFile(prefix+"/"+entries[3]->getPath(), entries[3]->getLength()); + createFile(prefix+"/"+entries[4]->getPath(), entries[4]->getLength()); + + CPPUNIT_ASSERT_EQUAL((size_t)2, adaptor.utime(Time(1000), Time(2000))); + + CPPUNIT_ASSERT_EQUAL((time_t)2000, + File(prefix+"/"+entries[0]->getPath()) + .getModifiedTime().getTime()); + + CPPUNIT_ASSERT_EQUAL((time_t)2000, + File(prefix+"/"+entries[4]->getPath()) + .getModifiedTime().getTime()); + + CPPUNIT_ASSERT((time_t)2000 != File(prefix+"/"+entries[1]->getPath()) + .getModifiedTime().getTime()); + CPPUNIT_ASSERT((time_t)2000 != File(prefix+"/"+entries[2]->getPath()) + .getModifiedTime().getTime()); + CPPUNIT_ASSERT((time_t)2000 != File(prefix+"/"+entries[3]->getPath()) + .getModifiedTime().getTime()); + +} + +} // namespace aria2 diff --git a/test/FileTest.cc b/test/FileTest.cc index 56fdf7f4..d756725b 100644 --- a/test/FileTest.cc +++ b/test/FileTest.cc @@ -1,4 +1,5 @@ #include "File.h" +#include "TestUtil.h" #include #include #include @@ -20,6 +21,7 @@ class FileTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGetDirname); CPPUNIT_TEST(testGetBasename); CPPUNIT_TEST(testRenameTo); + CPPUNIT_TEST(testUtime); CPPUNIT_TEST_SUITE_END(); private: @@ -36,6 +38,7 @@ public: void testGetDirname(); void testGetBasename(); void testRenameTo(); + void testUtime(); }; @@ -208,4 +211,20 @@ void FileTest::testRenameTo() CPPUNIT_ASSERT(f.renameTo(fname)); } +void FileTest::testUtime() +{ + File f("/tmp/FileTest_testUTime"); + createFile(f.getPath(), 0); + CPPUNIT_ASSERT(f.utime(Time(1000), Time(2000))); + + struct stat buf; + CPPUNIT_ASSERT(0 == stat(f.getPath().c_str(), &buf)); + CPPUNIT_ASSERT_EQUAL((time_t)1000, buf.st_atime); + CPPUNIT_ASSERT_EQUAL((time_t)2000, f.getModifiedTime().getTime()); + + File notFound("/tmp/FileTest_testUTime_notFound"); + notFound.remove(); + CPPUNIT_ASSERT(!notFound.utime(Time(1000), Time(2000))); +} + } // namespace aria2 diff --git a/test/Makefile.am b/test/Makefile.am index 84b66d4c..6fe5dc54 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -61,7 +61,8 @@ aria2c_SOURCES = AllTest.cc\ DirectDiskAdaptorTest.cc\ CookieTest.cc\ CookieStorageTest.cc\ - TimeTest.cc + TimeTest.cc\ + CopyDiskAdaptorTest.cc if HAVE_LIBZ aria2c_SOURCES += GZipDecoderTest.cc diff --git a/test/Makefile.in b/test/Makefile.in index 15f2d9bf..42dc84d8 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -194,8 +194,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \ ServerStatTest.cc NsCookieParserTest.cc \ DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \ - TimeTest.cc GZipDecoderTest.cc Sqlite3MozCookieParserTest.cc \ - MessageDigestHelperTest.cc \ + TimeTest.cc CopyDiskAdaptorTest.cc GZipDecoderTest.cc \ + Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \ IteratableChunkChecksumValidatorTest.cc \ IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \ BtBitfieldMessageTest.cc BtCancelMessageTest.cc \ @@ -366,8 +366,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \ InOrderURISelectorTest.$(OBJEXT) ServerStatTest.$(OBJEXT) \ NsCookieParserTest.$(OBJEXT) DirectDiskAdaptorTest.$(OBJEXT) \ CookieTest.$(OBJEXT) CookieStorageTest.$(OBJEXT) \ - TimeTest.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ - $(am__objects_3) $(am__objects_4) $(am__objects_5) + TimeTest.$(OBJEXT) CopyDiskAdaptorTest.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) $(am__objects_5) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) @@ -589,8 +590,9 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \ ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \ ServerStatTest.cc NsCookieParserTest.cc \ DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \ - TimeTest.cc $(am__append_1) $(am__append_2) $(am__append_3) \ - $(am__append_4) $(am__append_5) + TimeTest.cc CopyDiskAdaptorTest.cc $(am__append_1) \ + $(am__append_2) $(am__append_3) $(am__append_4) \ + $(am__append_5) #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} @@ -712,6 +714,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieStorageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHKeyExchangeTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAnnouncePeerMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAnnouncePeerReplyMessageTest.Po@am__quote@ diff --git a/test/MultiDiskAdaptorTest.cc b/test/MultiDiskAdaptorTest.cc index 0cc38dde..0b520e62 100644 --- a/test/MultiDiskAdaptorTest.cc +++ b/test/MultiDiskAdaptorTest.cc @@ -18,6 +18,7 @@ class MultiDiskAdaptorTest:public CppUnit::TestFixture { CPPUNIT_TEST(testReadData); CPPUNIT_TEST(testCutTrailingGarbage); CPPUNIT_TEST(testSize); + CPPUNIT_TEST(testUtime); CPPUNIT_TEST_SUITE_END(); private: SharedHandle adaptor; @@ -33,6 +34,7 @@ public: void testReadData(); void testCutTrailingGarbage(); void testSize(); + void testUtime(); }; @@ -181,8 +183,7 @@ void MultiDiskAdaptorTest::testSize() SharedHandle(new FileEntry(prefix+"2", 1, 1)) }; for(size_t i = 0; i < arrayLength(entries); ++i) { - createFile(topDirPath+"/"+entries[i]->getPath(), - entries[i]->getLength()); + createFile(topDirPath+"/"+entries[i]->getPath(), entries[i]->getLength()); } std::deque > fileEntries (&entries[0], &entries[arrayLength(entries)]); @@ -199,4 +200,44 @@ void MultiDiskAdaptorTest::testSize() CPPUNIT_ASSERT_EQUAL((uint64_t)2, adaptor.size()); } +void MultiDiskAdaptorTest::testUtime() +{ + std::string storeDir = "/tmp"; + std::string topDir = "aria2_MultiDiskAdaptorTest_testUtime"; + std::string prefix = storeDir+"/"+topDir; + SharedHandle entries[] = { + SharedHandle(new FileEntry("requested", 0, 0)), + SharedHandle(new FileEntry("notFound", 0, 0)), + SharedHandle(new FileEntry("notRequested", 0, 0)), + SharedHandle(new FileEntry("anotherRequested", 0, 0)), + }; + + createFile(prefix+"/"+entries[0]->getPath(), entries[0]->getLength()); + File(prefix+"/"+entries[1]->getPath()).remove(); + createFile(prefix+"/"+entries[2]->getPath(), entries[2]->getLength()); + createFile(prefix+"/"+entries[3]->getPath(), entries[3]->getLength()); + + entries[2]->setRequested(false); + + std::deque > fileEntries + (&entries[0], &entries[arrayLength(entries)]); + MultiDiskAdaptor adaptor; + adaptor.setStoreDir(storeDir); + adaptor.setTopDir(topDir); + adaptor.setFileEntries(fileEntries); + + CPPUNIT_ASSERT_EQUAL((size_t)2, adaptor.utime(Time(1000), Time(2000))); + + CPPUNIT_ASSERT_EQUAL((time_t)2000, + File(prefix+"/"+entries[0]->getPath()) + .getModifiedTime().getTime()); + + CPPUNIT_ASSERT_EQUAL((time_t)2000, + File(prefix+"/"+entries[3]->getPath()) + .getModifiedTime().getTime()); + + CPPUNIT_ASSERT((time_t)2000 != File(prefix+"/"+entries[2]->getPath()) + .getModifiedTime().getTime()); +} + } // namespace aria2 diff --git a/test/TestUtil.cc b/test/TestUtil.cc index 5a10e6fd..192c53ad 100644 --- a/test/TestUtil.cc +++ b/test/TestUtil.cc @@ -1,15 +1,29 @@ #include "TestUtil.h" #include "a2io.h" +#include "File.h" +#include "StringFormat.h" +#include "FatalException.h" #include #include #include +#include +#include namespace aria2 { void createFile(const std::string& path, size_t length) { + File(File(path).getDirname()).mkdirs(); int fd = creat(path.c_str(), OPEN_MODE); - ftruncate(fd, length); + if(fd == -1) { + throw FatalException(StringFormat("Could not create file=%s. cause:%s", + path.c_str(), strerror(errno)).str()); + } + if(-1 == ftruncate(fd, length)) { + throw FatalException(StringFormat("ftruncate failed. cause:%s", + strerror(errno)).str()); + } + close(fd); } };