diff --git a/src/xenia/vfs/device.cc b/src/xenia/vfs/device.cc index 1457a345a..e2b216387 100644 --- a/src/xenia/vfs/device.cc +++ b/src/xenia/vfs/device.cc @@ -19,15 +19,16 @@ Device::Device(const std::string& mount_path) : mount_path_(mount_path) {} Device::~Device() = default; void Device::Dump(StringBuffer* string_buffer) { + std::lock_guard lock(mutex_); root_entry_->Dump(string_buffer, 0); } -Entry* Device::ResolvePath(const char* path) { +Entry* Device::ResolvePath(std::string path) { // The filesystem will have stripped our prefix off already, so the path will // be in the form: // some\PATH.foo - XELOGFS("Device::ResolvePath(%s)", path); + XELOGFS("Device::ResolvePath(%s)", path.c_str()); // Walk the path, one separator at a time. auto entry = root_entry_.get(); diff --git a/src/xenia/vfs/device.h b/src/xenia/vfs/device.h index 2d378af25..0ee8b1a4e 100644 --- a/src/xenia/vfs/device.h +++ b/src/xenia/vfs/device.h @@ -13,6 +13,7 @@ #include #include +#include "xenia/base/mutex.h" #include "xenia/base/string_buffer.h" #include "xenia/vfs/entry.h" @@ -27,11 +28,12 @@ class Device { virtual bool Initialize() = 0; void Dump(StringBuffer* string_buffer); + xe::mutex& mutex() { return mutex_; } const std::string& mount_path() const { return mount_path_; } virtual bool is_read_only() const { return true; } - Entry* ResolvePath(const char* path); + Entry* ResolvePath(std::string path); virtual uint32_t total_allocation_units() const = 0; virtual uint32_t available_allocation_units() const = 0; @@ -39,6 +41,7 @@ class Device { virtual uint32_t bytes_per_sector() const = 0; protected: + xe::mutex mutex_; std::string mount_path_; std::unique_ptr root_entry_; }; diff --git a/src/xenia/vfs/devices/disc_image_device.cc b/src/xenia/vfs/devices/disc_image_device.cc index 5d0768c43..9f6b7a5ad 100644 --- a/src/xenia/vfs/devices/disc_image_device.cc +++ b/src/xenia/vfs/devices/disc_image_device.cc @@ -89,7 +89,7 @@ bool DiscImageDevice::VerifyMagic(ParseState& state, size_t offset) { DiscImageDevice::Error DiscImageDevice::ReadAllEntries( ParseState& state, const uint8_t* root_buffer) { - auto root_entry = new DiscImageEntry(this, "", mmap_.get()); + auto root_entry = new DiscImageEntry(this, nullptr, "", mmap_.get()); root_entry->attributes_ = kFileAttributeDirectory; root_entry_ = std::unique_ptr(root_entry); @@ -117,8 +117,8 @@ bool DiscImageDevice::ReadEntry(ParseState& state, const uint8_t* buffer, return false; } - auto entry = - new DiscImageEntry(this, std::string(name, name_length), mmap_.get()); + auto entry = new DiscImageEntry(this, parent, std::string(name, name_length), + mmap_.get()); entry->attributes_ = attributes | kFileAttributeReadOnly; entry->size_ = length; entry->allocation_size_ = xe::round_up(length, bytes_per_sector()); diff --git a/src/xenia/vfs/devices/disc_image_entry.cc b/src/xenia/vfs/devices/disc_image_entry.cc index b05457b96..d916660d3 100644 --- a/src/xenia/vfs/devices/disc_image_entry.cc +++ b/src/xenia/vfs/devices/disc_image_entry.cc @@ -17,9 +17,12 @@ namespace xe { namespace vfs { -DiscImageEntry::DiscImageEntry(Device* device, std::string path, +DiscImageEntry::DiscImageEntry(Device* device, Entry* parent, std::string path, MappedMemory* mmap) - : Entry(device, path), mmap_(mmap), data_offset_(0), data_size_(0) {} + : Entry(device, parent, path), + mmap_(mmap), + data_offset_(0), + data_size_(0) {} DiscImageEntry::~DiscImageEntry() = default; diff --git a/src/xenia/vfs/devices/disc_image_entry.h b/src/xenia/vfs/devices/disc_image_entry.h index a47612696..4ef4c6827 100644 --- a/src/xenia/vfs/devices/disc_image_entry.h +++ b/src/xenia/vfs/devices/disc_image_entry.h @@ -23,7 +23,8 @@ class DiscImageDevice; class DiscImageEntry : public Entry { public: - DiscImageEntry(Device* device, std::string path, MappedMemory* mmap); + DiscImageEntry(Device* device, Entry* parent, std::string path, + MappedMemory* mmap); ~DiscImageEntry() override; MappedMemory* mmap() const { return mmap_; } diff --git a/src/xenia/vfs/devices/host_path_device.cc b/src/xenia/vfs/devices/host_path_device.cc index d042e0327..1df07d462 100644 --- a/src/xenia/vfs/devices/host_path_device.cc +++ b/src/xenia/vfs/devices/host_path_device.cc @@ -35,7 +35,7 @@ bool HostPathDevice::Initialize() { } } - auto root_entry = new HostPathEntry(this, "", local_path_); + auto root_entry = new HostPathEntry(this, nullptr, "", local_path_); root_entry->attributes_ = kFileAttributeDirectory; root_entry_ = std::unique_ptr(root_entry); PopulateEntry(root_entry); @@ -43,12 +43,12 @@ bool HostPathDevice::Initialize() { return true; } -void HostPathDevice::PopulateEntry(HostPathEntry* entry) { - auto child_infos = xe::filesystem::ListFiles(entry->local_path()); +void HostPathDevice::PopulateEntry(HostPathEntry* parent_entry) { + auto child_infos = xe::filesystem::ListFiles(parent_entry->local_path()); for (auto& child_info : child_infos) { - auto child = - new HostPathEntry(this, xe::to_string(child_info.name), - xe::join_paths(entry->local_path(), child_info.name)); + auto child = new HostPathEntry( + this, parent_entry, xe::to_string(child_info.name), + xe::join_paths(parent_entry->local_path(), child_info.name)); child->create_timestamp_ = child_info.create_timestamp; child->access_timestamp_ = child_info.access_timestamp; child->write_timestamp_ = child_info.write_timestamp; @@ -65,7 +65,7 @@ void HostPathDevice::PopulateEntry(HostPathEntry* entry) { xe::round_up(child_info.total_size, bytes_per_sector()); } - entry->children_.push_back(std::unique_ptr(child)); + parent_entry->children_.push_back(std::unique_ptr(child)); if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) { PopulateEntry(child); diff --git a/src/xenia/vfs/devices/host_path_device.h b/src/xenia/vfs/devices/host_path_device.h index 5922bb8a6..0b02c30d5 100644 --- a/src/xenia/vfs/devices/host_path_device.h +++ b/src/xenia/vfs/devices/host_path_device.h @@ -35,7 +35,7 @@ class HostPathDevice : public Device { uint32_t bytes_per_sector() const override { return 2 * 1024; } private: - void PopulateEntry(HostPathEntry* entry); + void PopulateEntry(HostPathEntry* parent_entry); std::wstring local_path_; bool read_only_; diff --git a/src/xenia/vfs/devices/host_path_entry.cc b/src/xenia/vfs/devices/host_path_entry.cc index 2d18df824..89ff7d5f4 100644 --- a/src/xenia/vfs/devices/host_path_entry.cc +++ b/src/xenia/vfs/devices/host_path_entry.cc @@ -17,9 +17,9 @@ namespace xe { namespace vfs { -HostPathEntry::HostPathEntry(Device* device, std::string path, +HostPathEntry::HostPathEntry(Device* device, Entry* parent, std::string path, const std::wstring& local_path) - : Entry(device, path), local_path_(local_path) {} + : Entry(device, parent, path), local_path_(local_path) {} HostPathEntry::~HostPathEntry() = default; @@ -49,9 +49,9 @@ X_STATUS HostPathEntry::Open(KernelState* kernel_state, Mode mode, bool async, } DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0; HANDLE file = - CreateFile(local_path_.c_str(), desired_access, share_mode, NULL, - creation_disposition, - flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL); + CreateFileW(local_path_.c_str(), desired_access, share_mode, NULL, + creation_disposition, + flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (file == INVALID_HANDLE_VALUE) { // TODO(benvanik): pick correct response. return X_STATUS_NO_SUCH_FILE; diff --git a/src/xenia/vfs/devices/host_path_entry.h b/src/xenia/vfs/devices/host_path_entry.h index 8cf507a2d..917c0b43d 100644 --- a/src/xenia/vfs/devices/host_path_entry.h +++ b/src/xenia/vfs/devices/host_path_entry.h @@ -21,7 +21,7 @@ class HostPathDevice; class HostPathEntry : public Entry { public: - HostPathEntry(Device* device, std::string path, + HostPathEntry(Device* device, Entry* parent, std::string path, const std::wstring& local_path); ~HostPathEntry() override; diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index 5bfdb1ac0..f82a7c183 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -129,7 +129,7 @@ STFSContainerDevice::Error STFSContainerDevice::ReadHeaderAndVerify( STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries( const uint8_t* map_ptr) { - auto root_entry = new STFSContainerEntry(this, "", mmap_.get()); + auto root_entry = new STFSContainerEntry(this, nullptr, "", mmap_.get()); root_entry->attributes_ = kFileAttributeDirectory; root_entry_ = std::unique_ptr(root_entry); @@ -157,8 +157,16 @@ STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries( uint32_t access_timestamp = xe::load_and_swap(p + 0x3C); p += 0x40; + STFSContainerEntry* parent_entry = nullptr; + if (path_indicator == 0xFFFF) { + parent_entry = root_entry; + } else { + parent_entry = all_entries[path_indicator]; + } + auto entry = new STFSContainerEntry( - this, std::string((char*)filename, filename_length_flags & 0x3F), + this, parent_entry, + std::string((char*)filename, filename_length_flags & 0x3F), mmap_.get()); // bit 0x40 = consecutive blocks (not fragmented?) if (filename_length_flags & 0x80) { @@ -198,14 +206,7 @@ STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries( } } - if (path_indicator == 0xFFFF) { - // Root entry. - root_entry->children_.emplace_back(std::unique_ptr(entry)); - } else { - // Lookup and add. - auto parent = all_entries[path_indicator]; - parent->children_.emplace_back(std::unique_ptr(entry)); - } + parent_entry->children_.emplace_back(std::unique_ptr(entry)); } auto block_hash = GetBlockHash(map_ptr, table_block_index, 0); diff --git a/src/xenia/vfs/devices/stfs_container_entry.cc b/src/xenia/vfs/devices/stfs_container_entry.cc index 61d35c43f..a887f2ea4 100644 --- a/src/xenia/vfs/devices/stfs_container_entry.cc +++ b/src/xenia/vfs/devices/stfs_container_entry.cc @@ -15,9 +15,12 @@ namespace xe { namespace vfs { -STFSContainerEntry::STFSContainerEntry(Device* device, std::string path, - MappedMemory* mmap) - : Entry(device, path), mmap_(mmap), data_offset_(0), data_size_(0) {} +STFSContainerEntry::STFSContainerEntry(Device* device, Entry* parent, + std::string path, MappedMemory* mmap) + : Entry(device, parent, path), + mmap_(mmap), + data_offset_(0), + data_size_(0) {} STFSContainerEntry::~STFSContainerEntry() = default; diff --git a/src/xenia/vfs/devices/stfs_container_entry.h b/src/xenia/vfs/devices/stfs_container_entry.h index 55321957b..efa7f30c5 100644 --- a/src/xenia/vfs/devices/stfs_container_entry.h +++ b/src/xenia/vfs/devices/stfs_container_entry.h @@ -23,7 +23,8 @@ class STFSContainerDevice; class STFSContainerEntry : public Entry { public: - STFSContainerEntry(Device* device, std::string path, MappedMemory* mmap); + STFSContainerEntry(Device* device, Entry* parent, std::string path, + MappedMemory* mmap); ~STFSContainerEntry() override; MappedMemory* mmap() const { return mmap_; } diff --git a/src/xenia/vfs/entry.cc b/src/xenia/vfs/entry.cc index 97dd79f6b..2648f3cb8 100644 --- a/src/xenia/vfs/entry.cc +++ b/src/xenia/vfs/entry.cc @@ -16,8 +16,9 @@ namespace xe { namespace vfs { -Entry::Entry(Device* device, const std::string& path) +Entry::Entry(Device* device, Entry* parent, const std::string& path) : device_(device), + parent_(parent), path_(path), attributes_(0), size_(0), @@ -46,6 +47,7 @@ void Entry::Dump(xe::StringBuffer* string_buffer, int indent) { bool Entry::is_read_only() const { return device_->is_read_only(); } Entry* Entry::GetChild(std::string name) { + std::lock_guard lock(device_->mutex()); // TODO(benvanik): a faster search for (auto& child : children_) { if (strcasecmp(child->name().c_str(), name.c_str()) == 0) { @@ -57,6 +59,7 @@ Entry* Entry::GetChild(std::string name) { Entry* Entry::IterateChildren(const xe::filesystem::WildcardEngine& engine, size_t* current_index) { + std::lock_guard lock(device_->mutex()); while (*current_index < children_.size()) { auto& child = children_[*current_index]; *current_index = *current_index + 1; diff --git a/src/xenia/vfs/entry.h b/src/xenia/vfs/entry.h index 6027e8479..fd8166c69 100644 --- a/src/xenia/vfs/entry.h +++ b/src/xenia/vfs/entry.h @@ -62,6 +62,7 @@ class Entry { void Dump(xe::StringBuffer* string_buffer, int indent); Device* device() const { return device_; } + Entry* parent() const { return parent_; } const std::string& path() const { return path_; } const std::string& absolute_path() const { return absolute_path_; } const std::string& name() const { return name_; } @@ -91,9 +92,10 @@ class Entry { } protected: - Entry(Device* device, const std::string& path); + Entry(Device* device, Entry* parent, const std::string& path); Device* device_; + Entry* parent_; std::string path_; std::string absolute_path_; std::string name_; diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index 600f5aaca..b0101fdf9 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -26,17 +26,20 @@ VirtualFileSystem::~VirtualFileSystem() { } bool VirtualFileSystem::RegisterDevice(std::unique_ptr device) { + std::lock_guard lock(mutex_); devices_.emplace_back(std::move(device)); return true; } bool VirtualFileSystem::RegisterSymbolicLink(std::string path, std::string target) { + std::lock_guard lock(mutex_); symlinks_.insert({path, target}); return true; } bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) { + std::lock_guard lock(mutex_); auto& it = symlinks_.find(path); if (it == symlinks_.end()) { return false; @@ -46,6 +49,8 @@ bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) { } Entry* VirtualFileSystem::ResolvePath(std::string path) { + std::lock_guard lock(mutex_); + // Resolve relative paths std::string normalized_path(xe::filesystem::CanonicalizePath(path)); @@ -79,7 +84,7 @@ Entry* VirtualFileSystem::ResolvePath(std::string path) { // Scan all devices. for (auto& device : devices_) { if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) { - return device->ResolvePath(relative_path.c_str()); + return device->ResolvePath(relative_path); } } diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index b44b374e1..760606013 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -15,6 +15,7 @@ #include #include +#include "xenia/base/mutex.h" #include "xenia/vfs/device.h" #include "xenia/vfs/entry.h" @@ -34,6 +35,7 @@ class VirtualFileSystem { Entry* ResolvePath(std::string path); private: + xe::mutex mutex_; std::vector> devices_; std::unordered_map symlinks_; };