fix crash in create_zip for files without modification time

MemoryDevice::lastWriteTime returns file_time_type::min(). Converting
it to the system clock overflows, and on Windows std::localtime returns
nullptr for the resulting time, which was dereferenced
(access violation in zip_files test on MSVC).

Unknown or out of range time is now written as 1980-01-01 00:00,
the earliest MS-DOS date.
This commit is contained in:
ostermine 2026-10-10 16:39:20 +03:00
parent fa5466f675
commit a56158b78e

View file

@ -58,11 +58,22 @@ namespace {
}
uint32_t to_ms_dos_timestamp(const file_time_type& fileTime) {
// 1980-01-01 00:00, the earliest MS-DOS date; used for unknown time
// (devices without timestamps return file_time_type::min())
constexpr uint32_t DOS_EPOCH = (0 << 9 | 1 << 5 | 1) << 16;
if (fileTime == file_time_type::min()) {
return DOS_EPOCH;
}
auto timePoint = time_point_cast<system_clock::duration>(
fileTime - file_time_type::clock::now() + system_clock::now()
);
std::time_t timeT = system_clock::to_time_t(timePoint);
std::tm tm = *std::localtime(&timeT);
// localtime returns nullptr for out of range time on Windows
const std::tm* tmPtr = std::localtime(&timeT);
if (tmPtr == nullptr || tmPtr->tm_year < 80) {
return DOS_EPOCH;
}
const std::tm& tm = *tmPtr;
uint16_t date = (tm.tm_year - 80) << 9 | (tm.tm_mon + 1) << 5 | tm.tm_mday;
uint16_t time = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec / 2);
return (date << 16) | time;