Adding locks and parents to vfs.

Progress on #305.
This commit is contained in:
Ben Vanik 2015-06-29 05:07:29 -07:00
parent 9a80b5e5be
commit 0104a2290f
16 changed files with 65 additions and 40 deletions

View File

@ -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();

View File

@ -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_;
}; };

View File

@ -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());

View File

@ -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;

View File

@ -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_; }

View File

@ -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);

View File

@ -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_;

View File

@ -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,9 +49,9 @@ 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) {
// TODO(benvanik): pick correct response. // TODO(benvanik): pick correct response.
return X_STATUS_NO_SUCH_FILE; return X_STATUS_NO_SUCH_FILE;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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_; }

View File

@ -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;

View File

@ -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_;

View File

@ -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);
} }
} }

View File

@ -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_;
}; };