Some fs/ cleanup.
This commit is contained in:
parent
fdab788017
commit
383d3acbb0
|
@ -9,10 +9,14 @@
|
||||||
|
|
||||||
#include <xenia/kernel/fs/device.h>
|
#include <xenia/kernel/fs/device.h>
|
||||||
|
|
||||||
using namespace xe;
|
namespace xe {
|
||||||
using namespace xe::kernel;
|
namespace kernel {
|
||||||
using namespace xe::kernel::fs;
|
namespace fs {
|
||||||
|
|
||||||
Device::Device(const std::string& path) : path_(path) {}
|
Device::Device(const std::string& path) : path_(path) {}
|
||||||
|
|
||||||
Device::~Device() = default;
|
Device::~Device() = default;
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <xenia/common.h>
|
|
||||||
#include <xenia/core.h>
|
#include <xenia/core.h>
|
||||||
|
|
||||||
#include <xenia/kernel/fs/entry.h>
|
#include <xenia/kernel/fs/entry.h>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
|
@ -65,7 +65,7 @@ X_STATUS STFSContainerEntry::QueryDirectory(
|
||||||
|
|
||||||
auto end = (uint8_t*)out_info + length;
|
auto end = (uint8_t*)out_info + length;
|
||||||
|
|
||||||
auto entry = *stfs_entry_iterator_;
|
auto entry = stfs_entry_iterator_->get();
|
||||||
auto entry_name = entry->name;
|
auto entry_name = entry->name;
|
||||||
|
|
||||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
private:
|
private:
|
||||||
xe_mmap_ref mmap_;
|
xe_mmap_ref mmap_;
|
||||||
STFSEntry* stfs_entry_;
|
STFSEntry* stfs_entry_;
|
||||||
std::vector<STFSEntry*>::iterator stfs_entry_iterator_;
|
std::vector<std::unique_ptr<STFSEntry>>::iterator stfs_entry_iterator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#include <xenia/kernel/fs/entry.h>
|
#include <xenia/kernel/fs/entry.h>
|
||||||
#include <xenia/kernel/fs/device.h>
|
#include <xenia/kernel/fs/device.h>
|
||||||
|
|
||||||
using namespace xe;
|
namespace xe {
|
||||||
using namespace xe::kernel;
|
namespace kernel {
|
||||||
using namespace xe::kernel::fs;
|
namespace fs {
|
||||||
|
|
||||||
MemoryMapping::MemoryMapping(uint8_t* address, size_t length)
|
MemoryMapping::MemoryMapping(uint8_t* address, size_t length)
|
||||||
: address_(address), length_(length) {}
|
: address_(address), length_(length) {}
|
||||||
|
@ -28,3 +28,7 @@ Entry::Entry(Type type, Device* device, const std::string& path)
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry::~Entry() = default;
|
Entry::~Entry() = default;
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <xenia/common.h>
|
|
||||||
#include <xenia/core.h>
|
#include <xenia/core.h>
|
||||||
|
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
XEDECLARECLASS2(xe, kernel, KernelState);
|
namespace kernel {
|
||||||
XEDECLARECLASS2(xe, kernel, XFile);
|
class KernelState;
|
||||||
XEDECLARECLASS2(xe, kernel, XFileInfo);
|
class XFile;
|
||||||
XEDECLARECLASS2(xe, kernel, XDirectoryInfo);
|
class XFileInfo;
|
||||||
XEDECLARECLASS2(xe, kernel, XVolumeInfo);
|
class XFileSystemAttributeInfo;
|
||||||
XEDECLARECLASS2(xe, kernel, XFileSystemAttributeInfo);
|
class XDirectoryInfo;
|
||||||
|
class XVolumeInfo;
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -32,7 +32,6 @@ namespace fs {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
|
|
||||||
|
|
||||||
class MemoryMapping {
|
class MemoryMapping {
|
||||||
public:
|
public:
|
||||||
MemoryMapping(uint8_t* address, size_t length);
|
MemoryMapping(uint8_t* address, size_t length);
|
||||||
|
@ -46,7 +45,6 @@ private:
|
||||||
size_t length_;
|
size_t length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -64,19 +62,18 @@ public:
|
||||||
const std::string& name() const { return name_; }
|
const std::string& name() const { return name_; }
|
||||||
|
|
||||||
virtual X_STATUS QueryInfo(XFileInfo* out_info) = 0;
|
virtual X_STATUS QueryInfo(XFileInfo* out_info) = 0;
|
||||||
virtual X_STATUS QueryDirectory(XDirectoryInfo* out_info,
|
virtual X_STATUS QueryDirectory(XDirectoryInfo* out_info, size_t length,
|
||||||
size_t length, const char* file_name, bool restart) = 0;
|
const char* file_name, bool restart) = 0;
|
||||||
|
|
||||||
virtual bool can_map() { return false; }
|
virtual bool can_map() { return false; }
|
||||||
virtual MemoryMapping* CreateMemoryMapping(
|
virtual MemoryMapping* CreateMemoryMapping(xe_file_mode file_mode,
|
||||||
xe_file_mode file_mode, const size_t offset, const size_t length) {
|
const size_t offset,
|
||||||
|
const size_t length) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual X_STATUS Open(
|
virtual X_STATUS Open(KernelState* kernel_state, uint32_t desired_access,
|
||||||
KernelState* kernel_state,
|
bool async, XFile** out_file) = 0;
|
||||||
uint32_t desired_access, bool async,
|
|
||||||
XFile** out_file) = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type_;
|
Type type_;
|
||||||
|
@ -86,10 +83,8 @@ private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_FS_ENTRY_H_
|
#endif // XENIA_KERNEL_FS_ENTRY_H_
|
||||||
|
|
|
@ -14,14 +14,11 @@
|
||||||
#include <xenia/kernel/fs/devices/host_path_device.h>
|
#include <xenia/kernel/fs/devices/host_path_device.h>
|
||||||
#include <xenia/kernel/fs/devices/stfs_container_device.h>
|
#include <xenia/kernel/fs/devices/stfs_container_device.h>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
namespace fs {
|
||||||
|
|
||||||
using namespace xe;
|
FileSystem::FileSystem() {}
|
||||||
using namespace xe::kernel;
|
|
||||||
using namespace xe::kernel::fs;
|
|
||||||
|
|
||||||
|
|
||||||
FileSystem::FileSystem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystem::~FileSystem() {
|
FileSystem::~FileSystem() {
|
||||||
// Delete all devices.
|
// Delete all devices.
|
||||||
|
@ -106,14 +103,14 @@ int FileSystem::RegisterDevice(const std::string& path, Device* device) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileSystem::RegisterHostPathDevice(
|
int FileSystem::RegisterHostPathDevice(const std::string& path,
|
||||||
const std::string& path, const std::wstring& local_path) {
|
const std::wstring& local_path) {
|
||||||
Device* device = new HostPathDevice(path, local_path);
|
Device* device = new HostPathDevice(path, local_path);
|
||||||
return RegisterDevice(path, device);
|
return RegisterDevice(path, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileSystem::RegisterDiscImageDevice(
|
int FileSystem::RegisterDiscImageDevice(const std::string& path,
|
||||||
const std::string& path, const std::wstring& local_path) {
|
const std::wstring& local_path) {
|
||||||
DiscImageDevice* device = new DiscImageDevice(path, local_path);
|
DiscImageDevice* device = new DiscImageDevice(path, local_path);
|
||||||
if (device->Init()) {
|
if (device->Init()) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -121,8 +118,8 @@ int FileSystem::RegisterDiscImageDevice(
|
||||||
return RegisterDevice(path, device);
|
return RegisterDevice(path, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileSystem::RegisterSTFSContainerDevice(
|
int FileSystem::RegisterSTFSContainerDevice(const std::string& path,
|
||||||
const std::string& path, const std::wstring& local_path) {
|
const std::wstring& local_path) {
|
||||||
STFSContainerDevice* device = new STFSContainerDevice(path, local_path);
|
STFSContainerDevice* device = new STFSContainerDevice(path, local_path);
|
||||||
if (device->Init()) {
|
if (device->Init()) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -178,3 +175,7 @@ Entry* FileSystem::ResolvePath(const std::string& path) {
|
||||||
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
|
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
|
@ -13,21 +13,14 @@
|
||||||
|
|
||||||
#include <poly/math.h>
|
#include <poly/math.h>
|
||||||
|
|
||||||
using namespace xe;
|
namespace xe {
|
||||||
using namespace xe::kernel;
|
namespace kernel {
|
||||||
using namespace xe::kernel::fs;
|
namespace fs {
|
||||||
|
|
||||||
|
const size_t kXESectorSize = 2048;
|
||||||
|
|
||||||
namespace {
|
GDFXEntry::GDFXEntry()
|
||||||
|
: attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0) {}
|
||||||
#define kXESectorSize 2048
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GDFXEntry::GDFXEntry() :
|
|
||||||
attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
GDFXEntry::~GDFXEntry() {
|
GDFXEntry::~GDFXEntry() {
|
||||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||||
|
@ -57,7 +50,6 @@ void GDFXEntry::Dump(int indent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GDFX::GDFX(xe_mmap_ref mmap) {
|
GDFX::GDFX(xe_mmap_ref mmap) {
|
||||||
mmap_ = xe_mmap_retain(mmap);
|
mmap_ = xe_mmap_retain(mmap);
|
||||||
|
|
||||||
|
@ -70,30 +62,28 @@ GDFX::~GDFX() {
|
||||||
xe_mmap_release(mmap_);
|
xe_mmap_release(mmap_);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDFXEntry* GDFX::root_entry() {
|
GDFXEntry* GDFX::root_entry() { return root_entry_; }
|
||||||
return root_entry_;
|
|
||||||
}
|
|
||||||
|
|
||||||
GDFX::Error GDFX::Load() {
|
GDFX::Error GDFX::Load() {
|
||||||
Error result = kErrorOutOfMemory;
|
|
||||||
|
|
||||||
ParseState state;
|
ParseState state;
|
||||||
xe_zero_struct(&state, sizeof(state));
|
xe_zero_struct(&state, sizeof(state));
|
||||||
|
|
||||||
state.ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
|
state.ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
|
||||||
state.size = xe_mmap_get_length(mmap_);
|
state.size = xe_mmap_get_length(mmap_);
|
||||||
|
|
||||||
result = Verify(state);
|
auto result = Verify(state);
|
||||||
XEEXPECTZERO(result);
|
if (result != kSuccess) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = ReadAllEntries(state, state.ptr + state.root_offset);
|
result = ReadAllEntries(state, state.ptr + state.root_offset);
|
||||||
XEEXPECTZERO(result);
|
if (result != kSuccess) {
|
||||||
|
|
||||||
result = kSuccess;
|
|
||||||
XECLEANUP:
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
void GDFX::Dump() {
|
void GDFX::Dump() {
|
||||||
if (root_entry_) {
|
if (root_entry_) {
|
||||||
root_entry_->Dump(0);
|
root_entry_->Dump(0);
|
||||||
|
@ -126,8 +116,7 @@ GDFX::Error GDFX::Verify(ParseState& state) {
|
||||||
state.root_sector = poly::load<uint32_t>(fs_ptr + 20);
|
state.root_sector = poly::load<uint32_t>(fs_ptr + 20);
|
||||||
state.root_size = poly::load<uint32_t>(fs_ptr + 24);
|
state.root_size = poly::load<uint32_t>(fs_ptr + 24);
|
||||||
state.root_offset = state.game_offset + (state.root_sector * kXESectorSize);
|
state.root_offset = state.game_offset + (state.root_sector * kXESectorSize);
|
||||||
if (state.root_size < 13 ||
|
if (state.root_size < 13 || state.root_size > 32 * 1024 * 1024) {
|
||||||
state.root_size > 32 * 1024 * 1024) {
|
|
||||||
return kErrorDamagedFile;
|
return kErrorDamagedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,3 +197,7 @@ bool GDFX::ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
|
@ -10,23 +10,18 @@
|
||||||
#ifndef XENIA_KERNEL_FS_GDFX_H_
|
#ifndef XENIA_KERNEL_FS_GDFX_H_
|
||||||
#define XENIA_KERNEL_FS_GDFX_H_
|
#define XENIA_KERNEL_FS_GDFX_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
|
||||||
#include <xenia/core.h>
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xenia/core.h>
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
#include <xenia/kernel/fs/entry.h>
|
#include <xenia/kernel/fs/entry.h>
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
|
|
||||||
class GDFX;
|
class GDFX;
|
||||||
|
|
||||||
|
|
||||||
class GDFXEntry {
|
class GDFXEntry {
|
||||||
public:
|
public:
|
||||||
GDFXEntry();
|
GDFXEntry();
|
||||||
|
@ -44,7 +39,6 @@ public:
|
||||||
std::vector<GDFXEntry*> children;
|
std::vector<GDFXEntry*> children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class GDFX {
|
class GDFX {
|
||||||
public:
|
public:
|
||||||
enum Error {
|
enum Error {
|
||||||
|
@ -67,13 +61,18 @@ private:
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t* ptr;
|
uint8_t* ptr;
|
||||||
|
|
||||||
size_t size; // Size (bytes) of total image
|
// Size (bytes) of total image.
|
||||||
|
size_t size;
|
||||||
|
|
||||||
size_t game_offset; // Offset (bytes) of game partition
|
// Offset (bytes) of game partition.
|
||||||
|
size_t game_offset;
|
||||||
|
|
||||||
size_t root_sector; // Offset (sector) of root
|
// Offset (sector) of root.
|
||||||
size_t root_offset; // Offset (bytes) of root
|
size_t root_sector;
|
||||||
size_t root_size; // Size (bytes) of root
|
// Offset (bytes) of root.
|
||||||
|
size_t root_offset;
|
||||||
|
// Size (bytes) of root.
|
||||||
|
size_t root_size;
|
||||||
} ParseState;
|
} ParseState;
|
||||||
|
|
||||||
Error Verify(ParseState& state);
|
Error Verify(ParseState& state);
|
||||||
|
@ -87,10 +86,8 @@ private:
|
||||||
GDFXEntry* root_entry_;
|
GDFXEntry* root_entry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_FS_GDFX_H_
|
#endif // XENIA_KERNEL_FS_GDFX_H_
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace xe;
|
namespace xe {
|
||||||
using namespace xe::kernel;
|
namespace kernel {
|
||||||
using namespace xe::kernel::fs;
|
namespace fs {
|
||||||
|
|
||||||
#define XEGETUINT24BE(p) \
|
#define XEGETUINT24BE(p) \
|
||||||
(((uint32_t)poly::load_and_swap<uint8_t>((p)+0) << 16) | \
|
(((uint32_t)poly::load_and_swap<uint8_t>((p)+0) << 16) | \
|
||||||
|
@ -43,7 +43,6 @@ bool STFSVolumeDescriptor::Read(const uint8_t* p) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool STFSHeader::Read(const uint8_t* p) {
|
bool STFSHeader::Read(const uint8_t* p) {
|
||||||
xe_copy_struct(license_entries, p + 0x22C, 0x100);
|
xe_copy_struct(license_entries, p + 0x22C, 0x100);
|
||||||
xe_copy_struct(header_hash, p + 0x32C, 0x14);
|
xe_copy_struct(header_hash, p + 0x32C, 0x14);
|
||||||
|
@ -94,70 +93,55 @@ bool STFSHeader::Read(const uint8_t* p) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
STFSEntry::STFSEntry() :
|
STFSEntry::STFSEntry()
|
||||||
attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0),
|
: attributes(X_FILE_ATTRIBUTE_NONE),
|
||||||
update_timestamp(0), access_timestamp(0) {
|
offset(0),
|
||||||
}
|
size(0),
|
||||||
|
update_timestamp(0),
|
||||||
STFSEntry::~STFSEntry() {
|
access_timestamp(0) {}
|
||||||
for (auto it = children.begin(); it != children.end(); ++it) {
|
|
||||||
delete *it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STFSEntry* STFSEntry::GetChild(const char* name) {
|
STFSEntry* STFSEntry::GetChild(const char* name) {
|
||||||
// TODO(benvanik): a faster search
|
// TODO(benvanik): a faster search
|
||||||
for (auto it = children.begin(); it != children.end(); ++it) {
|
for (const auto& entry : children) {
|
||||||
STFSEntry* entry = *it;
|
|
||||||
if (strcasecmp(entry->name.c_str(), name) == 0) {
|
if (strcasecmp(entry->name.c_str(), name) == 0) {
|
||||||
return entry;
|
return entry.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void STFSEntry::Dump(int indent) {
|
void STFSEntry::Dump(int indent) {
|
||||||
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
|
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
|
||||||
for (auto it = children.begin(); it != children.end(); ++it) {
|
for (const auto& entry : children) {
|
||||||
STFSEntry* entry = *it;
|
|
||||||
entry->Dump(indent + 2);
|
entry->Dump(indent + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
STFS::STFS(xe_mmap_ref mmap) {
|
STFS::STFS(xe_mmap_ref mmap) {
|
||||||
mmap_ = xe_mmap_retain(mmap);
|
mmap_ = xe_mmap_retain(mmap);
|
||||||
|
|
||||||
root_entry_ = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STFS::~STFS() {
|
STFS::~STFS() {
|
||||||
delete root_entry_;
|
|
||||||
|
|
||||||
xe_mmap_release(mmap_);
|
xe_mmap_release(mmap_);
|
||||||
}
|
}
|
||||||
|
|
||||||
STFSEntry* STFS::root_entry() {
|
|
||||||
return root_entry_;
|
|
||||||
}
|
|
||||||
|
|
||||||
STFS::Error STFS::Load() {
|
STFS::Error STFS::Load() {
|
||||||
Error result = kErrorOutOfMemory;
|
|
||||||
|
|
||||||
uint8_t* map_ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
|
uint8_t* map_ptr = (uint8_t*)xe_mmap_get_addr(mmap_);
|
||||||
size_t map_size = xe_mmap_get_length(mmap_);
|
size_t map_size = xe_mmap_get_length(mmap_);
|
||||||
|
|
||||||
result = ReadHeaderAndVerify(map_ptr);
|
auto result = ReadHeaderAndVerify(map_ptr);
|
||||||
XEEXPECTZERO(result);
|
if (result != kSuccess) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = ReadAllEntries(map_ptr);
|
result = ReadAllEntries(map_ptr);
|
||||||
XEEXPECTZERO(result);
|
if (result != kSuccess) {
|
||||||
|
|
||||||
result = kSuccess;
|
|
||||||
XECLEANUP:
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
void STFS::Dump() {
|
void STFS::Dump() {
|
||||||
if (root_entry_) {
|
if (root_entry_) {
|
||||||
root_entry_->Dump(0);
|
root_entry_->Dump(0);
|
||||||
|
@ -192,10 +176,7 @@ STFS::Error STFS::ReadHeaderAndVerify(const uint8_t* map_ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||||
root_entry_ = new STFSEntry();
|
root_entry_.reset(new STFSEntry());
|
||||||
root_entry_->offset = 0;
|
|
||||||
root_entry_->size = 0;
|
|
||||||
root_entry_->name = "";
|
|
||||||
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
|
||||||
std::vector<STFSEntry*> entries;
|
std::vector<STFSEntry*> entries;
|
||||||
|
@ -221,7 +202,7 @@ STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||||
uint32_t access_timestamp = poly::load_and_swap<uint32_t>(p + 0x3C);
|
uint32_t access_timestamp = poly::load_and_swap<uint32_t>(p + 0x3C);
|
||||||
p += 0x40;
|
p += 0x40;
|
||||||
|
|
||||||
STFSEntry* entry = new STFSEntry();
|
auto entry = std::make_unique<STFSEntry>();
|
||||||
entry->name = std::string((char*)filename, filename_length_flags & 0x3F);
|
entry->name = std::string((char*)filename, filename_length_flags & 0x3F);
|
||||||
entry->name.append(1, '\0');
|
entry->name.append(1, '\0');
|
||||||
// bit 0x40 = consecutive blocks (not fragmented?)
|
// bit 0x40 = consecutive blocks (not fragmented?)
|
||||||
|
@ -234,18 +215,7 @@ STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||||
}
|
}
|
||||||
entry->update_timestamp = update_timestamp;
|
entry->update_timestamp = update_timestamp;
|
||||||
entry->access_timestamp = access_timestamp;
|
entry->access_timestamp = access_timestamp;
|
||||||
entries.push_back(entry);
|
entries.push_back(entry.get());
|
||||||
|
|
||||||
const uint8_t* p = map_ptr + entry->offset;
|
|
||||||
|
|
||||||
if (path_indicator == 0xFFFF) {
|
|
||||||
// Root entry.
|
|
||||||
root_entry_->children.push_back(entry);
|
|
||||||
} else {
|
|
||||||
// Lookup and add.
|
|
||||||
auto parent = entries[path_indicator];
|
|
||||||
parent->children.push_back(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in all block records.
|
// Fill in all block records.
|
||||||
// It's easier to do this now and just look them up later, at the cost
|
// It's easier to do this now and just look them up later, at the cost
|
||||||
|
@ -255,9 +225,7 @@ STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||||
uint32_t block_index = start_block_index;
|
uint32_t block_index = start_block_index;
|
||||||
size_t remaining_size = file_size;
|
size_t remaining_size = file_size;
|
||||||
uint32_t info = 0x80;
|
uint32_t info = 0x80;
|
||||||
while (remaining_size &&
|
while (remaining_size && block_index && info >= 0x80) {
|
||||||
block_index &&
|
|
||||||
info >= 0x80) {
|
|
||||||
size_t block_size = std::min(0x1000ull, remaining_size);
|
size_t block_size = std::min(0x1000ull, remaining_size);
|
||||||
size_t offset = BlockToOffset(ComputeBlockNumber(block_index));
|
size_t offset = BlockToOffset(ComputeBlockNumber(block_index));
|
||||||
entry->block_list.push_back({offset, block_size});
|
entry->block_list.push_back({offset, block_size});
|
||||||
|
@ -270,6 +238,15 @@ STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||||
info = block_hash.info;
|
info = block_hash.info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (path_indicator == 0xFFFF) {
|
||||||
|
// Root entry.
|
||||||
|
root_entry_->children.push_back(std::move(entry));
|
||||||
|
} else {
|
||||||
|
// Lookup and add.
|
||||||
|
auto parent = entries[path_indicator];
|
||||||
|
parent->children.push_back(std::move(entry));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block_hash = GetBlockHash(map_ptr, table_block_index, 0);
|
auto block_hash = GetBlockHash(map_ptr, table_block_index, 0);
|
||||||
|
@ -327,12 +304,14 @@ uint32_t STFS::ComputeBlockNumber(uint32_t block_index) {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
STFS::BlockHash_t STFS::GetBlockHash(
|
STFS::BlockHash_t STFS::GetBlockHash(const uint8_t* map_ptr,
|
||||||
const uint8_t* map_ptr,
|
uint32_t block_index,
|
||||||
uint32_t block_index, uint32_t table_offset) {
|
uint32_t table_offset) {
|
||||||
static const uint32_t table_spacing[] = {
|
static const uint32_t table_spacing[] = {
|
||||||
0xAB, 0x718F, 0xFE7DA, // The distance in blocks between tables
|
0xAB, 0x718F,
|
||||||
0xAC, 0x723A, 0xFD00B, // For when tables are 1 block and when they are 2 blocks
|
0xFE7DA, // The distance in blocks between tables
|
||||||
|
0xAC, 0x723A,
|
||||||
|
0xFD00B, // For when tables are 1 block and when they are 2 blocks
|
||||||
};
|
};
|
||||||
uint32_t record = block_index % 0xAA;
|
uint32_t record = block_index % 0xAA;
|
||||||
uint32_t table_index =
|
uint32_t table_index =
|
||||||
|
@ -350,3 +329,7 @@ STFS::BlockHash_t STFS::GetBlockHash(
|
||||||
uint32_t next_block_index = XEGETUINT24BE(record_data + 0x15);
|
uint32_t next_block_index = XEGETUINT24BE(record_data + 0x15);
|
||||||
return {next_block_index, info};
|
return {next_block_index, info};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
|
@ -10,23 +10,19 @@
|
||||||
#ifndef XENIA_KERNEL_FS_STFS_H_
|
#ifndef XENIA_KERNEL_FS_STFS_H_
|
||||||
#define XENIA_KERNEL_FS_STFS_H_
|
#define XENIA_KERNEL_FS_STFS_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
#include <memory>
|
||||||
#include <xenia/core.h>
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xenia/core.h>
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
#include <xenia/kernel/fs/entry.h>
|
#include <xenia/kernel/fs/entry.h>
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
|
|
||||||
class STFS;
|
class STFS;
|
||||||
|
|
||||||
|
|
||||||
// http://www.free60.org/STFS
|
// http://www.free60.org/STFS
|
||||||
|
|
||||||
enum STFSPackageType {
|
enum STFSPackageType {
|
||||||
|
@ -79,7 +75,6 @@ enum STFSDescriptorType : uint32_t {
|
||||||
STFS_DESCRIPTOR_SVOD = 1,
|
STFS_DESCRIPTOR_SVOD = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class STFSVolumeDescriptor {
|
class STFSVolumeDescriptor {
|
||||||
public:
|
public:
|
||||||
bool Read(const uint8_t* p);
|
bool Read(const uint8_t* p);
|
||||||
|
@ -94,7 +89,6 @@ public:
|
||||||
uint32_t total_unallocated_block_count;
|
uint32_t total_unallocated_block_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class STFSHeader {
|
class STFSHeader {
|
||||||
public:
|
public:
|
||||||
bool Read(const uint8_t* p);
|
bool Read(const uint8_t* p);
|
||||||
|
@ -132,11 +126,9 @@ public:
|
||||||
uint8_t title_thumbnail_image[0x4000];
|
uint8_t title_thumbnail_image[0x4000];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class STFSEntry {
|
class STFSEntry {
|
||||||
public:
|
public:
|
||||||
STFSEntry();
|
STFSEntry();
|
||||||
~STFSEntry();
|
|
||||||
|
|
||||||
STFSEntry* GetChild(const char* name);
|
STFSEntry* GetChild(const char* name);
|
||||||
|
|
||||||
|
@ -149,7 +141,7 @@ public:
|
||||||
uint32_t update_timestamp;
|
uint32_t update_timestamp;
|
||||||
uint32_t access_timestamp;
|
uint32_t access_timestamp;
|
||||||
|
|
||||||
std::vector<STFSEntry*> children;
|
std::vector<std::unique_ptr<STFSEntry>> children;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
@ -158,7 +150,6 @@ public:
|
||||||
std::vector<BlockRecord_t> block_list;
|
std::vector<BlockRecord_t> block_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class STFS {
|
class STFS {
|
||||||
public:
|
public:
|
||||||
enum Error {
|
enum Error {
|
||||||
|
@ -173,7 +164,7 @@ public:
|
||||||
virtual ~STFS();
|
virtual ~STFS();
|
||||||
|
|
||||||
const STFSHeader* header() const { return &header_; }
|
const STFSHeader* header() const { return &header_; }
|
||||||
STFSEntry* root_entry();
|
STFSEntry* root_entry() const { return root_entry_.get(); }
|
||||||
|
|
||||||
Error Load();
|
Error Load();
|
||||||
void Dump();
|
void Dump();
|
||||||
|
@ -188,21 +179,19 @@ private:
|
||||||
uint32_t next_block_index;
|
uint32_t next_block_index;
|
||||||
uint32_t info;
|
uint32_t info;
|
||||||
} BlockHash_t;
|
} BlockHash_t;
|
||||||
BlockHash_t GetBlockHash(const uint8_t* map_ptr,
|
BlockHash_t GetBlockHash(const uint8_t* map_ptr, uint32_t block_index,
|
||||||
uint32_t block_index, uint32_t table_offset);
|
uint32_t table_offset);
|
||||||
|
|
||||||
xe_mmap_ref mmap_;
|
xe_mmap_ref mmap_;
|
||||||
|
|
||||||
STFSPackageType package_type_;
|
STFSPackageType package_type_;
|
||||||
STFSHeader header_;
|
STFSHeader header_;
|
||||||
uint32_t table_size_shift_;
|
uint32_t table_size_shift_;
|
||||||
STFSEntry* root_entry_;
|
std::unique_ptr<STFSEntry> root_entry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_FS_STFS_H_
|
#endif // XENIA_KERNEL_FS_STFS_H_
|
||||||
|
|
Loading…
Reference in New Issue