[Kernel/VFS] Cleanup info query/set+sector size.
[VFS] Device now exposes name, attributes, component name max length. [VFS] Fix STFS device to return 0x200 sector size. XCTD compression userland code appears to always expect a sector size of 0x200. [Kernel] Move X_FILE_*_INFORMATION structs to new files. [Kernel] Move NtQueryInformationFile, NtSetInformationFile, NtQueryVolumeInformationFile to new file. [Kernel] Cleanup implementation of NtQueryInformationFile, NetSetInformationFile, NtQueryVolumeInformationFile. [Kernel] Properly validate arguments to NtQueryInformationFile, NetSetInformationFile, NtQueryVolumeInformationFile. [Kernel] Properly implement query of XFileFsVolumeInformation. [Kernel] Properly implement query of XFileFsSizeInformation. [Kernel] Properly implement query of XFileFsAttributeInformation.
This commit is contained in:
parent
087247184d
commit
cf0251cd9f
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_INFO_FILE_H_
|
||||
#define XENIA_KERNEL_INFO_FILE_H_
|
||||
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
// https://github.com/oukiar/vdash/blob/master/vdash/include/kernel.h
|
||||
enum X_FILE_INFORMATION_CLASS {
|
||||
XFileDirectoryInformation = 1,
|
||||
XFileFullDirectoryInformation,
|
||||
XFileBothDirectoryInformation,
|
||||
XFileBasicInformation,
|
||||
XFileStandardInformation,
|
||||
XFileInternalInformation,
|
||||
XFileEaInformation,
|
||||
XFileAccessInformation,
|
||||
XFileNameInformation,
|
||||
XFileRenameInformation,
|
||||
XFileLinkInformation,
|
||||
XFileNamesInformation,
|
||||
XFileDispositionInformation,
|
||||
XFilePositionInformation,
|
||||
XFileFullEaInformation,
|
||||
XFileModeInformation,
|
||||
XFileAlignmentInformation,
|
||||
XFileAllInformation,
|
||||
XFileAllocationInformation,
|
||||
XFileEndOfFileInformation,
|
||||
XFileAlternateNameInformation,
|
||||
XFileStreamInformation,
|
||||
XFileMountPartitionInformation,
|
||||
XFileMountPartitionsInformation,
|
||||
XFilePipeRemoteInformation,
|
||||
XFileSectorInformation,
|
||||
XFileXctdCompressionInformation,
|
||||
XFileCompressionInformation,
|
||||
XFileObjectIdInformation,
|
||||
XFileCompletionInformation,
|
||||
XFileMoveClusterInformation,
|
||||
XFileIoPriorityInformation,
|
||||
XFileReparsePointInformation,
|
||||
XFileNetworkOpenInformation,
|
||||
XFileAttributeTagInformation,
|
||||
XFileTrackingInformation,
|
||||
XFileMaximumInformation
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_internal_information
|
||||
struct X_FILE_INTERNAL_INFORMATION {
|
||||
be<uint64_t> index_number;
|
||||
};
|
||||
static_assert_size(X_FILE_INTERNAL_INFORMATION, 8);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information
|
||||
struct X_FILE_DISPOSITION_INFORMATION {
|
||||
uint8_t delete_file;
|
||||
};
|
||||
static_assert_size(X_FILE_DISPOSITION_INFORMATION, 1);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_position_information
|
||||
struct X_FILE_POSITION_INFORMATION {
|
||||
be<uint64_t> current_byte_offset;
|
||||
};
|
||||
static_assert_size(X_FILE_POSITION_INFORMATION, 8);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_end_of_file_information
|
||||
struct X_FILE_END_OF_FILE_INFORMATION {
|
||||
be<uint64_t> end_of_file;
|
||||
};
|
||||
static_assert_size(X_FILE_END_OF_FILE_INFORMATION, 8);
|
||||
|
||||
struct X_FILE_XCTD_COMPRESSION_INFORMATION {
|
||||
be<uint32_t> unknown;
|
||||
};
|
||||
static_assert_size(X_FILE_XCTD_COMPRESSION_INFORMATION, 4);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_completion_information
|
||||
struct X_FILE_COMPLETION_INFORMATION {
|
||||
be<uint32_t> handle;
|
||||
be<uint32_t> key;
|
||||
};
|
||||
static_assert_size(X_FILE_COMPLETION_INFORMATION, 8);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_network_open_information
|
||||
struct X_FILE_NETWORK_OPEN_INFORMATION {
|
||||
be<uint64_t> creation_time;
|
||||
be<uint64_t> last_access_time;
|
||||
be<uint64_t> last_write_time;
|
||||
be<uint64_t> change_time;
|
||||
be<uint64_t> allocation_size;
|
||||
be<uint64_t> end_of_file; // size in bytes
|
||||
be<uint32_t> attributes;
|
||||
be<uint32_t> pad;
|
||||
};
|
||||
static_assert_size(X_FILE_NETWORK_OPEN_INFORMATION, 56);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_INFO_FILE_H_
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_INFO_VOLUME_H_
|
||||
#define XENIA_KERNEL_INFO_VOLUME_H_
|
||||
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
enum X_FILE_FS_INFORMATION_CLASS {
|
||||
XFileFsVolumeInformation = 1,
|
||||
XFileFsSizeInformation = 3,
|
||||
XFileFsDeviceInformation,
|
||||
XFileFsAttributeInformation = 5,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_fs_volume_information
|
||||
struct X_FILE_FS_VOLUME_INFORMATION {
|
||||
be<uint64_t> creation_time;
|
||||
be<uint32_t> serial_number;
|
||||
be<uint32_t> label_length;
|
||||
uint8_t supports_objects;
|
||||
char label[1];
|
||||
uint8_t pad[6];
|
||||
};
|
||||
static_assert_size(X_FILE_FS_VOLUME_INFORMATION, 24);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_fs_size_information
|
||||
struct X_FILE_FS_SIZE_INFORMATION {
|
||||
be<uint64_t> total_allocation_units;
|
||||
be<uint64_t> available_allocation_units;
|
||||
be<uint32_t> sectors_per_allocation_unit;
|
||||
be<uint32_t> bytes_per_sector;
|
||||
};
|
||||
static_assert_size(X_FILE_FS_SIZE_INFORMATION, 24);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_attribute_information
|
||||
struct X_FILE_FS_ATTRIBUTE_INFORMATION {
|
||||
be<uint32_t> attributes;
|
||||
be<int32_t> component_name_max_length;
|
||||
be<uint32_t> name_length;
|
||||
char name[1];
|
||||
uint8_t pad[3];
|
||||
};
|
||||
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_INFO_VOLUME_H_
|
|
@ -11,6 +11,7 @@
|
|||
#include "xenia/base/memory.h"
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/kernel/info/file.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
|
@ -26,37 +27,6 @@ namespace xe {
|
|||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540287.aspx
|
||||
struct X_FILE_FS_VOLUME_INFORMATION {
|
||||
// FILE_FS_VOLUME_INFORMATION
|
||||
xe::be<uint64_t> creation_time;
|
||||
xe::be<uint32_t> serial_number;
|
||||
xe::be<uint32_t> label_length;
|
||||
xe::be<uint32_t> supports_objects;
|
||||
char label[1];
|
||||
};
|
||||
static_assert_size(X_FILE_FS_VOLUME_INFORMATION, 24);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540282.aspx
|
||||
struct X_FILE_FS_SIZE_INFORMATION {
|
||||
// FILE_FS_SIZE_INFORMATION
|
||||
xe::be<uint64_t> total_allocation_units;
|
||||
xe::be<uint64_t> available_allocation_units;
|
||||
xe::be<uint32_t> sectors_per_allocation_unit;
|
||||
xe::be<uint32_t> bytes_per_sector;
|
||||
};
|
||||
static_assert_size(X_FILE_FS_SIZE_INFORMATION, 24);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540251(v=vs.85).aspx
|
||||
struct X_FILE_FS_ATTRIBUTE_INFORMATION {
|
||||
// FILE_FS_ATTRIBUTE_INFORMATION
|
||||
xe::be<uint32_t> attributes;
|
||||
xe::be<int32_t> maximum_component_name_length;
|
||||
xe::be<uint32_t> fs_name_length;
|
||||
char fs_name[1];
|
||||
};
|
||||
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
|
||||
|
||||
struct CreateOptions {
|
||||
// https://processhacker.sourceforge.io/doc/ntioapi_8h.html
|
||||
static const uint32_t FILE_DIRECTORY_FILE = 0x00000001;
|
||||
|
@ -355,207 +325,6 @@ dword_result_t NtRemoveIoCompletion(
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtRemoveIoCompletion, kFileSystem, kImplemented);
|
||||
|
||||
dword_result_t NtSetInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||
lpvoid_t file_info, dword_t length, dword_t file_info_class) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
uint32_t info = 0;
|
||||
|
||||
// Grab file.
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (!file) {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (XSUCCEEDED(result)) {
|
||||
switch (file_info_class) {
|
||||
case XFileDispositionInformation: {
|
||||
// Used to set deletion flag. Which we don't support. Probably?
|
||||
info = 0;
|
||||
bool delete_on_close =
|
||||
(xe::load_and_swap<uint8_t>(file_info)) ? true : false;
|
||||
XELOGW("NtSetInformationFile ignoring delete on close: {}",
|
||||
delete_on_close);
|
||||
break;
|
||||
}
|
||||
case XFilePositionInformation:
|
||||
// struct FILE_POSITION_INFORMATION {
|
||||
// LARGE_INTEGER CurrentByteOffset;
|
||||
// };
|
||||
assert_true(length == 8);
|
||||
info = 8;
|
||||
file->set_position(xe::load_and_swap<uint64_t>(file_info));
|
||||
break;
|
||||
case XFileAllocationInformation:
|
||||
assert_true(length == 8);
|
||||
info = 8;
|
||||
XELOGW("NtSetInformationFile ignoring alloc");
|
||||
break;
|
||||
case XFileEndOfFileInformation: {
|
||||
assert_true(length == 8);
|
||||
auto eof = xe::load_and_swap<uint64_t>(file_info);
|
||||
result = file->SetLength(eof);
|
||||
|
||||
// Update the files vfs::Entry information
|
||||
file->entry()->update();
|
||||
break;
|
||||
}
|
||||
case XFileCompletionInformation: {
|
||||
// Info contains IO Completion handle and completion key
|
||||
assert_true(length == 8);
|
||||
|
||||
auto handle = xe::load_and_swap<uint32_t>(file_info + 0x0);
|
||||
auto key = xe::load_and_swap<uint32_t>(file_info + 0x4);
|
||||
auto port =
|
||||
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
|
||||
if (!port) {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
file->RegisterIOCompletionPort(key, port);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
info = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (io_status_block) {
|
||||
io_status_block->status = result;
|
||||
io_status_block->information = info;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT2(NtSetInformationFile, kFileSystem, kImplemented,
|
||||
kHighFrequency);
|
||||
|
||||
struct X_IO_STATUS_BLOCK {
|
||||
union {
|
||||
xe::be<uint32_t> status;
|
||||
xe::be<uint32_t> pointer;
|
||||
};
|
||||
xe::be<uint32_t> information;
|
||||
};
|
||||
|
||||
dword_result_t NtQueryInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
|
||||
lpvoid_t file_info_ptr, dword_t length, dword_t file_info_class) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
uint32_t info = 0;
|
||||
|
||||
// Grab file.
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (file) {
|
||||
switch (file_info_class) {
|
||||
case XFileInternalInformation:
|
||||
// Internal unique file pointer. Not sure why anyone would want this.
|
||||
assert_true(length == 8);
|
||||
info = 8;
|
||||
// TODO(benvanik): use pointer to fs:: entry?
|
||||
xe::store_and_swap<uint64_t>(file_info_ptr,
|
||||
xe::memory::hash_combine(0, file->path()));
|
||||
break;
|
||||
case XFilePositionInformation:
|
||||
// struct FILE_POSITION_INFORMATION {
|
||||
// LARGE_INTEGER CurrentByteOffset;
|
||||
// };
|
||||
assert_true(length == 8);
|
||||
info = 8;
|
||||
xe::store_and_swap<uint64_t>(file_info_ptr, file->position());
|
||||
break;
|
||||
case XFileNetworkOpenInformation: {
|
||||
// struct FILE_NETWORK_OPEN_INFORMATION {
|
||||
// LARGE_INTEGER CreationTime;
|
||||
// LARGE_INTEGER LastAccessTime;
|
||||
// LARGE_INTEGER LastWriteTime;
|
||||
// LARGE_INTEGER ChangeTime;
|
||||
// LARGE_INTEGER AllocationSize;
|
||||
// LARGE_INTEGER EndOfFile;
|
||||
// ULONG FileAttributes;
|
||||
// ULONG Unknown;
|
||||
// };
|
||||
assert_true(length == 56);
|
||||
|
||||
// Make sure we're working with up-to-date information, just in case the
|
||||
// file size has changed via something other than NtSetInfoFile
|
||||
// (eg. seems NtWriteFile might extend the file in some cases)
|
||||
file->entry()->update();
|
||||
|
||||
auto file_info = file_info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
|
||||
file_info->creation_time = file->entry()->create_timestamp();
|
||||
file_info->last_access_time = file->entry()->access_timestamp();
|
||||
file_info->last_write_time = file->entry()->write_timestamp();
|
||||
file_info->change_time = file->entry()->write_timestamp();
|
||||
file_info->allocation_size = file->entry()->allocation_size();
|
||||
file_info->end_of_file = file->entry()->size();
|
||||
file_info->attributes = file->entry()->attributes();
|
||||
info = 56;
|
||||
break;
|
||||
}
|
||||
case XFileXctdCompressionInformation: {
|
||||
assert_true(length == 4);
|
||||
XELOGE(
|
||||
"NtQueryInformationFile(XFileXctdCompressionInformation) "
|
||||
"unimplemented");
|
||||
// This is wrong and puts files into wrong states for games that use
|
||||
// XctdDecompression.
|
||||
/*
|
||||
uint32_t magic;
|
||||
uint32_t bytes_read;
|
||||
uint64_t cur_pos = file->position();
|
||||
|
||||
file->set_position(0);
|
||||
// FIXME(Triang3l): For now, XFile can be read only to guest buffers -
|
||||
// this line won't work, implement reading to host buffers if needed.
|
||||
result = file->Read(&magic, sizeof(magic), 0, &bytes_read);
|
||||
if (XSUCCEEDED(result)) {
|
||||
if (bytes_read == sizeof(magic)) {
|
||||
info = 4;
|
||||
*file_info_ptr.as<xe::be<uint32_t>*>() =
|
||||
magic == xe::byte_swap(0x0FF512ED) ? 1 : 0;
|
||||
} else {
|
||||
result = X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
file->set_position(cur_pos);
|
||||
info = 4;
|
||||
*/
|
||||
xe::store_and_swap<uint32_t>(file_info_ptr, 0);
|
||||
result = X_STATUS_UNSUCCESSFUL;
|
||||
info = 0;
|
||||
} break;
|
||||
case XFileSectorInformation:
|
||||
// TODO(benvanik): return sector this file's on.
|
||||
assert_true(length == 4);
|
||||
XELOGE("NtQueryInformationFile(XFileSectorInformation) unimplemented");
|
||||
result = X_STATUS_UNSUCCESSFUL;
|
||||
info = 0;
|
||||
break;
|
||||
default:
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
info = 0;
|
||||
result = X_STATUS_UNSUCCESSFUL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (io_status_block_ptr) {
|
||||
io_status_block_ptr->status = result;
|
||||
io_status_block_ptr->information = info; // # bytes written
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtQueryInformationFile, kFileSystem, kImplemented);
|
||||
|
||||
dword_result_t NtQueryFullAttributesFile(
|
||||
pointer_t<X_OBJECT_ATTRIBUTES> obj_attribs,
|
||||
pointer_t<X_FILE_NETWORK_OPEN_INFORMATION> file_info) {
|
||||
|
@ -592,82 +361,6 @@ dword_result_t NtQueryFullAttributesFile(
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtQueryFullAttributesFile, kFileSystem, kImplemented);
|
||||
|
||||
dword_result_t NtQueryVolumeInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
|
||||
lpvoid_t fs_info_ptr, dword_t length, dword_t fs_info_class) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
uint32_t info = 0;
|
||||
|
||||
// Grab file.
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (file) {
|
||||
switch (fs_info_class) {
|
||||
case 1: { // FileFsVolumeInformation
|
||||
// TODO(gibbed): actual value
|
||||
std::string name = "test";
|
||||
X_FILE_FS_VOLUME_INFORMATION* volume_info =
|
||||
fs_info_ptr.as<X_FILE_FS_VOLUME_INFORMATION*>();
|
||||
volume_info->creation_time = 0;
|
||||
volume_info->serial_number = 12345678;
|
||||
volume_info->supports_objects = 0;
|
||||
volume_info->label_length = uint32_t(name.size());
|
||||
std::memcpy(volume_info->label, name.data(), name.size());
|
||||
info = length;
|
||||
break;
|
||||
}
|
||||
case 3: { // FileFsSizeInformation
|
||||
X_FILE_FS_SIZE_INFORMATION* fs_size_info =
|
||||
fs_info_ptr.as<X_FILE_FS_SIZE_INFORMATION*>();
|
||||
fs_size_info->total_allocation_units =
|
||||
file->device()->total_allocation_units();
|
||||
fs_size_info->available_allocation_units =
|
||||
file->device()->available_allocation_units();
|
||||
fs_size_info->sectors_per_allocation_unit =
|
||||
file->device()->sectors_per_allocation_unit();
|
||||
fs_size_info->bytes_per_sector = file->device()->bytes_per_sector();
|
||||
info = length;
|
||||
break;
|
||||
}
|
||||
case 5: { // FileFsAttributeInformation
|
||||
// TODO(gibbed): actual value
|
||||
std::string name = "test";
|
||||
X_FILE_FS_ATTRIBUTE_INFORMATION* fs_attribute_info =
|
||||
fs_info_ptr.as<X_FILE_FS_ATTRIBUTE_INFORMATION*>();
|
||||
fs_attribute_info->attributes = 0;
|
||||
fs_attribute_info->maximum_component_name_length = 255;
|
||||
fs_attribute_info->fs_name_length = uint32_t(name.size());
|
||||
std::memcpy(fs_attribute_info->fs_name, name.data(), name.size());
|
||||
info = length;
|
||||
break;
|
||||
}
|
||||
case 2: // FileFsLabelInformation
|
||||
case 4: // FileFsDeviceInformation
|
||||
case 6: // FileFsControlInformation
|
||||
case 7: // FileFsFullSizeInformation
|
||||
case 8: // FileFsObjectIdInformation
|
||||
default:
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
info = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = X_STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
if (XFAILED(result)) {
|
||||
info = 0;
|
||||
}
|
||||
if (io_status_block_ptr) {
|
||||
io_status_block_ptr->status = result;
|
||||
io_status_block_ptr->information = info;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtQueryVolumeInformationFile, kFileSystem,
|
||||
kImplemented);
|
||||
|
||||
dword_result_t NtQueryDirectoryFile(
|
||||
dword_t file_handle, dword_t event_handle, function_t apc_routine,
|
||||
lpvoid_t apc_context, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/memory.h"
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/kernel/info/file.h"
|
||||
#include "xenia/kernel/info/volume.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
#include "xenia/kernel/xevent.h"
|
||||
#include "xenia/kernel/xfile.h"
|
||||
#include "xenia/kernel/xiocompletion.h"
|
||||
#include "xenia/kernel/xsymboliclink.h"
|
||||
#include "xenia/kernel/xthread.h"
|
||||
#include "xenia/vfs/device.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
uint32_t GetQueryFileInfoMinimumLength(uint32_t info_class) {
|
||||
switch (info_class) {
|
||||
case XFileInternalInformation:
|
||||
return sizeof(X_FILE_INTERNAL_INFORMATION);
|
||||
case XFilePositionInformation:
|
||||
return sizeof(X_FILE_POSITION_INFORMATION);
|
||||
case XFileXctdCompressionInformation:
|
||||
return sizeof(X_FILE_XCTD_COMPRESSION_INFORMATION);
|
||||
case XFileNetworkOpenInformation:
|
||||
return sizeof(X_FILE_NETWORK_OPEN_INFORMATION);
|
||||
// TODO(gibbed): structures to get the size of.
|
||||
case XFileModeInformation:
|
||||
case XFileAlignmentInformation:
|
||||
case XFileSectorInformation:
|
||||
case XFileIoPriorityInformation:
|
||||
return 4;
|
||||
case XFileNameInformation:
|
||||
case XFileAllocationInformation:
|
||||
return 8;
|
||||
case XFileBasicInformation:
|
||||
return 40;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dword_result_t NtQueryInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
|
||||
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
|
||||
uint32_t minimum_length = GetQueryFileInfoMinimumLength(info_class);
|
||||
if (!minimum_length) {
|
||||
return X_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
if (info_length < minimum_length) {
|
||||
return X_STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (!file) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
info_ptr.Zero(info_length);
|
||||
|
||||
X_STATUS status = X_STATUS_SUCCESS;
|
||||
uint32_t out_length;
|
||||
|
||||
switch (info_class) {
|
||||
case XFileInternalInformation: {
|
||||
// Internal unique file pointer. Not sure why anyone would want this.
|
||||
// TODO(benvanik): use pointer to fs::entry?
|
||||
auto info = info_ptr.as<X_FILE_INTERNAL_INFORMATION*>();
|
||||
info->index_number = xe::memory::hash_combine(0, file->path());
|
||||
out_length = sizeof(*info);
|
||||
break;
|
||||
}
|
||||
case XFilePositionInformation: {
|
||||
auto info = info_ptr.as<X_FILE_POSITION_INFORMATION*>();
|
||||
info->current_byte_offset = file->position();
|
||||
out_length = sizeof(*info);
|
||||
break;
|
||||
}
|
||||
case XFileSectorInformation: {
|
||||
// TODO(benvanik): return sector this file's on.
|
||||
XELOGE("NtQueryInformationFile(XFileSectorInformation) unimplemented");
|
||||
status = X_STATUS_INVALID_PARAMETER;
|
||||
out_length = 0;
|
||||
break;
|
||||
}
|
||||
case XFileXctdCompressionInformation: {
|
||||
XELOGE(
|
||||
"NtQueryInformationFile(XFileXctdCompressionInformation) "
|
||||
"unimplemented");
|
||||
// Files that are XCTD compressed begin with the magic 0x0FF512ED but we
|
||||
// shouldn't detect this that way. There's probably a flag somewhere
|
||||
// (attributes?) that defines if it's compressed or not.
|
||||
status = X_STATUS_INVALID_PARAMETER;
|
||||
out_length = 0;
|
||||
break;
|
||||
};
|
||||
case XFileNetworkOpenInformation: {
|
||||
// Make sure we're working with up-to-date information, just in case the
|
||||
// file size has changed via something other than NtSetInfoFile
|
||||
// (eg. seems NtWriteFile might extend the file in some cases)
|
||||
file->entry()->update();
|
||||
|
||||
auto info = info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
|
||||
info->creation_time = file->entry()->create_timestamp();
|
||||
info->last_access_time = file->entry()->access_timestamp();
|
||||
info->last_write_time = file->entry()->write_timestamp();
|
||||
info->change_time = file->entry()->write_timestamp();
|
||||
info->allocation_size = file->entry()->allocation_size();
|
||||
info->end_of_file = file->entry()->size();
|
||||
info->attributes = file->entry()->attributes();
|
||||
out_length = sizeof(*info);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
status = X_STATUS_INVALID_PARAMETER;
|
||||
out_length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (io_status_block_ptr) {
|
||||
io_status_block_ptr->status = status;
|
||||
io_status_block_ptr->information = out_length;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtQueryInformationFile, kFileSystem, kImplemented);
|
||||
|
||||
uint32_t GetSetFileInfoMinimumLength(uint32_t info_class) {
|
||||
switch (info_class) {
|
||||
case XFileDispositionInformation:
|
||||
return sizeof(X_FILE_DISPOSITION_INFORMATION);
|
||||
case XFilePositionInformation:
|
||||
return sizeof(X_FILE_POSITION_INFORMATION);
|
||||
case XFileCompletionInformation:
|
||||
return sizeof(X_FILE_COMPLETION_INFORMATION);
|
||||
// TODO(gibbed): structures to get the size of.
|
||||
case XFileModeInformation:
|
||||
case XFileIoPriorityInformation:
|
||||
return 4;
|
||||
case XFileAllocationInformation:
|
||||
case XFileEndOfFileInformation:
|
||||
case XFileMountPartitionInformation:
|
||||
return 8;
|
||||
case XFileRenameInformation:
|
||||
case XFileLinkInformation:
|
||||
return 16;
|
||||
case XFileBasicInformation:
|
||||
return 40;
|
||||
case XFileMountPartitionsInformation:
|
||||
return 152;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dword_result_t NtSetInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
|
||||
uint32_t minimum_length = GetSetFileInfoMinimumLength(info_class);
|
||||
if (!minimum_length) {
|
||||
return X_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
if (info_length < minimum_length) {
|
||||
return X_STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (!file) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
uint32_t out_length;
|
||||
|
||||
switch (info_class) {
|
||||
case XFileDispositionInformation: {
|
||||
// Used to set deletion flag. Which we don't support. Probably?
|
||||
auto info = info_ptr.as<X_FILE_DISPOSITION_INFORMATION*>();
|
||||
bool delete_on_close = info->delete_file ? true : false;
|
||||
out_length = 0;
|
||||
XELOGW("NtSetInformationFile ignoring delete on close: {}",
|
||||
delete_on_close);
|
||||
break;
|
||||
}
|
||||
case XFilePositionInformation: {
|
||||
auto info = info_ptr.as<X_FILE_POSITION_INFORMATION*>();
|
||||
file->set_position(info->current_byte_offset);
|
||||
out_length = sizeof(*info);
|
||||
break;
|
||||
}
|
||||
case XFileAllocationInformation: {
|
||||
XELOGW("NtSetInformationFile ignoring alloc");
|
||||
out_length = 8;
|
||||
break;
|
||||
}
|
||||
case XFileEndOfFileInformation: {
|
||||
auto info = info_ptr.as<X_FILE_END_OF_FILE_INFORMATION*>();
|
||||
result = file->SetLength(info->end_of_file);
|
||||
out_length = sizeof(*info);
|
||||
|
||||
// Update the files vfs::Entry information
|
||||
file->entry()->update();
|
||||
break;
|
||||
}
|
||||
case XFileCompletionInformation: {
|
||||
// Info contains IO Completion handle and completion key
|
||||
auto info = info_ptr.as<X_FILE_COMPLETION_INFORMATION*>();
|
||||
auto handle = uint32_t(info->handle);
|
||||
auto key = uint32_t(info->key);
|
||||
out_length = sizeof(*info);
|
||||
auto port =
|
||||
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
|
||||
if (!port) {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
} else {
|
||||
file->RegisterIOCompletionPort(key, port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
out_length = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (io_status_block) {
|
||||
io_status_block->status = result;
|
||||
io_status_block->information = out_length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT2(NtSetInformationFile, kFileSystem, kImplemented,
|
||||
kHighFrequency);
|
||||
|
||||
uint32_t GetQueryVolumeInfoMinimumLength(uint32_t info_class) {
|
||||
switch (info_class) {
|
||||
case XFileFsVolumeInformation:
|
||||
return sizeof(X_FILE_FS_VOLUME_INFORMATION);
|
||||
case XFileFsSizeInformation:
|
||||
return sizeof(X_FILE_FS_SIZE_INFORMATION);
|
||||
case XFileFsAttributeInformation:
|
||||
return sizeof(X_FILE_FS_ATTRIBUTE_INFORMATION);
|
||||
// TODO(gibbed): structures to get the size of.
|
||||
case XFileFsDeviceInformation:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dword_result_t NtQueryVolumeInformationFile(
|
||||
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
|
||||
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
|
||||
uint32_t minimum_length = GetQueryVolumeInfoMinimumLength(info_class);
|
||||
if (!minimum_length) {
|
||||
return X_STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
if (info_length < minimum_length) {
|
||||
return X_STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
|
||||
if (!file) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
info_ptr.Zero(info_length);
|
||||
|
||||
X_STATUS status = X_STATUS_SUCCESS;
|
||||
uint32_t out_length;
|
||||
|
||||
switch (info_class) {
|
||||
case XFileFsVolumeInformation: {
|
||||
auto info = info_ptr.as<X_FILE_FS_VOLUME_INFORMATION*>();
|
||||
info->creation_time = 0;
|
||||
info->serial_number = 0; // set for FATX, but we don't do that currently
|
||||
info->supports_objects = 0;
|
||||
info->label_length = 0;
|
||||
out_length = offsetof(X_FILE_FS_VOLUME_INFORMATION, label);
|
||||
break;
|
||||
}
|
||||
case XFileFsSizeInformation: {
|
||||
auto device = file->device();
|
||||
auto info = info_ptr.as<X_FILE_FS_SIZE_INFORMATION*>();
|
||||
info->total_allocation_units = device->total_allocation_units();
|
||||
info->available_allocation_units = device->available_allocation_units();
|
||||
info->sectors_per_allocation_unit = device->sectors_per_allocation_unit();
|
||||
info->bytes_per_sector = device->bytes_per_sector();
|
||||
// TODO(gibbed): sanity check, XCTD userland code seems to require this.
|
||||
assert_true(info->bytes_per_sector == 0x200);
|
||||
out_length = sizeof(*info);
|
||||
break;
|
||||
}
|
||||
case XFileFsAttributeInformation: {
|
||||
auto device = file->device();
|
||||
const auto& name = device->name();
|
||||
auto info = info_ptr.as<X_FILE_FS_ATTRIBUTE_INFORMATION*>();
|
||||
info->attributes = device->attributes();
|
||||
info->component_name_max_length = device->component_name_max_length();
|
||||
info->name_length = uint32_t(name.size());
|
||||
if (info_length >= 12 + name.size()) {
|
||||
std::memcpy(info->name, name.data(), name.size());
|
||||
out_length =
|
||||
offsetof(X_FILE_FS_ATTRIBUTE_INFORMATION, name) + info->name_length;
|
||||
} else {
|
||||
status = X_STATUS_BUFFER_OVERFLOW;
|
||||
out_length = offsetof(X_FILE_FS_ATTRIBUTE_INFORMATION, name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XFileFsDeviceInformation:
|
||||
default: {
|
||||
// Unsupported, for now.
|
||||
assert_always();
|
||||
out_length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (io_status_block_ptr) {
|
||||
io_status_block_ptr->status = status;
|
||||
io_status_block_ptr->information = out_length;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(NtQueryVolumeInformationFile, kFileSystem,
|
||||
kImplemented);
|
||||
|
||||
void RegisterIoInfoExports(xe::cpu::ExportResolver* export_resolver,
|
||||
KernelState* kernel_state) {}
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
|
@ -91,6 +91,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
|
|||
RegisterHalExports(export_resolver_, kernel_state_);
|
||||
RegisterHidExports(export_resolver_, kernel_state_);
|
||||
RegisterIoExports(export_resolver_, kernel_state_);
|
||||
RegisterIoInfoExports(export_resolver_, kernel_state_);
|
||||
RegisterMemoryExports(export_resolver_, kernel_state_);
|
||||
RegisterMiscExports(export_resolver_, kernel_state_);
|
||||
RegisterModuleExports(export_resolver_, kernel_state_);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@ DECLARE_REGISTER_EXPORTS(Error);
|
|||
DECLARE_REGISTER_EXPORTS(Hal);
|
||||
DECLARE_REGISTER_EXPORTS(Hid);
|
||||
DECLARE_REGISTER_EXPORTS(Io);
|
||||
DECLARE_REGISTER_EXPORTS(IoInfo);
|
||||
DECLARE_REGISTER_EXPORTS(Memory);
|
||||
DECLARE_REGISTER_EXPORTS(Misc);
|
||||
DECLARE_REGISTER_EXPORTS(Module);
|
||||
|
|
|
@ -23,58 +23,55 @@
|
|||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff545822.aspx
|
||||
struct X_FILE_NETWORK_OPEN_INFORMATION {
|
||||
xe::be<uint64_t> creation_time;
|
||||
xe::be<uint64_t> last_access_time;
|
||||
xe::be<uint64_t> last_write_time;
|
||||
xe::be<uint64_t> change_time;
|
||||
xe::be<uint64_t> allocation_size;
|
||||
xe::be<uint64_t> end_of_file; // size in bytes
|
||||
xe::be<uint32_t> attributes;
|
||||
xe::be<uint32_t> pad;
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_status_block
|
||||
struct X_IO_STATUS_BLOCK {
|
||||
union {
|
||||
be<uint32_t> status;
|
||||
be<uint32_t> pointer;
|
||||
};
|
||||
be<uint32_t> information;
|
||||
};
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540248.aspx
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_directory_information
|
||||
class X_FILE_DIRECTORY_INFORMATION {
|
||||
public:
|
||||
// FILE_DIRECTORY_INFORMATION
|
||||
xe::be<uint32_t> next_entry_offset; // 0x0
|
||||
xe::be<uint32_t> file_index; // 0x4
|
||||
xe::be<uint64_t> creation_time; // 0x8
|
||||
xe::be<uint64_t> last_access_time; // 0x10
|
||||
xe::be<uint64_t> last_write_time; // 0x18
|
||||
xe::be<uint64_t> change_time; // 0x20
|
||||
xe::be<uint64_t> end_of_file; // 0x28 size in bytes
|
||||
xe::be<uint64_t> allocation_size; // 0x30
|
||||
xe::be<uint32_t> attributes; // 0x38 X_FILE_ATTRIBUTES
|
||||
xe::be<uint32_t> file_name_length; // 0x3C
|
||||
be<uint32_t> next_entry_offset; // 0x0
|
||||
be<uint32_t> file_index; // 0x4
|
||||
be<uint64_t> creation_time; // 0x8
|
||||
be<uint64_t> last_access_time; // 0x10
|
||||
be<uint64_t> last_write_time; // 0x18
|
||||
be<uint64_t> change_time; // 0x20
|
||||
be<uint64_t> end_of_file; // 0x28 size in bytes
|
||||
be<uint64_t> allocation_size; // 0x30
|
||||
be<uint32_t> attributes; // 0x38 X_FILE_ATTRIBUTES
|
||||
be<uint32_t> file_name_length; // 0x3C
|
||||
char file_name[1]; // 0x40
|
||||
|
||||
void Write(uint8_t* base, uint32_t p) {
|
||||
uint8_t* dst = base + p;
|
||||
uint8_t* src = reinterpret_cast<uint8_t*>(this);
|
||||
X_FILE_DIRECTORY_INFORMATION* info;
|
||||
X_FILE_DIRECTORY_INFORMATION* right;
|
||||
do {
|
||||
info = reinterpret_cast<X_FILE_DIRECTORY_INFORMATION*>(src);
|
||||
xe::store_and_swap<uint32_t>(dst, info->next_entry_offset);
|
||||
xe::store_and_swap<uint32_t>(dst + 4, info->file_index);
|
||||
xe::store_and_swap<uint64_t>(dst + 8, info->creation_time);
|
||||
xe::store_and_swap<uint64_t>(dst + 16, info->last_access_time);
|
||||
xe::store_and_swap<uint64_t>(dst + 24, info->last_write_time);
|
||||
xe::store_and_swap<uint64_t>(dst + 32, info->change_time);
|
||||
xe::store_and_swap<uint64_t>(dst + 40, info->end_of_file);
|
||||
xe::store_and_swap<uint64_t>(dst + 48, info->allocation_size);
|
||||
xe::store_and_swap<uint32_t>(dst + 56, info->attributes);
|
||||
xe::store_and_swap<uint32_t>(dst + 60, info->file_name_length);
|
||||
memcpy(dst + 64, info->file_name, info->file_name_length);
|
||||
auto left = reinterpret_cast<X_FILE_DIRECTORY_INFORMATION*>(dst);
|
||||
right = reinterpret_cast<X_FILE_DIRECTORY_INFORMATION*>(src);
|
||||
left->next_entry_offset = right->next_entry_offset;
|
||||
left->file_index = right->file_index;
|
||||
left->creation_time = right->creation_time;
|
||||
left->last_access_time = right->last_access_time;
|
||||
left->last_write_time = right->last_write_time;
|
||||
left->change_time = right->change_time;
|
||||
left->end_of_file = right->end_of_file;
|
||||
left->allocation_size = right->allocation_size;
|
||||
left->attributes = right->attributes;
|
||||
left->file_name_length = right->file_name_length;
|
||||
std::memcpy(left->file_name, right->file_name, right->file_name_length);
|
||||
|
||||
dst += info->next_entry_offset;
|
||||
src += info->next_entry_offset;
|
||||
} while (info->next_entry_offset != 0);
|
||||
dst += right->next_entry_offset;
|
||||
src += right->next_entry_offset;
|
||||
} while (right->next_entry_offset != 0);
|
||||
}
|
||||
};
|
||||
static_assert_size(X_FILE_DIRECTORY_INFORMATION, 72);
|
||||
|
||||
class XFile : public XObject {
|
||||
public:
|
||||
|
|
|
@ -33,6 +33,10 @@ class Device {
|
|||
virtual void Dump(StringBuffer* string_buffer) = 0;
|
||||
virtual Entry* ResolvePath(const std::string_view path) = 0;
|
||||
|
||||
virtual const std::string& name() const = 0;
|
||||
virtual uint32_t attributes() const = 0;
|
||||
virtual uint32_t component_name_max_length() const = 0;
|
||||
|
||||
virtual uint32_t total_allocation_units() const = 0;
|
||||
virtual uint32_t available_allocation_units() const = 0;
|
||||
virtual uint32_t sectors_per_allocation_unit() const = 0;
|
||||
|
|
|
@ -20,7 +20,7 @@ const size_t kXESectorSize = 2048;
|
|||
|
||||
DiscImageDevice::DiscImageDevice(const std::string_view mount_path,
|
||||
const std::filesystem::path& host_path)
|
||||
: Device(mount_path), host_path_(host_path) {}
|
||||
: Device(mount_path), name_("GDFX"), host_path_(host_path) {}
|
||||
|
||||
DiscImageDevice::~DiscImageDevice() = default;
|
||||
|
||||
|
|
|
@ -31,13 +31,17 @@ class DiscImageDevice : public Device {
|
|||
void Dump(StringBuffer* string_buffer) override;
|
||||
Entry* ResolvePath(const std::string_view path) override;
|
||||
|
||||
const std::string& name() const override { return name_; }
|
||||
uint32_t attributes() const override { return 0; }
|
||||
uint32_t component_name_max_length() const override { return 255; }
|
||||
|
||||
uint32_t total_allocation_units() const override {
|
||||
return uint32_t(mmap_->size() / sectors_per_allocation_unit() /
|
||||
bytes_per_sector());
|
||||
}
|
||||
uint32_t available_allocation_units() const override { return 0; }
|
||||
uint32_t sectors_per_allocation_unit() const override { return 1; }
|
||||
uint32_t bytes_per_sector() const override { return 2 * 1024; }
|
||||
uint32_t bytes_per_sector() const override { return 0x200; }
|
||||
|
||||
private:
|
||||
enum class Error {
|
||||
|
@ -48,6 +52,7 @@ class DiscImageDevice : public Device {
|
|||
kErrorDamagedFile = -31,
|
||||
};
|
||||
|
||||
std::string name_;
|
||||
std::filesystem::path host_path_;
|
||||
std::unique_ptr<Entry> root_entry_;
|
||||
std::unique_ptr<MappedMemory> mmap_;
|
||||
|
|
|
@ -21,7 +21,10 @@ namespace vfs {
|
|||
HostPathDevice::HostPathDevice(const std::string_view mount_path,
|
||||
const std::filesystem::path& host_path,
|
||||
bool read_only)
|
||||
: Device(mount_path), host_path_(host_path), read_only_(read_only) {}
|
||||
: Device(mount_path),
|
||||
name_("STFS"),
|
||||
host_path_(host_path),
|
||||
read_only_(read_only) {}
|
||||
|
||||
HostPathDevice::~HostPathDevice() = default;
|
||||
|
||||
|
|
|
@ -31,14 +31,19 @@ class HostPathDevice : public Device {
|
|||
|
||||
bool is_read_only() const override { return read_only_; }
|
||||
|
||||
const std::string& name() const override { return name_; }
|
||||
uint32_t attributes() const override { return 0; }
|
||||
uint32_t component_name_max_length() const override { return 40; }
|
||||
|
||||
uint32_t total_allocation_units() const override { return 128 * 1024; }
|
||||
uint32_t available_allocation_units() const override { return 128 * 1024; }
|
||||
uint32_t sectors_per_allocation_unit() const override { return 1; }
|
||||
uint32_t bytes_per_sector() const override { return 2 * 1024; }
|
||||
uint32_t bytes_per_sector() const override { return 0x200; }
|
||||
|
||||
private:
|
||||
void PopulateEntry(HostPathEntry* parent_entry);
|
||||
|
||||
std::string name_;
|
||||
std::filesystem::path host_path_;
|
||||
std::unique_ptr<Entry> root_entry_;
|
||||
bool read_only_;
|
||||
|
|
|
@ -55,7 +55,15 @@ uint64_t decode_fat_timestamp(uint32_t date, uint32_t time) {
|
|||
|
||||
StfsContainerDevice::StfsContainerDevice(const std::string_view mount_path,
|
||||
const std::filesystem::path& host_path)
|
||||
: Device(mount_path), host_path_(host_path) {}
|
||||
: Device(mount_path),
|
||||
name_("STFS"),
|
||||
host_path_(host_path),
|
||||
mmap_total_size_(),
|
||||
base_offset_(),
|
||||
magic_offset_(),
|
||||
package_type_(),
|
||||
header_(),
|
||||
table_size_shift_() {}
|
||||
|
||||
StfsContainerDevice::~StfsContainerDevice() = default;
|
||||
|
||||
|
@ -370,7 +378,7 @@ StfsContainerDevice::Error StfsContainerDevice::ReadEntrySVOD(
|
|||
// Entry is a file
|
||||
entry->attributes_ = kFileAttributeNormal | kFileAttributeReadOnly;
|
||||
entry->size_ = length;
|
||||
entry->allocation_size_ = xe::round_up(length, bytes_per_sector());
|
||||
entry->allocation_size_ = xe::round_up(length, kSectorSize);
|
||||
entry->data_offset_ = data_address;
|
||||
entry->data_size_ = length;
|
||||
entry->block_ = data_block;
|
||||
|
@ -536,7 +544,7 @@ StfsContainerDevice::Error StfsContainerDevice::ReadSTFS() {
|
|||
entry->data_size_ = file_size;
|
||||
}
|
||||
entry->size_ = file_size;
|
||||
entry->allocation_size_ = xe::round_up(file_size, bytes_per_sector());
|
||||
entry->allocation_size_ = xe::round_up(file_size, kSectorSize);
|
||||
|
||||
entry->create_timestamp_ = decode_fat_timestamp(update_date, update_time);
|
||||
entry->access_timestamp_ = decode_fat_timestamp(access_date, access_time);
|
||||
|
@ -618,7 +626,7 @@ StfsContainerDevice::BlockHash StfsContainerDevice::GetBlockHash(
|
|||
// table and then subtract one sector to land on the table itself.
|
||||
size_t hash_offset = BlockToOffsetSTFS(
|
||||
xe::round_up(block_index + 1, kSTFSHashSpacing) - kSTFSHashSpacing);
|
||||
hash_offset -= bytes_per_sector();
|
||||
hash_offset -= kSectorSize;
|
||||
const uint8_t* hash_data = map_ptr + hash_offset;
|
||||
|
||||
// table_index += table_offset - (1 << table_size_shift_);
|
||||
|
|
|
@ -173,15 +173,21 @@ class StfsContainerDevice : public Device {
|
|||
void Dump(StringBuffer* string_buffer) override;
|
||||
Entry* ResolvePath(const std::string_view path) override;
|
||||
|
||||
const std::string& name() const override { return name_; }
|
||||
uint32_t attributes() const override { return 0; }
|
||||
uint32_t component_name_max_length() const override { return 40; }
|
||||
|
||||
uint32_t total_allocation_units() const override {
|
||||
return uint32_t(mmap_total_size_ / sectors_per_allocation_unit() /
|
||||
bytes_per_sector());
|
||||
}
|
||||
uint32_t available_allocation_units() const override { return 0; }
|
||||
uint32_t sectors_per_allocation_unit() const override { return 1; }
|
||||
uint32_t bytes_per_sector() const override { return 4 * 1024; }
|
||||
uint32_t sectors_per_allocation_unit() const override { return 8; }
|
||||
uint32_t bytes_per_sector() const override { return 0x200; }
|
||||
|
||||
private:
|
||||
const uint32_t kSectorSize = 0x1000;
|
||||
|
||||
enum class Error {
|
||||
kSuccess = 0,
|
||||
kErrorOutOfMemory = -1,
|
||||
|
@ -215,6 +221,7 @@ class StfsContainerDevice : public Device {
|
|||
BlockHash GetBlockHash(const uint8_t* map_ptr, uint32_t block_index,
|
||||
uint32_t table_offset);
|
||||
|
||||
std::string name_;
|
||||
std::filesystem::path host_path_;
|
||||
std::map<size_t, std::unique_ptr<MappedMemory>> mmap_;
|
||||
size_t mmap_total_size_;
|
||||
|
|
|
@ -22,7 +22,8 @@ StfsContainerEntry::StfsContainerEntry(Device* device, Entry* parent,
|
|||
: Entry(device, parent, path),
|
||||
mmap_(mmap),
|
||||
data_offset_(0),
|
||||
data_size_(0) {}
|
||||
data_size_(0),
|
||||
block_(0) {}
|
||||
|
||||
StfsContainerEntry::~StfsContainerEntry() = default;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
@ -163,47 +163,6 @@ enum X_FILE_ATTRIBUTES : uint32_t {
|
|||
X_FILE_ATTRIBUTE_ENCRYPTED = 0x4000,
|
||||
};
|
||||
|
||||
// https://github.com/oukiar/vdash/blob/master/vdash/include/kernel.h
|
||||
enum X_FILE_INFORMATION_CLASS {
|
||||
XFileDirectoryInformation = 1,
|
||||
XFileFullDirectoryInformation,
|
||||
XFileBothDirectoryInformation,
|
||||
XFileBasicInformation,
|
||||
XFileStandardInformation,
|
||||
XFileInternalInformation,
|
||||
XFileEaInformation,
|
||||
XFileAccessInformation,
|
||||
XFileNameInformation,
|
||||
XFileRenameInformation,
|
||||
XFileLinkInformation,
|
||||
XFileNamesInformation,
|
||||
XFileDispositionInformation,
|
||||
XFilePositionInformation,
|
||||
XFileFullEaInformation,
|
||||
XFileModeInformation,
|
||||
XFileAlignmentInformation,
|
||||
XFileAllInformation,
|
||||
XFileAllocationInformation,
|
||||
XFileEndOfFileInformation,
|
||||
XFileAlternateNameInformation,
|
||||
XFileStreamInformation,
|
||||
XFileMountPartitionInformation,
|
||||
XFileMountPartitionsInformation,
|
||||
XFilePipeRemoteInformation,
|
||||
XFileSectorInformation,
|
||||
XFileXctdCompressionInformation,
|
||||
XFileCompressionInformation,
|
||||
XFileObjectIdInformation,
|
||||
XFileCompletionInformation,
|
||||
XFileMoveClusterInformation,
|
||||
XFileIoPriorityInformation,
|
||||
XFileReparsePointInformation,
|
||||
XFileNetworkOpenInformation,
|
||||
XFileAttributeTagInformation,
|
||||
XFileTrackingInformation,
|
||||
XFileMaximumInformation
|
||||
};
|
||||
|
||||
// Known as XOVERLAPPED to 360 code.
|
||||
struct XAM_OVERLAPPED {
|
||||
xe::be<uint32_t> result; // 0x0
|
||||
|
|
Loading…
Reference in New Issue