Move NtCreateFile/NtOpenFile to VFS, implement (mostly) for real.
Progress on #305.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/filesystem.h"
|
||||
#include "xenia/base/string.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
#include "xenia/vfs/devices/host_path_device.h"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
XFile::XFile(KernelState* kernel_state, vfs::Mode mode, vfs::Entry* entry)
|
||||
XFile::XFile(KernelState* kernel_state, uint32_t file_access, vfs::Entry* entry)
|
||||
: XObject(kernel_state, kTypeFile),
|
||||
entry_(entry),
|
||||
mode_(mode),
|
||||
file_access_(file_access),
|
||||
position_(0),
|
||||
find_index_(0) {
|
||||
async_event_ = new XEvent(kernel_state);
|
||||
|
||||
@@ -81,6 +81,7 @@ class XFile : public XObject {
|
||||
|
||||
vfs::Device* device() const { return entry_->device(); }
|
||||
vfs::Entry* entry() const { return entry_; }
|
||||
uint32_t file_access() const { return file_access_; }
|
||||
|
||||
const std::string& path() const { return entry_->path(); }
|
||||
const std::string& name() const { return entry_->name(); }
|
||||
@@ -102,7 +103,7 @@ class XFile : public XObject {
|
||||
virtual void* GetWaitHandle();
|
||||
|
||||
protected:
|
||||
XFile(KernelState* kernel_state, vfs::Mode mode, vfs::Entry* entry);
|
||||
XFile(KernelState* kernel_state, uint32_t file_access, vfs::Entry* entry);
|
||||
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,
|
||||
@@ -112,7 +113,7 @@ class XFile : public XObject {
|
||||
|
||||
private:
|
||||
vfs::Entry* entry_;
|
||||
vfs::Mode mode_;
|
||||
uint32_t file_access_;
|
||||
XEvent* async_event_;
|
||||
|
||||
// TODO(benvanik): create flags, open state, etc.
|
||||
|
||||
@@ -57,9 +57,9 @@ X_STATUS XUserModule::LoadFromFile(std::string path) {
|
||||
std::vector<uint8_t> buffer(fs_entry->size());
|
||||
|
||||
// Open file for reading.
|
||||
XFile* file_ptr = nullptr;
|
||||
result = fs_entry->Open(kernel_state(), vfs::Mode::READ, false, &file_ptr);
|
||||
object_ref<XFile> file(file_ptr);
|
||||
object_ref<XFile> file;
|
||||
result =
|
||||
fs_entry->Open(kernel_state(), vfs::FileAccess::kGenericRead, &file);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -152,98 +152,45 @@ class X_FILE_FS_ATTRIBUTE_INFORMATION {
|
||||
};
|
||||
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
||||
|
||||
struct FileDisposition {
|
||||
static const uint32_t X_FILE_SUPERSEDE = 0x00000000;
|
||||
static const uint32_t X_FILE_OPEN = 0x00000001;
|
||||
static const uint32_t X_FILE_CREATE = 0x00000002;
|
||||
static const uint32_t X_FILE_OPEN_IF = 0x00000003;
|
||||
static const uint32_t X_FILE_OVERWRITE = 0x00000004;
|
||||
static const uint32_t X_FILE_OVERWRITE_IF = 0x00000005;
|
||||
};
|
||||
|
||||
struct FileAccess {
|
||||
static const uint32_t X_GENERIC_READ = 0x80000000;
|
||||
static const uint32_t X_GENERIC_WRITE = 0x40000000;
|
||||
static const uint32_t X_GENERIC_EXECUTE = 0x20000000;
|
||||
static const uint32_t X_GENERIC_ALL = 0x10000000;
|
||||
static const uint32_t X_FILE_READ_DATA = 0x00000001;
|
||||
static const uint32_t X_FILE_WRITE_DATA = 0x00000002;
|
||||
static const uint32_t X_FILE_APPEND_DATA = 0x00000004;
|
||||
};
|
||||
|
||||
X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state,
|
||||
uint32_t handle_ptr, uint32_t desired_access,
|
||||
X_OBJECT_ATTRIBUTES* object_attrs,
|
||||
const char* object_name, uint32_t io_status_block_ptr,
|
||||
uint32_t allocation_size_ptr, uint32_t file_attributes,
|
||||
uint32_t share_access, uint32_t creation_disposition) {
|
||||
uint32_t share_access,
|
||||
FileDisposition creation_disposition) {
|
||||
uint64_t allocation_size = 0; // is this correct???
|
||||
if (allocation_size_ptr != 0) {
|
||||
allocation_size = SHIM_MEM_64(allocation_size_ptr);
|
||||
}
|
||||
|
||||
X_STATUS result = X_STATUS_NO_SUCH_FILE;
|
||||
uint32_t info = X_FILE_DOES_NOT_EXIST;
|
||||
uint32_t handle;
|
||||
|
||||
auto fs = kernel_state->file_system();
|
||||
Entry* entry;
|
||||
|
||||
object_ref<XFile> root_file;
|
||||
// Compute path, possibly attrs relative.
|
||||
std::string target_path = object_name;
|
||||
if (object_attrs->root_directory != 0xFFFFFFFD && // ObDosDevices
|
||||
object_attrs->root_directory != 0) {
|
||||
root_file = kernel_state->object_table()->LookupObject<XFile>(
|
||||
auto root_file = kernel_state->object_table()->LookupObject<XFile>(
|
||||
object_attrs->root_directory);
|
||||
assert_not_null(root_file);
|
||||
assert_true(root_file->type() == XObject::Type::kTypeFile);
|
||||
|
||||
// Resolve the file using the device the root directory is part of.
|
||||
auto device = root_file->device();
|
||||
auto target_path = xe::join_paths(root_file->path(), object_name);
|
||||
entry = device->ResolvePath(target_path.c_str());
|
||||
} else {
|
||||
// Resolve the file using the virtual file system.
|
||||
entry = fs->ResolvePath(object_name);
|
||||
}
|
||||
|
||||
bool wants_write = desired_access & FileAccess::X_GENERIC_WRITE ||
|
||||
desired_access & FileAccess::X_GENERIC_ALL ||
|
||||
desired_access & FileAccess::X_FILE_WRITE_DATA ||
|
||||
desired_access & FileAccess::X_FILE_APPEND_DATA;
|
||||
if (wants_write) {
|
||||
if (entry && entry->is_read_only()) {
|
||||
// We don't support any write modes.
|
||||
XELOGW("Attempted to open the file/dir for create/write");
|
||||
desired_access = FileAccess::X_GENERIC_READ;
|
||||
}
|
||||
target_path = xe::join_paths(
|
||||
device->mount_path(), xe::join_paths(root_file->path(), object_name));
|
||||
}
|
||||
|
||||
// Attempt open (or create).
|
||||
object_ref<XFile> file;
|
||||
if (!entry) {
|
||||
result = X_STATUS_NO_SUCH_FILE;
|
||||
info = X_FILE_DOES_NOT_EXIST;
|
||||
} else {
|
||||
// Open the file/directory.
|
||||
vfs::Mode mode;
|
||||
if (desired_access & FileAccess::X_FILE_APPEND_DATA) {
|
||||
mode = vfs::Mode::READ_APPEND;
|
||||
} else if (wants_write) {
|
||||
mode = vfs::Mode::READ_WRITE;
|
||||
} else {
|
||||
mode = vfs::Mode::READ;
|
||||
}
|
||||
XFile* file_ptr = nullptr;
|
||||
result = entry->Open(kernel_state, mode,
|
||||
false, // TODO(benvanik): pick async mode, if needed.
|
||||
&file_ptr);
|
||||
file = object_ref<XFile>(file_ptr);
|
||||
}
|
||||
FileAction file_action;
|
||||
X_STATUS result = kernel_state->file_system()->OpenFile(
|
||||
kernel_state, target_path, creation_disposition, desired_access, &file,
|
||||
&file_action);
|
||||
uint32_t info = uint32_t(file_action);
|
||||
|
||||
X_HANDLE handle = X_INVALID_HANDLE_VALUE;
|
||||
if (XSUCCEEDED(result)) {
|
||||
// Handle ref is incremented, so return that.
|
||||
handle = file->handle();
|
||||
result = X_STATUS_SUCCESS;
|
||||
info = X_FILE_OPENED;
|
||||
}
|
||||
|
||||
if (io_status_block_ptr) {
|
||||
@@ -282,7 +229,7 @@ SHIM_CALL NtCreateFile_shim(PPCContext* ppc_context,
|
||||
auto result = NtCreateFile(
|
||||
ppc_context, kernel_state, handle_ptr, desired_access, &object_attrs,
|
||||
object_name, io_status_block_ptr, allocation_size_ptr, file_attributes,
|
||||
share_access, creation_disposition);
|
||||
share_access, FileDisposition(creation_disposition));
|
||||
|
||||
free(object_name);
|
||||
SHIM_SET_RETURN_32(result);
|
||||
@@ -305,7 +252,7 @@ SHIM_CALL NtOpenFile_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||
|
||||
auto result = NtCreateFile(
|
||||
ppc_context, kernel_state, handle_ptr, desired_access, &object_attrs,
|
||||
object_name, io_status_block_ptr, 0, 0, 0, FileDisposition::X_FILE_OPEN);
|
||||
object_name, io_status_block_ptr, 0, 0, 0, FileDisposition::kOpen);
|
||||
|
||||
free(object_name);
|
||||
SHIM_SET_RETURN_32(result);
|
||||
@@ -451,7 +398,7 @@ SHIM_CALL NtWriteFile_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||
|
||||
// Grab file.
|
||||
auto file = kernel_state->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (!ev) {
|
||||
if (!file) {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user