Move NtCreateFile/NtOpenFile to VFS, implement (mostly) for real.

Progress on #305.
This commit is contained in:
Ben Vanik
2015-06-29 10:33:36 -07:00
parent 0104a2290f
commit cc08e9019a
25 changed files with 459 additions and 159 deletions

View File

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

View File

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

View File

@@ -16,9 +16,9 @@
namespace xe {
namespace vfs {
DiscImageFile::DiscImageFile(KernelState* kernel_state, Mode mode,
DiscImageFile::DiscImageFile(KernelState* kernel_state, uint32_t file_access,
DiscImageEntry* entry)
: XFile(kernel_state, mode, entry), entry_(entry) {}
: XFile(kernel_state, file_access, entry), entry_(entry) {}
DiscImageFile::~DiscImageFile() = default;

View File

@@ -19,7 +19,7 @@ class DiscImageEntry;
class DiscImageFile : public XFile {
public:
DiscImageFile(KernelState* kernel_state, Mode desired_access,
DiscImageFile(KernelState* kernel_state, uint32_t file_access,
DiscImageEntry* entry);
~DiscImageFile() override;

View File

@@ -46,25 +46,10 @@ bool HostPathDevice::Initialize() {
void HostPathDevice::PopulateEntry(HostPathEntry* parent_entry) {
auto child_infos = xe::filesystem::ListFiles(parent_entry->local_path());
for (auto& child_info : child_infos) {
auto child = new HostPathEntry(
this, parent_entry, xe::to_string(child_info.name),
xe::join_paths(parent_entry->local_path(), child_info.name));
child->create_timestamp_ = child_info.create_timestamp;
child->access_timestamp_ = child_info.access_timestamp;
child->write_timestamp_ = child_info.write_timestamp;
if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) {
child->attributes_ = kFileAttributeDirectory;
} else {
child->attributes_ = kFileAttributeNormal;
if (read_only_) {
child->attributes_ |= kFileAttributeReadOnly;
}
child->size_ = child_info.total_size;
child->allocation_size_ =
xe::round_up(child_info.total_size, bytes_per_sector());
}
auto child = HostPathEntry::Create(
this, parent_entry,
xe::join_paths(parent_entry->local_path(), child_info.name),
child_info);
parent_entry->children_.push_back(std::unique_ptr<Entry>(child));
if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) {

View File

@@ -9,6 +9,7 @@
#include "xenia/vfs/devices/host_path_entry.h"
#include "xenia/base/logging.h"
#include "xenia/base/mapped_memory.h"
#include "xenia/base/math.h"
#include "xenia/base/string.h"
@@ -23,41 +24,70 @@ HostPathEntry::HostPathEntry(Device* device, Entry* parent, std::string path,
HostPathEntry::~HostPathEntry() = default;
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;
HostPathEntry* HostPathEntry::Create(Device* device, Entry* parent,
const std::wstring& full_path,
xe::filesystem::FileInfo file_info) {
auto entry = new HostPathEntry(device, parent, xe::to_string(file_info.name),
full_path);
entry->create_timestamp_ = file_info.create_timestamp;
entry->access_timestamp_ = file_info.access_timestamp;
entry->write_timestamp_ = file_info.write_timestamp;
if (file_info.type == xe::filesystem::FileInfo::Type::kDirectory) {
entry->attributes_ = kFileAttributeDirectory;
} else {
entry->attributes_ = kFileAttributeNormal;
if (device->is_read_only()) {
entry->attributes_ |= kFileAttributeReadOnly;
}
entry->size_ = file_info.total_size;
entry->allocation_size_ =
xe::round_up(file_info.total_size, device->bytes_per_sector());
}
return entry;
}
X_STATUS HostPathEntry::Open(KernelState* kernel_state, uint32_t desired_access,
object_ref<XFile>* out_file) {
if (is_read_only() && (desired_access & (FileAccess::kFileWriteData |
FileAccess::kFileAppendData))) {
XELOGE("Attempting to open file for write access on read-only device");
return X_STATUS_ACCESS_DENIED;
}
DWORD open_access = 0;
if (desired_access & FileAccess::kGenericRead) {
open_access |= GENERIC_READ;
}
if (desired_access & FileAccess::kGenericWrite) {
open_access |= GENERIC_WRITE;
}
if (desired_access & FileAccess::kGenericExecute) {
open_access |= GENERIC_EXECUTE;
}
if (desired_access & FileAccess::kGenericAll) {
open_access |= GENERIC_ALL;
}
if (desired_access & FileAccess::kFileReadData) {
open_access |= FILE_READ_DATA;
}
if (desired_access & FileAccess::kFileWriteData) {
open_access |= FILE_WRITE_DATA;
}
if (desired_access & FileAccess::kFileAppendData) {
open_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;
// We assume we've already created the file in the caller.
DWORD creation_disposition = OPEN_EXISTING;
HANDLE file =
CreateFileW(local_path_.c_str(), desired_access, share_mode, NULL,
creation_disposition,
flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL);
creation_disposition, 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);
*out_file = object_ref<XFile>(
new HostPathFile(kernel_state, desired_access, this, file));
return X_STATUS_SUCCESS;
}
@@ -67,5 +97,38 @@ std::unique_ptr<MappedMemory> HostPathEntry::OpenMapped(MappedMemory::Mode mode,
return MappedMemory::Open(local_path_, mode, offset, length);
}
std::unique_ptr<Entry> HostPathEntry::CreateEntryInternal(std::string name,
uint32_t attributes) {
auto full_path = xe::join_paths(local_path_, xe::to_wstring(name));
if (attributes & kFileAttributeDirectory) {
if (!xe::filesystem::CreateFolder(full_path)) {
return nullptr;
}
} else {
auto file = xe::filesystem::OpenFile(full_path, "wb");
if (!file) {
return nullptr;
}
fclose(file);
}
xe::filesystem::FileInfo file_info;
if (!xe::filesystem::GetInfo(full_path, &file_info)) {
return nullptr;
}
return std::unique_ptr<Entry>(
HostPathEntry::Create(device_, this, full_path, file_info));
}
bool HostPathEntry::DeleteEntryInternal(Entry* entry) {
auto full_path = xe::join_paths(local_path_, xe::to_wstring(entry->name()));
if (entry->attributes() & kFileAttributeDirectory) {
// Delete entire directory and contents.
return xe::filesystem::DeleteFolder(full_path);
} else {
// Delete file.
return xe::filesystem::DeleteFile(full_path);
}
}
} // namespace vfs
} // namespace xe

View File

@@ -12,6 +12,7 @@
#include <string>
#include "xenia/base/filesystem.h"
#include "xenia/vfs/entry.h"
namespace xe {
@@ -25,10 +26,14 @@ class HostPathEntry : public Entry {
const std::wstring& local_path);
~HostPathEntry() override;
static HostPathEntry* Create(Device* device, Entry* parent,
const std::wstring& full_path,
xe::filesystem::FileInfo file_info);
const std::wstring& local_path() { return local_path_; }
X_STATUS Open(KernelState* kernel_state, Mode mode, bool async,
XFile** out_file) override;
X_STATUS Open(KernelState* kernel_state, uint32_t desired_access,
object_ref<XFile>* out_file) override;
bool can_map() const override { return true; }
std::unique_ptr<MappedMemory> OpenMapped(MappedMemory::Mode mode,
@@ -38,6 +43,10 @@ class HostPathEntry : public Entry {
private:
friend class HostPathDevice;
std::unique_ptr<Entry> CreateEntryInternal(std::string name,
uint32_t attributes) override;
bool DeleteEntryInternal(Entry* entry) override;
std::wstring local_path_;
};

View File

@@ -14,9 +14,9 @@
namespace xe {
namespace vfs {
HostPathFile::HostPathFile(KernelState* kernel_state, Mode mode,
HostPathFile::HostPathFile(KernelState* kernel_state, uint32_t file_access,
HostPathEntry* entry, HANDLE file_handle)
: XFile(kernel_state, mode, entry),
: XFile(kernel_state, file_access, entry),
entry_(entry),
file_handle_(file_handle) {}
@@ -24,6 +24,10 @@ HostPathFile::~HostPathFile() { CloseHandle(file_handle_); }
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_read) {
if (!(file_access() & FileAccess::kFileReadData)) {
return X_STATUS_ACCESS_DENIED;
}
OVERLAPPED overlapped;
overlapped.Pointer = (PVOID)byte_offset;
overlapped.hEvent = NULL;
@@ -41,6 +45,11 @@ X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
size_t byte_offset,
size_t* out_bytes_written) {
if (!(file_access() & FileAccess::kFileWriteData |
FileAccess::kFileAppendData)) {
return X_STATUS_ACCESS_DENIED;
}
OVERLAPPED overlapped;
overlapped.Pointer = (PVOID)byte_offset;
overlapped.hEvent = NULL;

View File

@@ -21,8 +21,8 @@ class HostPathEntry;
class HostPathFile : public XFile {
public:
HostPathFile(KernelState* kernel_state, Mode mode, HostPathEntry* entry,
HANDLE file_handle);
HostPathFile(KernelState* kernel_state, uint32_t file_access,
HostPathEntry* entry, HANDLE file_handle);
~HostPathFile() override;
protected:

View File

@@ -24,9 +24,11 @@ STFSContainerEntry::STFSContainerEntry(Device* device, Entry* parent,
STFSContainerEntry::~STFSContainerEntry() = default;
X_STATUS STFSContainerEntry::Open(KernelState* kernel_state, Mode mode,
bool async, XFile** out_file) {
*out_file = new STFSContainerFile(kernel_state, mode, this);
X_STATUS STFSContainerEntry::Open(KernelState* kernel_state,
uint32_t desired_access,
object_ref<XFile>* out_file) {
*out_file = object_ref<XFile>(
new STFSContainerFile(kernel_state, desired_access, this));
return X_STATUS_SUCCESS;
}

View File

@@ -31,8 +31,8 @@ class STFSContainerEntry : public Entry {
size_t data_offset() const { return data_offset_; }
size_t data_size() const { return data_size_; }
X_STATUS Open(KernelState* kernel_state, Mode desired_access, bool async,
XFile** out_file) override;
X_STATUS Open(KernelState* kernel_state, uint32_t desired_access,
object_ref<XFile>* out_file) override;
struct BlockRecord {
size_t offset;

View File

@@ -16,9 +16,10 @@
namespace xe {
namespace vfs {
STFSContainerFile::STFSContainerFile(KernelState* kernel_state, Mode mode,
STFSContainerFile::STFSContainerFile(KernelState* kernel_state,
uint32_t file_access,
STFSContainerEntry* entry)
: XFile(kernel_state, mode, entry), entry_(entry) {}
: XFile(kernel_state, file_access, entry), entry_(entry) {}
STFSContainerFile::~STFSContainerFile() = default;

View File

@@ -19,7 +19,7 @@ class STFSContainerEntry;
class STFSContainerFile : public XFile {
public:
STFSContainerFile(KernelState* kernel_state, Mode mode,
STFSContainerFile(KernelState* kernel_state, uint32_t file_access,
STFSContainerEntry* entry);
~STFSContainerFile() override;