Renaming xe::fs to xe::filesystem and xe::kernel::fs to xe::vfs.
Progress on #294.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/filesystem.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
|
||||
@@ -96,9 +96,9 @@ std::vector<XCONTENT_DATA> ContentManager::ListContent(uint32_t device_id,
|
||||
// Search path:
|
||||
// content_root/title_id/type_name/*
|
||||
auto package_root = ResolvePackageRoot(content_type);
|
||||
auto file_infos = xe::fs::ListFiles(package_root);
|
||||
auto file_infos = xe::filesystem::ListFiles(package_root);
|
||||
for (const auto& file_info : file_infos) {
|
||||
if (file_info.type != xe::fs::FileInfo::Type::kDirectory) {
|
||||
if (file_info.type != xe::filesystem::FileInfo::Type::kDirectory) {
|
||||
// Directories only.
|
||||
continue;
|
||||
}
|
||||
@@ -116,7 +116,7 @@ std::vector<XCONTENT_DATA> ContentManager::ListContent(uint32_t device_id,
|
||||
std::unique_ptr<ContentPackage> ContentManager::ResolvePackage(
|
||||
std::string root_name, const XCONTENT_DATA& data) {
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
if (!xe::fs::PathExists(package_path)) {
|
||||
if (!xe::filesystem::PathExists(package_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ std::unique_ptr<ContentPackage> ContentManager::ResolvePackage(
|
||||
|
||||
bool ContentManager::ContentExists(const XCONTENT_DATA& data) {
|
||||
auto path = ResolvePackagePath(data);
|
||||
return xe::fs::PathExists(path);
|
||||
return xe::filesystem::PathExists(path);
|
||||
}
|
||||
|
||||
X_RESULT ContentManager::CreateContent(std::string root_name,
|
||||
@@ -142,12 +142,12 @@ X_RESULT ContentManager::CreateContent(std::string root_name,
|
||||
}
|
||||
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
if (xe::fs::PathExists(package_path)) {
|
||||
if (xe::filesystem::PathExists(package_path)) {
|
||||
// Exists, must not!
|
||||
return X_ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
if (!xe::fs::CreateFolder(package_path)) {
|
||||
if (!xe::filesystem::CreateFolder(package_path)) {
|
||||
return X_ERROR_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ X_RESULT ContentManager::OpenContent(std::string root_name,
|
||||
}
|
||||
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
if (!xe::fs::PathExists(package_path)) {
|
||||
if (!xe::filesystem::PathExists(package_path)) {
|
||||
// Does not exist, must be created.
|
||||
return X_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ X_RESULT ContentManager::GetContentThumbnail(const XCONTENT_DATA& data,
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
auto thumb_path = xe::join_paths(package_path, kThumbnailFileName);
|
||||
if (xe::fs::PathExists(thumb_path)) {
|
||||
if (xe::filesystem::PathExists(thumb_path)) {
|
||||
auto file = _wfopen(thumb_path.c_str(), L"rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t file_len = ftell(file);
|
||||
@@ -221,8 +221,8 @@ X_RESULT ContentManager::SetContentThumbnail(const XCONTENT_DATA& data,
|
||||
std::vector<uint8_t> buffer) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
xe::fs::CreateFolder(package_path);
|
||||
if (xe::fs::PathExists(package_path)) {
|
||||
xe::filesystem::CreateFolder(package_path);
|
||||
if (xe::filesystem::PathExists(package_path)) {
|
||||
auto thumb_path = xe::join_paths(package_path, kThumbnailFileName);
|
||||
auto file = _wfopen(thumb_path.c_str(), L"wb");
|
||||
fwrite(buffer.data(), 1, buffer.size(), file);
|
||||
@@ -237,8 +237,8 @@ X_RESULT ContentManager::DeleteContent(const XCONTENT_DATA& data) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
if (xe::fs::PathExists(package_path)) {
|
||||
xe::fs::DeleteFolder(package_path);
|
||||
if (xe::filesystem::PathExists(package_path)) {
|
||||
xe::filesystem::DeleteFolder(package_path);
|
||||
return X_ERROR_SUCCESS;
|
||||
} else {
|
||||
return X_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
Device::Device(const std::string& path) : path_(path) {}
|
||||
|
||||
Device::~Device() = default;
|
||||
|
||||
// TODO(gibbed): make virtual + move implementation into HostPathDevice/etc.
|
||||
X_STATUS Device::QueryVolumeInfo(X_FILE_FS_VOLUME_INFORMATION* out_info,
|
||||
size_t length) {
|
||||
assert_not_null(out_info);
|
||||
const char* name = "test"; // TODO(gibbed): actual value
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
size_t name_length = strlen(name);
|
||||
if (((uint8_t*)&out_info->label[0]) + name_length > end) {
|
||||
return X_STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
out_info->creation_time = 0;
|
||||
out_info->serial_number = 12345678;
|
||||
out_info->supports_objects = 0;
|
||||
out_info->label_length = (uint32_t)name_length;
|
||||
memcpy(out_info->label, name, name_length);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(gibbed): make virtual + move implementation into HostPathDevice/etc.
|
||||
X_STATUS Device::QuerySizeInfo(X_FILE_FS_SIZE_INFORMATION* out_info,
|
||||
size_t length) {
|
||||
assert_not_null(out_info);
|
||||
out_info->total_allocation_units = 1234; // TODO(gibbed): actual value
|
||||
out_info->available_allocation_units = 0; // TODO(gibbed): actual value
|
||||
out_info->sectors_per_allocation_unit = 1; // TODO(gibbed): actual value
|
||||
out_info->bytes_per_sector = 1024; // TODO(gibbed): actual value
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO(gibbed): make virtual + move implementation into HostPathDevice/etc.
|
||||
X_STATUS Device::QueryAttributeInfo(X_FILE_FS_ATTRIBUTE_INFORMATION* out_info,
|
||||
size_t length) {
|
||||
assert_not_null(out_info);
|
||||
const char* name = "test"; // TODO(gibbed): actual value
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
size_t name_length = strlen(name);
|
||||
if (((uint8_t*)&out_info->fs_name[0]) + name_length > end) {
|
||||
return X_STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
out_info->attributes = 0;
|
||||
out_info->maximum_component_name_length = 255; // TODO(gibbed): actual value
|
||||
out_info->fs_name_length = (uint32_t)name_length;
|
||||
memcpy(out_info->fs_name, name, name_length);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class Device {
|
||||
public:
|
||||
Device(const std::string& path);
|
||||
virtual ~Device();
|
||||
|
||||
const std::string& path() const { return path_; }
|
||||
|
||||
virtual bool is_read_only() const { return true; }
|
||||
|
||||
virtual std::unique_ptr<Entry> ResolvePath(const char* path) = 0;
|
||||
|
||||
virtual X_STATUS QueryVolumeInfo(X_FILE_FS_VOLUME_INFORMATION* out_info,
|
||||
size_t length);
|
||||
virtual X_STATUS QuerySizeInfo(X_FILE_FS_SIZE_INFORMATION* out_info,
|
||||
size_t length);
|
||||
virtual X_STATUS QueryAttributeInfo(X_FILE_FS_ATTRIBUTE_INFORMATION* out_info,
|
||||
size_t length);
|
||||
|
||||
protected:
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICE_H_
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/disc_image_device.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
#include "xenia/kernel/fs/devices/disc_image_entry.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
DiscImageDevice::DiscImageDevice(const std::string& path,
|
||||
const std::wstring& local_path)
|
||||
: Device(path), local_path_(local_path), gdfx_(nullptr) {}
|
||||
|
||||
DiscImageDevice::~DiscImageDevice() { delete gdfx_; }
|
||||
|
||||
int DiscImageDevice::Init() {
|
||||
mmap_ = MappedMemory::Open(local_path_, MappedMemory::Mode::kRead);
|
||||
if (!mmap_) {
|
||||
XELOGE("Disc image could not be mapped");
|
||||
return 1;
|
||||
}
|
||||
|
||||
gdfx_ = new GDFX(mmap_.get());
|
||||
GDFX::Error error = gdfx_->Load();
|
||||
if (error != GDFX::kSuccess) {
|
||||
XELOGE("GDFX init failed: %d", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// gdfx_->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Entry> DiscImageDevice::ResolvePath(const char* path) {
|
||||
// The filesystem will have stripped our prefix off already, so the path will
|
||||
// be in the form:
|
||||
// some\PATH.foo
|
||||
|
||||
XELOGFS("DiscImageDevice::ResolvePath(%s)", path);
|
||||
|
||||
GDFXEntry* gdfx_entry = gdfx_->root_entry();
|
||||
|
||||
// Walk the path, one separator at a time.
|
||||
auto path_parts = xe::split_path(path);
|
||||
for (auto& part : path_parts) {
|
||||
gdfx_entry = gdfx_entry->GetChild(part.c_str());
|
||||
if (!gdfx_entry) {
|
||||
// Not found.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<DiscImageEntry>(this, path, mmap_.get(), gdfx_entry);
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class GDFX;
|
||||
|
||||
class DiscImageDevice : public Device {
|
||||
public:
|
||||
DiscImageDevice(const std::string& path, const std::wstring& local_path);
|
||||
~DiscImageDevice() override;
|
||||
|
||||
int Init();
|
||||
|
||||
std::unique_ptr<Entry> ResolvePath(const char* path) override;
|
||||
|
||||
private:
|
||||
std::wstring local_path_;
|
||||
std::unique_ptr<MappedMemory> mmap_;
|
||||
GDFX* gdfx_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
|
||||
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/disc_image_entry.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/kernel/fs/devices/disc_image_file.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class DiscImageMemoryMapping : public MemoryMapping {
|
||||
public:
|
||||
DiscImageMemoryMapping(uint8_t* address, size_t length)
|
||||
: MemoryMapping(address, length) {}
|
||||
|
||||
~DiscImageMemoryMapping() override = default;
|
||||
};
|
||||
|
||||
DiscImageEntry::DiscImageEntry(Device* device, const char* path,
|
||||
MappedMemory* mmap, GDFXEntry* gdfx_entry)
|
||||
: Entry(device, path),
|
||||
mmap_(mmap),
|
||||
gdfx_entry_(gdfx_entry),
|
||||
it_(gdfx_entry->children.begin()) {}
|
||||
|
||||
DiscImageEntry::~DiscImageEntry() {}
|
||||
|
||||
X_STATUS DiscImageEntry::QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
assert_not_null(out_info);
|
||||
out_info->creation_time = 0;
|
||||
out_info->last_access_time = 0;
|
||||
out_info->last_write_time = 0;
|
||||
out_info->change_time = 0;
|
||||
out_info->allocation_size = xe::round_up(gdfx_entry_->size, 2048);
|
||||
out_info->end_of_file = gdfx_entry_->size;
|
||||
out_info->attributes = gdfx_entry_->attributes;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS DiscImageEntry::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
|
||||
size_t length, const char* file_name,
|
||||
bool restart) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
GDFXEntry* entry(nullptr);
|
||||
|
||||
if (file_name != nullptr) {
|
||||
// Only queries in the current directory are supported for now
|
||||
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||
|
||||
find_engine_.SetRule(file_name);
|
||||
|
||||
// Always restart the search?
|
||||
it_ = gdfx_entry_->children.begin();
|
||||
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
} else {
|
||||
if (restart) {
|
||||
it_ = gdfx_entry_->children.begin();
|
||||
}
|
||||
|
||||
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
auto entry_name = entry->name;
|
||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
out_info->next_entry_offset = 0;
|
||||
out_info->file_index = 0xCDCDCDCD;
|
||||
out_info->creation_time = 0;
|
||||
out_info->last_access_time = 0;
|
||||
out_info->last_write_time = 0;
|
||||
out_info->change_time = 0;
|
||||
out_info->end_of_file = entry->size;
|
||||
out_info->allocation_size = xe::round_up(entry->size, 2048);
|
||||
out_info->attributes = entry->attributes;
|
||||
out_info->file_name_length = static_cast<uint32_t>(entry->name.size());
|
||||
memcpy(out_info->file_name, entry->name.c_str(), entry->name.size());
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryMapping> DiscImageEntry::CreateMemoryMapping(
|
||||
Mode map_mode, const size_t offset, const size_t length) {
|
||||
if (map_mode != Mode::READ) {
|
||||
// Only allow reads.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t real_offset = gdfx_entry_->offset + offset;
|
||||
size_t real_length =
|
||||
length ? std::min(length, gdfx_entry_->size) : gdfx_entry_->size;
|
||||
return std::make_unique<DiscImageMemoryMapping>(mmap_->data() + real_offset,
|
||||
real_length);
|
||||
}
|
||||
|
||||
X_STATUS DiscImageEntry::Open(KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) {
|
||||
*out_file = new DiscImageFile(kernel_state, mode, this);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_ENTRY_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_ENTRY_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class DiscImageEntry : public Entry {
|
||||
public:
|
||||
DiscImageEntry(Device* device, const char* path, MappedMemory* mmap,
|
||||
GDFXEntry* gdfx_entry);
|
||||
~DiscImageEntry() override;
|
||||
|
||||
MappedMemory* mmap() const { return mmap_; }
|
||||
GDFXEntry* gdfx_entry() const { return gdfx_entry_; }
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
bool can_map() override { return true; }
|
||||
std::unique_ptr<MemoryMapping> CreateMemoryMapping(
|
||||
Mode map_mode, const size_t offset, const size_t length) override;
|
||||
|
||||
X_STATUS Open(KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) override;
|
||||
|
||||
private:
|
||||
MappedMemory* mmap_;
|
||||
GDFXEntry* gdfx_entry_;
|
||||
|
||||
xe::fs::WildcardEngine find_engine_;
|
||||
GDFXEntry::child_it_t it_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_ENTRY_H_
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/disc_image_file.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
#include "xenia/kernel/fs/devices/disc_image_entry.h"
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
DiscImageFile::DiscImageFile(KernelState* kernel_state, Mode mode,
|
||||
DiscImageEntry* entry)
|
||||
: XFile(kernel_state, mode), entry_(entry) {}
|
||||
|
||||
DiscImageFile::~DiscImageFile() { delete entry_; }
|
||||
|
||||
const std::string& DiscImageFile::path() const { return entry_->path(); }
|
||||
|
||||
const std::string& DiscImageFile::name() const { return entry_->name(); }
|
||||
|
||||
Device* DiscImageFile::device() const { return entry_->device(); }
|
||||
|
||||
X_STATUS DiscImageFile::QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
return entry_->QueryInfo(out_info);
|
||||
}
|
||||
|
||||
X_STATUS DiscImageFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
|
||||
size_t length, const char* file_name,
|
||||
bool restart) {
|
||||
return entry_->QueryDirectory(out_info, length, file_name, restart);
|
||||
}
|
||||
|
||||
X_STATUS DiscImageFile::ReadSync(void* buffer, size_t buffer_length,
|
||||
size_t byte_offset, size_t* out_bytes_read) {
|
||||
GDFXEntry* gdfx_entry = entry_->gdfx_entry();
|
||||
if (byte_offset >= gdfx_entry->size) {
|
||||
return X_STATUS_END_OF_FILE;
|
||||
}
|
||||
size_t real_offset = gdfx_entry->offset + byte_offset;
|
||||
size_t real_length = std::min(buffer_length, gdfx_entry->size - byte_offset);
|
||||
std::memcpy(buffer, entry_->mmap()->data() + real_offset, real_length);
|
||||
*out_bytes_read = real_length;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class DiscImageEntry;
|
||||
|
||||
class DiscImageFile : public XFile {
|
||||
public:
|
||||
DiscImageFile(KernelState* kernel_state, Mode desired_access,
|
||||
DiscImageEntry* entry);
|
||||
~DiscImageFile() override;
|
||||
|
||||
const std::string& path() const override;
|
||||
const std::string& name() const override;
|
||||
|
||||
Device* device() const override;
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
protected:
|
||||
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||
size_t* out_bytes_read) override;
|
||||
|
||||
private:
|
||||
DiscImageEntry* entry_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/host_path_device.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/kernel/fs/devices/host_path_entry.h"
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
HostPathDevice::HostPathDevice(const std::string& path,
|
||||
const std::wstring& local_path, bool read_only)
|
||||
: Device(path), local_path_(local_path), read_only_(read_only) {}
|
||||
|
||||
HostPathDevice::~HostPathDevice() {}
|
||||
|
||||
std::unique_ptr<Entry> HostPathDevice::ResolvePath(const char* path) {
|
||||
// The filesystem will have stripped our prefix off already, so the path will
|
||||
// be in the form:
|
||||
// some\PATH.foo
|
||||
|
||||
XELOGFS("HostPathDevice::ResolvePath(%s)", path);
|
||||
|
||||
auto rel_path = xe::to_wstring(path);
|
||||
auto full_path = xe::join_paths(local_path_, rel_path);
|
||||
full_path = xe::fix_path_separators(full_path);
|
||||
|
||||
// Only check the file exists when the device is read-only
|
||||
if (read_only_) {
|
||||
if (!xe::fs::PathExists(full_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(benvanik): get file info
|
||||
// TODO(benvanik): switch based on type
|
||||
|
||||
return std::make_unique<HostPathEntry>(this, path, full_path);
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class HostPathDevice : public Device {
|
||||
public:
|
||||
HostPathDevice(const std::string& path, const std::wstring& local_path,
|
||||
bool read_only);
|
||||
~HostPathDevice() override;
|
||||
|
||||
bool is_read_only() const { return read_only_; }
|
||||
|
||||
std::unique_ptr<Entry> ResolvePath(const char* path) override;
|
||||
|
||||
private:
|
||||
std::wstring local_path_;
|
||||
bool read_only_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_
|
||||
@@ -1,182 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/host_path_entry.h"
|
||||
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/kernel/fs/devices/host_path_file.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class HostPathMemoryMapping : public MemoryMapping {
|
||||
public:
|
||||
HostPathMemoryMapping(std::unique_ptr<MappedMemory> mmap)
|
||||
: MemoryMapping(mmap->data(), mmap->size()), mmap_(std::move(mmap)) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<MappedMemory> mmap_;
|
||||
};
|
||||
|
||||
HostPathEntry::HostPathEntry(Device* device, const char* path,
|
||||
const std::wstring& local_path)
|
||||
: Entry(device, path),
|
||||
local_path_(local_path),
|
||||
find_file_(INVALID_HANDLE_VALUE) {}
|
||||
|
||||
HostPathEntry::~HostPathEntry() {
|
||||
if (find_file_ != INVALID_HANDLE_VALUE) {
|
||||
FindClose(find_file_);
|
||||
}
|
||||
}
|
||||
|
||||
#define COMBINE_TIME(t) (((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime)
|
||||
|
||||
X_STATUS HostPathEntry::QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
if (!GetFileAttributesEx(local_path_.c_str(), GetFileExInfoStandard, &data)) {
|
||||
return X_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
uint64_t file_size = ((uint64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow;
|
||||
|
||||
out_info->creation_time = COMBINE_TIME(data.ftCreationTime);
|
||||
out_info->last_access_time = COMBINE_TIME(data.ftLastAccessTime);
|
||||
out_info->last_write_time = COMBINE_TIME(data.ftLastWriteTime);
|
||||
out_info->change_time = COMBINE_TIME(data.ftLastWriteTime);
|
||||
out_info->allocation_size = xe::round_up(file_size, 4096);
|
||||
out_info->end_of_file = file_size;
|
||||
out_info->attributes = (X_FILE_ATTRIBUTES)data.dwFileAttributes;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS HostPathEntry::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
|
||||
size_t length, const char* file_name,
|
||||
bool restart) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
WIN32_FIND_DATA ffd;
|
||||
|
||||
HANDLE handle = find_file_;
|
||||
|
||||
if (restart == true && handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(find_file_);
|
||||
handle = find_file_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
std::wstring target_path = local_path_;
|
||||
if (!file_name) {
|
||||
target_path = xe::join_paths(target_path, L"*");
|
||||
} else {
|
||||
target_path = xe::join_paths(target_path, xe::to_wstring(file_name));
|
||||
}
|
||||
handle = find_file_ = FindFirstFile(target_path.c_str(), &ffd);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
} else {
|
||||
if (FindNextFile(handle, &ffd) == FALSE) {
|
||||
FindClose(handle);
|
||||
find_file_ = INVALID_HANDLE_VALUE;
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
size_t entry_name_length = wcslen(ffd.cFileName);
|
||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name_length > end) {
|
||||
FindClose(handle);
|
||||
find_file_ = INVALID_HANDLE_VALUE;
|
||||
return X_STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
uint64_t file_size = ((uint64_t)ffd.nFileSizeHigh << 32) | ffd.nFileSizeLow;
|
||||
|
||||
out_info->next_entry_offset = 0;
|
||||
out_info->file_index = 0xCDCDCDCD;
|
||||
out_info->creation_time = COMBINE_TIME(ffd.ftCreationTime);
|
||||
out_info->last_access_time = COMBINE_TIME(ffd.ftLastAccessTime);
|
||||
out_info->last_write_time = COMBINE_TIME(ffd.ftLastWriteTime);
|
||||
out_info->change_time = COMBINE_TIME(ffd.ftLastWriteTime);
|
||||
out_info->end_of_file = file_size;
|
||||
out_info->allocation_size = xe::round_up(file_size, 4096);
|
||||
out_info->attributes = (X_FILE_ATTRIBUTES)ffd.dwFileAttributes;
|
||||
|
||||
out_info->file_name_length = (uint32_t)entry_name_length;
|
||||
for (size_t i = 0; i < entry_name_length; ++i) {
|
||||
out_info->file_name[i] =
|
||||
ffd.cFileName[i] < 256 ? (char)ffd.cFileName[i] : '?';
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryMapping> HostPathEntry::CreateMemoryMapping(
|
||||
Mode map_mode, const size_t offset, const size_t length) {
|
||||
auto mmap = MappedMemory::Open(
|
||||
local_path_, map_mode == Mode::READ ? MappedMemory::Mode::kRead
|
||||
: MappedMemory::Mode::kReadWrite,
|
||||
offset, length);
|
||||
if (!mmap) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<HostPathMemoryMapping>(std::move(mmap));
|
||||
}
|
||||
|
||||
X_STATUS HostPathEntry::Open(KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) {
|
||||
// TODO(benvanik): plumb through proper disposition/access mode.
|
||||
DWORD desired_access =
|
||||
is_read_only() ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
|
||||
if (mode == Mode::READ_APPEND) {
|
||||
desired_access |= FILE_APPEND_DATA;
|
||||
}
|
||||
DWORD share_mode = FILE_SHARE_READ;
|
||||
DWORD creation_disposition;
|
||||
switch (mode) {
|
||||
case Mode::READ:
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
break;
|
||||
case Mode::READ_WRITE:
|
||||
creation_disposition = OPEN_ALWAYS;
|
||||
break;
|
||||
case Mode::READ_APPEND:
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(mode);
|
||||
break;
|
||||
}
|
||||
DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0;
|
||||
HANDLE file =
|
||||
CreateFile(local_path_.c_str(), desired_access, share_mode, NULL,
|
||||
creation_disposition,
|
||||
flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
// TODO(benvanik): pick correct response.
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
*out_file = new HostPathFile(kernel_state, mode, this, file);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_HOST_PATH_ENTRY_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_HOST_PATH_ENTRY_H_
|
||||
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class HostPathEntry : public Entry {
|
||||
public:
|
||||
HostPathEntry(Device* device, const char* path,
|
||||
const std::wstring& local_path);
|
||||
~HostPathEntry() override;
|
||||
|
||||
const std::wstring& local_path() { return local_path_; }
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
bool can_map() override { return true; }
|
||||
std::unique_ptr<MemoryMapping> CreateMemoryMapping(
|
||||
Mode map_mode, const size_t offset, const size_t length) override;
|
||||
|
||||
X_STATUS Open(KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) override;
|
||||
|
||||
private:
|
||||
std::wstring local_path_;
|
||||
HANDLE find_file_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_HOST_PATH_ENTRY_H_
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/host_path_file.h"
|
||||
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
#include "xenia/kernel/fs/devices/host_path_entry.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
HostPathFile::HostPathFile(KernelState* kernel_state, Mode mode,
|
||||
HostPathEntry* entry, HANDLE file_handle)
|
||||
: entry_(entry), file_handle_(file_handle), XFile(kernel_state, mode) {}
|
||||
|
||||
HostPathFile::~HostPathFile() {
|
||||
CloseHandle(file_handle_);
|
||||
delete entry_;
|
||||
}
|
||||
|
||||
const std::string& HostPathFile::path() const { return entry_->path(); }
|
||||
|
||||
const std::string& HostPathFile::name() const { return entry_->name(); }
|
||||
|
||||
Device* HostPathFile::device() const { return entry_->device(); }
|
||||
|
||||
X_STATUS HostPathFile::QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
return entry_->QueryInfo(out_info);
|
||||
}
|
||||
|
||||
X_STATUS HostPathFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
|
||||
size_t length, const char* file_name,
|
||||
bool restart) {
|
||||
return entry_->QueryDirectory(out_info, length, file_name, restart);
|
||||
}
|
||||
|
||||
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
|
||||
size_t byte_offset, size_t* out_bytes_read) {
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Pointer = (PVOID)byte_offset;
|
||||
overlapped.hEvent = NULL;
|
||||
DWORD bytes_read = 0;
|
||||
BOOL read = ReadFile(file_handle_, buffer, (DWORD)buffer_length, &bytes_read,
|
||||
&overlapped);
|
||||
if (read) {
|
||||
*out_bytes_read = bytes_read;
|
||||
return X_STATUS_SUCCESS;
|
||||
} else {
|
||||
return X_STATUS_END_OF_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
|
||||
size_t byte_offset,
|
||||
size_t* out_bytes_written) {
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Pointer = (PVOID)byte_offset;
|
||||
overlapped.hEvent = NULL;
|
||||
DWORD bytes_written = 0;
|
||||
BOOL wrote = WriteFile(file_handle_, buffer, (DWORD)buffer_length,
|
||||
&bytes_written, &overlapped);
|
||||
if (wrote) {
|
||||
*out_bytes_written = bytes_written;
|
||||
return X_STATUS_SUCCESS;
|
||||
} else {
|
||||
return X_STATUS_END_OF_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_HOST_PATH_FILE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_HOST_PATH_FILE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class HostPathEntry;
|
||||
|
||||
class HostPathFile : public XFile {
|
||||
public:
|
||||
HostPathFile(KernelState* kernel_state, Mode mode, HostPathEntry* entry,
|
||||
HANDLE file_handle);
|
||||
~HostPathFile() override;
|
||||
|
||||
const std::string& path() const override;
|
||||
const std::string& name() const override;
|
||||
|
||||
Device* device() const override;
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
protected:
|
||||
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||
size_t* out_bytes_read) override;
|
||||
X_STATUS WriteSync(const void* buffer, size_t buffer_length,
|
||||
size_t byte_offset, size_t* out_bytes_written) override;
|
||||
|
||||
private:
|
||||
HostPathEntry* entry_;
|
||||
HANDLE file_handle_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_HOST_PATH_FILE_H_
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/stfs_container_device.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
STFSContainerDevice::STFSContainerDevice(const std::string& path,
|
||||
const std::wstring& local_path)
|
||||
: Device(path), local_path_(local_path), stfs_(nullptr) {}
|
||||
|
||||
STFSContainerDevice::~STFSContainerDevice() { delete stfs_; }
|
||||
|
||||
int STFSContainerDevice::Init() {
|
||||
mmap_ = MappedMemory::Open(local_path_, MappedMemory::Mode::kRead);
|
||||
if (!mmap_) {
|
||||
XELOGE("STFS container could not be mapped");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stfs_ = new STFS(mmap_.get());
|
||||
STFS::Error error = stfs_->Load();
|
||||
if (error != STFS::kSuccess) {
|
||||
XELOGE("STFS init failed: %d", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// stfs_->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Entry> STFSContainerDevice::ResolvePath(const char* path) {
|
||||
// The filesystem will have stripped our prefix off already, so the path will
|
||||
// be in the form:
|
||||
// some\PATH.foo
|
||||
|
||||
XELOGFS("STFSContainerDevice::ResolvePath(%s)", path);
|
||||
|
||||
STFSEntry* stfs_entry = stfs_->root_entry();
|
||||
|
||||
// Walk the path, one separator at a time.
|
||||
auto path_parts = xe::split_path(path);
|
||||
for (auto& part : path_parts) {
|
||||
stfs_entry = stfs_entry->GetChild(part.c_str());
|
||||
if (!stfs_entry) {
|
||||
// Not found.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<STFSContainerEntry>(this, path, mmap_.get(),
|
||||
stfs_entry);
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class STFS;
|
||||
|
||||
class STFSContainerDevice : public Device {
|
||||
public:
|
||||
STFSContainerDevice(const std::string& path, const std::wstring& local_path);
|
||||
~STFSContainerDevice() override;
|
||||
|
||||
int Init();
|
||||
|
||||
std::unique_ptr<Entry> ResolvePath(const char* path) override;
|
||||
|
||||
private:
|
||||
std::wstring local_path_;
|
||||
std::unique_ptr<MappedMemory> mmap_;
|
||||
STFS* stfs_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_
|
||||
@@ -1,100 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
||||
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_file.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
STFSContainerEntry::STFSContainerEntry(Device* device, const char* path,
|
||||
MappedMemory* mmap,
|
||||
STFSEntry* stfs_entry)
|
||||
: Entry(device, path),
|
||||
mmap_(mmap),
|
||||
stfs_entry_(stfs_entry),
|
||||
it_(stfs_entry_->children.begin()) {}
|
||||
|
||||
STFSContainerEntry::~STFSContainerEntry() = default;
|
||||
|
||||
X_STATUS STFSContainerEntry::QueryInfo(
|
||||
X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
assert_not_null(out_info);
|
||||
out_info->creation_time = stfs_entry_->update_timestamp;
|
||||
out_info->last_access_time = stfs_entry_->access_timestamp;
|
||||
out_info->last_write_time = stfs_entry_->update_timestamp;
|
||||
out_info->change_time = stfs_entry_->update_timestamp;
|
||||
out_info->allocation_size = xe::round_up(stfs_entry_->size, 4096);
|
||||
out_info->end_of_file = stfs_entry_->size;
|
||||
out_info->attributes = stfs_entry_->attributes;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS STFSContainerEntry::QueryDirectory(
|
||||
X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) {
|
||||
assert_not_null(out_info);
|
||||
|
||||
STFSEntry* entry(nullptr);
|
||||
|
||||
if (file_name != nullptr) {
|
||||
// Only queries in the current directory are supported for now
|
||||
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||
|
||||
find_engine_.SetRule(file_name);
|
||||
|
||||
// Always restart the search?
|
||||
it_ = stfs_entry_->children.begin();
|
||||
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
} else {
|
||||
if (restart) {
|
||||
it_ = stfs_entry_->children.begin();
|
||||
}
|
||||
|
||||
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||
if (!entry) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
auto end = (uint8_t*)out_info + length;
|
||||
auto entry_name = entry->name;
|
||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||
return X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
out_info->file_index = 0xCDCDCDCD;
|
||||
out_info->creation_time = entry->update_timestamp;
|
||||
out_info->last_access_time = entry->access_timestamp;
|
||||
out_info->last_write_time = entry->update_timestamp;
|
||||
out_info->change_time = entry->update_timestamp;
|
||||
out_info->end_of_file = entry->size;
|
||||
out_info->allocation_size = xe::round_up(entry->size, 4096);
|
||||
out_info->attributes = entry->attributes;
|
||||
out_info->file_name_length = static_cast<uint32_t>(entry->name.size());
|
||||
memcpy(out_info->file_name, entry->name.c_str(), entry->name.size());
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS STFSContainerEntry::Open(KernelState* kernel_state, Mode mode,
|
||||
bool async, XFile** out_file) {
|
||||
*out_file = new STFSContainerFile(kernel_state, mode, this);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
||||
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class STFSContainerEntry : public Entry {
|
||||
public:
|
||||
STFSContainerEntry(Device* device, const char* path, MappedMemory* mmap,
|
||||
STFSEntry* stfs_entry);
|
||||
~STFSContainerEntry() override;
|
||||
|
||||
MappedMemory* mmap() const { return mmap_; }
|
||||
STFSEntry* stfs_entry() const { return stfs_entry_; }
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
X_STATUS Open(KernelState* kernel_state, Mode desired_access, bool async,
|
||||
XFile** out_file) override;
|
||||
|
||||
private:
|
||||
MappedMemory* mmap_;
|
||||
STFSEntry* stfs_entry_;
|
||||
|
||||
xe::fs::WildcardEngine find_engine_;
|
||||
STFSEntry::child_it_t it_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/devices/stfs_container_file.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
STFSContainerFile::STFSContainerFile(KernelState* kernel_state, Mode mode,
|
||||
STFSContainerEntry* entry)
|
||||
: XFile(kernel_state, mode), entry_(entry) {}
|
||||
|
||||
STFSContainerFile::~STFSContainerFile() { delete entry_; }
|
||||
|
||||
const std::string& STFSContainerFile::path() const { return entry_->path(); }
|
||||
|
||||
const std::string& STFSContainerFile::name() const { return entry_->name(); }
|
||||
|
||||
Device* STFSContainerFile::device() const { return entry_->device(); }
|
||||
|
||||
X_STATUS STFSContainerFile::QueryInfo(
|
||||
X_FILE_NETWORK_OPEN_INFORMATION* out_info) {
|
||||
return entry_->QueryInfo(out_info);
|
||||
}
|
||||
|
||||
X_STATUS STFSContainerFile::QueryDirectory(
|
||||
X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) {
|
||||
return entry_->QueryDirectory(out_info, length, file_name, restart);
|
||||
}
|
||||
|
||||
X_STATUS STFSContainerFile::ReadSync(void* buffer, size_t buffer_length,
|
||||
size_t byte_offset,
|
||||
size_t* out_bytes_read) {
|
||||
STFSEntry* stfs_entry = entry_->stfs_entry();
|
||||
if (byte_offset >= stfs_entry->size) {
|
||||
return X_STATUS_END_OF_FILE;
|
||||
}
|
||||
|
||||
// Each block is 4096.
|
||||
// Blocks may not be sequential, so we need to read by blocks and handle the
|
||||
// offsets.
|
||||
size_t real_length = std::min(buffer_length, stfs_entry->size - byte_offset);
|
||||
size_t start_block = byte_offset / 4096;
|
||||
size_t end_block =
|
||||
std::min(stfs_entry->block_list.size(),
|
||||
(size_t)ceil((byte_offset + real_length) / 4096.0));
|
||||
uint8_t* dest_ptr = (uint8_t*)buffer;
|
||||
size_t remaining_length = real_length;
|
||||
for (size_t n = start_block; n < end_block; n++) {
|
||||
auto& record = stfs_entry->block_list[n];
|
||||
size_t offset = record.offset;
|
||||
size_t read_length = std::min(remaining_length, record.length);
|
||||
if (n == start_block) {
|
||||
offset += byte_offset % 4096;
|
||||
read_length = std::min(read_length, record.length - (byte_offset % 4096));
|
||||
}
|
||||
memcpy(dest_ptr, entry_->mmap()->data() + offset, read_length);
|
||||
dest_ptr += read_length;
|
||||
remaining_length -= read_length;
|
||||
}
|
||||
*out_bytes_read = real_length;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_FILE_H_
|
||||
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_FILE_H_
|
||||
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class STFSContainerEntry;
|
||||
|
||||
class STFSContainerFile : public XFile {
|
||||
public:
|
||||
STFSContainerFile(KernelState* kernel_state, Mode mode,
|
||||
STFSContainerEntry* entry);
|
||||
~STFSContainerFile() override;
|
||||
|
||||
const std::string& path() const override;
|
||||
const std::string& name() const override;
|
||||
|
||||
Device* device() const override;
|
||||
|
||||
X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) override;
|
||||
X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, size_t length,
|
||||
const char* file_name, bool restart) override;
|
||||
|
||||
protected:
|
||||
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||
size_t* out_bytes_read) override;
|
||||
|
||||
private:
|
||||
STFSContainerEntry* entry_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_FILE_H_
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
MemoryMapping::MemoryMapping(uint8_t* address, size_t length)
|
||||
: address_(address), length_(length) {}
|
||||
|
||||
MemoryMapping::~MemoryMapping() {}
|
||||
|
||||
Entry::Entry(Device* device, const std::string& path)
|
||||
: device_(device), path_(path) {
|
||||
assert_not_null(device);
|
||||
absolute_path_ = device->path() + path;
|
||||
name_ = xe::find_name_from_path(path);
|
||||
}
|
||||
|
||||
Entry::~Entry() = default;
|
||||
|
||||
bool Entry::is_read_only() const { return device_->is_read_only(); }
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_ENTRY_H_
|
||||
#define XENIA_KERNEL_FS_ENTRY_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class KernelState;
|
||||
class XFile;
|
||||
struct X_FILE_NETWORK_OPEN_INFORMATION;
|
||||
class X_FILE_DIRECTORY_INFORMATION;
|
||||
class X_FILE_FS_ATTRIBUTE_INFORMATION;
|
||||
class X_FILE_FS_SIZE_INFORMATION;
|
||||
class X_FILE_FS_VOLUME_INFORMATION;
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class Device;
|
||||
|
||||
enum class Mode {
|
||||
READ,
|
||||
READ_WRITE,
|
||||
READ_APPEND,
|
||||
};
|
||||
|
||||
class MemoryMapping {
|
||||
public:
|
||||
MemoryMapping(uint8_t* address, size_t length);
|
||||
virtual ~MemoryMapping();
|
||||
|
||||
uint8_t* address() const { return address_; }
|
||||
size_t length() const { return length_; }
|
||||
|
||||
private:
|
||||
uint8_t* address_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
class Entry {
|
||||
public:
|
||||
Entry(Device* device, const std::string& path);
|
||||
virtual ~Entry();
|
||||
|
||||
Device* device() const { return device_; }
|
||||
const std::string& path() const { return path_; }
|
||||
const std::string& absolute_path() const { return absolute_path_; }
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
bool is_read_only() const;
|
||||
|
||||
virtual X_STATUS QueryInfo(X_FILE_NETWORK_OPEN_INFORMATION* out_info) = 0;
|
||||
virtual X_STATUS QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
|
||||
size_t length, const char* file_name,
|
||||
bool restart) = 0;
|
||||
|
||||
virtual bool can_map() { return false; }
|
||||
|
||||
virtual std::unique_ptr<MemoryMapping> CreateMemoryMapping(
|
||||
Mode map_mode, const size_t offset, const size_t length) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual X_STATUS Open(KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) = 0;
|
||||
|
||||
private:
|
||||
Device* device_;
|
||||
std::string path_;
|
||||
std::string absolute_path_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_ENTRY_H_
|
||||
@@ -1,207 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/filesystem.h"
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/kernel/fs/devices/disc_image_device.h"
|
||||
#include "xenia/kernel/fs/devices/host_path_device.h"
|
||||
#include "xenia/kernel/fs/devices/stfs_container_device.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
FileSystem::FileSystem() {}
|
||||
|
||||
FileSystem::~FileSystem() {
|
||||
// Delete all devices.
|
||||
// This will explode if anyone is still using data from them.
|
||||
for (std::vector<Device*>::iterator it = devices_.begin();
|
||||
it != devices_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
devices_.clear();
|
||||
symlinks_.clear();
|
||||
}
|
||||
|
||||
fs::FileSystemType FileSystem::InferType(const std::wstring& local_path) {
|
||||
auto last_slash = local_path.find_last_of(xe::path_separator);
|
||||
auto last_dot = local_path.find_last_of('.');
|
||||
if (last_dot < last_slash) {
|
||||
last_dot = std::wstring::npos;
|
||||
}
|
||||
if (last_dot == std::wstring::npos) {
|
||||
// Likely an STFS container.
|
||||
return FileSystemType::STFS_TITLE;
|
||||
} else if (local_path.substr(last_dot) == L".xex") {
|
||||
// Treat as a naked xex file.
|
||||
return FileSystemType::XEX_FILE;
|
||||
} else {
|
||||
// Assume a disc image.
|
||||
return FileSystemType::DISC_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
int FileSystem::InitializeFromPath(fs::FileSystemType type,
|
||||
const std::wstring& local_path) {
|
||||
switch (type) {
|
||||
case FileSystemType::STFS_TITLE: {
|
||||
// Register the container in the virtual filesystem.
|
||||
int result_code =
|
||||
RegisterSTFSContainerDevice("\\Device\\Cdrom0", local_path);
|
||||
if (result_code) {
|
||||
XELOGE("Unable to mount STFS container");
|
||||
return result_code;
|
||||
}
|
||||
|
||||
// TODO(benvanik): figure out paths.
|
||||
// Create symlinks to the device.
|
||||
CreateSymbolicLink("game:", "\\Device\\Cdrom0");
|
||||
CreateSymbolicLink("d:", "\\Device\\Cdrom0");
|
||||
break;
|
||||
}
|
||||
case FileSystemType::XEX_FILE: {
|
||||
// Get the parent path of the file.
|
||||
auto last_slash = local_path.find_last_of(xe::path_separator);
|
||||
std::wstring parent_path = local_path.substr(0, last_slash);
|
||||
|
||||
// Register the local directory in the virtual filesystem.
|
||||
int result_code = RegisterHostPathDevice(
|
||||
"\\Device\\Harddisk0\\Partition0", parent_path, true);
|
||||
if (result_code) {
|
||||
XELOGE("Unable to mount local directory");
|
||||
return result_code;
|
||||
}
|
||||
|
||||
// Create symlinks to the device.
|
||||
CreateSymbolicLink("game:", "\\Device\\Harddisk0\\Partition0");
|
||||
CreateSymbolicLink("d:", "\\Device\\Harddisk0\\Partition0");
|
||||
break;
|
||||
}
|
||||
case FileSystemType::DISC_IMAGE: {
|
||||
// Register the disc image in the virtual filesystem.
|
||||
int result_code = RegisterDiscImageDevice("\\Device\\Cdrom0", local_path);
|
||||
if (result_code) {
|
||||
XELOGE("Unable to mount disc image");
|
||||
return result_code;
|
||||
}
|
||||
|
||||
// Create symlinks to the device.
|
||||
CreateSymbolicLink("game:", "\\Device\\Cdrom0");
|
||||
CreateSymbolicLink("d:", "\\Device\\Cdrom0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileSystem::RegisterDevice(const std::string& path, Device* device) {
|
||||
devices_.push_back(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileSystem::RegisterHostPathDevice(const std::string& path,
|
||||
const std::wstring& local_path,
|
||||
bool read_only) {
|
||||
Device* device = new HostPathDevice(path, local_path, read_only);
|
||||
return RegisterDevice(path, device);
|
||||
}
|
||||
|
||||
int FileSystem::RegisterDiscImageDevice(const std::string& path,
|
||||
const std::wstring& local_path) {
|
||||
DiscImageDevice* device = new DiscImageDevice(path, local_path);
|
||||
if (device->Init()) {
|
||||
return 1;
|
||||
}
|
||||
return RegisterDevice(path, device);
|
||||
}
|
||||
|
||||
int FileSystem::RegisterSTFSContainerDevice(const std::string& path,
|
||||
const std::wstring& local_path) {
|
||||
STFSContainerDevice* device = new STFSContainerDevice(path, local_path);
|
||||
if (device->Init()) {
|
||||
return 1;
|
||||
}
|
||||
return RegisterDevice(path, device);
|
||||
}
|
||||
|
||||
int FileSystem::CreateSymbolicLink(const std::string& path,
|
||||
const std::string& target) {
|
||||
symlinks_.insert({path, target});
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileSystem::DeleteSymbolicLink(const std::string& path) {
|
||||
auto& it = symlinks_.find(path);
|
||||
if (it == symlinks_.end()) {
|
||||
return 1;
|
||||
}
|
||||
symlinks_.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Entry> FileSystem::ResolvePath(const std::string& path) {
|
||||
// Resolve relative paths
|
||||
std::string normalized_path(xe::fs::CanonicalizePath(path));
|
||||
|
||||
// Resolve symlinks.
|
||||
std::string device_path;
|
||||
std::string relative_path;
|
||||
for (const auto& it : symlinks_) {
|
||||
if (xe::find_first_of_case(normalized_path, it.first) == 0) {
|
||||
// Found symlink!
|
||||
device_path = it.second;
|
||||
relative_path = normalized_path.substr(it.first.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Not to fret, check to see if the path is fully qualified.
|
||||
if (device_path.empty()) {
|
||||
for (auto& device : devices_) {
|
||||
if (xe::find_first_of_case(normalized_path, device->path()) == 0) {
|
||||
device_path = device->path();
|
||||
relative_path = normalized_path.substr(device_path.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device_path.empty()) {
|
||||
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Scan all devices.
|
||||
for (auto& device : devices_) {
|
||||
if (strcasecmp(device_path.c_str(), device->path().c_str()) == 0) {
|
||||
return device->ResolvePath(relative_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
|
||||
device_path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
X_STATUS FileSystem::Open(std::unique_ptr<Entry> entry,
|
||||
KernelState* kernel_state, Mode mode, bool async,
|
||||
XFile** out_file) {
|
||||
auto result = entry->Open(kernel_state, mode, async, out_file);
|
||||
if (XSUCCEEDED(result)) {
|
||||
entry.release();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_FILESYSTEM_H_
|
||||
#define XENIA_KERNEL_FS_FILESYSTEM_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class Device;
|
||||
|
||||
enum class FileSystemType {
|
||||
STFS_TITLE,
|
||||
DISC_IMAGE,
|
||||
XEX_FILE,
|
||||
};
|
||||
|
||||
class FileSystem {
|
||||
public:
|
||||
FileSystem();
|
||||
~FileSystem();
|
||||
|
||||
FileSystemType InferType(const std::wstring& local_path);
|
||||
int InitializeFromPath(FileSystemType type, const std::wstring& local_path);
|
||||
|
||||
int RegisterDevice(const std::string& path, Device* device);
|
||||
int RegisterHostPathDevice(const std::string& path,
|
||||
const std::wstring& local_path, bool read_only);
|
||||
int RegisterDiscImageDevice(const std::string& path,
|
||||
const std::wstring& local_path);
|
||||
int RegisterSTFSContainerDevice(const std::string& path,
|
||||
const std::wstring& local_path);
|
||||
|
||||
int CreateSymbolicLink(const std::string& path, const std::string& target);
|
||||
int DeleteSymbolicLink(const std::string& path);
|
||||
|
||||
std::unique_ptr<Entry> ResolvePath(const std::string& path);
|
||||
X_STATUS Open(std::unique_ptr<Entry> entry, KernelState* kernel_state,
|
||||
Mode mode, bool async, XFile** out_file);
|
||||
|
||||
private:
|
||||
std::vector<Device*> devices_;
|
||||
std::unordered_map<std::string, std::string> symlinks_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_FILESYSTEM_H_
|
||||
@@ -1,207 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
* Major contributions to this file from:
|
||||
* - abgx360
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/gdfx.h"
|
||||
|
||||
#include "xenia/base/math.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
const size_t kXESectorSize = 2048;
|
||||
|
||||
GDFXEntry::GDFXEntry()
|
||||
: attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0) {}
|
||||
|
||||
GDFXEntry::~GDFXEntry() {
|
||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||
it != children.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
GDFXEntry* GDFXEntry::GetChild(const xe::fs::WildcardEngine& engine,
|
||||
child_it_t& ref_it) {
|
||||
GDFXEntry* child_entry(nullptr);
|
||||
while (ref_it != children.end()) {
|
||||
if (engine.Match((*ref_it)->name)) {
|
||||
child_entry = (*ref_it);
|
||||
++ref_it;
|
||||
break;
|
||||
}
|
||||
++ref_it;
|
||||
}
|
||||
return child_entry;
|
||||
}
|
||||
|
||||
GDFXEntry* GDFXEntry::GetChild(const char* name) {
|
||||
// TODO(benvanik): a faster search
|
||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||
it != children.end(); ++it) {
|
||||
GDFXEntry* entry = *it;
|
||||
if (strcasecmp(entry->name.c_str(), name) == 0) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GDFXEntry::Dump(int indent) {
|
||||
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
|
||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||
it != children.end(); ++it) {
|
||||
GDFXEntry* entry = *it;
|
||||
entry->Dump(indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
GDFX::GDFX(MappedMemory* mmap) : mmap_(mmap) { root_entry_ = nullptr; }
|
||||
|
||||
GDFX::~GDFX() { delete root_entry_; }
|
||||
|
||||
GDFXEntry* GDFX::root_entry() { return root_entry_; }
|
||||
|
||||
GDFX::Error GDFX::Load() {
|
||||
ParseState state = {0};
|
||||
|
||||
state.ptr = mmap_->data();
|
||||
state.size = mmap_->size();
|
||||
|
||||
auto result = Verify(state);
|
||||
if (result != kSuccess) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ReadAllEntries(state, state.ptr + state.root_offset);
|
||||
if (result != kSuccess) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
void GDFX::Dump() {
|
||||
if (root_entry_) {
|
||||
root_entry_->Dump(0);
|
||||
}
|
||||
}
|
||||
|
||||
GDFX::Error GDFX::Verify(ParseState& state) {
|
||||
// Find sector 32 of the game partition - try at a few points.
|
||||
const static size_t likely_offsets[] = {
|
||||
0x00000000, 0x0000FB20, 0x00020600, 0x0FD90000,
|
||||
};
|
||||
bool magic_found = false;
|
||||
for (size_t n = 0; n < xe::countof(likely_offsets); n++) {
|
||||
state.game_offset = likely_offsets[n];
|
||||
if (VerifyMagic(state, state.game_offset + (32 * kXESectorSize))) {
|
||||
magic_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!magic_found) {
|
||||
// File doesn't have the magic values - likely not a real GDFX source.
|
||||
return kErrorFileMismatch;
|
||||
}
|
||||
|
||||
// Read sector 32 to get FS state.
|
||||
if (state.size < state.game_offset + (32 * kXESectorSize)) {
|
||||
return kErrorReadError;
|
||||
}
|
||||
uint8_t* fs_ptr = state.ptr + state.game_offset + (32 * kXESectorSize);
|
||||
state.root_sector = xe::load<uint32_t>(fs_ptr + 20);
|
||||
state.root_size = xe::load<uint32_t>(fs_ptr + 24);
|
||||
state.root_offset = state.game_offset + (state.root_sector * kXESectorSize);
|
||||
if (state.root_size < 13 || state.root_size > 32 * 1024 * 1024) {
|
||||
return kErrorDamagedFile;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
bool GDFX::VerifyMagic(ParseState& state, size_t offset) {
|
||||
// Simple check to see if the given offset contains the magic value.
|
||||
return memcmp(state.ptr + offset, "MICROSOFT*XBOX*MEDIA", 20) == 0;
|
||||
}
|
||||
|
||||
GDFX::Error GDFX::ReadAllEntries(ParseState& state,
|
||||
const uint8_t* root_buffer) {
|
||||
root_entry_ = new GDFXEntry();
|
||||
root_entry_->offset = 0;
|
||||
root_entry_->size = 0;
|
||||
root_entry_->name = "";
|
||||
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
||||
|
||||
if (!ReadEntry(state, root_buffer, 0, root_entry_)) {
|
||||
return kErrorOutOfMemory;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
bool GDFX::ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||
uint16_t entry_ordinal, GDFXEntry* parent) {
|
||||
const uint8_t* p = buffer + (entry_ordinal * 4);
|
||||
|
||||
uint16_t node_l = xe::load<uint16_t>(p + 0);
|
||||
uint16_t node_r = xe::load<uint16_t>(p + 2);
|
||||
size_t sector = xe::load<uint32_t>(p + 4);
|
||||
size_t length = xe::load<uint32_t>(p + 8);
|
||||
uint8_t attributes = xe::load<uint8_t>(p + 12);
|
||||
uint8_t name_length = xe::load<uint8_t>(p + 13);
|
||||
char* name = (char*)(p + 14);
|
||||
|
||||
if (node_l && !ReadEntry(state, buffer, node_l, parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GDFXEntry* entry = new GDFXEntry();
|
||||
entry->name = std::string(name, name_length);
|
||||
entry->attributes = (X_FILE_ATTRIBUTES)attributes;
|
||||
|
||||
// Add to parent.
|
||||
parent->children.push_back(entry);
|
||||
|
||||
if (attributes & X_FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// Folder.
|
||||
entry->offset = 0;
|
||||
entry->size = 0;
|
||||
if (length) {
|
||||
// Not a leaf - read in children.
|
||||
if (state.size < state.game_offset + (sector * kXESectorSize)) {
|
||||
// Out of bounds read.
|
||||
return false;
|
||||
}
|
||||
// Read child list.
|
||||
uint8_t* folder_ptr =
|
||||
state.ptr + state.game_offset + (sector * kXESectorSize);
|
||||
if (!ReadEntry(state, folder_ptr, 0, entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// File.
|
||||
entry->offset = state.game_offset + (sector * kXESectorSize);
|
||||
entry->size = length;
|
||||
}
|
||||
|
||||
// Read next file in the list.
|
||||
if (node_r && !ReadEntry(state, buffer, node_r, parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_GDFX_H_
|
||||
#define XENIA_KERNEL_FS_GDFX_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class GDFX;
|
||||
|
||||
class GDFXEntry {
|
||||
public:
|
||||
GDFXEntry();
|
||||
~GDFXEntry();
|
||||
|
||||
typedef std::vector<GDFXEntry*> child_t;
|
||||
typedef child_t::iterator child_it_t;
|
||||
|
||||
GDFXEntry* GetChild(const xe::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||
GDFXEntry* GetChild(const char* name);
|
||||
|
||||
void Dump(int indent);
|
||||
|
||||
std::string name;
|
||||
X_FILE_ATTRIBUTES attributes;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
child_t children;
|
||||
};
|
||||
|
||||
class GDFX {
|
||||
public:
|
||||
enum Error {
|
||||
kSuccess = 0,
|
||||
kErrorOutOfMemory = -1,
|
||||
kErrorReadError = -10,
|
||||
kErrorFileMismatch = -30,
|
||||
kErrorDamagedFile = -31,
|
||||
};
|
||||
|
||||
GDFX(MappedMemory* mmap);
|
||||
virtual ~GDFX();
|
||||
|
||||
GDFXEntry* root_entry();
|
||||
|
||||
Error Load();
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
uint8_t* ptr;
|
||||
|
||||
// Size (bytes) of total image.
|
||||
size_t size;
|
||||
|
||||
// Offset (bytes) of game partition.
|
||||
size_t game_offset;
|
||||
|
||||
// Offset (sector) of root.
|
||||
size_t root_sector;
|
||||
// Offset (bytes) of root.
|
||||
size_t root_offset;
|
||||
// Size (bytes) of root.
|
||||
size_t root_size;
|
||||
} ParseState;
|
||||
|
||||
Error Verify(ParseState& state);
|
||||
bool VerifyMagic(ParseState& state, size_t offset);
|
||||
Error ReadAllEntries(ParseState& state, const uint8_t* root_buffer);
|
||||
bool ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||
uint16_t entry_ordinal, GDFXEntry* parent);
|
||||
|
||||
MappedMemory* mmap_;
|
||||
|
||||
GDFXEntry* root_entry_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_GDFX_H_
|
||||
@@ -1,345 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
* Major contributions to this file from:
|
||||
* - free60
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/fs/stfs.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
#define XEGETUINT24BE(p) \
|
||||
(((uint32_t)xe::load_and_swap<uint8_t>((p) + 0) << 16) | \
|
||||
((uint32_t)xe::load_and_swap<uint8_t>((p) + 1) << 8) | \
|
||||
(uint32_t)xe::load_and_swap<uint8_t>((p) + 2))
|
||||
#define XEGETUINT24LE(p) \
|
||||
(((uint32_t)xe::load<uint8_t>((p) + 2) << 16) | \
|
||||
((uint32_t)xe::load<uint8_t>((p) + 1) << 8) | \
|
||||
(uint32_t)xe::load<uint8_t>((p) + 0))
|
||||
|
||||
bool STFSVolumeDescriptor::Read(const uint8_t* p) {
|
||||
descriptor_size = xe::load_and_swap<uint8_t>(p + 0x00);
|
||||
if (descriptor_size != 0x24) {
|
||||
XELOGE("STFS volume descriptor size mismatch, expected 0x24 but got 0x%X",
|
||||
descriptor_size);
|
||||
return false;
|
||||
}
|
||||
reserved = xe::load_and_swap<uint8_t>(p + 0x01);
|
||||
block_separation = xe::load_and_swap<uint8_t>(p + 0x02);
|
||||
file_table_block_count = xe::load_and_swap<uint16_t>(p + 0x03);
|
||||
file_table_block_number = XEGETUINT24BE(p + 0x05);
|
||||
memcpy(top_hash_table_hash, p + 0x08, 0x14);
|
||||
total_allocated_block_count = xe::load_and_swap<uint32_t>(p + 0x1C);
|
||||
total_unallocated_block_count = xe::load_and_swap<uint32_t>(p + 0x20);
|
||||
return true;
|
||||
};
|
||||
|
||||
bool STFSHeader::Read(const uint8_t* p) {
|
||||
memcpy(license_entries, p + 0x22C, 0x100);
|
||||
memcpy(header_hash, p + 0x32C, 0x14);
|
||||
header_size = xe::load_and_swap<uint32_t>(p + 0x340);
|
||||
content_type = (STFSContentType)xe::load_and_swap<uint32_t>(p + 0x344);
|
||||
metadata_version = xe::load_and_swap<uint32_t>(p + 0x348);
|
||||
if (metadata_version > 1) {
|
||||
// This is a variant of thumbnail data/etc.
|
||||
// Can just ignore it for now (until we parse thumbnails).
|
||||
XELOGW("STFSContainer doesn't support version %d yet", metadata_version);
|
||||
}
|
||||
content_size = xe::load_and_swap<uint32_t>(p + 0x34C);
|
||||
media_id = xe::load_and_swap<uint32_t>(p + 0x354);
|
||||
version = xe::load_and_swap<uint32_t>(p + 0x358);
|
||||
base_version = xe::load_and_swap<uint32_t>(p + 0x35C);
|
||||
title_id = xe::load_and_swap<uint32_t>(p + 0x360);
|
||||
platform = (STFSPlatform)xe::load_and_swap<uint8_t>(p + 0x364);
|
||||
executable_type = xe::load_and_swap<uint8_t>(p + 0x365);
|
||||
disc_number = xe::load_and_swap<uint8_t>(p + 0x366);
|
||||
disc_in_set = xe::load_and_swap<uint8_t>(p + 0x367);
|
||||
save_game_id = xe::load_and_swap<uint32_t>(p + 0x368);
|
||||
memcpy(console_id, p + 0x36C, 0x5);
|
||||
memcpy(profile_id, p + 0x371, 0x8);
|
||||
data_file_count = xe::load_and_swap<uint32_t>(p + 0x39D);
|
||||
data_file_combined_size = xe::load_and_swap<uint64_t>(p + 0x3A1);
|
||||
descriptor_type = (STFSDescriptorType)xe::load_and_swap<uint8_t>(p + 0x3A9);
|
||||
if (descriptor_type != STFS_DESCRIPTOR_STFS) {
|
||||
XELOGE("STFS descriptor format not supported: %d", descriptor_type);
|
||||
return false;
|
||||
}
|
||||
if (!volume_descriptor.Read(p + 0x379)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(device_id, p + 0x3FD, 0x14);
|
||||
for (size_t n = 0; n < 0x900 / 2; n++) {
|
||||
display_names[n] = xe::load_and_swap<uint16_t>(p + 0x411 + n * 2);
|
||||
display_descs[n] = xe::load_and_swap<uint16_t>(p + 0xD11 + n * 2);
|
||||
}
|
||||
for (size_t n = 0; n < 0x80 / 2; n++) {
|
||||
publisher_name[n] = xe::load_and_swap<uint16_t>(p + 0x1611 + n * 2);
|
||||
title_name[n] = xe::load_and_swap<uint16_t>(p + 0x1691 + n * 2);
|
||||
}
|
||||
transfer_flags = xe::load_and_swap<uint8_t>(p + 0x1711);
|
||||
thumbnail_image_size = xe::load_and_swap<uint32_t>(p + 0x1712);
|
||||
title_thumbnail_image_size = xe::load_and_swap<uint32_t>(p + 0x1716);
|
||||
memcpy(thumbnail_image, p + 0x171A, 0x4000);
|
||||
memcpy(title_thumbnail_image, p + 0x571A, 0x4000);
|
||||
return true;
|
||||
}
|
||||
|
||||
STFSEntry::STFSEntry()
|
||||
: attributes(X_FILE_ATTRIBUTE_NONE),
|
||||
offset(0),
|
||||
size(0),
|
||||
update_timestamp(0),
|
||||
access_timestamp(0) {}
|
||||
|
||||
STFSEntry* STFSEntry::GetChild(const xe::fs::WildcardEngine& engine,
|
||||
child_it_t& ref_it) {
|
||||
STFSEntry* child_entry(nullptr);
|
||||
while (ref_it != children.end()) {
|
||||
if (engine.Match((*ref_it)->name)) {
|
||||
child_entry = (*ref_it).get();
|
||||
++ref_it;
|
||||
break;
|
||||
}
|
||||
++ref_it;
|
||||
}
|
||||
return child_entry;
|
||||
}
|
||||
|
||||
STFSEntry* STFSEntry::GetChild(const char* name) {
|
||||
// TODO(benvanik): a faster search
|
||||
for (const auto& entry : children) {
|
||||
if (strcasecmp(entry->name.c_str(), name) == 0) {
|
||||
return entry.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void STFSEntry::Dump(int indent) {
|
||||
printf("%s%s\n", std::string(indent, ' ').c_str(), name.c_str());
|
||||
for (const auto& entry : children) {
|
||||
entry->Dump(indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
STFS::STFS(MappedMemory* mmap) : mmap_(mmap) {}
|
||||
|
||||
STFS::~STFS() {}
|
||||
|
||||
STFS::Error STFS::Load() {
|
||||
uint8_t* map_ptr = mmap_->data();
|
||||
|
||||
auto result = ReadHeaderAndVerify(map_ptr);
|
||||
if (result != kSuccess) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ReadAllEntries(map_ptr);
|
||||
if (result != kSuccess) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
void STFS::Dump() {
|
||||
if (root_entry_) {
|
||||
root_entry_->Dump(0);
|
||||
}
|
||||
}
|
||||
|
||||
STFS::Error STFS::ReadHeaderAndVerify(const uint8_t* map_ptr) {
|
||||
// Check signature.
|
||||
if (memcmp(map_ptr, "LIVE", 4) == 0) {
|
||||
package_type_ = STFS_PACKAGE_LIVE;
|
||||
} else if (memcmp(map_ptr, "PIRS", 4) == 0) {
|
||||
package_type_ = STFS_PACKAGE_PIRS;
|
||||
} else if (memcmp(map_ptr, "CON", 3) == 0) {
|
||||
package_type_ = STFS_PACKAGE_CON;
|
||||
} else {
|
||||
// Unexpected format.
|
||||
return STFS::Error::kErrorFileMismatch;
|
||||
}
|
||||
|
||||
// Read header.
|
||||
if (!header_.Read(map_ptr)) {
|
||||
return STFS::Error::kErrorDamagedFile;
|
||||
}
|
||||
|
||||
if (((header_.header_size + 0x0FFF) & 0xB000) == 0xB000) {
|
||||
table_size_shift_ = 0;
|
||||
} else {
|
||||
table_size_shift_ = 1;
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
STFS::Error STFS::ReadAllEntries(const uint8_t* map_ptr) {
|
||||
root_entry_.reset(new STFSEntry());
|
||||
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
||||
|
||||
std::vector<STFSEntry*> entries;
|
||||
|
||||
// Load all listings.
|
||||
auto& volume_descriptor = header_.volume_descriptor;
|
||||
uint32_t table_block_index = volume_descriptor.file_table_block_number;
|
||||
for (size_t n = 0; n < volume_descriptor.file_table_block_count; n++) {
|
||||
const uint8_t* p =
|
||||
map_ptr + BlockToOffset(ComputeBlockNumber(table_block_index));
|
||||
for (size_t m = 0; m < 0x1000 / 0x40; m++) {
|
||||
const uint8_t* filename = p; // 0x28b
|
||||
if (filename[0] == 0) {
|
||||
// Done.
|
||||
break;
|
||||
}
|
||||
uint8_t filename_length_flags = xe::load_and_swap<uint8_t>(p + 0x28);
|
||||
uint32_t allocated_block_count = XEGETUINT24LE(p + 0x29);
|
||||
uint32_t start_block_index = XEGETUINT24LE(p + 0x2F);
|
||||
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 update_timestamp = xe::load_and_swap<uint32_t>(p + 0x38);
|
||||
uint32_t access_timestamp = xe::load_and_swap<uint32_t>(p + 0x3C);
|
||||
p += 0x40;
|
||||
|
||||
auto entry = std::make_unique<STFSEntry>();
|
||||
entry->name = std::string((char*)filename, filename_length_flags & 0x3F);
|
||||
// bit 0x40 = consecutive blocks (not fragmented?)
|
||||
if (filename_length_flags & 0x80) {
|
||||
entry->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
||||
} else {
|
||||
entry->attributes = X_FILE_ATTRIBUTE_NORMAL;
|
||||
entry->offset = BlockToOffset(ComputeBlockNumber(start_block_index));
|
||||
entry->size = file_size;
|
||||
}
|
||||
entry->update_timestamp = update_timestamp;
|
||||
entry->access_timestamp = access_timestamp;
|
||||
entries.push_back(entry.get());
|
||||
|
||||
// Fill in all block records.
|
||||
// It's easier to do this now and just look them up later, at the cost
|
||||
// of some memory. Nasty chain walk.
|
||||
// TODO(benvanik): optimize if flag 0x40 (consecutive) is set.
|
||||
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 && info >= 0x80) {
|
||||
size_t block_size = std::min(0x1000ull, remaining_size);
|
||||
size_t offset = BlockToOffset(ComputeBlockNumber(block_index));
|
||||
entry->block_list.push_back({offset, block_size});
|
||||
remaining_size -= block_size;
|
||||
auto block_hash = GetBlockHash(map_ptr, block_index, 0);
|
||||
if (table_size_shift_ && block_hash.info < 0x80) {
|
||||
block_hash = GetBlockHash(map_ptr, block_index, 1);
|
||||
}
|
||||
block_index = block_hash.next_block_index;
|
||||
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);
|
||||
if (table_size_shift_ && block_hash.info < 0x80) {
|
||||
block_hash = GetBlockHash(map_ptr, table_block_index, 1);
|
||||
}
|
||||
table_block_index = block_hash.next_block_index;
|
||||
if (table_block_index == 0xFFFFFF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
size_t STFS::BlockToOffset(uint32_t block) {
|
||||
if (block >= 0xFFFFFF) {
|
||||
return -1;
|
||||
} else {
|
||||
return ((header_.header_size + 0x0FFF) & 0xF000) + (block << 12);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t STFS::ComputeBlockNumber(uint32_t block_index) {
|
||||
uint32_t block_shift = 0;
|
||||
if (((header_.header_size + 0x0FFF) & 0xB000) == 0xB000) {
|
||||
block_shift = 1;
|
||||
} else {
|
||||
if ((header_.volume_descriptor.block_separation & 0x1) == 0x1) {
|
||||
block_shift = 0;
|
||||
} else {
|
||||
block_shift = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t base = (block_index + 0xAA) / 0xAA;
|
||||
if (package_type_ == STFS_PACKAGE_CON) {
|
||||
base <<= block_shift;
|
||||
}
|
||||
uint32_t block = base + block_index;
|
||||
if (block_index >= 0xAA) {
|
||||
base = (block_index + 0x70E4) / 0x70E4;
|
||||
if (package_type_ == STFS_PACKAGE_CON) {
|
||||
base <<= block_shift;
|
||||
}
|
||||
block += base;
|
||||
if (block_index >= 0x70E4) {
|
||||
base = (block_index + 0x4AF768) / 0x4AF768;
|
||||
if (package_type_ == STFS_PACKAGE_CON) {
|
||||
base <<= block_shift;
|
||||
}
|
||||
block += base;
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
STFS::BlockHash_t STFS::GetBlockHash(const uint8_t* map_ptr,
|
||||
uint32_t block_index,
|
||||
uint32_t table_offset) {
|
||||
static const uint32_t table_spacing[] = {
|
||||
0xAB, 0x718F,
|
||||
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 table_index =
|
||||
(block_index / 0xAA) * table_spacing[table_size_shift_ * 3 + 0];
|
||||
if (block_index >= 0xAA) {
|
||||
table_index += ((block_index / 0x70E4) + 1) << table_size_shift_;
|
||||
if (block_index >= 0x70E4) {
|
||||
table_index += 1 << table_size_shift_;
|
||||
}
|
||||
}
|
||||
// table_index += table_offset - (1 << table_size_shift_);
|
||||
const uint8_t* hash_data = map_ptr + BlockToOffset(table_index);
|
||||
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 = XEGETUINT24BE(record_data + 0x15);
|
||||
return {next_block_index, info};
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
@@ -1,201 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_FS_STFS_H_
|
||||
#define XENIA_KERNEL_FS_STFS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/fs.h"
|
||||
#include "xenia/base/mapped_memory.h"
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace fs {
|
||||
|
||||
class STFS;
|
||||
|
||||
// http://www.free60.org/STFS
|
||||
|
||||
enum STFSPackageType {
|
||||
STFS_PACKAGE_CON,
|
||||
STFS_PACKAGE_PIRS,
|
||||
STFS_PACKAGE_LIVE,
|
||||
};
|
||||
|
||||
enum STFSContentType : uint32_t {
|
||||
STFS_CONTENT_ARCADE_TITLE = 0x000D0000,
|
||||
STFS_CONTENT_AVATAR_ITEM = 0x00009000,
|
||||
STFS_CONTENT_CACHE_FILE = 0x00040000,
|
||||
STFS_CONTENT_COMMUNITY_GAME = 0x02000000,
|
||||
STFS_CONTENT_GAME_DEMO = 0x00080000,
|
||||
STFS_CONTENT_GAMER_PICTURE = 0x00020000,
|
||||
STFS_CONTENT_GAME_TITLE = 0x000A0000,
|
||||
STFS_CONTENT_GAME_TRAILER = 0x000C0000,
|
||||
STFS_CONTENT_GAME_VIDEO = 0x00400000,
|
||||
STFS_CONTENT_INSTALLED_GAME = 0x00004000,
|
||||
STFS_CONTENT_INSTALLER = 0x000B0000,
|
||||
STFS_CONTENT_IPTV_PAUSE_BUFFER = 0x00002000,
|
||||
STFS_CONTENT_LICENSE_STORE = 0x000F0000,
|
||||
STFS_CONTENT_MARKETPLACE_CONTENT = 0x00000002,
|
||||
STFS_CONTENT_MOVIE = 0x00100000,
|
||||
STFS_CONTENT_MUSIC_VIDEO = 0x00300000,
|
||||
STFS_CONTENT_PODCAST_VIDEO = 0x00500000,
|
||||
STFS_CONTENT_PROFILE = 0x00010000,
|
||||
STFS_CONTENT_PUBLISHER = 0x00000003,
|
||||
STFS_CONTENT_SAVED_GAME = 0x00000001,
|
||||
STFS_CONTENT_STORAGE_DOWNLOAD = 0x00050000,
|
||||
STFS_CONTENT_THEME = 0x00030000,
|
||||
STFS_CONTENT_TV = 0x00200000,
|
||||
STFS_CONTENT_VIDEO = 0x00090000,
|
||||
STFS_CONTENT_VIRAL_VIDEO = 0x00600000,
|
||||
STFS_CONTENT_XBOX_DOWNLOAD = 0x00070000,
|
||||
STFS_CONTENT_XBOX_ORIGINAL_GAME = 0x00005000,
|
||||
STFS_CONTENT_XBOX_SAVED_GAME = 0x00060000,
|
||||
STFS_CONTENT_XBOX_360_TITLE = 0x00001000,
|
||||
STFS_CONTENT_XBOX_TITLE = 0x00005000,
|
||||
STFS_CONTENT_XNA = 0x000E0000,
|
||||
};
|
||||
|
||||
enum STFSPlatform : uint8_t {
|
||||
STFS_PLATFORM_XBOX_360 = 0x02,
|
||||
STFS_PLATFORM_PC = 0x04,
|
||||
};
|
||||
|
||||
enum STFSDescriptorType : uint32_t {
|
||||
STFS_DESCRIPTOR_STFS = 0,
|
||||
STFS_DESCRIPTOR_SVOD = 1,
|
||||
};
|
||||
|
||||
class STFSVolumeDescriptor {
|
||||
public:
|
||||
bool Read(const uint8_t* p);
|
||||
|
||||
uint8_t descriptor_size;
|
||||
uint8_t reserved;
|
||||
uint8_t block_separation;
|
||||
uint16_t file_table_block_count;
|
||||
uint32_t file_table_block_number;
|
||||
uint8_t top_hash_table_hash[0x14];
|
||||
uint32_t total_allocated_block_count;
|
||||
uint32_t total_unallocated_block_count;
|
||||
};
|
||||
|
||||
class STFSHeader {
|
||||
public:
|
||||
bool Read(const uint8_t* p);
|
||||
|
||||
uint8_t license_entries[0x100];
|
||||
uint8_t header_hash[0x14];
|
||||
uint32_t header_size;
|
||||
STFSContentType content_type;
|
||||
uint32_t metadata_version;
|
||||
uint64_t content_size;
|
||||
uint32_t media_id;
|
||||
uint32_t version;
|
||||
uint32_t base_version;
|
||||
uint32_t title_id;
|
||||
STFSPlatform platform;
|
||||
uint8_t executable_type;
|
||||
uint8_t disc_number;
|
||||
uint8_t disc_in_set;
|
||||
uint32_t save_game_id;
|
||||
uint8_t console_id[0x5];
|
||||
uint8_t profile_id[0x8];
|
||||
STFSVolumeDescriptor volume_descriptor;
|
||||
uint32_t data_file_count;
|
||||
uint64_t data_file_combined_size;
|
||||
STFSDescriptorType descriptor_type;
|
||||
uint8_t device_id[0x14];
|
||||
wchar_t display_names[0x900 / 2];
|
||||
wchar_t display_descs[0x900 / 2];
|
||||
wchar_t publisher_name[0x80 / 2];
|
||||
wchar_t title_name[0x80 / 2];
|
||||
uint8_t transfer_flags;
|
||||
uint32_t thumbnail_image_size;
|
||||
uint32_t title_thumbnail_image_size;
|
||||
uint8_t thumbnail_image[0x4000];
|
||||
uint8_t title_thumbnail_image[0x4000];
|
||||
};
|
||||
|
||||
class STFSEntry {
|
||||
public:
|
||||
STFSEntry();
|
||||
|
||||
typedef std::vector<std::unique_ptr<STFSEntry>> child_t;
|
||||
typedef child_t::iterator child_it_t;
|
||||
|
||||
STFSEntry* GetChild(const xe::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||
STFSEntry* GetChild(const char* name);
|
||||
|
||||
void Dump(int indent);
|
||||
|
||||
std::string name;
|
||||
X_FILE_ATTRIBUTES attributes;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
uint32_t update_timestamp;
|
||||
uint32_t access_timestamp;
|
||||
child_t children;
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
} BlockRecord_t;
|
||||
std::vector<BlockRecord_t> block_list;
|
||||
};
|
||||
|
||||
class STFS {
|
||||
public:
|
||||
enum Error {
|
||||
kSuccess = 0,
|
||||
kErrorOutOfMemory = -1,
|
||||
kErrorReadError = -10,
|
||||
kErrorFileMismatch = -30,
|
||||
kErrorDamagedFile = -31,
|
||||
};
|
||||
|
||||
STFS(MappedMemory* mmap);
|
||||
virtual ~STFS();
|
||||
|
||||
const STFSHeader* header() const { return &header_; }
|
||||
STFSEntry* root_entry() const { return root_entry_.get(); }
|
||||
|
||||
Error Load();
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
Error ReadHeaderAndVerify(const uint8_t* map_ptr);
|
||||
Error ReadAllEntries(const uint8_t* map_ptr);
|
||||
size_t BlockToOffset(uint32_t block);
|
||||
uint32_t ComputeBlockNumber(uint32_t block_index);
|
||||
|
||||
typedef struct {
|
||||
uint32_t next_block_index;
|
||||
uint32_t info;
|
||||
} BlockHash_t;
|
||||
BlockHash_t GetBlockHash(const uint8_t* map_ptr, uint32_t block_index,
|
||||
uint32_t table_offset);
|
||||
|
||||
MappedMemory* mmap_;
|
||||
|
||||
STFSPackageType package_type_;
|
||||
STFSHeader header_;
|
||||
uint32_t table_size_shift_;
|
||||
std::unique_ptr<STFSEntry> root_entry_;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_FS_STFS_H_
|
||||
@@ -19,10 +19,10 @@
|
||||
#include "xenia/cpu/export_resolver.h"
|
||||
#include "xenia/kernel/app.h"
|
||||
#include "xenia/kernel/content_manager.h"
|
||||
#include "xenia/kernel/fs/filesystem.h"
|
||||
#include "xenia/kernel/object_table.h"
|
||||
#include "xenia/kernel/user_profile.h"
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/vfs/virtual_file_system.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -84,7 +84,7 @@ class KernelState {
|
||||
Emulator* emulator() const { return emulator_; }
|
||||
Memory* memory() const { return memory_; }
|
||||
cpu::Processor* processor() const { return processor_; }
|
||||
fs::FileSystem* file_system() const { return file_system_; }
|
||||
vfs::VirtualFileSystem* file_system() const { return file_system_; }
|
||||
|
||||
uint32_t title_id() const;
|
||||
|
||||
@@ -140,7 +140,7 @@ class KernelState {
|
||||
Emulator* emulator_;
|
||||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
fs::FileSystem* file_system_;
|
||||
vfs::VirtualFileSystem* file_system_;
|
||||
|
||||
Dispatcher* dispatcher_;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
XFile::XFile(KernelState* kernel_state, fs::Mode mode)
|
||||
XFile::XFile(KernelState* kernel_state, vfs::Mode mode)
|
||||
: mode_(mode), position_(0), XObject(kernel_state, kTypeFile) {
|
||||
async_event_ = new XEvent(kernel_state);
|
||||
async_event_->Initialize(false, false);
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#ifndef XENIA_KERNEL_XBOXKRNL_XFILE_H_
|
||||
#define XENIA_KERNEL_XBOXKRNL_XFILE_H_
|
||||
|
||||
#include "xenia/kernel/fs/entry.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
#include "xenia/vfs/entry.h"
|
||||
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
@@ -139,7 +139,7 @@ class XFile : public XObject {
|
||||
virtual const std::string& path() const = 0;
|
||||
virtual const std::string& name() const = 0;
|
||||
|
||||
virtual fs::Device* device() const = 0;
|
||||
virtual vfs::Device* device() const = 0;
|
||||
|
||||
size_t position() const { return position_; }
|
||||
void set_position(size_t value) { position_ = value; }
|
||||
@@ -160,7 +160,7 @@ class XFile : public XObject {
|
||||
virtual void* GetWaitHandle();
|
||||
|
||||
protected:
|
||||
XFile(KernelState* kernel_state, fs::Mode mode);
|
||||
XFile(KernelState* kernel_state, vfs::Mode mode);
|
||||
virtual X_STATUS ReadSync(void* buffer, size_t buffer_length,
|
||||
size_t byte_offset, size_t* out_bytes_read) = 0;
|
||||
virtual X_STATUS WriteSync(const void* buffer, size_t buffer_length,
|
||||
@@ -169,7 +169,7 @@ class XFile : public XObject {
|
||||
}
|
||||
|
||||
private:
|
||||
fs::Mode mode_;
|
||||
vfs::Mode mode_;
|
||||
XEvent* async_event_;
|
||||
|
||||
// TODO(benvanik): create flags, open state, etc.
|
||||
|
||||
@@ -51,7 +51,7 @@ X_STATUS XUserModule::LoadFromFile(std::string path) {
|
||||
// If the FS supports mapping, map the file in and load from that.
|
||||
if (fs_entry->can_map()) {
|
||||
// Map.
|
||||
auto mmap = fs_entry->CreateMemoryMapping(fs::Mode::READ, 0, 0);
|
||||
auto mmap = fs_entry->CreateMemoryMapping(vfs::Mode::READ, 0, 0);
|
||||
if (!mmap) {
|
||||
return result;
|
||||
}
|
||||
@@ -70,7 +70,7 @@ X_STATUS XUserModule::LoadFromFile(std::string path) {
|
||||
// Open file for reading.
|
||||
XFile* file_ptr = nullptr;
|
||||
result = kernel_state()->file_system()->Open(
|
||||
std::move(fs_entry), kernel_state(), fs::Mode::READ, false, &file_ptr);
|
||||
std::move(fs_entry), kernel_state(), vfs::Mode::READ, false, &file_ptr);
|
||||
object_ref<XFile> file(file_ptr);
|
||||
if (result) {
|
||||
return result;
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/kernel/async_request.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/fs/device.h"
|
||||
#include "xenia/kernel/objects/xevent.h"
|
||||
#include "xenia/kernel/objects/xfile.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl_private.h"
|
||||
#include "xenia/vfs/device.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
using namespace xe::kernel::fs;
|
||||
using namespace xe::vfs;
|
||||
|
||||
// TODO(benvanik): replace X_OBJECT_ATTRIBUTES with new style and remove this.
|
||||
class X_ANSI_STRING_OLD {
|
||||
@@ -127,7 +127,7 @@ X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state,
|
||||
uint32_t info = X_FILE_DOES_NOT_EXIST;
|
||||
uint32_t handle;
|
||||
|
||||
FileSystem* fs = kernel_state->file_system();
|
||||
auto fs = kernel_state->file_system();
|
||||
std::unique_ptr<Entry> entry;
|
||||
|
||||
object_ref<XFile> root_file;
|
||||
@@ -165,13 +165,13 @@ X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state,
|
||||
info = X_FILE_DOES_NOT_EXIST;
|
||||
} else {
|
||||
// Open the file/directory.
|
||||
fs::Mode mode;
|
||||
vfs::Mode mode;
|
||||
if (desired_access & FileAccess::X_FILE_APPEND_DATA) {
|
||||
mode = fs::Mode::READ_APPEND;
|
||||
mode = vfs::Mode::READ_APPEND;
|
||||
} else if (wants_write) {
|
||||
mode = fs::Mode::READ_WRITE;
|
||||
mode = vfs::Mode::READ_WRITE;
|
||||
} else {
|
||||
mode = fs::Mode::READ;
|
||||
mode = vfs::Mode::READ;
|
||||
}
|
||||
XFile* file_ptr = nullptr;
|
||||
result = fs->Open(std::move(entry), kernel_state, mode,
|
||||
@@ -638,7 +638,7 @@ SHIM_CALL NtQueryFullAttributesFile_shim(PPCContext* ppc_context,
|
||||
}
|
||||
|
||||
// Resolve the file using the virtual file system.
|
||||
FileSystem* fs = kernel_state->file_system();
|
||||
auto fs = kernel_state->file_system();
|
||||
auto entry = fs->ResolvePath(object_name);
|
||||
if (entry) {
|
||||
// Found.
|
||||
|
||||
Reference in New Issue
Block a user