XFile: Track asynchronous/synchronous flag (and return appropriately in nt Read/Write file)

This commit is contained in:
Dr. Chat 2015-12-30 17:34:26 -06:00
parent cbc74c92f4
commit 2a590f31fe
3 changed files with 57 additions and 11 deletions

View File

@ -83,6 +83,18 @@ class X_FILE_FS_ATTRIBUTE_INFORMATION {
};
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,
pointer_t<X_OBJECT_ATTRIBUTES> object_attrs,
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;
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 = file->handle();
@ -177,7 +193,7 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
}
if (XSUCCEEDED(result)) {
if (true) {
if (true || file->is_synchronous()) {
// Synchronous.
size_t bytes_read = 0;
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
// though were are completing immediately.
// Low bit probably means do not queue to IO ports.
if ((uint32_t)apc_routine_ptr & ~1) {
if (apc_context) {
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
// we have written the info out.
signal_event = true;
@ -262,7 +283,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
// Execute write.
if (XSUCCEEDED(result)) {
// TODO(benvanik): async path.
if (true) {
if (true || file->is_synchronous()) {
// Synchronous request.
size_t bytes_written = 0;
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;
}
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
// we have written the info out.
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.
result = X_STATUS_PENDING;
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->information = info;
io_status_block->information = 0;
}
if (ev && signal_event) {
@ -306,7 +341,7 @@ dword_result_t NtCreateIoCompletion(lpdword_t out_handle,
return X_STATUS_SUCCESS;
}
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub);
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kImplemented);
// Dequeues a packet from the completion port.
dword_result_t NtRemoveIoCompletion(
@ -341,7 +376,7 @@ dword_result_t NtRemoveIoCompletion(
return status;
}
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kStub);
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kImplemented);
dword_result_t NtSetInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
@ -389,7 +424,8 @@ dword_result_t NtSetInformationFile(
auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) {
return X_STATUS_INVALID_HANDLE;
result = X_STATUS_INVALID_HANDLE;
break;
}
file->RegisterIOCompletionPort(key, port);
@ -496,6 +532,7 @@ dword_result_t NtQueryInformationFile(
file->set_position(cur_pos);
info = 4;
*/
xe::store_and_swap<uint32_t>(file_info_ptr, 0);
result = X_STATUS_UNSUCCESSFUL;
info = 0;
} break;

View File

@ -18,8 +18,10 @@
namespace xe {
namespace kernel {
XFile::XFile(KernelState* kernel_state, vfs::File* file)
: XObject(kernel_state, kTypeFile), file_(file) {
XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
: XObject(kernel_state, kTypeFile),
file_(file),
is_synchronous_(synchronous) {
async_event_ = threading::Event::CreateAutoResetEvent(false);
}
@ -174,6 +176,7 @@ bool XFile::Save(ByteStream* stream) {
stream->Write(file_->entry()->absolute_path());
stream->Write<uint64_t>(position_);
stream->Write(file_access());
stream->Write<bool>(is_synchronous_);
return true;
}
@ -190,6 +193,7 @@ object_ref<XFile> XFile::Restore(KernelState* kernel_state,
auto abs_path = stream->Read<std::string>();
uint64_t position = stream->Read<uint64_t>();
auto access = stream->Read<uint32_t>();
auto is_synchronous = stream->Read<bool>();
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->position_ = position;
file->is_synchronous_ = is_synchronous;
return object_ref<XFile>(file);
}

View File

@ -81,7 +81,7 @@ class XFile : public XObject {
public:
static const Type kType = kTypeFile;
XFile(KernelState* kernel_state, vfs::File* file);
XFile(KernelState* kernel_state, vfs::File* file, bool synchronous);
~XFile() override;
vfs::Device* device() const { return file_->entry()->device(); }
@ -111,6 +111,8 @@ class XFile : public XObject {
static object_ref<XFile> Restore(KernelState* kernel_state,
ByteStream* stream);
bool is_synchronous() const { return is_synchronous_; }
protected:
void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
@ -133,6 +135,8 @@ class XFile : public XObject {
xe::filesystem::WildcardEngine find_engine_;
size_t find_index_ = 0;
bool is_synchronous_ = false;
};
} // namespace kernel