* proper FAT timestamp handling

This commit is contained in:
Ink 2017-01-10 19:45:00 +03:00
parent 0d8a81137c
commit fe3d31067f
2 changed files with 35 additions and 7 deletions

View File

@ -128,7 +128,7 @@ bool DiscImageDevice::ReadEntry(ParseState* state, const uint8_t* buffer,
entry->size_ = length; entry->size_ = length;
entry->allocation_size_ = xe::round_up(length, bytes_per_sector()); 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->create_timestamp_ = 10000 * 11644473600000LL;
entry->access_timestamp_ = 10000 * 11644473600000LL; entry->access_timestamp_ = 10000 * 11644473600000LL;
entry->write_timestamp_ = 10000 * 11644473600000LL; entry->write_timestamp_ = 10000 * 11644473600000LL;

View File

@ -16,6 +16,11 @@
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/vfs/devices/stfs_container_entry.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 xe {
namespace vfs { namespace vfs {
@ -28,6 +33,25 @@ uint32_t load_uint24_le(const uint8_t* p) {
(static_cast<uint32_t>(p[1]) << 8) | static_cast<uint32_t>(p[0]); (static_cast<uint32_t>(p[1]) << 8) | static_cast<uint32_t>(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, StfsContainerDevice::StfsContainerDevice(const std::string& mount_path,
const std::wstring& local_path) const std::wstring& local_path)
: Device(mount_path), local_path_(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); uint32_t start_block_index = load_uint24_le(p + 0x2F);
uint16_t path_indicator = xe::load_and_swap<uint16_t>(p + 0x32); uint16_t path_indicator = xe::load_and_swap<uint16_t>(p + 0x32);
uint32_t file_size = xe::load_and_swap<uint32_t>(p + 0x34); uint32_t file_size = xe::load_and_swap<uint32_t>(p + 0x34);
uint32_t update_timestamp = xe::load_and_swap<uint32_t>(p + 0x38);
uint32_t access_timestamp = xe::load_and_swap<uint32_t>(p + 0x3C); // both date and time parts of the timestamp are big endian
uint16_t update_date = xe::load_and_swap<uint16_t>(p + 0x38);
uint16_t update_time = xe::load_and_swap<uint16_t>(p + 0x3A);
uint32_t access_date = xe::load_and_swap<uint16_t>(p + 0x3C);
uint32_t access_time = xe::load_and_swap<uint16_t>(p + 0x3E);
p += 0x40; p += 0x40;
StfsContainerEntry* parent_entry = nullptr; StfsContainerEntry* parent_entry = nullptr;
@ -185,10 +213,10 @@ StfsContainerDevice::Error StfsContainerDevice::ReadAllEntries(
entry->size_ = file_size; entry->size_ = file_size;
entry->allocation_size_ = xe::round_up(file_size, bytes_per_sector()); entry->allocation_size_ = xe::round_up(file_size, bytes_per_sector());
// Convert to 100-nanosecond intervals since January 1, 1601 (UTC) entry->create_timestamp_ = decode_fat_timestamp(update_date, update_time);
entry->create_timestamp_ = (update_timestamp + 11644473600000LL) * 10000; entry->access_timestamp_ = decode_fat_timestamp(access_date, access_time);
entry->access_timestamp_ = (access_timestamp + 11644473600000LL) * 10000; entry->write_timestamp_ = entry->create_timestamp_;
entry->write_timestamp_ = (update_timestamp + 11644473600000LL) * 10000;
all_entries.push_back(entry.get()); all_entries.push_back(entry.get());
// Fill in all block records. // Fill in all block records.