From fe3d31067fde17a7590ecb19d6f6c9c89cdd475c Mon Sep 17 00:00:00 2001 From: Ink Date: Tue, 10 Jan 2017 19:45:00 +0300 Subject: [PATCH] * proper FAT timestamp handling --- src/xenia/vfs/devices/disc_image_device.cc | 2 +- .../vfs/devices/stfs_container_device.cc | 40 ++++++++++++++++--- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/xenia/vfs/devices/disc_image_device.cc b/src/xenia/vfs/devices/disc_image_device.cc index b2a4ab5e4..9db2def38 100644 --- a/src/xenia/vfs/devices/disc_image_device.cc +++ b/src/xenia/vfs/devices/disc_image_device.cc @@ -128,7 +128,7 @@ bool DiscImageDevice::ReadEntry(ParseState* state, const uint8_t* buffer, entry->size_ = length; entry->allocation_size_ = xe::round_up(length, bytes_per_sector()); - // Set to January 1, 1601 (UTC) in 100-nanosecond intervals + // Set to January 1, 1970 (UTC) in 100-nanosecond intervals entry->create_timestamp_ = 10000 * 11644473600000LL; entry->access_timestamp_ = 10000 * 11644473600000LL; entry->write_timestamp_ = 10000 * 11644473600000LL; diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index 4f5776262..dfe5d5a07 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -16,6 +16,11 @@ #include "xenia/base/math.h" #include "xenia/vfs/devices/stfs_container_entry.h" +#if XE_PLATFORM_WIN32 +#include "xenia/base/platform_win.h" +#define timegm _mkgmtime +#endif + namespace xe { namespace vfs { @@ -28,6 +33,25 @@ uint32_t load_uint24_le(const uint8_t* p) { (static_cast(p[1]) << 8) | static_cast(p[0]); } +// Convert FAT timestamp to 100-nanosecond intervals since January 1, 1601 (UTC) +uint64_t decode_fat_timestamp(uint32_t date, uint32_t time) { + struct tm tm = {0}; + // 80 is the difference between 1980 (FAT) and 1900 (tm); + tm.tm_year = ((0xFE00 & date) >> 9) + 80; + tm.tm_mon = (0x01E0 & date) >> 5; + tm.tm_mday = (0x001F & date) >> 0; + tm.tm_hour = (0xF800 & time) >> 11; + tm.tm_min = (0x07E0 & time) >> 5; + tm.tm_sec = (0x001F & time) << 1; // the value stored in 2-seconds intervals + tm.tm_isdst = 0; + time_t timet = timegm(&tm); + if (timet == -1) { + return 0; + } + // 11644473600LL is a difference between 1970 and 1601 + return (timet + 11644473600LL) * 10000000; +} + StfsContainerDevice::StfsContainerDevice(const std::string& mount_path, const std::wstring& local_path) : Device(mount_path), local_path_(local_path) {} @@ -157,8 +181,12 @@ StfsContainerDevice::Error StfsContainerDevice::ReadAllEntries( uint32_t start_block_index = load_uint24_le(p + 0x2F); uint16_t path_indicator = xe::load_and_swap(p + 0x32); uint32_t file_size = xe::load_and_swap(p + 0x34); - uint32_t update_timestamp = xe::load_and_swap(p + 0x38); - uint32_t access_timestamp = xe::load_and_swap(p + 0x3C); + + // both date and time parts of the timestamp are big endian + uint16_t update_date = xe::load_and_swap(p + 0x38); + uint16_t update_time = xe::load_and_swap(p + 0x3A); + uint32_t access_date = xe::load_and_swap(p + 0x3C); + uint32_t access_time = xe::load_and_swap(p + 0x3E); p += 0x40; StfsContainerEntry* parent_entry = nullptr; @@ -185,10 +213,10 @@ StfsContainerDevice::Error StfsContainerDevice::ReadAllEntries( entry->size_ = file_size; entry->allocation_size_ = xe::round_up(file_size, bytes_per_sector()); - // Convert to 100-nanosecond intervals since January 1, 1601 (UTC) - entry->create_timestamp_ = (update_timestamp + 11644473600000LL) * 10000; - entry->access_timestamp_ = (access_timestamp + 11644473600000LL) * 10000; - entry->write_timestamp_ = (update_timestamp + 11644473600000LL) * 10000; + entry->create_timestamp_ = decode_fat_timestamp(update_date, update_time); + entry->access_timestamp_ = decode_fat_timestamp(access_date, access_time); + entry->write_timestamp_ = entry->create_timestamp_; + all_entries.push_back(entry.get()); // Fill in all block records.