Files
Xenia-Canary/src/xenia/vfs/entry.cc
Ben Vanik 3c96b6fa0a DANGER DANGER. Switching to global critical region.
This changes almost all locks held by guest threads to use a single global
critical region. This emulates the behavior on the PPC of disabling
interrupts (by calls like KeRaiseIrqlToDpcLevel or masking interrupts),
and prevents deadlocks from occuring when threads are suspended or
otherwise blocked.
This has performance implications and a pass is needed to ensure the
locking is as granular as possible. It could also break everything
because it's fundamentally unsound. We'll see.
2015-09-06 09:30:54 -07:00

124 lines
3.2 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 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& 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::join_paths(device->mount_path(), path);
name_ = xe::find_name_from_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(std::string name) {
auto global_lock = global_critical_region_.Acquire();
// TODO(benvanik): a faster search
for (auto& child : children_) {
if (strcasecmp(child->name().c_str(), name.c_str()) == 0) {
return child.get();
}
}
return nullptr;
}
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(std::string 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