From ab1ba9a5084c69825b9e24e43968143ec8989e92 Mon Sep 17 00:00:00 2001
From: Ben Vanik <ben.vanik@gmail.com>
Date: Wed, 16 Oct 2013 21:32:53 -0700
Subject: [PATCH] Partially implemented NtQueryFullAttributes. Enough to get
 past the ShaderDump test most games seem to do.

---
 .../kernel/modules/xboxkrnl/xboxkrnl_io.cc    | 57 +++++++++++++------
 src/xenia/kernel/shim_utils.h                 |  1 +
 src/xenia/kernel/xbox.h                       | 57 ++++++++++++++++++-
 3 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_io.cc
index 310833e58..505c4ee7a 100644
--- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_io.cc
+++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_io.cc
@@ -39,26 +39,14 @@ SHIM_CALL NtCreateFile_shim(
   uint32_t share_access = SHIM_GET_ARG_32(6);
   uint32_t creation_disposition = SHIM_GET_ARG_32(7);
 
-  struct OBJECT_ATTRIBUTES {
-    uint32_t  root_directory;
-    uint32_t  object_name_ptr;
-    uint32_t  attributes;
-  } attrs;
-  attrs.root_directory  = SHIM_MEM_32(object_attributes_ptr);
-  attrs.object_name_ptr = SHIM_MEM_32(object_attributes_ptr + 4);
-  attrs.attributes      = SHIM_MEM_32(object_attributes_ptr + 8);
-  X_ANSI_STRING object_name;
-  object_name.length          = SHIM_MEM_16(attrs.object_name_ptr);
-  object_name.maximum_length  = SHIM_MEM_16(attrs.object_name_ptr + 2);
-  object_name.buffer          =
-      (char*)SHIM_MEM_ADDR(SHIM_MEM_32(attrs.object_name_ptr + 4));
+  X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr);
 
   XELOGD(
       "NtCreateFile(%.8X, %.8X, %.8X(%s), %.8X, %.8X, %.8X, %d, %d)",
       handle_ptr,
       desired_access,
       object_attributes_ptr,
-      object_name.buffer,
+      attrs.object_name.buffer,
       io_status_block_ptr,
       allocation_size_ptr,
       file_attributes,
@@ -76,7 +64,7 @@ SHIM_CALL NtCreateFile_shim(
 
   // Resolve the file using the virtual file system.
   FileSystem* fs = state->filesystem();
-  Entry* entry = fs->ResolvePath(object_name.buffer);
+  Entry* entry = fs->ResolvePath(attrs.object_name.buffer);
   XFile* file = NULL;
   if (entry && entry->type() == Entry::kTypeFile) {
     // Open the file.
@@ -231,12 +219,49 @@ SHIM_CALL NtReadFile_shim(
 
 SHIM_CALL NtQueryInformationFile_shim(
     xe_ppc_state_t* ppc_state, KernelState* state) {
+  uint32_t file_handle = SHIM_GET_ARG_32(0);
+  uint32_t io_status_block_ptr = SHIM_GET_ARG_32(1);
+  uint32_t file_info_ptr = SHIM_GET_ARG_32(2);
+  uint32_t length = SHIM_GET_ARG_32(3);
+  uint32_t file_info_class = SHIM_GET_ARG_32(4);
+
+  XELOGD(
+      "NtQueryInformationFile(%.8X, %.8X, %.8X, %.8X, %.8X)",
+      file_handle,
+      io_status_block_ptr,
+      file_info_ptr,
+      length,
+      file_info_class);
+
   SHIM_SET_RETURN(X_STATUS_NO_SUCH_FILE);
 }
 
 SHIM_CALL NtQueryFullAttributesFile_shim(
     xe_ppc_state_t* ppc_state, KernelState* state) {
-  SHIM_SET_RETURN(X_STATUS_NO_SUCH_FILE);
+  uint32_t object_attributes_ptr = SHIM_GET_ARG_32(0);
+  uint32_t file_info_ptr = SHIM_GET_ARG_32(1);
+
+  X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr);
+
+  XELOGD(
+      "NtQueryFullAttributesFile(%.8X(%s), %.8X)",
+      object_attributes_ptr,
+      attrs.object_name.buffer,
+      file_info_ptr);
+
+  X_STATUS result = X_STATUS_NO_SUCH_FILE;
+
+  // Resolve the file using the virtual file system.
+  FileSystem* fs = state->filesystem();
+  Entry* entry = fs->ResolvePath(attrs.object_name.buffer);
+  if (entry && entry->type() == Entry::kTypeFile) {
+    // Found.
+    // TODO(benvanik): set file_info_ptr data
+    XEASSERTALWAYS();
+    result = X_STATUS_SUCCESS;
+  }
+
+  SHIM_SET_RETURN(result);
 }
 
 SHIM_CALL NtQueryVolumeInformationFile_shim(
diff --git a/src/xenia/kernel/shim_utils.h b/src/xenia/kernel/shim_utils.h
index dcde6e25b..16120245b 100644
--- a/src/xenia/kernel/shim_utils.h
+++ b/src/xenia/kernel/shim_utils.h
@@ -30,6 +30,7 @@ namespace kernel {
       (xe_kernel_export_shim_fn)export_name##_shim, \
       NULL);
 
+#define SHIM_MEM_BASE         ppc_state->membase
 #define SHIM_MEM_ADDR(a)      (a ? (ppc_state->membase + a) : NULL)
 
 #define SHIM_MEM_16(a)        (uint16_t)XEGETUINT16BE(SHIM_MEM_ADDR(a))
diff --git a/src/xenia/kernel/xbox.h b/src/xenia/kernel/xbox.h
index 1e4f95f23..05db3e193 100644
--- a/src/xenia/kernel/xbox.h
+++ b/src/xenia/kernel/xbox.h
@@ -107,11 +107,64 @@ typedef uint32_t X_STATUS;
 #define X_LANGUAGE_JAPANESE       2
 
 
-typedef struct {
+class X_ANSI_STRING {
+public:
   uint16_t  length;
   uint16_t  maximum_length;
   char*     buffer;
-} X_ANSI_STRING;
+
+  X_ANSI_STRING() {
+    Zero();
+  }
+  X_ANSI_STRING(const uint8_t* base, uint32_t p) {
+    Read(base, p);
+  }
+  void Read(const uint8_t* base, uint32_t p) {
+    length = XEGETUINT16BE(base + p);
+    maximum_length = XEGETUINT16BE(base + p + 2);
+    if (maximum_length) {
+      buffer = (char*)(base + XEGETUINT32BE(base + p + 4));
+    } else {
+      buffer = 0;
+    }
+  }
+  void Zero() {
+    length = maximum_length = 0;
+    buffer = 0;
+  }
+};
+
+
+class X_OBJECT_ATTRIBUTES {
+public:
+  uint32_t      root_directory;
+  uint32_t      object_name_ptr;
+  X_ANSI_STRING object_name;
+  uint32_t      attributes;
+
+  X_OBJECT_ATTRIBUTES() {
+    Zero();
+  }
+  X_OBJECT_ATTRIBUTES(const uint8_t* base, uint32_t p) {
+    Read(base, p);
+  }
+  void Read(const uint8_t* base, uint32_t p) {
+    root_directory  = XEGETUINT32BE(base + p);
+    object_name_ptr = XEGETUINT32BE(base + p + 4);
+    if (object_name_ptr) {
+      object_name.Read(base, object_name_ptr);
+    } else {
+      object_name.Zero();
+    }
+    attributes      = XEGETUINT32BE(base + p + 8);
+  }
+  void Zero() {
+    root_directory = 0;
+    object_name_ptr = 0;
+    object_name.Zero();
+    attributes = 0;
+  }
+};
 
 
 }  // namespace kernel