[VFS] Add StfsHashEntry struct to view hash entry flags in more detail

+ small adds to StfsHeader
This commit is contained in:
emoose 2020-01-11 19:40:51 +00:00
parent 4f7bc2f946
commit 44c2f72a30
2 changed files with 41 additions and 25 deletions

View File

@ -542,16 +542,16 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
if (entry->attributes() & X_FILE_ATTRIBUTE_NORMAL) {
uint32_t block_index = start_block_index;
size_t remaining_size = file_size;
uint32_t info = 0x80;
while (remaining_size && block_index) {
assert_true(block_index != 0xffffff);
size_t block_size =
std::min(static_cast<size_t>(0x1000), remaining_size);
size_t offset = STFSDataBlockToOffset(block_index);
entry->block_list_.push_back({0, offset, block_size});
remaining_size -= block_size;
auto block_hash = STFSGetLevel0HashEntry(data, block_index);
block_index = block_hash.next_block_index;
info = block_hash.info;
block_index = block_hash.level0_next_block();
}
}
@ -559,7 +559,7 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
}
auto block_hash = STFSGetLevel0HashEntry(data, table_block_index);
table_block_index = block_hash.next_block_index;
table_block_index = block_hash.level0_next_block();
}
if (all_entries.size() > 0) {
@ -634,7 +634,7 @@ size_t StfsContainerDevice::STFSDataBlockToBackingHashBlockOffset(
STFSDataBlockToBackingHashBlock(block, level));
}
StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevelNHashEntry(
StfsHashEntry StfsContainerDevice::STFSGetLevelNHashEntry(
const uint8_t* map_ptr, uint32_t block_index, uint32_t level,
bool secondary_block) {
uint32_t record = block_index;
@ -652,13 +652,11 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevelNHashEntry(
const uint8_t* hash_data = map_ptr + hash_offset;
const uint8_t* record_data = hash_data + record * 0x18;
uint32_t info = xe::load_and_swap<uint8_t>(record_data + 0x14);
uint32_t next_block_index = load_uint24_be(record_data + 0x15);
return {next_block_index, info};
auto* entry = (StfsHashEntry*)(hash_data + record * 0x18);
return *entry;
}
StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry(
StfsHashEntry StfsContainerDevice::STFSGetLevel0HashEntry(
const uint8_t* map_ptr, uint32_t block_index) {
bool use_secondary_block = false;
// Use secondary block for root table if RootActiveIndex flag is set
@ -679,7 +677,7 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry(
auto l2_entry =
STFSGetLevelNHashEntry(map_ptr, block_index, 2, use_secondary_block);
use_secondary_block = false;
if (l2_entry.info & 0x40) { // ActiveIndex flag
if (l2_entry.levelN_activeindex()) {
use_secondary_block = true;
}
}
@ -689,7 +687,7 @@ StfsContainerDevice::BlockHash StfsContainerDevice::STFSGetLevel0HashEntry(
auto l1_entry =
STFSGetLevelNHashEntry(map_ptr, block_index, 1, use_secondary_block);
use_secondary_block = false;
if (l1_entry.info & 0x40) { // ActiveIndex flag
if (l1_entry.levelN_activeindex()) {
use_secondary_block = true;
}
}

View File

@ -59,6 +59,26 @@ struct StfsVolumeDescriptor {
};
static_assert_size(StfsVolumeDescriptor, 0x24);
struct StfsHashEntry {
uint8_t sha1[0x14];
uint8_t info0; // usually contains flags
uint8_t info1;
uint8_t info2;
uint8_t info3;
// If this is a level0 entry, this points to the next block in the chain
uint32_t level0_next_block() { return info3 | (info2 << 8) | (info1 << 16); }
// If this is level 1 or 2, this says whether the hash table this entry refers
// to is using the secondary block or not
bool levelN_activeindex() { return info0 & 0x40; }
bool levelN_writeable() { return info0 & 0x80; }
};
static_assert_size(StfsHashEntry, 0x18);
/* SVOD */
struct SvodDeviceDescriptor {
uint8_t descriptor_length;
@ -385,13 +405,16 @@ struct StfsHeader {
XContentInstaller installer;
uint8_t padding[0x2F2];
bool has_installer() {
return header.header_size == 0xAD0E && installer.type != 0;
}
void set_defaults() {
memset(this, 0, sizeof(StfsHeader));
header.magic = xe::vfs::XContentPackageType::kPackageTypeCon;
header.licenses[0].licensee_id =
-1; // X360 gamesaves seem to set licenses like this
header.header_size = 0x971A;
header.licenses[0].licensee_id = -1; // gamesaves set licenses like this ?
header.header_size = 0x971A; // no installer section in header
metadata.metadata_version = 2;
memcpy(metadata.console_id, "XENIA", 5);
@ -441,11 +464,6 @@ class StfsContainerDevice : public Device {
kSingleFile = 0x4,
};
struct BlockHash {
uint32_t next_block_index;
uint32_t info;
};
const uint32_t kSTFSDataBlocksPerHashLevel[3] = {0xAA, 0x70E4, 0x4AF768};
uint32_t ReadMagic(const std::wstring& path);
@ -469,12 +487,12 @@ class StfsContainerDevice : public Device {
size_t STFSDataBlockToBackingHashBlockOffset(uint64_t block,
uint32_t level = 0);
BlockHash STFSGetLevelNHashEntry(const uint8_t* map_ptr, uint32_t block_index,
uint32_t level,
bool secondary_block = false);
StfsHashEntry STFSGetLevelNHashEntry(const uint8_t* map_ptr,
uint32_t block_index, uint32_t level,
bool secondary_block = false);
BlockHash STFSGetLevel0HashEntry(const uint8_t* map_ptr,
uint32_t block_index);
StfsHashEntry STFSGetLevel0HashEntry(const uint8_t* map_ptr,
uint32_t block_index);
std::wstring local_path_;
std::map<size_t, std::unique_ptr<MappedMemory>> mmap_;