parent
9a80b5e5be
commit
0104a2290f
|
@ -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<xe::mutex> 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();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#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<Entry> root_entry_;
|
||||
};
|
||||
|
|
|
@ -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<Entry>(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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_; }
|
||||
|
|
|
@ -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<Entry>(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<Entry>(child));
|
||||
parent_entry->children_.push_back(std::unique_ptr<Entry>(child));
|
||||
|
||||
if (child_info.type == xe::filesystem::FileInfo::Type::kDirectory) {
|
||||
PopulateEntry(child);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Entry>(root_entry);
|
||||
|
@ -157,8 +157,16 @@ STFSContainerDevice::Error STFSContainerDevice::ReadAllEntries(
|
|||
uint32_t access_timestamp = xe::load_and_swap<uint32_t>(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>(entry));
|
||||
} else {
|
||||
// Lookup and add.
|
||||
auto parent = all_entries[path_indicator];
|
||||
parent->children_.emplace_back(std::unique_ptr<Entry>(entry));
|
||||
}
|
||||
parent_entry->children_.emplace_back(std::unique_ptr<Entry>(entry));
|
||||
}
|
||||
|
||||
auto block_hash = GetBlockHash(map_ptr, table_block_index, 0);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_; }
|
||||
|
|
|
@ -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<xe::mutex> 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<xe::mutex> lock(device_->mutex());
|
||||
while (*current_index < children_.size()) {
|
||||
auto& child = children_[*current_index];
|
||||
*current_index = *current_index + 1;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -26,17 +26,20 @@ VirtualFileSystem::~VirtualFileSystem() {
|
|||
}
|
||||
|
||||
bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
|
||||
std::lock_guard<xe::mutex> lock(mutex_);
|
||||
devices_.emplace_back(std::move(device));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VirtualFileSystem::RegisterSymbolicLink(std::string path,
|
||||
std::string target) {
|
||||
std::lock_guard<xe::mutex> lock(mutex_);
|
||||
symlinks_.insert({path, target});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VirtualFileSystem::UnregisterSymbolicLink(std::string path) {
|
||||
std::lock_guard<xe::mutex> 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<xe::mutex> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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<std::unique_ptr<Device>> devices_;
|
||||
std::unordered_map<std::string, std::string> symlinks_;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue