From 52d5c3fee373193776239ff1a0af18fa1337daf8 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 1 Sep 2020 13:47:03 +0200 Subject: [PATCH] Downloads: set the last modifier date/time of the files to the current UTC time, no need to expose the actual date/time --- src/libs/utils/impl/Zipper.cpp | 45 +++++++++++++++++------- src/libs/utils/include/utils/Zipper.hpp | 5 ++- src/lms/ui/resource/DownloadResource.cpp | 4 +-- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/libs/utils/impl/Zipper.cpp b/src/libs/utils/impl/Zipper.cpp index b189fd28..6fef7430 100644 --- a/src/libs/utils/impl/Zipper.cpp +++ b/src/libs/utils/impl/Zipper.cpp @@ -22,6 +22,9 @@ #include #include +#include +#include + #include "utils/Path.hpp" // Done using specs from https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT @@ -56,6 +59,7 @@ namespace Zip void write8(std::size_t offset, std::uint8_t value); void write16(std::size_t offset, std::uint16_t value); void write32(std::size_t offset, std::uint32_t value); + void writeDateTime(std::size_t offset, const Wt::WDateTime& time); private: std::byte* _buffer {}; @@ -84,6 +88,24 @@ namespace Zip _buffer[offset + 3] = static_cast(value >> 24); } + void + ZipHeader::writeDateTime(std::size_t offset, const Wt::WDateTime& dateTime) + { + std::uint32_t encodedDateTime{}; + + // Date + encodedDateTime |= ((dateTime.date().year() - 1980) << 25); + encodedDateTime |= (dateTime.date().month() << 21); + encodedDateTime |= (dateTime.date().day() << 16); + + // Time + encodedDateTime |= (dateTime.time().hour() << 11); + encodedDateTime |= (dateTime.time().minute() << 5); + encodedDateTime |= (dateTime.time().second() << 1); + + write32(offset, encodedDateTime); + } + class LocalFileHeader : public ZipHeader { public: @@ -94,11 +116,7 @@ namespace Zip void setVersionNeededToExtract(unsigned major, unsigned minor) { assert(minor < 10); write16(4, major*10 + minor); } void setGeneralPurposeFlags(std::uint16_t flags) { write16(6, flags); } void setCompressionMethod(CompressionMethod compressionMethod) { write16(8, compressionMethod); } - void setLastModifiedDateTime() - { // TODO - write16(10, 0); // time - write16(12, 0); // date - } + void setLastModifiedDateTime(const Wt::WDateTime& dateTime) { writeDateTime(10, dateTime); } void setCrc32UncompressedData(std::uint32_t crc) { write32(14, crc); } void setCompressedSize(std::size_t size) { write32(18, size); } void setUncompressedSize(std::size_t size) { write32(22, size); } @@ -129,11 +147,7 @@ namespace Zip void setVersionNeededToExtract(unsigned major, unsigned minor) { assert(minor < 10); write16(6, major*10 + minor); } void setGeneralPurposeFlags(std::uint16_t flags) { write16(8, flags); } void setCompressionMethod(CompressionMethod method) { write16(10, method); } - void setLastModifiedDateTime() - { - write16(12, 0); // time - write16(14, 0); // date - } + void setLastModifiedDateTime(const Wt::WDateTime& dateTime) { writeDateTime(12, dateTime); } void setCrc32UncompressedData(std::uint32_t crc32) { write32(16, crc32); } void setCompressedSize(std::size_t size) { write32(20, size); } void setUncompressedSize(std::size_t size) { write32(24, size); } @@ -163,7 +177,7 @@ namespace Zip static constexpr std::size_t getHeaderSize() { return 22; } }; - Zipper::Zipper(const std::map& files) + Zipper::Zipper(const std::map& files, const Wt::WDateTime& lastModifiedTime) { for (const auto& [filename, filePath] : files) { @@ -175,6 +189,11 @@ namespace Zip if (ec) throw ZipperException {"Cannot get file size for '" + filePath.string() + "': " + ec.message()}; + if (lastModifiedTime.isValid()) + fileContext.lastModifiedTime = lastModifiedTime; + else + fileContext.lastModifiedTime = getLastWriteTime(filePath); + _files[filename] = std::move(fileContext); _totalZipSize += LocalFileHeader::getHeaderSize(); @@ -279,7 +298,7 @@ namespace Zip header.setCrc32UncompressedData(ZipHeader::UnknownCrc32); header.setCompressedSize(ZipHeader::UnknownFileSize); header.setUncompressedSize(ZipHeader::UnknownFileSize); - header.setLastModifiedDateTime(); // getLastWriteTime(*_currentFile)); + header.setLastModifiedDateTime(_currentFile->second.lastModifiedTime); header.setFileNameLength(_currentFile->first.size()); header.setExtraFieldLength(0); @@ -393,7 +412,7 @@ namespace Zip header.setCompressionMethod(ZipHeader::CompressionMethod::NoCompression); header.setCompressedSize(_currentFile->second.fileSize); header.setUncompressedSize(_currentFile->second.fileSize); - header.setLastModifiedDateTime(); // getLastWriteTime(*_currentFile)); + header.setLastModifiedDateTime(_currentFile->second.lastModifiedTime); header.setCrc32UncompressedData(_currentFile->second.fileCrc32.getResult()); header.setFileNameLength(_currentFile->first.size()); header.setExtraFieldLength(0); diff --git a/src/libs/utils/include/utils/Zipper.hpp b/src/libs/utils/include/utils/Zipper.hpp index d464abe2..381e366c 100644 --- a/src/libs/utils/include/utils/Zipper.hpp +++ b/src/libs/utils/include/utils/Zipper.hpp @@ -23,6 +23,8 @@ #include #include +#include + #include "Exception.hpp" #include "utils/Crc32Calculator.hpp" @@ -41,7 +43,7 @@ namespace Zip using SizeZype = std::uint64_t; - Zipper(const std::map& files); + Zipper(const std::map& files, const Wt::WDateTime& lastModifiedTime = {}); static constexpr std::size_t minOutputBufferSize = 64; std::size_t writeSome(std::byte* buffer, std::size_t bufferSize); @@ -64,6 +66,7 @@ namespace Zip { std::filesystem::path filePath; std::size_t fileSize; + Wt::WDateTime lastModifiedTime; Utils::Crc32Calculator fileCrc32; std::size_t localFileHeaderOffset {}; }; diff --git a/src/lms/ui/resource/DownloadResource.cpp b/src/lms/ui/resource/DownloadResource.cpp index 3f01d9d3..dfa96f5d 100644 --- a/src/lms/ui/resource/DownloadResource.cpp +++ b/src/lms/ui/resource/DownloadResource.cpp @@ -22,8 +22,8 @@ #include #include -#include #include +#include #include "database/Artist.hpp" #include "database/Release.hpp" @@ -165,7 +165,7 @@ createZipper(const std::vector& tracks) files.emplace(fileName, track->getPath()); } - return std::make_unique(files); + return std::make_unique(files, Wt::WLocalDateTime::currentDateTime().toUTC()); } DownloadReleaseResource::DownloadReleaseResource(Database::IdType releaseId)