commit
3800e300d4
|
@ -83,6 +83,18 @@ class X_FILE_FS_ATTRIBUTE_INFORMATION {
|
||||||
};
|
};
|
||||||
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
||||||
|
|
||||||
|
struct CreateOptions {
|
||||||
|
// http://processhacker.sourceforge.net/doc/ntioapi_8h.html
|
||||||
|
static const uint32_t FILE_DIRECTORY_FILE = 0x00000001;
|
||||||
|
// Optimization - files access will be sequential, not random.
|
||||||
|
static const uint32_t FILE_SEQUENTIAL_ONLY = 0x00000004;
|
||||||
|
static const uint32_t FILE_SYNCHRONOUS_IO_ALERT = 0x00000010;
|
||||||
|
static const uint32_t FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;
|
||||||
|
static const uint32_t FILE_NON_DIRECTORY_FILE = 0x00000040;
|
||||||
|
// Optimization - file access will be random, not sequential.
|
||||||
|
static const uint32_t FILE_RANDOM_ACCESS = 0x00000800;
|
||||||
|
};
|
||||||
|
|
||||||
dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
|
dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
|
||||||
pointer_t<X_OBJECT_ATTRIBUTES> object_attrs,
|
pointer_t<X_OBJECT_ATTRIBUTES> object_attrs,
|
||||||
pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||||
|
@ -130,7 +142,11 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
|
||||||
|
|
||||||
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));
|
// If true, desired_access SYNCHRONIZE flag must be set.
|
||||||
|
bool synchronous =
|
||||||
|
(create_options & CreateOptions::FILE_SYNCHRONOUS_IO_ALERT) ||
|
||||||
|
(create_options & CreateOptions::FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
file = object_ref<XFile>(new XFile(kernel_state(), vfs_file, synchronous));
|
||||||
|
|
||||||
// Handle ref is incremented, so return that.
|
// Handle ref is incremented, so return that.
|
||||||
handle = file->handle();
|
handle = file->handle();
|
||||||
|
@ -177,7 +193,7 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (XSUCCEEDED(result)) {
|
if (XSUCCEEDED(result)) {
|
||||||
if (true) {
|
if (true || file->is_synchronous()) {
|
||||||
// Synchronous.
|
// Synchronous.
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
result = file->Read(buffer, buffer_length,
|
result = file->Read(buffer, buffer_length,
|
||||||
|
@ -190,6 +206,7 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
|
||||||
|
|
||||||
// Queue the APC callback. It must be delivered via the APC mechanism even
|
// Queue the APC callback. It must be delivered via the APC mechanism even
|
||||||
// though were are completing immediately.
|
// though were are completing immediately.
|
||||||
|
// Low bit probably means do not queue to IO ports.
|
||||||
if ((uint32_t)apc_routine_ptr & ~1) {
|
if ((uint32_t)apc_routine_ptr & ~1) {
|
||||||
if (apc_context) {
|
if (apc_context) {
|
||||||
auto thread = XThread::GetCurrentThread();
|
auto thread = XThread::GetCurrentThread();
|
||||||
|
@ -198,6 +215,10 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!file->is_synchronous()) {
|
||||||
|
result = X_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
// Mark that we should signal the event now. We do this after
|
// Mark that we should signal the event now. We do this after
|
||||||
// we have written the info out.
|
// we have written the info out.
|
||||||
signal_event = true;
|
signal_event = true;
|
||||||
|
@ -262,7 +283,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
|
||||||
// Execute write.
|
// Execute write.
|
||||||
if (XSUCCEEDED(result)) {
|
if (XSUCCEEDED(result)) {
|
||||||
// TODO(benvanik): async path.
|
// TODO(benvanik): async path.
|
||||||
if (true) {
|
if (true || file->is_synchronous()) {
|
||||||
// Synchronous request.
|
// Synchronous request.
|
||||||
size_t bytes_written = 0;
|
size_t bytes_written = 0;
|
||||||
result = file->Write(buffer, buffer_length,
|
result = file->Write(buffer, buffer_length,
|
||||||
|
@ -272,6 +293,15 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
|
||||||
info = (int32_t)bytes_written;
|
info = (int32_t)bytes_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!file->is_synchronous()) {
|
||||||
|
result = X_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io_status_block) {
|
||||||
|
io_status_block->status = X_STATUS_SUCCESS;
|
||||||
|
io_status_block->information = info;
|
||||||
|
}
|
||||||
|
|
||||||
// Mark that we should signal the event now. We do this after
|
// Mark that we should signal the event now. We do this after
|
||||||
// we have written the info out.
|
// we have written the info out.
|
||||||
signal_event = true;
|
signal_event = true;
|
||||||
|
@ -279,12 +309,17 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
|
||||||
// X_STATUS_PENDING if not returning immediately.
|
// X_STATUS_PENDING if not returning immediately.
|
||||||
result = X_STATUS_PENDING;
|
result = X_STATUS_PENDING;
|
||||||
info = 0;
|
info = 0;
|
||||||
|
|
||||||
|
if (io_status_block) {
|
||||||
|
io_status_block->status = X_STATUS_SUCCESS;
|
||||||
|
io_status_block->information = info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io_status_block) {
|
if (XFAILED(result) && io_status_block) {
|
||||||
io_status_block->status = result;
|
io_status_block->status = result;
|
||||||
io_status_block->information = info;
|
io_status_block->information = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev && signal_event) {
|
if (ev && signal_event) {
|
||||||
|
@ -306,7 +341,7 @@ dword_result_t NtCreateIoCompletion(lpdword_t out_handle,
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub);
|
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kImplemented);
|
||||||
|
|
||||||
// Dequeues a packet from the completion port.
|
// Dequeues a packet from the completion port.
|
||||||
dword_result_t NtRemoveIoCompletion(
|
dword_result_t NtRemoveIoCompletion(
|
||||||
|
@ -341,7 +376,7 @@ dword_result_t NtRemoveIoCompletion(
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kStub);
|
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kImplemented);
|
||||||
|
|
||||||
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,
|
||||||
|
@ -389,7 +424,8 @@ dword_result_t NtSetInformationFile(
|
||||||
auto port =
|
auto port =
|
||||||
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
|
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
|
||||||
if (!port) {
|
if (!port) {
|
||||||
return X_STATUS_INVALID_HANDLE;
|
result = X_STATUS_INVALID_HANDLE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->RegisterIOCompletionPort(key, port);
|
file->RegisterIOCompletionPort(key, port);
|
||||||
|
@ -496,6 +532,7 @@ dword_result_t NtQueryInformationFile(
|
||||||
file->set_position(cur_pos);
|
file->set_position(cur_pos);
|
||||||
info = 4;
|
info = 4;
|
||||||
*/
|
*/
|
||||||
|
xe::store_and_swap<uint32_t>(file_info_ptr, 0);
|
||||||
result = X_STATUS_UNSUCCESSFUL;
|
result = X_STATUS_UNSUCCESSFUL;
|
||||||
info = 0;
|
info = 0;
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XFile::XFile(KernelState* kernel_state, vfs::File* file)
|
XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
|
||||||
: XObject(kernel_state, kTypeFile), file_(file) {
|
: XObject(kernel_state, kTypeFile),
|
||||||
|
file_(file),
|
||||||
|
is_synchronous_(synchronous) {
|
||||||
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +176,7 @@ bool XFile::Save(ByteStream* stream) {
|
||||||
stream->Write(file_->entry()->absolute_path());
|
stream->Write(file_->entry()->absolute_path());
|
||||||
stream->Write<uint64_t>(position_);
|
stream->Write<uint64_t>(position_);
|
||||||
stream->Write(file_access());
|
stream->Write(file_access());
|
||||||
|
stream->Write<bool>(is_synchronous_);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +193,7 @@ object_ref<XFile> XFile::Restore(KernelState* kernel_state,
|
||||||
auto abs_path = stream->Read<std::string>();
|
auto abs_path = stream->Read<std::string>();
|
||||||
uint64_t position = stream->Read<uint64_t>();
|
uint64_t position = stream->Read<uint64_t>();
|
||||||
auto access = stream->Read<uint32_t>();
|
auto access = stream->Read<uint32_t>();
|
||||||
|
auto is_synchronous = stream->Read<bool>();
|
||||||
|
|
||||||
XELOGD("XFile %.8X (%s)", file->handle(), abs_path.c_str());
|
XELOGD("XFile %.8X (%s)", file->handle(), abs_path.c_str());
|
||||||
|
|
||||||
|
@ -204,6 +208,7 @@ object_ref<XFile> XFile::Restore(KernelState* kernel_state,
|
||||||
|
|
||||||
file->file_ = vfs_file;
|
file->file_ = vfs_file;
|
||||||
file->position_ = position;
|
file->position_ = position;
|
||||||
|
file->is_synchronous_ = is_synchronous;
|
||||||
|
|
||||||
return object_ref<XFile>(file);
|
return object_ref<XFile>(file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ class XFile : public XObject {
|
||||||
public:
|
public:
|
||||||
static const Type kType = kTypeFile;
|
static const Type kType = kTypeFile;
|
||||||
|
|
||||||
XFile(KernelState* kernel_state, vfs::File* file);
|
XFile(KernelState* kernel_state, vfs::File* file, bool synchronous);
|
||||||
~XFile() override;
|
~XFile() override;
|
||||||
|
|
||||||
vfs::Device* device() const { return file_->entry()->device(); }
|
vfs::Device* device() const { return file_->entry()->device(); }
|
||||||
|
@ -111,6 +111,8 @@ class XFile : public XObject {
|
||||||
static object_ref<XFile> Restore(KernelState* kernel_state,
|
static object_ref<XFile> Restore(KernelState* kernel_state,
|
||||||
ByteStream* stream);
|
ByteStream* stream);
|
||||||
|
|
||||||
|
bool is_synchronous() const { return is_synchronous_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
|
void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
|
||||||
|
|
||||||
|
@ -133,6 +135,8 @@ class XFile : public XObject {
|
||||||
|
|
||||||
xe::filesystem::WildcardEngine find_engine_;
|
xe::filesystem::WildcardEngine find_engine_;
|
||||||
size_t find_index_ = 0;
|
size_t find_index_ = 0;
|
||||||
|
|
||||||
|
bool is_synchronous_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
Loading…
Reference in New Issue