From 366f91e1916497a17928936164dea16a36300ad1 Mon Sep 17 00:00:00 2001
From: "Dr. Chat" <arkolbed@gmail.com>
Date: Tue, 15 Dec 2015 18:21:49 -0600
Subject: [PATCH] XFile Save/Restore

---
 src/xenia/kernel/xfile.cc   | 60 ++++++++++++++++++++++++++++++++-----
 src/xenia/kernel/xfile.h    | 13 +++++---
 src/xenia/kernel/xobject.cc |  2 +-
 3 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/src/xenia/kernel/xfile.cc b/src/xenia/kernel/xfile.cc
index c2e00e9a5..8de977a88 100644
--- a/src/xenia/kernel/xfile.cc
+++ b/src/xenia/kernel/xfile.cc
@@ -9,7 +9,10 @@
 
 #include "xenia/kernel/xfile.h"
 
+#include "xenia/base/byte_stream.h"
+#include "xenia/base/logging.h"
 #include "xenia/base/math.h"
+#include "xenia/kernel/kernel_state.h"
 #include "xenia/kernel/xevent.h"
 
 namespace xe {
@@ -17,15 +20,14 @@ namespace kernel {
 
 XFile::XFile(KernelState* kernel_state, vfs::File* file)
     : XObject(kernel_state, kTypeFile), file_(file) {
-  async_event_ = new XEvent(kernel_state);
-  async_event_->Initialize(false, false);
+  async_event_ = threading::Event::CreateAutoResetEvent(false);
 }
 
+XFile::XFile() : XObject(kTypeFile) {}
+
 XFile::~XFile() {
   // TODO(benvanik): signal that the file is closing?
-  async_event_->Set(0, false);
-  async_event_->Delete();
-
+  async_event_->Set();
   file_->Destroy();
 }
 
@@ -107,7 +109,7 @@ X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
     *out_bytes_read = bytes_read;
   }
 
-  async_event_->Set(0, false);
+  async_event_->Set();
   return result;
 }
 
@@ -137,7 +139,7 @@ X_STATUS XFile::Write(const void* buffer, size_t buffer_length,
     *out_bytes_written = bytes_written;
   }
 
-  async_event_->Set(0, false);
+  async_event_->Set();
   return result;
 }
 
@@ -160,6 +162,50 @@ void XFile::RemoveIOCompletionPort(uint32_t key) {
   }
 }
 
+bool XFile::Save(ByteStream* stream) {
+  XELOGD("XFile %.8X (%s)", handle(), file_->entry()->absolute_path().c_str());
+
+  if (!SaveObject(stream)) {
+    return false;
+  }
+
+  stream->Write(file_->entry()->absolute_path());
+  stream->Write<uint64_t>(position_);
+  stream->Write(file_access());
+
+  return true;
+}
+
+object_ref<XFile> XFile::Restore(KernelState* kernel_state,
+                                 ByteStream* stream) {
+  auto file = new XFile();
+  file->kernel_state_ = kernel_state;
+  if (!file->RestoreObject(stream)) {
+    delete file;
+    return nullptr;
+  }
+
+  auto abs_path = stream->Read<std::string>();
+  uint64_t position = stream->Read<uint64_t>();
+  auto access = stream->Read<uint32_t>();
+
+  XELOGD("XFile %.8X (%s)", file->handle(), abs_path.c_str());
+
+  vfs::File* vfs_file = nullptr;
+  vfs::FileAction action;
+  auto res = kernel_state->file_system()->OpenFile(
+      abs_path, vfs::FileDisposition::kOpen, access, &vfs_file, &action);
+  if (XFAILED(res)) {
+    XELOGE("Failed to open XFile: error %.8X", res);
+    return object_ref<XFile>(file);
+  }
+
+  file->file_ = vfs_file;
+  file->position_ = position;
+
+  return object_ref<XFile>(file);
+}
+
 void XFile::NotifyIOCompletionPorts(
     XIOCompletion::IONotification& notification) {
   std::lock_guard<std::mutex> lock(completion_port_lock_);
diff --git a/src/xenia/kernel/xfile.h b/src/xenia/kernel/xfile.h
index 851ad6e05..cb7426cf1 100644
--- a/src/xenia/kernel/xfile.h
+++ b/src/xenia/kernel/xfile.h
@@ -87,7 +87,7 @@ class XFile : public XObject {
   vfs::Device* device() const { return file_->entry()->device(); }
   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_->file_access(); }
 
   const std::string& path() const { return file_->entry()->path(); }
   const std::string& name() const { return file_->entry()->name(); }
@@ -105,19 +105,24 @@ class XFile : public XObject {
                  size_t* out_bytes_written, uint32_t apc_context);
 
   xe::threading::WaitHandle* GetWaitHandle() override {
-    return async_event_->GetWaitHandle();
+    return async_event_.get();
   }
 
   void RegisterIOCompletionPort(uint32_t key, object_ref<XIOCompletion> port);
   void RemoveIOCompletionPort(uint32_t key);
 
+  bool Save(ByteStream* stream);
+  static object_ref<XFile> Restore(KernelState* kernel_state,
+                                   ByteStream* stream);
+
  protected:
   void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
 
  private:
+  XFile();
+
   vfs::File* file_ = nullptr;
-  uint32_t file_access_ = 0;
-  XEvent* async_event_ = nullptr;
+  std::unique_ptr<threading::Event> async_event_ = nullptr;
 
   std::mutex completion_port_lock_;
   std::vector<std::pair<uint32_t, object_ref<XIOCompletion>>> completion_ports_;
diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc
index d6fc3398a..0e06f0200 100644
--- a/src/xenia/kernel/xobject.cc
+++ b/src/xenia/kernel/xobject.cc
@@ -133,7 +133,7 @@ object_ref<XObject> XObject::Restore(KernelState* kernel_state, Type type,
     case kTypeEvent:
       return XEvent::Restore(kernel_state, stream);
     case kTypeFile:
-      break;
+      return XFile::Restore(kernel_state, stream);
     case kTypeIOCompletion:
       break;
     case kTypeModule: