Remove vfs dependency on kernel, implement I/O completion ports

This commit is contained in:
Dr. Chat 2015-12-15 16:52:41 -06:00 committed by Ben Vanik
parent a5c22ec214
commit bcacb9b127
21 changed files with 385 additions and 101 deletions

View File

@ -14,6 +14,7 @@
#include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
#include "xenia/kernel/xevent.h" #include "xenia/kernel/xevent.h"
#include "xenia/kernel/xiocompletion.h"
#include "xenia/kernel/xfile.h" #include "xenia/kernel/xfile.h"
#include "xenia/kernel/xthread.h" #include "xenia/kernel/xthread.h"
#include "xenia/vfs/device.h" #include "xenia/vfs/device.h"
@ -120,15 +121,17 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
} }
// Attempt open (or create). // Attempt open (or create).
object_ref<XFile> file; vfs::File* vfs_file;
xe::vfs::FileAction file_action; vfs::FileAction file_action;
X_STATUS result = kernel_state()->file_system()->OpenFile( X_STATUS result = kernel_state()->file_system()->OpenFile(
kernel_state(), target_path, target_path, vfs::FileDisposition((uint32_t)creation_disposition),
xe::vfs::FileDisposition((uint32_t)creation_disposition), desired_access, desired_access, &vfs_file, &file_action);
&file, &file_action); object_ref<XFile> file = nullptr;
X_HANDLE handle = X_INVALID_HANDLE_VALUE; X_HANDLE handle = X_INVALID_HANDLE_VALUE;
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
file = object_ref<XFile>(new XFile(kernel_state(), vfs_file));
// Handle ref is incremented, so return that. // Handle ref is incremented, so return that.
handle = file->handle(); handle = file->handle();
} }
@ -178,7 +181,8 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
// Synchronous. // Synchronous.
size_t bytes_read = 0; size_t bytes_read = 0;
result = file->Read(buffer, buffer_length, result = file->Read(buffer, buffer_length,
byte_offset_ptr ? *byte_offset_ptr : -1, &bytes_read); byte_offset_ptr ? *byte_offset_ptr : -1, &bytes_read,
apc_context);
if (io_status_block) { if (io_status_block) {
io_status_block->status = result; io_status_block->status = result;
io_status_block->information = (uint32_t)bytes_read; io_status_block->information = (uint32_t)bytes_read;
@ -261,9 +265,9 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
if (true) { if (true) {
// Synchronous request. // Synchronous request.
size_t bytes_written = 0; size_t bytes_written = 0;
result = result = file->Write(buffer, buffer_length,
file->Write(buffer, buffer_length, byte_offset_ptr ? *byte_offset_ptr : -1,
byte_offset_ptr ? *byte_offset_ptr : -1, &bytes_written); &bytes_written, apc_context);
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
info = (int32_t)bytes_written; info = (int32_t)bytes_written;
} }
@ -291,13 +295,54 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
} }
DECLARE_XBOXKRNL_EXPORT(NtWriteFile, ExportTag::kImplemented); DECLARE_XBOXKRNL_EXPORT(NtWriteFile, ExportTag::kImplemented);
dword_result_t NtCreateIoCompletion(lpvoid_t out_handle, dword_t desired_access, dword_result_t NtCreateIoCompletion(lpdword_t out_handle,
dword_t desired_access,
lpvoid_t object_attribs, lpvoid_t object_attribs,
dword_t num_concurrent_threads) { dword_t num_concurrent_threads) {
return X_STATUS_UNSUCCESSFUL; auto completion = new XIOCompletion(kernel_state());
if (out_handle) {
*out_handle = completion->handle();
}
return X_STATUS_SUCCESS;
} }
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub); DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub);
// Dequeues a packet from the completion port.
dword_result_t NtRemoveIoCompletion(
dword_t handle, lpdword_t key_context, lpdword_t apc_context,
pointer_t<X_IO_STATUS_BLOCK> io_status_block, lpqword_t timeout) {
X_STATUS status = X_STATUS_SUCCESS;
uint32_t info = 0;
auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) {
status = X_STATUS_INVALID_HANDLE;
}
uint64_t timeout_ticks = timeout ? *timeout : 0;
if (port->WaitForNotification(timeout_ticks)) {
auto notification = port->DequeueNotification();
if (key_context) {
*key_context = notification.key_context;
}
if (apc_context) {
*apc_context = notification.apc_context;
}
if (io_status_block) {
io_status_block->status = notification.status;
io_status_block->information = notification.num_bytes;
}
} else {
status = X_STATUS_TIMEOUT;
}
return status;
}
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kStub);
dword_result_t NtSetInformationFile( dword_result_t NtSetInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block, dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
lpvoid_t file_info, dword_t length, dword_t file_info_class) { lpvoid_t file_info, dword_t length, dword_t file_info_class) {
@ -335,9 +380,21 @@ dword_result_t NtSetInformationFile(
info = 8; info = 8;
XELOGW("NtSetInformationFile ignoring alloc/eof"); XELOGW("NtSetInformationFile ignoring alloc/eof");
break; break;
case XFileCompletionInformation: case XFileCompletionInformation: {
// Games appear to call NtCreateIoCompletion right before this // Info contains IO Completion handle and completion key
assert_true(length == 8);
auto handle = xe::load_and_swap<uint32_t>(file_info + 0x0);
auto key = xe::load_and_swap<uint32_t>(file_info + 0x4);
auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) {
return X_STATUS_INVALID_HANDLE;
}
file->RegisterIOCompletionPort(key, port);
break; break;
}
default: default:
// Unsupported, for now. // Unsupported, for now.
assert_always(); assert_always();

View File

@ -15,10 +15,8 @@
namespace xe { namespace xe {
namespace kernel { namespace kernel {
XFile::XFile(KernelState* kernel_state, uint32_t file_access, vfs::Entry* entry) XFile::XFile(KernelState* kernel_state, vfs::File* file)
: XObject(kernel_state, kTypeFile), : XObject(kernel_state, kTypeFile), file_(file) {
entry_(entry),
file_access_(file_access) {
async_event_ = new XEvent(kernel_state); async_event_ = new XEvent(kernel_state);
async_event_->Initialize(false, false); async_event_->Initialize(false, false);
} }
@ -27,6 +25,8 @@ XFile::~XFile() {
// TODO(benvanik): signal that the file is closing? // TODO(benvanik): signal that the file is closing?
async_event_->Set(0, false); async_event_->Set(0, false);
async_event_->Delete(); async_event_->Delete();
file_->Destroy();
} }
X_STATUS XFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info, X_STATUS XFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
@ -44,7 +44,7 @@ X_STATUS XFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
// Always restart the search? // Always restart the search?
find_index_ = 0; find_index_ = 0;
entry = entry_->IterateChildren(find_engine_, &find_index_); entry = file_->entry()->IterateChildren(find_engine_, &find_index_);
if (!entry) { if (!entry) {
return X_STATUS_NO_SUCH_FILE; return X_STATUS_NO_SUCH_FILE;
} }
@ -53,7 +53,7 @@ X_STATUS XFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
find_index_ = 0; find_index_ = 0;
} }
entry = entry_->IterateChildren(find_engine_, &find_index_); entry = file_->entry()->IterateChildren(find_engine_, &find_index_);
if (!entry) { if (!entry) {
return X_STATUS_NO_SUCH_FILE; return X_STATUS_NO_SUCH_FILE;
} }
@ -83,34 +83,92 @@ X_STATUS XFile::QueryDirectory(X_FILE_DIRECTORY_INFORMATION* out_info,
} }
X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) { size_t* out_bytes_read, uint32_t apc_context) {
if (byte_offset == -1) { if (byte_offset == -1) {
// Read from current position. // Read from current position.
byte_offset = position_; byte_offset = position_;
} }
size_t bytes_read = 0;
X_STATUS result = X_STATUS result =
ReadSync(buffer, buffer_length, byte_offset, out_bytes_read); file_->ReadSync(buffer, buffer_length, byte_offset, &bytes_read);
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
position_ += *out_bytes_read; position_ += bytes_read;
} }
XIOCompletion::IONotification notify;
notify.apc_context = apc_context;
notify.num_bytes = uint32_t(bytes_read);
notify.status = result;
NotifyIOCompletionPorts(notify);
if (out_bytes_read) {
*out_bytes_read = bytes_read;
}
async_event_->Set(0, false); async_event_->Set(0, false);
return result; return result;
} }
X_STATUS XFile::Write(const void* buffer, size_t buffer_length, X_STATUS XFile::Write(const void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_written) { size_t byte_offset, size_t* out_bytes_written,
uint32_t apc_context) {
if (byte_offset == -1) { if (byte_offset == -1) {
// Write from current position. // Write from current position.
byte_offset = position_; byte_offset = position_;
} }
size_t bytes_written = 0;
X_STATUS result = X_STATUS result =
WriteSync(buffer, buffer_length, byte_offset, out_bytes_written); file_->WriteSync(buffer, buffer_length, byte_offset, &bytes_written);
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
position_ += *out_bytes_written; position_ += bytes_written;
} }
XIOCompletion::IONotification notify;
notify.apc_context = apc_context;
notify.num_bytes = uint32_t(bytes_written);
notify.status = result;
NotifyIOCompletionPorts(notify);
if (out_bytes_written) {
*out_bytes_written = bytes_written;
}
async_event_->Set(0, false); async_event_->Set(0, false);
return result; return result;
} }
void XFile::RegisterIOCompletionPort(uint32_t key,
object_ref<XIOCompletion> port) {
std::lock_guard<std::mutex> lock(completion_port_lock_);
completion_ports_.push_back({key, port});
}
void XFile::RemoveIOCompletionPort(uint32_t key) {
std::lock_guard<std::mutex> lock(completion_port_lock_);
for (auto it = completion_ports_.begin(); it != completion_ports_.end();
it++) {
if (it->first == key) {
completion_ports_.erase(it);
break;
}
}
}
void XFile::NotifyIOCompletionPorts(
XIOCompletion::IONotification& notification) {
std::lock_guard<std::mutex> lock(completion_port_lock_);
for (auto port : completion_ports_) {
notification.key_context = port.first;
port.second->QueueNotification(notification);
}
}
} // namespace kernel } // namespace kernel
} // namespace xe } // namespace xe

View File

@ -14,9 +14,11 @@
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
#include "xenia/kernel/xevent.h" #include "xenia/kernel/xevent.h"
#include "xenia/kernel/xiocompletion.h"
#include "xenia/kernel/xobject.h" #include "xenia/kernel/xobject.h"
#include "xenia/vfs/device.h" #include "xenia/vfs/device.h"
#include "xenia/vfs/entry.h" #include "xenia/vfs/entry.h"
#include "xenia/vfs/file.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"
namespace xe { namespace xe {
@ -79,14 +81,16 @@ class XFile : public XObject {
public: public:
static const Type kType = kTypeFile; static const Type kType = kTypeFile;
XFile(KernelState* kernel_state, vfs::File* file);
~XFile() override; ~XFile() override;
vfs::Device* device() const { return entry_->device(); } vfs::Device* device() const { return file_->entry()->device(); }
vfs::Entry* entry() const { return entry_; } vfs::Entry* entry() const { return file_->entry(); }
vfs::File* file() const { return file_; }
uint32_t file_access() const { return file_access_; } uint32_t file_access() const { return file_access_; }
const std::string& path() const { return entry_->path(); } const std::string& path() const { return file_->entry()->path(); }
const std::string& name() const { return entry_->name(); } const std::string& name() const { return file_->entry()->name(); }
size_t position() const { return position_; } size_t position() const { return position_; }
void set_position(size_t value) { position_ = value; } void set_position(size_t value) { position_ = value; }
@ -95,29 +99,29 @@ class XFile : public XObject {
const char* file_name, bool restart); const char* file_name, bool restart);
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read); size_t* out_bytes_read, uint32_t apc_context);
X_STATUS Write(const void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS Write(const void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_written); size_t* out_bytes_written, uint32_t apc_context);
xe::threading::WaitHandle* GetWaitHandle() override { xe::threading::WaitHandle* GetWaitHandle() override {
return async_event_->GetWaitHandle(); return async_event_->GetWaitHandle();
} }
void RegisterIOCompletionPort(uint32_t key, object_ref<XIOCompletion> port);
void RemoveIOCompletionPort(uint32_t key);
protected: protected:
XFile(KernelState* kernel_state, uint32_t file_access, vfs::Entry* entry); void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
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,
size_t byte_offset, size_t* out_bytes_written) {
return X_STATUS_ACCESS_DENIED;
}
private: private:
vfs::Entry* entry_ = nullptr; vfs::File* file_ = nullptr;
uint32_t file_access_ = 0; uint32_t file_access_ = 0;
XEvent* async_event_ = nullptr; XEvent* async_event_ = nullptr;
std::mutex completion_port_lock_;
std::vector<std::pair<uint32_t, object_ref<XIOCompletion>>> completion_ports_;
// TODO(benvanik): create flags, open state, etc. // TODO(benvanik): create flags, open state, etc.
size_t position_ = 0; size_t position_ = 0;

View File

@ -0,0 +1,50 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/kernel/xiocompletion.h"
namespace xe {
namespace kernel {
XIOCompletion::XIOCompletion(KernelState* kernel_state)
: XObject(kernel_state, kTypeIOCompletion) {
notification_semaphore_ = threading::Semaphore::Create(0, kMaxNotifications);
}
XIOCompletion::~XIOCompletion() = default;
void XIOCompletion::QueueNotification(IONotification& notification) {
std::unique_lock<std::mutex> lock(notification_lock_);
notifications_.push(notification);
notification_semaphore_->Release(1, nullptr);
}
XIOCompletion::IONotification XIOCompletion::DequeueNotification() {
std::unique_lock<std::mutex> lock(notification_lock_);
assert_false(notifications_.empty());
auto notification = notifications_.front();
notifications_.pop();
return notification;
}
bool XIOCompletion::WaitForNotification(uint64_t wait_ticks) {
auto ms = std::chrono::milliseconds(TimeoutTicksToMs(wait_ticks));
auto res = threading::Wait(notification_semaphore_.get(), false, ms);
if (res == threading::WaitResult::kSuccess) {
return true;
}
return false;
}
} // namespace kernel
} // namespace xe

View File

@ -0,0 +1,54 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_KERNEL_XIOCOMPLETION_H_
#define XENIA_KERNEL_XIOCOMPLETION_H_
#include <queue>
#include "xenia/base/threading.h"
#include "xenia/kernel/xobject.h"
#include "xenia/xbox.h"
namespace xe {
namespace kernel {
class XIOCompletion : public XObject {
public:
static const Type kType = kTypeIOCompletion;
explicit XIOCompletion(KernelState* kernel_state);
~XIOCompletion() override;
struct IONotification {
uint32_t key_context;
uint32_t apc_context;
uint32_t status;
uint32_t num_bytes;
};
void QueueNotification(IONotification& notification);
IONotification DequeueNotification();
// If you call this and it returns true, you MUST dequeue a notification!
// Returns true if the wait was cancelled because a notification was queued.
bool WaitForNotification(uint64_t wait_ticks);
private:
static const uint32_t kMaxNotifications = 1024;
std::mutex notification_lock_;
std::queue<IONotification> notifications_;
std::unique_ptr<threading::Semaphore> notification_semaphore_ = nullptr;
};
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XIOCOMPLETION_H_

View File

@ -26,11 +26,8 @@ DiscImageEntry::DiscImageEntry(Device* device, Entry* parent, std::string path,
DiscImageEntry::~DiscImageEntry() = default; DiscImageEntry::~DiscImageEntry() = default;
X_STATUS DiscImageEntry::Open(kernel::KernelState* kernel_state, X_STATUS DiscImageEntry::Open(uint32_t desired_access, File** out_file) {
uint32_t desired_access, *out_file = new DiscImageFile(desired_access, this);
kernel::object_ref<kernel::XFile>* out_file) {
*out_file = kernel::object_ref<kernel::XFile>(
new DiscImageFile(kernel_state, desired_access, this));
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }

View File

@ -32,8 +32,7 @@ class DiscImageEntry : public Entry {
size_t data_offset() const { return data_offset_; } size_t data_offset() const { return data_offset_; }
size_t data_size() const { return data_size_; } size_t data_size() const { return data_size_; }
X_STATUS Open(kernel::KernelState* kernel_state, uint32_t desired_access, X_STATUS Open(uint32_t desired_access, File** out_file) override;
kernel::object_ref<kernel::XFile>* out_file) override;
bool can_map() const override { return true; } bool can_map() const override { return true; }
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode, std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,

View File

@ -16,12 +16,13 @@
namespace xe { namespace xe {
namespace vfs { namespace vfs {
DiscImageFile::DiscImageFile(kernel::KernelState* kernel_state, DiscImageFile::DiscImageFile(uint32_t file_access, DiscImageEntry* entry)
uint32_t file_access, DiscImageEntry* entry) : File(file_access, entry), entry_(entry) {}
: XFile(kernel_state, file_access, entry), entry_(entry) {}
DiscImageFile::~DiscImageFile() = default; DiscImageFile::~DiscImageFile() = default;
void DiscImageFile::Destroy() { delete this; }
X_STATUS DiscImageFile::ReadSync(void* buffer, size_t buffer_length, X_STATUS DiscImageFile::ReadSync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_read) { size_t byte_offset, size_t* out_bytes_read) {
if (byte_offset >= entry_->size()) { if (byte_offset >= entry_->size()) {

View File

@ -10,22 +10,26 @@
#ifndef XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_ #ifndef XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_
#define XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_ #define XENIA_VFS_DEVICES_DISC_IMAGE_FILE_H_
#include "xenia/kernel/xfile.h" #include "xenia/vfs/file.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
class DiscImageEntry; class DiscImageEntry;
class DiscImageFile : public kernel::XFile { class DiscImageFile : public File {
public: public:
DiscImageFile(kernel::KernelState* kernel_state, uint32_t file_access, DiscImageFile(uint32_t file_access, DiscImageEntry* entry);
DiscImageEntry* entry);
~DiscImageFile() override; ~DiscImageFile() override;
protected: void Destroy() override;
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) override; 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 {
return X_STATUS_ACCESS_DENIED;
}
private: private:
DiscImageEntry* entry_; DiscImageEntry* entry_;

View File

@ -14,6 +14,7 @@
#include "xenia/base/mapped_memory.h" #include "xenia/base/mapped_memory.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/string.h" #include "xenia/base/string.h"
#include "xenia/vfs/device.h"
#include "xenia/vfs/devices/host_path_file.h" #include "xenia/vfs/devices/host_path_file.h"
namespace xe { namespace xe {
@ -47,9 +48,7 @@ HostPathEntry* HostPathEntry::Create(Device* device, Entry* parent,
return entry; return entry;
} }
X_STATUS HostPathEntry::Open(kernel::KernelState* kernel_state, X_STATUS HostPathEntry::Open(uint32_t desired_access, File** out_file) {
uint32_t desired_access,
kernel::object_ref<kernel::XFile>* out_file) {
if (is_read_only() && (desired_access & (FileAccess::kFileWriteData | if (is_read_only() && (desired_access & (FileAccess::kFileWriteData |
FileAccess::kFileAppendData))) { FileAccess::kFileAppendData))) {
XELOGE("Attempting to open file for write access on read-only device"); XELOGE("Attempting to open file for write access on read-only device");
@ -61,8 +60,7 @@ X_STATUS HostPathEntry::Open(kernel::KernelState* kernel_state,
// TODO(benvanik): pick correct response. // TODO(benvanik): pick correct response.
return X_STATUS_NO_SUCH_FILE; return X_STATUS_NO_SUCH_FILE;
} }
*out_file = kernel::object_ref<kernel::XFile>(new HostPathFile( *out_file = new HostPathFile(desired_access, this, std::move(file_handle));
kernel_state, desired_access, this, std::move(file_handle)));
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }

View File

@ -32,8 +32,7 @@ class HostPathEntry : public Entry {
const std::wstring& local_path() { return local_path_; } const std::wstring& local_path() { return local_path_; }
X_STATUS Open(kernel::KernelState* kernel_state, uint32_t desired_access, X_STATUS Open(uint32_t desired_access, File** out_file) override;
kernel::object_ref<kernel::XFile>* out_file) override;
bool can_map() const override { return true; } bool can_map() const override { return true; }
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode, std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,

View File

@ -15,17 +15,17 @@ namespace xe {
namespace vfs { namespace vfs {
HostPathFile::HostPathFile( HostPathFile::HostPathFile(
kernel::KernelState* kernel_state, uint32_t file_access, uint32_t file_access, HostPathEntry* entry,
HostPathEntry* entry,
std::unique_ptr<xe::filesystem::FileHandle> file_handle) std::unique_ptr<xe::filesystem::FileHandle> file_handle)
: XFile(kernel_state, file_access, entry), : File(file_access, entry), file_handle_(std::move(file_handle)) {}
file_handle_(std::move(file_handle)) {}
HostPathFile::~HostPathFile() = default; HostPathFile::~HostPathFile() = default;
void HostPathFile::Destroy() { delete this; }
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length, X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_read) { size_t byte_offset, size_t* out_bytes_read) {
if (!(file_access() & FileAccess::kFileReadData)) { if (!(file_access_ & FileAccess::kFileReadData)) {
return X_STATUS_ACCESS_DENIED; return X_STATUS_ACCESS_DENIED;
} }
@ -39,7 +39,7 @@ X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length, X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
size_t byte_offset, size_t byte_offset,
size_t* out_bytes_written) { size_t* out_bytes_written) {
if (!(file_access() & if (!(file_access_ &
(FileAccess::kFileWriteData | FileAccess::kFileAppendData))) { (FileAccess::kFileWriteData | FileAccess::kFileAppendData))) {
return X_STATUS_ACCESS_DENIED; return X_STATUS_ACCESS_DENIED;
} }

View File

@ -13,21 +13,21 @@
#include <string> #include <string>
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
#include "xenia/kernel/xfile.h" #include "xenia/vfs/file.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
class HostPathEntry; class HostPathEntry;
class HostPathFile : public kernel::XFile { class HostPathFile : public File {
public: public:
HostPathFile(kernel::KernelState* kernel_state, uint32_t file_access, HostPathFile(uint32_t file_access, HostPathEntry* entry,
HostPathEntry* entry,
std::unique_ptr<xe::filesystem::FileHandle> file_handle); std::unique_ptr<xe::filesystem::FileHandle> file_handle);
~HostPathFile() override; ~HostPathFile() override;
protected: void Destroy() override;
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) override; size_t* out_bytes_read) override;
X_STATUS WriteSync(const void* buffer, size_t buffer_length, X_STATUS WriteSync(const void* buffer, size_t buffer_length,

View File

@ -24,11 +24,8 @@ StfsContainerEntry::StfsContainerEntry(Device* device, Entry* parent,
StfsContainerEntry::~StfsContainerEntry() = default; StfsContainerEntry::~StfsContainerEntry() = default;
X_STATUS StfsContainerEntry::Open(kernel::KernelState* kernel_state, X_STATUS StfsContainerEntry::Open(uint32_t desired_access, File** out_file) {
uint32_t desired_access, *out_file = new StfsContainerFile(desired_access, this);
kernel::object_ref<kernel::XFile>* out_file) {
*out_file = kernel::object_ref<kernel::XFile>(
new StfsContainerFile(kernel_state, desired_access, this));
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }

View File

@ -16,6 +16,7 @@
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
#include "xenia/base/mapped_memory.h" #include "xenia/base/mapped_memory.h"
#include "xenia/vfs/entry.h" #include "xenia/vfs/entry.h"
#include "xenia/vfs/file.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
@ -32,8 +33,7 @@ class StfsContainerEntry : public Entry {
size_t data_offset() const { return data_offset_; } size_t data_offset() const { return data_offset_; }
size_t data_size() const { return data_size_; } size_t data_size() const { return data_size_; }
X_STATUS Open(kernel::KernelState* kernel_state, uint32_t desired_access, X_STATUS Open(uint32_t desired_access, File** out_file) override;
kernel::object_ref<kernel::XFile>* out_file) override;
struct BlockRecord { struct BlockRecord {
size_t offset; size_t offset;

View File

@ -16,13 +16,14 @@
namespace xe { namespace xe {
namespace vfs { namespace vfs {
StfsContainerFile::StfsContainerFile(kernel::KernelState* kernel_state, StfsContainerFile::StfsContainerFile(uint32_t file_access,
uint32_t file_access,
StfsContainerEntry* entry) StfsContainerEntry* entry)
: XFile(kernel_state, file_access, entry), entry_(entry) {} : File(file_access, entry) {}
StfsContainerFile::~StfsContainerFile() = default; StfsContainerFile::~StfsContainerFile() = default;
void StfsContainerFile::Destroy() { delete this; }
X_STATUS StfsContainerFile::ReadSync(void* buffer, size_t buffer_length, X_STATUS StfsContainerFile::ReadSync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t byte_offset,
size_t* out_bytes_read) { size_t* out_bytes_read) {

View File

@ -10,22 +10,28 @@
#ifndef XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_ #ifndef XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_
#define XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_ #define XENIA_VFS_DEVICES_STFS_CONTAINER_FILE_H_
#include "xenia/kernel/xfile.h" #include "xenia/vfs/file.h"
#include "xenia/xbox.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
class StfsContainerEntry; class StfsContainerEntry;
class StfsContainerFile : public kernel::XFile { class StfsContainerFile : public File {
public: public:
StfsContainerFile(kernel::KernelState* kernel_state, uint32_t file_access, StfsContainerFile(uint32_t file_access, StfsContainerEntry* entry);
StfsContainerEntry* entry);
~StfsContainerFile() override; ~StfsContainerFile() override;
protected: void Destroy() override;
X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, X_STATUS ReadSync(void* buffer, size_t buffer_length, size_t byte_offset,
size_t* out_bytes_read) override; 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 {
return X_STATUS_ACCESS_DENIED;
}
private: private:
StfsContainerEntry* entry_; StfsContainerEntry* entry_;

View File

@ -18,7 +18,6 @@
#include "xenia/base/mapped_memory.h" #include "xenia/base/mapped_memory.h"
#include "xenia/base/mutex.h" #include "xenia/base/mutex.h"
#include "xenia/base/string_buffer.h" #include "xenia/base/string_buffer.h"
#include "xenia/kernel/xobject.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"
namespace xe { namespace xe {
@ -32,6 +31,7 @@ namespace xe {
namespace vfs { namespace vfs {
class Device; class Device;
class File;
// Matches http://source.winehq.org/source/include/winternl.h#1591. // Matches http://source.winehq.org/source/include/winternl.h#1591.
enum class FileAction { enum class FileAction {
@ -106,9 +106,9 @@ class Entry {
bool Delete(); bool Delete();
void Touch(); void Touch();
virtual X_STATUS Open(kernel::KernelState* kernel_state, // If successful, out_file points to a new file. When finished, call
uint32_t desired_access, // file->Destroy()
kernel::object_ref<kernel::XFile>* out_file) = 0; virtual X_STATUS Open(uint32_t desired_access, File** out_file) = 0;
virtual bool can_map() const { return false; } virtual bool can_map() const { return false; }
virtual std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode, virtual std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,

61
src/xenia/vfs/file.h Normal file
View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_VFS_FILE_H_
#define XENIA_VFS_FILE_H_
#include <cstdint>
#include "xenia/xbox.h"
namespace xe {
namespace vfs {
class Entry;
class File {
public:
File(uint32_t file_access, Entry* entry)
: file_access_(file_access), entry_(entry) {}
virtual ~File() = default;
virtual void Destroy() = 0;
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,
size_t byte_offset, size_t* out_bytes_written) = 0;
// TODO: Parameters
virtual X_STATUS ReadAsync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_read) {
return X_STATUS_NOT_IMPLEMENTED;
}
// TODO: Parameters
virtual X_STATUS WriteAsync(const void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_written) {
return X_STATUS_NOT_IMPLEMENTED;
}
// xe::filesystem::FileAccess
uint32_t file_access() const { return file_access_; }
const Entry* entry() const { return entry_; }
Entry* entry() { return entry_; }
protected:
// xe::filesystem::FileAccess
uint32_t file_access_ = 0;
Entry* entry_ = nullptr;
};
} // namespace vfs
} // namespace xe
#endif // XENIA_VFS_FILE_H_

View File

@ -140,10 +140,10 @@ bool VirtualFileSystem::DeletePath(std::string path) {
return parent->Delete(entry); return parent->Delete(entry);
} }
X_STATUS VirtualFileSystem::OpenFile( X_STATUS VirtualFileSystem::OpenFile(std::string path,
kernel::KernelState* kernel_state, std::string path, FileDisposition creation_disposition,
FileDisposition creation_disposition, uint32_t desired_access, uint32_t desired_access, File** out_file,
kernel::object_ref<kernel::XFile>* out_file, FileAction* out_action) { FileAction* out_action) {
// Cleanup access. // Cleanup access.
if (desired_access & FileAccess::kGenericRead) { if (desired_access & FileAccess::kGenericRead) {
desired_access |= FileAccess::kFileReadData; desired_access |= FileAccess::kFileReadData;
@ -253,7 +253,7 @@ X_STATUS VirtualFileSystem::OpenFile(
} }
// Open. // Open.
auto result = entry->Open(kernel_state, desired_access, out_file); auto result = entry->Open(desired_access, out_file);
if (XFAILED(result)) { if (XFAILED(result)) {
*out_action = FileAction::kDoesNotExist; *out_action = FileAction::kDoesNotExist;
} }

View File

@ -16,9 +16,9 @@
#include <vector> #include <vector>
#include "xenia/base/mutex.h" #include "xenia/base/mutex.h"
#include "xenia/kernel/xobject.h"
#include "xenia/vfs/device.h" #include "xenia/vfs/device.h"
#include "xenia/vfs/entry.h" #include "xenia/vfs/entry.h"
#include "xenia/vfs/file.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
@ -39,10 +39,8 @@ class VirtualFileSystem {
Entry* CreatePath(std::string path, uint32_t attributes); Entry* CreatePath(std::string path, uint32_t attributes);
bool DeletePath(std::string path); bool DeletePath(std::string path);
X_STATUS OpenFile(kernel::KernelState* kernel_state, std::string path, X_STATUS OpenFile(std::string path, FileDisposition creation_disposition,
FileDisposition creation_disposition, uint32_t desired_access, File** out_file,
uint32_t desired_access,
kernel::object_ref<kernel::XFile>* out_file,
FileAction* out_action); FileAction* out_action);
private: private: