parent
9a80b5e5be
commit
0104a2290f
|
@ -19,15 +19,16 @@ Device::Device(const std::string& mount_path) : mount_path_(mount_path) {}
|
||||||
Device::~Device() = default;
|
Device::~Device() = default;
|
||||||
|
|
||||||
void Device::Dump(StringBuffer* string_buffer) {
|
void Device::Dump(StringBuffer* string_buffer) {
|
||||||
|
std::lock_guard<xe::mutex> lock(mutex_);
|
||||||
root_entry_->Dump(string_buffer, 0);
|
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
|
// The filesystem will have stripped our prefix off already, so the path will
|
||||||
// be in the form:
|
// be in the form:
|
||||||
// some\PATH.foo
|
// some\PATH.foo
|
||||||
|
|
||||||
XELOGFS("Device::ResolvePath(%s)", path);
|
XELOGFS("Device::ResolvePath(%s)", path.c_str());
|
||||||
|
|
||||||
// Walk the path, one separator at a time.
|
// Walk the path, one separator at a time.
|
||||||
auto entry = root_entry_.get();
|
auto entry = root_entry_.get();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "xenia/base/mutex.h"
|
||||||
#include "xenia/base/string_buffer.h"
|
#include "xenia/base/string_buffer.h"
|
||||||
#include "xenia/vfs/entry.h"
|
#include "xenia/vfs/entry.h"
|
||||||
|
|
||||||
|
@ -27,11 +28,12 @@ class Device {
|
||||||
virtual bool Initialize() = 0;
|
virtual bool Initialize() = 0;
|
||||||
void Dump(StringBuffer* string_buffer);
|
void Dump(StringBuffer* string_buffer);
|
||||||
|
|
||||||
|
xe::mutex& mutex() { return mutex_; }
|
||||||
const std::string& mount_path() const { return mount_path_; }
|
const std::string& mount_path() const { return mount_path_; }
|
||||||
|
|
||||||
virtual bool is_read_only() const { return true; }
|
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 total_allocation_units() const = 0;
|
||||||
virtual uint32_t available_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;
|
virtual uint32_t bytes_per_sector() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
xe::mutex mutex_;
|
||||||
std::string mount_path_;
|
std::string mount_path_;
|
||||||
std::unique_ptr<Entry> root_entry_;
|
std::unique_ptr<Entry> root_entry_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -89,7 +89,7 @@ bool DiscImageDevice::VerifyMagic(ParseState& state, size_t offset) {
|
||||||
|
|
||||||
DiscImageDevice::Error DiscImageDevice::ReadAllEntries(
|
DiscImageDevice::Error DiscImageDevice::ReadAllEntries(
|
||||||
ParseState& state, const uint8_t* root_buffer) {
|
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->attributes_ = kFileAttributeDirectory;
|
||||||
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ bool DiscImageDevice::ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto entry =
|
auto entry = new DiscImageEntry(this, parent, std::string(name, name_length),
|
||||||
new DiscImageEntry(this, std::string(name, name_length), mmap_.get());
|
mmap_.get());
|
||||||
entry->attributes_ = attributes | kFileAttributeReadOnly;
|
entry->attributes_ = attributes | kFileAttributeReadOnly;
|
||||||
entry->size_ = length;
|
entry->size_ = length;
|
||||||
entry->allocation_size_ = xe::round_up(length, bytes_per_sector());
|
entry->allocation_size_ = xe::round_up(length, bytes_per_sector());
|
||||||
|
|
|
@ -17,9 +17,12 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace vfs {
|
namespace vfs {
|
||||||
|
|
||||||
DiscImageEntry::DiscImageEntry(Device* device, std::string path,
|
DiscImageEntry::DiscImageEntry(Device* device, Entry* parent, std::string path,
|
||||||
MappedMemory* mmap)
|
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;
|
DiscImageEntry::~DiscImageEntry() = default;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ class DiscImageDevice;
|
||||||
|
|
||||||
class DiscImageEntry : public Entry {
|
class DiscImageEntry : public Entry {
|
||||||
public:
|
public:
|
||||||
DiscImageEntry(Device* device, std::string path, MappedMemory* mmap);
|
DiscImageEntry(Device* device, Entry* parent, std::string path,
|
||||||
|
MappedMemory* mmap);
|
||||||
~DiscImageEntry() override;
|
~DiscImageEntry() override;
|
||||||
|
|
||||||
MappedMemory* mmap() const { return mmap_; }
|
MappedMemory* mmap() const { return mmap_; }
|
||||||
|
|
|
@ -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->attributes_ = kFileAttributeDirectory;
|
||||||
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
||||||
PopulateEntry(root_entry);
|
PopulateEntry(root_entry);
|
||||||
|
@ -43,12 +43,12 @@ bool HostPathDevice::Initialize() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostPathDevice::PopulateEntry(HostPathEntry* entry) {
|
void HostPathDevice::PopulateEntry(HostPathEntry* parent_entry) {
|
||||||
auto child_infos = xe::filesystem::ListFiles(entry->local_path());
|
auto child_infos = xe::filesystem::ListFiles(parent_entry->local_path());
|
||||||
for (auto& child_info : child_infos) {
|
for (auto& child_info : child_infos) {
|
||||||
auto child =
|
auto child = new HostPathEntry(
|
||||||
new HostPathEntry(this, xe::to_string(child_info.name),
|
this, parent_entry, xe::to_string(child_info.name),
|
||||||
xe::join_paths(entry->local_path(), child_info.name));
|
xe::join_paths(parent_entry->local_path(), child_info.name));
|
||||||
child->create_timestamp_ = child_info.create_timestamp;
|
child->create_timestamp_ = child_info.create_timestamp;
|
||||||
child->access_timestamp_ = child_info.access_timestamp;
|
child->access_timestamp_ = child_info.access_timestamp;
|
||||||
child->write_timestamp_ = child_info.write_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());
|
xe::round_up(child_info.total_size, bytes_per_sector());
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->children_.push_back(std::unique_ptr<Entry>(child));
|
parent_entry->children_.push_back(std::unique_ptr<Entry>(child));
|
||||||
|
|
||||||
if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) {
|
if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) {
|
||||||
PopulateEntry(child);
|
PopulateEntry(child);
|
||||||
|
|
|
@ -35,7 +35,7 @@ class HostPathDevice : public Device {
|
||||||
uint32_t bytes_per_sector() const override { return 2 * 1024; }
|
uint32_t bytes_per_sector() const override { return 2 * 1024; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PopulateEntry(HostPathEntry* entry);
|
void PopulateEntry(HostPathEntry* parent_entry);
|
||||||
|
|
||||||
std::wstring local_path_;
|
std::wstring local_path_;
|
||||||
bool read_only_;
|
bool read_only_;
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace vfs {
|
namespace vfs {
|
||||||
|
|
||||||
HostPathEntry::HostPathEntry(Device* device, std::string path,
|
HostPathEntry::HostPathEntry(Device* device, Entry* parent, std::string path,
|
||||||
const std::wstring& local_path)
|
const std::wstring& local_path)
|
||||||
: Entry(device, path), local_path_(local_path) {}
|
: Entry(device, parent, path), local_path_(local_path) {}
|
||||||
|
|
||||||
HostPathEntry::~HostPathEntry() = default;
|
HostPathEntry::~HostPathEntry() = default;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ X_STATUS HostPathEntry::Open(KernelState* kernel_state, Mode mode, bool async,
|
||||||
}
|
}
|
||||||
DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0;
|
DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0;
|
||||||
HANDLE file =
|
HANDLE file =
|
||||||
CreateFile(local_path_.c_str(), desired_access, share_mode, NULL,
|
CreateFileW(local_path_.c_str(), desired_access, share_mode, NULL,
|
||||||
creation_disposition,
|
creation_disposition,
|
||||||
flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
if (file == INVALID_HANDLE_VALUE) {
|
if (file == INVALID_HANDLE_VALUE) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ class HostPathDevice;
|
||||||
|
|
||||||
class HostPathEntry : public Entry {
|
class HostPathEntry : public Entry {
|
||||||
public:
|
public:
|
||||||
HostPathEntry(Device* device, std::string path,
|
HostPathEntry(Device* device, Entry* parent, std::string path,
|
||||||
const std::wstring& local_path);
|
const std::wstring& local_path);
|
||||||
~HostPathEntry() override;
|
~HostPathEntry() override;
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ STFSContainerDevice::Error STFSContainerDevice::ReadHeaderAndVerify(
|
||||||
|
|
||||||
STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries(
|
STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries(
|
||||||
const uint8_t* map_ptr) {
|
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->attributes_ = kFileAttributeDirectory;
|
||||||
|
|
||||||
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
root_entry_ = std::unique_ptr<Entry>(root_entry);
|
||||||
|
@ -157,8 +157,16 @@ STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries(
|
||||||
uint32_t access_timestamp = xe::load_and_swap<uint32_t>(p + 0x3C);
|
uint32_t access_timestamp = xe::load_and_swap<uint32_t>(p + 0x3C);
|
||||||
p += 0x40;
|
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(
|
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());
|
mmap_.get());
|
||||||
// bit 0x40 = consecutive blocks (not fragmented?)
|
// bit 0x40 = consecutive blocks (not fragmented?)
|
||||||
if (filename_length_flags & 0x80) {
|
if (filename_length_flags & 0x80) {
|
||||||
|
@ -198,14 +206,7 @@ STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_indicator == 0xFFFF) {
|
parent_entry->children_.emplace_back(std::unique_ptr<Entry>(entry));
|
||||||
// Root entry.
|
|
||||||
root_entry->children_.emplace_back(std::unique_ptr<Entry>(entry));
|
|
||||||
} else {
|
|
||||||
// Lookup and add.
|
|
||||||
auto parent = all_entries[path_indicator];
|
|
||||||
parent->children_.emplace_back(std::unique_ptr<Entry>(entry));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block_hash = GetBlockHash(map_ptr, table_block_index, 0);
|
auto block_hash = GetBlockHash(map_ptr, table_block_index, 0);
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace vfs {
|
namespace vfs {
|
||||||
|
|
||||||
STFSContainerEntry::STFSContainerEntry(Device* device, std::string path,
|
STFSContainerEntry::STFSContainerEntry(Device* device, Entry* parent,
|
||||||
MappedMemory* mmap)
|
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) {}
|
||||||
|
|
||||||
STFSContainerEntry::~STFSContainerEntry() = default;
|
STFSContainerEntry::~STFSContainerEntry() = default;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ class STFSContainerDevice;
|
||||||
|
|
||||||
class STFSContainerEntry : public Entry {
|
class STFSContainerEntry : public Entry {
|
||||||
public:
|
public:
|
||||||
STFSContainerEntry(Device* device, std::string path, MappedMemory* mmap);
|
STFSContainerEntry(Device* device, Entry* parent, std::string path,
|
||||||
|
MappedMemory* mmap);
|
||||||
~STFSContainerEntry() override;
|
~STFSContainerEntry() override;
|
||||||
|
|
||||||
MappedMemory* mmap() const { return mmap_; }
|
MappedMemory* mmap() const { return mmap_; }
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace vfs {
|
namespace vfs {
|
||||||
|
|
||||||
Entry::Entry(Device* device, const std::string& path)
|
Entry::Entry(Device* device, Entry* parent, const std::string& path)
|
||||||
: device_(device),
|
: device_(device),
|
||||||
|
parent_(parent),
|
||||||
path_(path),
|
path_(path),
|
||||||
attributes_(0),
|
attributes_(0),
|
||||||
size_(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(); }
|
bool Entry::is_read_only() const { return device_->is_read_only(); }
|
||||||
|
|
||||||
Entry* Entry::GetChild(std::string name) {
|
Entry* Entry::GetChild(std::string name) {
|
||||||
|
std::lock_guard<xe::mutex> lock(device_->mutex());
|
||||||
// TODO(benvanik): a faster search
|
// TODO(benvanik): a faster search
|
||||||
for (auto& child : children_) {
|
for (auto& child : children_) {
|
||||||
if (strcasecmp(child->name().c_str(), name.c_str()) == 0) {
|
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,
|
Entry* Entry::IterateChildren(const xe::filesystem::WildcardEngine& engine,
|
||||||
size_t* current_index) {
|
size_t* current_index) {
|
||||||
|
std::lock_guard<xe::mutex> lock(device_->mutex());
|
||||||
while (*current_index < children_.size()) {
|
while (*current_index < children_.size()) {
|
||||||
auto& child = children_[*current_index];
|
auto& child = children_[*current_index];
|
||||||
*current_index = *current_index + 1;
|
*current_index = *current_index + 1;
|
||||||
|
|
|
@ -62,6 +62,7 @@ class Entry {
|
||||||
void Dump(xe::StringBuffer* string_buffer, int indent);
|
void Dump(xe::StringBuffer* string_buffer, int indent);
|
||||||
|
|
||||||
Device* device() const { return device_; }
|
Device* device() const { return device_; }
|
||||||
|
Entry* parent() const { return parent_; }
|
||||||
const std::string& path() const { return path_; }
|
const std::string& path() const { return path_; }
|
||||||
const std::string& absolute_path() const { return absolute_path_; }
|
const std::string& absolute_path() const { return absolute_path_; }
|
||||||
const std::string& name() const { return name_; }
|
const std::string& name() const { return name_; }
|
||||||
|
@ -91,9 +92,10 @@ class Entry {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entry(Device* device, const std::string& path);
|
Entry(Device* device, Entry* parent, const std::string& path);
|
||||||
|
|
||||||
Device* device_;
|
Device* device_;
|
||||||
|
Entry* parent_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
std::string absolute_path_;
|
std::string absolute_path_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
|
@ -26,17 +26,20 @@ VirtualFileSystem::~VirtualFileSystem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
|
bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
|
||||||
|
std::lock_guard<xe::mutex> lock(mutex_);
|
||||||
devices_.emplace_back(std::move(device));
|
devices_.emplace_back(std::move(device));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::RegisterSymbolicLink(std::string path,
|
bool VirtualFileSystem::RegisterSymbolicLink(std::string path,
|
||||||
std::string target) {
|
std::string target) {
|
||||||
|
std::lock_guard<xe::mutex> lock(mutex_);
|
||||||
symlinks_.insert({path, target});
|
symlinks_.insert({path, target});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) {
|
bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) {
|
||||||
|
std::lock_guard<xe::mutex> lock(mutex_);
|
||||||
auto& it = symlinks_.find(path);
|
auto& it = symlinks_.find(path);
|
||||||
if (it == symlinks_.end()) {
|
if (it == symlinks_.end()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -46,6 +49,8 @@ bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* VirtualFileSystem::ResolvePath(std::string path) {
|
Entry* VirtualFileSystem::ResolvePath(std::string path) {
|
||||||
|
std::lock_guard<xe::mutex> lock(mutex_);
|
||||||
|
|
||||||
// Resolve relative paths
|
// Resolve relative paths
|
||||||
std::string normalized_path(xe::filesystem::CanonicalizePath(path));
|
std::string normalized_path(xe::filesystem::CanonicalizePath(path));
|
||||||
|
|
||||||
|
@ -79,7 +84,7 @@ Entry* VirtualFileSystem::ResolvePath(std::string path) {
|
||||||
// Scan all devices.
|
// Scan all devices.
|
||||||
for (auto& device : devices_) {
|
for (auto& device : devices_) {
|
||||||
if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
|
if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
|
||||||
return device->ResolvePath(relative_path.c_str());
|
return device->ResolvePath(relative_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/mutex.h"
|
||||||
#include "xenia/vfs/device.h"
|
#include "xenia/vfs/device.h"
|
||||||
#include "xenia/vfs/entry.h"
|
#include "xenia/vfs/entry.h"
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ class VirtualFileSystem {
|
||||||
Entry* ResolvePath(std::string path);
|
Entry* ResolvePath(std::string path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
xe::mutex mutex_;
|
||||||
std::vector<std::unique_ptr<Device>> devices_;
|
std::vector<std::unique_ptr<Device>> devices_;
|
||||||
std::unordered_map<std::string, std::string> symlinks_;
|
std::unordered_map<std::string, std::string> symlinks_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue