Renaming xe::fs to xe::filesystem and xe::kernel::fs to xe::vfs.

Progress on #294.
This commit is contained in:
Ben Vanik
2015-06-27 13:31:21 -07:00
parent bc75b0ab87
commit 0716cf84c0
45 changed files with 374 additions and 428 deletions

View File

@@ -0,0 +1,68 @@
/**
******************************************************************************
* 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/vfs/devices/disc_image_device.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/vfs/gdfx.h"
#include "xenia/vfs/devices/disc_image_entry.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,42 @@
/**
******************************************************************************
* 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_VFS_DEVICES_DISC_IMAGE_DEVICE_H_
#define XENIA_VFS_DEVICES_DISC_IMAGE_DEVICE_H_
#include <memory>
#include <string>
#include "xenia/base/mapped_memory.h"
#include "xenia/vfs/device.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_DISC_IMAGE_DEVICE_H_

View File

@@ -0,0 +1,121 @@
/**
******************************************************************************
* 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/vfs/devices/disc_image_entry.h"
#include <algorithm>
#include "xenia/base/math.h"
#include "xenia/vfs/devices/disc_image_file.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,54 @@
/**
******************************************************************************
* 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_VFS_DEVICES_DISC_IMAGE_ENTRY_H_
#define XENIA_VFS_DEVICES_DISC_IMAGE_ENTRY_H_
#include <vector>
#include "xenia/base/filesystem.h"
#include "xenia/base/mapped_memory.h"
#include "xenia/vfs/entry.h"
#include "xenia/vfs/gdfx.h"
namespace xe {
namespace vfs {
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::filesystem::WildcardEngine find_engine_;
GDFXEntry::child_it_t it_;
};
} // namespace vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_DISC_IMAGE_ENTRY_H_

View File

@@ -0,0 +1,57 @@
/**
******************************************************************************
* 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/vfs/devices/disc_image_file.h"
#include <algorithm>
#include "xenia/vfs/device.h"
#include "xenia/vfs/devices/disc_image_entry.h"
#include "xenia/vfs/gdfx.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* 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_VFS_DEVICES_DISC_IMAGE_FILE_H_
#define XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_
#include "xenia/kernel/objects/xfile.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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/vfs/devices/host_path_device.h"
#include "xenia/base/filesystem.h"
#include "xenia/base/logging.h"
#include "xenia/vfs/devices/host_path_entry.h"
#include "xenia/kernel/objects/xfile.h"
namespace xe {
namespace vfs {
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::filesystem::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 vfs
} // namespace xe

View File

@@ -0,0 +1,38 @@
/**
******************************************************************************
* 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_VFS_DEVICES_HOST_PATH_DEVICE_H_
#define XENIA_VFS_DEVICES_HOST_PATH_DEVICE_H_
#include <string>
#include "xenia/vfs/device.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_HOST_PATH_DEVICE_H_

View File

@@ -0,0 +1,180 @@
/**
******************************************************************************
* 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/vfs/devices/host_path_entry.h"
#include "xenia/base/mapped_memory.h"
#include "xenia/base/math.h"
#include "xenia/base/string.h"
#include "xenia/vfs/devices/host_path_file.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,45 @@
/**
******************************************************************************
* 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_VFS_DEVICES_HOST_PATH_ENTRY_H_
#define XENIA_VFS_DEVICES_HOST_PATH_ENTRY_H_
#include "xenia/vfs/entry.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_HOST_PATH_ENTRY_H_

View File

@@ -0,0 +1,77 @@
/**
******************************************************************************
* 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/vfs/devices/host_path_file.h"
#include "xenia/vfs/device.h"
#include "xenia/vfs/devices/host_path_entry.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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_VFS_DEVICES_HOST_PATH_FILE_H_
#define XENIA_VFS_DEVICES_HOST_PATH_FILE_H_
#include <string>
#include "xenia/kernel/objects/xfile.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_HOST_PATH_FILE_H_

View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* 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/vfs/devices/stfs_container_device.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/vfs/stfs.h"
#include "xenia/vfs/devices/stfs_container_entry.h"
#include "xenia/kernel/objects/xfile.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,42 @@
/**
******************************************************************************
* 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_VFS_DEVICES_STFS_CONTAINER_DEVICE_H_
#define XENIA_VFS_DEVICES_STFS_CONTAINER_DEVICE_H_
#include <memory>
#include <string>
#include "xenia/base/mapped_memory.h"
#include "xenia/vfs/device.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_STFS_CONTAINER_DEVICE_H_

View File

@@ -0,0 +1,98 @@
/**
******************************************************************************
* 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/vfs/devices/stfs_container_entry.h"
#include "xenia/base/math.h"
#include "xenia/vfs/devices/stfs_container_file.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,51 @@
/**
******************************************************************************
* 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_VFS_DEVICES_STFS_CONTAINER_ENTRY_H_
#define XENIA_VFS_DEVICES_STFS_CONTAINER_ENTRY_H_
#include <vector>
#include <iterator>
#include "xenia/base/filesystem.h"
#include "xenia/base/mapped_memory.h"
#include "xenia/vfs/entry.h"
#include "xenia/vfs/stfs.h"
namespace xe {
namespace vfs {
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::filesystem::WildcardEngine find_engine_;
STFSEntry::child_it_t it_;
};
} // namespace vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_STFS_CONTAINER_ENTRY_H_

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* 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/vfs/devices/stfs_container_file.h"
#include <algorithm>
#include "xenia/vfs/device.h"
#include "xenia/vfs/devices/stfs_container_entry.h"
#include "xenia/vfs/stfs.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe

View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* 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_VFS_DEVICES_STFS_CONTAINER_FILE_H_
#define XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_
#include "xenia/kernel/objects/xfile.h"
namespace xe {
namespace vfs {
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 vfs
} // namespace xe
#endif // XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_