From 870a59f2252cd0e27255ce42e6f84fd9dff09c00 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sun, 19 Jan 2014 06:56:56 -0800 Subject: [PATCH] Turns out NtQueryDirectoryFile only returns a single entry at a time. --- .../kernel/fs/devices/disc_image_entry.cc | 50 +++++-------- .../kernel/fs/devices/host_path_entry.cc | 75 ++++++++----------- .../kernel/fs/devices/stfs_container_entry.cc | 49 ++++-------- src/xenia/kernel/xboxkrnl_io.cc | 43 ++++++++--- src/xenia/xbox.h | 47 +++++++----- 5 files changed, 126 insertions(+), 138 deletions(-) diff --git a/src/xenia/kernel/fs/devices/disc_image_entry.cc b/src/xenia/kernel/fs/devices/disc_image_entry.cc index 42518c648..2b4b51834 100644 --- a/src/xenia/kernel/fs/devices/disc_image_entry.cc +++ b/src/xenia/kernel/fs/devices/disc_image_entry.cc @@ -84,45 +84,29 @@ X_STATUS DiscImageEntry::QueryDirectory( } } - auto current_buf = (uint8_t*)out_info; - auto end = current_buf + length; + auto end = (uint8_t*)out_info + length; - XDirectoryInfo* current = (XDirectoryInfo*)current_buf; - if (((uint8_t*)¤t->file_name[0]) + xestrlena((*gdfx_entry_iterator_)->name.c_str()) > end) { + auto entry = *gdfx_entry_iterator_; + auto entry_name = entry->name.c_str(); + size_t entry_name_length = xestrlena(entry_name); + + if (((uint8_t*)&out_info->file_name[0]) + entry_name_length > end) { gdfx_entry_iterator_ = gdfx_entry_->children.end(); return X_STATUS_UNSUCCESSFUL; } - do { - auto entry = *gdfx_entry_iterator_; + out_info->next_entry_offset = 0; + out_info->file_index = 0xCDCDCDCD; + out_info->creation_time = 0; + out_info->last_access_time = 0; + out_info->last_write_time = 0; + out_info->change_time = 0; + out_info->end_of_file = entry->size; + out_info->allocation_size = 2048; + out_info->attributes = (X_FILE_ATTRIBUTES)entry->attributes; + out_info->file_name_length = (uint32_t)entry_name_length; + memcpy(out_info->file_name, entry_name, entry_name_length); - auto file_name = entry->name.c_str(); - size_t file_name_length = xestrlena(file_name); - if (((uint8_t*)&((XDirectoryInfo*)current_buf)->file_name[0]) + file_name_length > end) { - break; - } - - current = (XDirectoryInfo*)current_buf; - current->file_index = 0xCDCDCDCD; - current->creation_time = 0; - current->last_access_time = 0; - current->last_write_time = 0; - current->change_time = 0; - current->end_of_file = entry->size; - current->allocation_size = 2048; - current->attributes = (X_FILE_ATTRIBUTES)entry->attributes; - - current->file_name_length = (uint32_t)file_name_length; - memcpy(current->file_name, file_name, file_name_length); - - auto next_buf = (((uint8_t*)¤t->file_name[0]) + file_name_length); - next_buf += 8 - ((uint8_t)next_buf % 8); - - current->next_entry_offset = (uint32_t)(next_buf - current_buf); - current_buf = next_buf; - } while (current_buf < end && - (++gdfx_entry_iterator_) != gdfx_entry_->children.end()); - current->next_entry_offset = 0; return X_STATUS_SUCCESS; } diff --git a/src/xenia/kernel/fs/devices/host_path_entry.cc b/src/xenia/kernel/fs/devices/host_path_entry.cc index 2f98317ad..037563625 100644 --- a/src/xenia/kernel/fs/devices/host_path_entry.cc +++ b/src/xenia/kernel/fs/devices/host_path_entry.cc @@ -87,10 +87,19 @@ X_STATUS HostPathEntry::QueryDirectory( } if (handle == INVALID_HANDLE_VALUE) { - handle = find_file_ = FindFirstFile(local_path_, &ffd); + xechar_t target_path[XE_MAX_PATH]; + xestrcpy(target_path, XE_MAX_PATH, local_path_); + if (file_name == NULL) { + xestrcat(target_path, XE_MAX_PATH, XETEXT("*")); + } + else { + auto target_length = xestrlen(local_path_); + xestrwiden(target_path + target_length, XECOUNT(target_path) - target_length, file_name); + } + handle = find_file_ = FindFirstFile(target_path, &ffd); if (handle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { - return X_STATUS_NO_SUCH_FILE; + return X_STATUS_NO_MORE_FILES; } return X_STATUS_UNSUCCESSFUL; } @@ -99,53 +108,35 @@ X_STATUS HostPathEntry::QueryDirectory( if (FindNextFile(handle, &ffd) == FALSE) { FindClose(handle); find_file_ = INVALID_HANDLE_VALUE; - return X_STATUS_UNSUCCESSFUL; + return X_STATUS_NO_MORE_FILES; } } - XDirectoryInfo* current; - - auto current_buf = (uint8_t*)out_info; - auto end = current_buf + length; - - current = (XDirectoryInfo*)current_buf; - if (((uint8_t*)¤t->file_name[0]) + wcslen(ffd.cFileName) > end) { + auto end = (uint8_t*)out_info + length; + size_t entry_name_length = wcslen(ffd.cFileName); + if (((uint8_t*)&out_info->file_name[0]) + entry_name_length > end) { FindClose(handle); find_file_ = INVALID_HANDLE_VALUE; - return X_STATUS_UNSUCCESSFUL; + return X_STATUS_BUFFER_OVERFLOW; } - do { - size_t file_name_length = wcslen(ffd.cFileName); - if (((uint8_t*)&((XDirectoryInfo*)current_buf)->file_name[0]) + - file_name_length > end) { - break; - } + out_info->next_entry_offset = 0; + out_info->file_index = 0xCDCDCDCD; + out_info->creation_time = COMBINE_TIME(ffd.ftCreationTime); + out_info->last_access_time = COMBINE_TIME(ffd.ftLastAccessTime); + out_info->last_write_time = COMBINE_TIME(ffd.ftLastWriteTime); + out_info->change_time = COMBINE_TIME(ffd.ftLastWriteTime); + out_info->end_of_file = + ((uint64_t)ffd.nFileSizeHigh << 32) | ffd.nFileSizeLow; + out_info->allocation_size = 4096; + out_info->attributes = (X_FILE_ATTRIBUTES)ffd.dwFileAttributes; - current = (XDirectoryInfo*)current_buf; - current->file_index = 0xCDCDCDCD; - current->creation_time = COMBINE_TIME(ffd.ftCreationTime); - current->last_access_time = COMBINE_TIME(ffd.ftLastAccessTime); - current->last_write_time = COMBINE_TIME(ffd.ftLastWriteTime); - current->change_time = COMBINE_TIME(ffd.ftLastWriteTime); - current->end_of_file = - ((uint64_t)ffd.nFileSizeHigh << 32) | ffd.nFileSizeLow; - current->allocation_size = 4096; - current->attributes = (X_FILE_ATTRIBUTES)ffd.dwFileAttributes; + out_info->file_name_length = (uint32_t)entry_name_length; + for (size_t i = 0; i < entry_name_length; ++i) { + out_info->file_name[i] = + ffd.cFileName[i] < 256 ? (char)ffd.cFileName[i] : '?'; + } - current->file_name_length = (uint32_t)file_name_length; - for (size_t i = 0; i < file_name_length; ++i) { - current->file_name[i] = - ffd.cFileName[i] < 256 ? (char)ffd.cFileName[i] : '?'; - } - - auto next_buf = (((uint8_t*)¤t->file_name[0]) + file_name_length); - next_buf += 8 - ((uint8_t)next_buf % 8); - - current->next_entry_offset = (uint32_t)(next_buf - current_buf); - current_buf = next_buf; - } while (current_buf < end && FindNextFile(handle, &ffd) == TRUE); - current->next_entry_offset = 0; return X_STATUS_SUCCESS; } @@ -177,9 +168,9 @@ X_STATUS HostPathEntry::Open( share_mode, NULL, creation_disposition, - flags_and_attributes, + flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (!file) { + if (file == INVALID_HANDLE_VALUE) { // TODO(benvanik): pick correct response. return X_STATUS_ACCESS_DENIED; } diff --git a/src/xenia/kernel/fs/devices/stfs_container_entry.cc b/src/xenia/kernel/fs/devices/stfs_container_entry.cc index 05fb7752d..a91d1234b 100644 --- a/src/xenia/kernel/fs/devices/stfs_container_entry.cc +++ b/src/xenia/kernel/fs/devices/stfs_container_entry.cc @@ -63,45 +63,28 @@ X_STATUS STFSContainerEntry::QueryDirectory( } } - auto current_buf = (uint8_t*)out_info; - auto end = current_buf + length; + auto end = (uint8_t*)out_info + length; - XDirectoryInfo* current = (XDirectoryInfo*)current_buf; - if (((uint8_t*)¤t->file_name[0]) + xestrlena((*stfs_entry_iterator_)->name.c_str()) > end) { + auto entry = *stfs_entry_iterator_; + auto entry_name = entry->name.c_str(); + size_t entry_name_length = xestrlena(entry_name); + + if (((uint8_t*)&out_info->file_name[0]) + entry_name_length > end) { stfs_entry_iterator_ = stfs_entry_->children.end(); return X_STATUS_UNSUCCESSFUL; } - do { - auto entry = *stfs_entry_iterator_; + out_info->file_index = 0xCDCDCDCD; + out_info->creation_time = entry->update_timestamp; + out_info->last_access_time = entry->access_timestamp; + out_info->last_write_time = entry->update_timestamp; + out_info->change_time = entry->update_timestamp; + out_info->end_of_file = entry->size; + out_info->allocation_size = 4096; + out_info->attributes = entry->attributes; + out_info->file_name_length = (uint32_t)entry_name_length; + memcpy(out_info->file_name, entry_name, entry_name_length); - auto file_name = entry->name.c_str(); - size_t file_name_length = xestrlena(file_name); - if (((uint8_t*)&((XDirectoryInfo*)current_buf)->file_name[0]) + file_name_length > end) { - break; - } - - current = (XDirectoryInfo*)current_buf; - current->file_index = 0xCDCDCDCD; - current->creation_time = entry->update_timestamp; - current->last_access_time = entry->access_timestamp; - current->last_write_time = entry->update_timestamp; - current->change_time = entry->update_timestamp; - current->end_of_file = entry->size; - current->allocation_size = 4096; - current->attributes = entry->attributes; - - current->file_name_length = (uint32_t)file_name_length; - memcpy(current->file_name, file_name, file_name_length); - - auto next_buf = (((uint8_t*)¤t->file_name[0]) + file_name_length); - next_buf += 8 - ((uint8_t)next_buf % 8); - - current->next_entry_offset = (uint32_t)(next_buf - current_buf); - current_buf = next_buf; - } while (current_buf < end && - (++stfs_entry_iterator_) != stfs_entry_->children.end()); - current->next_entry_offset = 0; return X_STATUS_SUCCESS; } diff --git a/src/xenia/kernel/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl_io.cc index 374ad7619..de57f0c50 100644 --- a/src/xenia/kernel/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl_io.cc @@ -39,12 +39,14 @@ SHIM_CALL NtCreateFile_shim( X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr); + char* object_name = attrs.object_name.Duplicate(); + XELOGD( "NtCreateFile(%.8X, %.8X, %.8X(%s), %.8X, %.8X, %.8X, %d, %d)", handle_ptr, desired_access, object_attributes_ptr, - attrs.object_name.buffer, + !object_name ? "(null)" : object_name, io_status_block_ptr, allocation_size_ptr, file_attributes, @@ -69,11 +71,17 @@ SHIM_CALL NtCreateFile_shim( attrs.root_directory, (XObject**)&root_file); XEASSERT(XSUCCEEDED(result)); XEASSERT(root_file->type() == XObject::Type::kTypeFile); - XEASSERTALWAYS(); + + auto root_path = root_file->absolute_path(); + auto target_path = xestrdupa((std::string(root_path) + std::string(object_name)).c_str()); + entry = fs->ResolvePath(target_path); + xe_free(target_path); + } + else { + // Resolve the file using the virtual file system. + entry = fs->ResolvePath(object_name); } - // Resolve the file using the virtual file system. - entry = fs->ResolvePath(attrs.object_name.buffer); XFile* file = NULL; if (entry && entry->type() == Entry::kTypeFile) { // Open the file. @@ -104,6 +112,8 @@ SHIM_CALL NtCreateFile_shim( SHIM_SET_MEM_32(handle_ptr, handle); } } + + xe_free(object_name); SHIM_SET_RETURN(result); } @@ -117,12 +127,14 @@ SHIM_CALL NtOpenFile_shim( X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr); + char* object_name = attrs.object_name.Duplicate(); + XELOGD( - "NtOpenFile(%.8X, %.8X, %.8X(%s), %.8X, %d)", + "watNtOpenFile(%.8X, %.8X, %.8X(%s), %.8X, %d)", handle_ptr, desired_access, object_attributes_ptr, - attrs.object_name.buffer, + !object_name ? "(null)" : object_name, io_status_block_ptr, open_options); @@ -141,7 +153,7 @@ SHIM_CALL NtOpenFile_shim( // Resolve the file using the virtual file system. FileSystem* fs = state->file_system(); - Entry* entry = fs->ResolvePath(attrs.object_name.buffer); + Entry* entry = fs->ResolvePath(object_name); XFile* file = NULL; if (entry && entry->type() == Entry::kTypeFile) { // Open the file. @@ -173,6 +185,8 @@ SHIM_CALL NtOpenFile_shim( SHIM_SET_MEM_32(handle_ptr, handle); } } + + xe_free(object_name); SHIM_SET_RETURN(result); } @@ -445,10 +459,12 @@ SHIM_CALL NtQueryFullAttributesFile_shim( X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr); + char* object_name = attrs.object_name.Duplicate(); + XELOGD( "NtQueryFullAttributesFile(%.8X(%s), %.8X)", object_attributes_ptr, - attrs.object_name.buffer, + !object_name ? "(null)" : object_name, file_info_ptr); X_STATUS result = X_STATUS_NO_SUCH_FILE; @@ -464,7 +480,7 @@ SHIM_CALL NtQueryFullAttributesFile_shim( // Resolve the file using the virtual file system. FileSystem* fs = state->file_system(); - Entry* entry = fs->ResolvePath(attrs.object_name.buffer); + Entry* entry = fs->ResolvePath(object_name); if (entry && entry->type() == Entry::kTypeFile) { // Found. XFileInfo file_info; @@ -474,6 +490,7 @@ SHIM_CALL NtQueryFullAttributesFile_shim( } } + xe_free(object_name); SHIM_SET_RETURN(result); } @@ -497,10 +514,11 @@ SHIM_CALL NtQueryDirectoryFile_shim( uint32_t file_info_ptr = SHIM_GET_ARG_32(5); uint32_t length = SHIM_GET_ARG_32(6); uint32_t file_name_ptr = SHIM_GET_ARG_32(7); - uint32_t restart_scan = SHIM_GET_ARG_32(8); + uint64_t sp = ppc_state->r[1]; + uint32_t restart_scan = SHIM_MEM_32(sp + 0x54); XELOGD( - "NtQueryDirectoryFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %.8X)", + "NtQueryDirectoryFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %.8X, %d)", file_handle, event_handle, apc_routine, @@ -508,7 +526,8 @@ SHIM_CALL NtQueryDirectoryFile_shim( io_status_block_ptr, file_info_ptr, length, - file_name_ptr); + file_name_ptr, + restart_scan); if (length < 72) { SHIM_SET_RETURN(X_STATUS_INFO_LENGTH_MISMATCH); diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 837e5dc89..73055cb33 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -34,6 +34,8 @@ typedef uint32_t X_STATUS; #define X_STATUS_TIMEOUT ((X_STATUS)0x00000102L) #define X_STATUS_PENDING ((X_STATUS)0x00000103L) #define X_STATUS_TIMER_RESUME_IGNORED ((X_STATUS)0x40000025L) +#define X_STATUS_BUFFER_OVERFLOW ((X_STATUS)0x80000005L) +#define X_STATUS_NO_MORE_FILES ((X_STATUS)0x80000006L) #define X_STATUS_UNSUCCESSFUL ((X_STATUS)0xC0000001L) #define X_STATUS_NOT_IMPLEMENTED ((X_STATUS)0xC0000002L) #define X_STATUS_INFO_LENGTH_MISMATCH ((X_STATUS)0xC0000004L) @@ -202,11 +204,12 @@ typedef enum _X_FILE_INFORMATION_CLASS { class X_ANSI_STRING { -public: - uint16_t length; - uint16_t maximum_length; - char* buffer; +private: + uint16_t length; + uint16_t maximum_length; + const char* buffer; +public: X_ANSI_STRING() { Zero(); } @@ -217,7 +220,7 @@ public: length = XEGETUINT16BE(base + p); maximum_length = XEGETUINT16BE(base + p + 2); if (maximum_length) { - buffer = (char*)(base + XEGETUINT32BE(base + p + 4)); + buffer = (const char*)(base + XEGETUINT32BE(base + p + 4)); } else { buffer = 0; } @@ -226,6 +229,14 @@ public: length = maximum_length = 0; buffer = 0; } + char* Duplicate() { + if (buffer == NULL) { + return NULL; + } + auto copy = (char*)xe_calloc(length+1); + xestrncpya(copy, length+1, buffer, length); + return copy; + } }; @@ -266,20 +277,20 @@ typedef enum _X_INPUT_FLAG { } X_INPUT_FLAG; typedef enum _X_INPUT_GAMEPAD_BUTTON { - X_INPUT_GAMEPAD_DPAD_UP = 0x0001, - X_INPUT_GAMEPAD_DPAD_DOWN = 0x0002, - X_INPUT_GAMEPAD_DPAD_LEFT = 0x0004, - X_INPUT_GAMEPAD_DPAD_RIGHT = 0x0008, - X_INPUT_GAMEPAD_START = 0x0010, - X_INPUT_GAMEPAD_BACK = 0x0020, - X_INPUT_GAMEPAD_LEFT_THUMB = 0x0040, - X_INPUT_GAMEPAD_RIGHT_THUMB = 0x0080, - X_INPUT_GAMEPAD_LEFT_SHOULDER = 0x0100, + X_INPUT_GAMEPAD_DPAD_UP = 0x0001, + X_INPUT_GAMEPAD_DPAD_DOWN = 0x0002, + X_INPUT_GAMEPAD_DPAD_LEFT = 0x0004, + X_INPUT_GAMEPAD_DPAD_RIGHT = 0x0008, + X_INPUT_GAMEPAD_START = 0x0010, + X_INPUT_GAMEPAD_BACK = 0x0020, + X_INPUT_GAMEPAD_LEFT_THUMB = 0x0040, + X_INPUT_GAMEPAD_RIGHT_THUMB = 0x0080, + X_INPUT_GAMEPAD_LEFT_SHOULDER = 0x0100, X_INPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200, - X_INPUT_GAMEPAD_A = 0x1000, - X_INPUT_GAMEPAD_B = 0x2000, - X_INPUT_GAMEPAD_X = 0x4000, - X_INPUT_GAMEPAD_Y = 0x8000, + X_INPUT_GAMEPAD_A = 0x1000, + X_INPUT_GAMEPAD_B = 0x2000, + X_INPUT_GAMEPAD_X = 0x4000, + X_INPUT_GAMEPAD_Y = 0x8000, } X_INPUT_GAMEPAD_BUTTON; class X_INPUT_GAMEPAD {