[VFS] Allow specifying root entry to open from with OpenFile.
[Kernel] NtCreateFile now opens from root entry when available instead
of needlessly building a full path and resolving from that.
[VFS] Reduce code duplication by adding Entry::ResolvePath.
[VFS] Remove ResolveBasePath to avoid multiple calls to find_base_guest_path.
138 lines
3.6 KiB
C++
138 lines
3.6 KiB
C++
/**
|
|
******************************************************************************
|
|
* 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/vfs/entry.h"
|
|
|
|
#include "xenia/base/filesystem.h"
|
|
#include "xenia/base/string.h"
|
|
#include "xenia/vfs/device.h"
|
|
|
|
namespace xe {
|
|
namespace vfs {
|
|
|
|
Entry::Entry(Device* device, Entry* parent, const std::string_view path)
|
|
: device_(device),
|
|
parent_(parent),
|
|
path_(path),
|
|
attributes_(0),
|
|
size_(0),
|
|
allocation_size_(0),
|
|
create_timestamp_(0),
|
|
access_timestamp_(0),
|
|
write_timestamp_(0) {
|
|
assert_not_null(device);
|
|
absolute_path_ = xe::utf8::join_guest_paths(device->mount_path(), path);
|
|
name_ = xe::utf8::find_name_from_guest_path(path);
|
|
}
|
|
|
|
Entry::~Entry() = default;
|
|
|
|
void Entry::Dump(xe::StringBuffer* string_buffer, int indent) {
|
|
for (int i = 0; i < indent; ++i) {
|
|
string_buffer->Append(' ');
|
|
}
|
|
string_buffer->Append(name());
|
|
string_buffer->Append('\n');
|
|
for (auto& child : children_) {
|
|
child->Dump(string_buffer, indent + 2);
|
|
}
|
|
}
|
|
|
|
bool Entry::is_read_only() const { return device_->is_read_only(); }
|
|
|
|
Entry* Entry::GetChild(const std::string_view name) {
|
|
auto global_lock = global_critical_region_.Acquire();
|
|
auto it = std::find_if(children_.cbegin(), children_.cend(),
|
|
[&](const auto& child) {
|
|
return xe::utf8::equal_case(child->name(), name);
|
|
});
|
|
if (it == children_.cend()) {
|
|
return nullptr;
|
|
}
|
|
return (*it).get();
|
|
}
|
|
|
|
Entry* Entry::ResolvePath(const std::string_view path) {
|
|
// Walk the path, one separator at a time.
|
|
Entry* entry = this;
|
|
for (auto& part : xe::utf8::split_path(path)) {
|
|
entry = entry->GetChild(part);
|
|
if (!entry) {
|
|
// Not found.
|
|
return nullptr;
|
|
}
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
Entry* Entry::IterateChildren(const xe::filesystem::WildcardEngine& engine,
|
|
size_t* current_index) {
|
|
auto global_lock = global_critical_region_.Acquire();
|
|
while (*current_index < children_.size()) {
|
|
auto& child = children_[*current_index];
|
|
*current_index = *current_index + 1;
|
|
if (engine.Match(child->name())) {
|
|
return child.get();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Entry* Entry::CreateEntry(const std::string_view name, uint32_t attributes) {
|
|
auto global_lock = global_critical_region_.Acquire();
|
|
if (is_read_only()) {
|
|
return nullptr;
|
|
}
|
|
if (GetChild(name)) {
|
|
// Already exists.
|
|
return nullptr;
|
|
}
|
|
auto entry = CreateEntryInternal(name, attributes);
|
|
if (!entry) {
|
|
return nullptr;
|
|
}
|
|
children_.push_back(std::move(entry));
|
|
// TODO(benvanik): resort? would break iteration?
|
|
Touch();
|
|
return children_.back().get();
|
|
}
|
|
|
|
bool Entry::Delete(Entry* entry) {
|
|
auto global_lock = global_critical_region_.Acquire();
|
|
if (is_read_only()) {
|
|
return false;
|
|
}
|
|
if (entry->parent() != this) {
|
|
return false;
|
|
}
|
|
if (!DeleteEntryInternal(entry)) {
|
|
return false;
|
|
}
|
|
for (auto it = children_.begin(); it != children_.end(); ++it) {
|
|
if (it->get() == entry) {
|
|
children_.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
Touch();
|
|
return true;
|
|
}
|
|
|
|
bool Entry::Delete() {
|
|
assert_not_null(parent_);
|
|
return parent_->Delete(this);
|
|
}
|
|
|
|
void Entry::Touch() {
|
|
// TODO(benvanik): update timestamps.
|
|
}
|
|
|
|
} // namespace vfs
|
|
} // namespace xe
|