Support for wildcard queries
Provides support for persistent wildcard file requests, as described in #96 Also moved CanonicalizePath into common code (poly::fs)
This commit is contained in:
parent
3d980dd294
commit
4f7761c5e2
|
@ -0,0 +1,194 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "poly/fs.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace poly {
|
||||||
|
namespace fs {
|
||||||
|
|
||||||
|
std::string CanonicalizePath(const std::string& original_path) {
|
||||||
|
char path_separator('\\');
|
||||||
|
std::string path(poly::fix_path_separators(original_path, path_separator));
|
||||||
|
|
||||||
|
std::vector<std::string::size_type> path_breaks;
|
||||||
|
|
||||||
|
std::string::size_type pos(path.find_first_of(path_separator));
|
||||||
|
std::string::size_type pos_n(std::string::npos);
|
||||||
|
|
||||||
|
while (pos != std::string::npos) {
|
||||||
|
if ((pos_n = path.find_first_of(path_separator, pos + 1)) == std::string::npos) {
|
||||||
|
pos_n = path.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto diff(pos_n - pos);
|
||||||
|
switch (diff)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pos_n = std::string::npos;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// Duplicate separators
|
||||||
|
path.erase(pos, 1);
|
||||||
|
pos_n -= 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Potential marker for current directory
|
||||||
|
if (path[pos + 1] == '.') {
|
||||||
|
path.erase(pos, 2);
|
||||||
|
pos_n -= 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path_breaks.push_back(pos);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Potential marker for parent directory
|
||||||
|
if (path[pos + 1] == '.' && path[pos + 2] == '.'){
|
||||||
|
if (path_breaks.empty()) {
|
||||||
|
// Ensure we don't override the device name
|
||||||
|
std::string::size_type loc(path.find_first_of(':'));
|
||||||
|
auto req(pos + 3);
|
||||||
|
if (loc == std::string::npos || loc > req) {
|
||||||
|
path.erase(0, req);
|
||||||
|
pos_n -= req;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path.erase(loc + 1, req - (loc + 1));
|
||||||
|
pos_n -= req - (loc + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto last(path_breaks.back());
|
||||||
|
auto last_diff((pos + 3) - last);
|
||||||
|
path.erase(last, last_diff);
|
||||||
|
pos_n = last;
|
||||||
|
// Also remove path reference
|
||||||
|
path_breaks.erase(path_breaks.end() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path_breaks.push_back(pos);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
path_breaks.push_back(pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = pos_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing seperator
|
||||||
|
if (!path.empty() && path.back() == path_separator) {
|
||||||
|
path.erase(path.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final sanity check for dead paths
|
||||||
|
if ((path.size() == 1 && (path[0] == '.' || path[0] == path_separator))
|
||||||
|
|| (path.size() == 2 && path[0] == '.' && path[1] == '.')) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
WildcardFlags WildcardFlags::FIRST(true, false);
|
||||||
|
WildcardFlags WildcardFlags::LAST(false, true);
|
||||||
|
|
||||||
|
WildcardFlags::WildcardFlags()
|
||||||
|
: FromStart(false)
|
||||||
|
, ToEnd(false)
|
||||||
|
, WithCase(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
WildcardFlags::WildcardFlags(bool start, bool end)
|
||||||
|
: FromStart(start)
|
||||||
|
, ToEnd(end)
|
||||||
|
, WithCase(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
WildcardRule::WildcardRule(std::string str_match, const WildcardFlags &flags)
|
||||||
|
: match(str_match)
|
||||||
|
, rules(flags)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool WildcardRule::Check(std::string& str) const
|
||||||
|
{
|
||||||
|
if( match.empty() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( str.size() < match.size() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type result(str.find(match));
|
||||||
|
|
||||||
|
if( result != std::string::npos ) {
|
||||||
|
if( rules.FromStart && result != 0 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rules.ToEnd && result != ( ( str.size() -1 ) - match.size() ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
str.erase(0, result + match.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WildcardEngine::PreparePattern(const std::string &pattern)
|
||||||
|
{
|
||||||
|
rules.clear();
|
||||||
|
|
||||||
|
WildcardFlags flags(WildcardFlags::FIRST);
|
||||||
|
size_t n = 0;
|
||||||
|
size_t last = 0;
|
||||||
|
while ((n = pattern.find_first_of('*', last)) != pattern.npos) {
|
||||||
|
if (last != n) {
|
||||||
|
std::string str_str(pattern.substr(last, n - last));
|
||||||
|
rules.push_back(WildcardRule(str_str, flags));
|
||||||
|
}
|
||||||
|
last = n + 1;
|
||||||
|
flags = WildcardFlags();
|
||||||
|
}
|
||||||
|
if (last != pattern.size()) {
|
||||||
|
std::string str_str(pattern.substr(last));
|
||||||
|
rules.push_back(WildcardRule(str_str, WildcardFlags::LAST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WildcardEngine::SetRule(const std::string &pattern)
|
||||||
|
{
|
||||||
|
PreparePattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WildcardEngine::Match(const std::string &str) const
|
||||||
|
{
|
||||||
|
std::string str_copy(str);
|
||||||
|
|
||||||
|
for (const auto& rule : rules) {
|
||||||
|
if (!(rule.Check(str_copy))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fs
|
||||||
|
} // namespace poly
|
|
@ -15,6 +15,9 @@
|
||||||
#include "poly/config.h"
|
#include "poly/config.h"
|
||||||
#include "poly/string.h"
|
#include "poly/string.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace poly {
|
namespace poly {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
|
@ -35,6 +38,44 @@ struct FileInfo {
|
||||||
};
|
};
|
||||||
std::vector<FileInfo> ListFiles(const std::wstring& path);
|
std::vector<FileInfo> ListFiles(const std::wstring& path);
|
||||||
|
|
||||||
|
std::string CanonicalizePath(const std::string& original_path);
|
||||||
|
|
||||||
|
class WildcardFlags
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool
|
||||||
|
FromStart: 1,
|
||||||
|
ToEnd : 1,
|
||||||
|
WithCase : 1; // Unused for now
|
||||||
|
|
||||||
|
WildcardFlags();
|
||||||
|
WildcardFlags(bool start, bool end);
|
||||||
|
|
||||||
|
static WildcardFlags FIRST;
|
||||||
|
static WildcardFlags LAST;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WildcardRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WildcardRule(std::string str_match, const WildcardFlags &flags);
|
||||||
|
bool Check(std::string& str) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string match;
|
||||||
|
WildcardFlags rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WildcardEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetRule(const std::string &pattern);
|
||||||
|
bool Match(const std::string &str) const;
|
||||||
|
private:
|
||||||
|
std::vector<WildcardRule> rules;
|
||||||
|
void PreparePattern(const std::string &pattern);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
} // namespace poly
|
} // namespace poly
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
'config.h',
|
'config.h',
|
||||||
'cxx_compat.h',
|
'cxx_compat.h',
|
||||||
'fs.h',
|
'fs.h',
|
||||||
|
'fs.cc',
|
||||||
'logging.cc',
|
'logging.cc',
|
||||||
'logging.h',
|
'logging.h',
|
||||||
'main.h',
|
'main.h',
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "xenia/kernel/fs/gdfx.h"
|
|
||||||
#include "xenia/kernel/fs/devices/disc_image_file.h"
|
#include "xenia/kernel/fs/devices/disc_image_file.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -31,7 +30,7 @@ DiscImageEntry::DiscImageEntry(Device* device, const char* path,
|
||||||
: Entry(device, path),
|
: Entry(device, path),
|
||||||
mmap_(mmap),
|
mmap_(mmap),
|
||||||
gdfx_entry_(gdfx_entry),
|
gdfx_entry_(gdfx_entry),
|
||||||
gdfx_entry_iterator_(gdfx_entry->children.end()) {}
|
it_(gdfx_entry->children.end()) {}
|
||||||
|
|
||||||
DiscImageEntry::~DiscImageEntry() {}
|
DiscImageEntry::~DiscImageEntry() {}
|
||||||
|
|
||||||
|
@ -51,39 +50,34 @@ X_STATUS DiscImageEntry::QueryDirectory(XDirectoryInfo* out_info, size_t length,
|
||||||
const char* file_name, bool restart) {
|
const char* file_name, bool restart) {
|
||||||
assert_not_null(out_info);
|
assert_not_null(out_info);
|
||||||
|
|
||||||
// TODO(benvanik): move to common code.
|
GDFXEntry* entry(nullptr);
|
||||||
assert_null(file_name);
|
|
||||||
GDFXEntry* entry = nullptr;
|
if (file_name != nullptr) {
|
||||||
if (file_name) {
|
// Only queries in the current directory are supported for now
|
||||||
// Specified filename, return just that info.
|
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||||
assert_true(std::strchr(file_name, '*') == nullptr);
|
|
||||||
entry = gdfx_entry_->GetChild(file_name);
|
find_engine_.SetRule(file_name);
|
||||||
|
|
||||||
|
// Always restart the search?
|
||||||
|
it_ = gdfx_entry_->children.begin();
|
||||||
|
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return X_STATUS_NO_SUCH_FILE;
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (restart == true &&
|
else {
|
||||||
gdfx_entry_iterator_ != gdfx_entry_->children.end()) {
|
if (restart) {
|
||||||
gdfx_entry_iterator_ = gdfx_entry_->children.end();
|
it_ = gdfx_entry_->children.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
entry = gdfx_entry_->GetChild(find_engine_, it_);
|
||||||
gdfx_entry_iterator_ = gdfx_entry_->children.begin();
|
if (!entry) {
|
||||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
++gdfx_entry_iterator_;
|
|
||||||
if (gdfx_entry_iterator_ == gdfx_entry_->children.end()) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end = (uint8_t*)out_info + length;
|
auto end = (uint8_t*)out_info + length;
|
||||||
entry = *gdfx_entry_iterator_;
|
|
||||||
auto entry_name = entry->name;
|
auto entry_name = entry->name;
|
||||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||||
gdfx_entry_iterator_ = gdfx_entry_->children.end();
|
|
||||||
return X_STATUS_NO_MORE_FILES;
|
return X_STATUS_NO_MORE_FILES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +90,7 @@ X_STATUS DiscImageEntry::QueryDirectory(XDirectoryInfo* out_info, size_t length,
|
||||||
out_info->change_time = 0;
|
out_info->change_time = 0;
|
||||||
out_info->end_of_file = entry->size;
|
out_info->end_of_file = entry->size;
|
||||||
out_info->allocation_size = 2048;
|
out_info->allocation_size = 2048;
|
||||||
out_info->attributes = (X_FILE_ATTRIBUTES)entry->attributes;
|
out_info->attributes = entry->attributes;
|
||||||
out_info->file_name_length = static_cast<uint32_t>(entry->name.size());
|
out_info->file_name_length = static_cast<uint32_t>(entry->name.size());
|
||||||
memcpy(out_info->file_name, entry->name.c_str(), entry->name.size());
|
memcpy(out_info->file_name, entry->name.c_str(), entry->name.size());
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,13 @@
|
||||||
#include "poly/mapped_memory.h"
|
#include "poly/mapped_memory.h"
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
#include "xenia/kernel/fs/entry.h"
|
#include "xenia/kernel/fs/entry.h"
|
||||||
|
#include "poly/fs.h"
|
||||||
|
#include "xenia/kernel/fs/gdfx.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
class GDFXEntry;
|
|
||||||
|
|
||||||
class DiscImageEntry : public Entry {
|
class DiscImageEntry : public Entry {
|
||||||
public:
|
public:
|
||||||
DiscImageEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
DiscImageEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
||||||
|
@ -45,7 +45,9 @@ class DiscImageEntry : public Entry {
|
||||||
private:
|
private:
|
||||||
poly::MappedMemory* mmap_;
|
poly::MappedMemory* mmap_;
|
||||||
GDFXEntry* gdfx_entry_;
|
GDFXEntry* gdfx_entry_;
|
||||||
std::vector<GDFXEntry*>::iterator gdfx_entry_iterator_;
|
|
||||||
|
poly::fs::WildcardEngine find_engine_;
|
||||||
|
GDFXEntry::child_it_t it_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
#include "xenia/kernel/fs/devices/stfs_container_entry.h"
|
||||||
|
|
||||||
#include "xenia/kernel/fs/stfs.h"
|
|
||||||
#include "xenia/kernel/fs/devices/stfs_container_file.h"
|
#include "xenia/kernel/fs/devices/stfs_container_file.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -22,7 +21,8 @@ STFSContainerEntry::STFSContainerEntry(Device* device, const char* path,
|
||||||
: Entry(device, path),
|
: Entry(device, path),
|
||||||
mmap_(mmap),
|
mmap_(mmap),
|
||||||
stfs_entry_(stfs_entry),
|
stfs_entry_(stfs_entry),
|
||||||
stfs_entry_iterator_(stfs_entry->children.end()) {}
|
it_(stfs_entry_->children.end())
|
||||||
|
{ }
|
||||||
|
|
||||||
STFSContainerEntry::~STFSContainerEntry() = default;
|
STFSContainerEntry::~STFSContainerEntry() = default;
|
||||||
|
|
||||||
|
@ -44,37 +44,33 @@ X_STATUS STFSContainerEntry::QueryDirectory(XDirectoryInfo* out_info,
|
||||||
bool restart) {
|
bool restart) {
|
||||||
assert_not_null(out_info);
|
assert_not_null(out_info);
|
||||||
|
|
||||||
// TODO(benvanik): move to common code.
|
STFSEntry* entry(nullptr);
|
||||||
STFSEntry* entry = nullptr;
|
|
||||||
if (file_name) {
|
if( file_name != nullptr ) {
|
||||||
// Specified filename, return just that info.
|
// Only queries in the current directory are supported for now
|
||||||
assert_true(std::strchr(file_name, '*') == nullptr);
|
assert_true(std::strchr(file_name, '\\') == nullptr);
|
||||||
entry = stfs_entry_->GetChild(file_name);
|
|
||||||
|
find_engine_.SetRule(file_name);
|
||||||
|
|
||||||
|
// Always restart the search?
|
||||||
|
it_ = stfs_entry_->children.begin();
|
||||||
|
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return X_STATUS_NO_SUCH_FILE;
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (restart && stfs_entry_iterator_ != stfs_entry_->children.end()) {
|
if (restart) {
|
||||||
stfs_entry_iterator_ = stfs_entry_->children.end();
|
it_ = stfs_entry_->children.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
entry = stfs_entry_->GetChild(find_engine_, it_);
|
||||||
stfs_entry_iterator_ = stfs_entry_->children.begin();
|
if (!entry) {
|
||||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
++stfs_entry_iterator_;
|
|
||||||
if (stfs_entry_iterator_ == stfs_entry_->children.end()) {
|
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end = (uint8_t*)out_info + length;
|
auto end = (uint8_t*)out_info + length;
|
||||||
entry = stfs_entry_iterator_->get();
|
|
||||||
auto entry_name = entry->name;
|
auto entry_name = entry->name;
|
||||||
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
if (((uint8_t*)&out_info->file_name[0]) + entry_name.size() > end) {
|
||||||
stfs_entry_iterator_ = stfs_entry_->children.end();
|
|
||||||
return X_STATUS_NO_MORE_FILES;
|
return X_STATUS_NO_MORE_FILES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,18 @@
|
||||||
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_ENTRY_H_
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "poly/mapped_memory.h"
|
#include "poly/mapped_memory.h"
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
#include "xenia/kernel/fs/entry.h"
|
#include "xenia/kernel/fs/entry.h"
|
||||||
|
#include "poly/fs.h"
|
||||||
|
#include "xenia/kernel/fs/stfs.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
class STFSEntry;
|
|
||||||
|
|
||||||
class STFSContainerEntry : public Entry {
|
class STFSContainerEntry : public Entry {
|
||||||
public:
|
public:
|
||||||
STFSContainerEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
STFSContainerEntry(Device* device, const char* path, poly::MappedMemory* mmap,
|
||||||
|
@ -41,7 +42,9 @@ class STFSContainerEntry : public Entry {
|
||||||
private:
|
private:
|
||||||
poly::MappedMemory* mmap_;
|
poly::MappedMemory* mmap_;
|
||||||
STFSEntry* stfs_entry_;
|
STFSEntry* stfs_entry_;
|
||||||
std::vector<std::unique_ptr<STFSEntry>>::iterator stfs_entry_iterator_;
|
|
||||||
|
poly::fs::WildcardEngine find_engine_;
|
||||||
|
STFSEntry::child_it_t it_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "xenia/kernel/fs/devices/disc_image_device.h"
|
#include "xenia/kernel/fs/devices/disc_image_device.h"
|
||||||
#include "xenia/kernel/fs/devices/host_path_device.h"
|
#include "xenia/kernel/fs/devices/host_path_device.h"
|
||||||
#include "xenia/kernel/fs/devices/stfs_container_device.h"
|
#include "xenia/kernel/fs/devices/stfs_container_device.h"
|
||||||
|
#include "poly/fs.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -147,92 +148,9 @@ int FileSystem::DeleteSymbolicLink(const std::string& path) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FileSystem::CanonicalizePath(const std::string& original_path) const {
|
|
||||||
char path_separator('\\');
|
|
||||||
std::string path(poly::fix_path_separators(original_path, path_separator));
|
|
||||||
|
|
||||||
std::vector<std::string::size_type> path_breaks;
|
|
||||||
|
|
||||||
std::string::size_type pos(path.find_first_of(path_separator));
|
|
||||||
std::string::size_type pos_n(std::string::npos);
|
|
||||||
|
|
||||||
while (pos != std::string::npos) {
|
|
||||||
if ((pos_n = path.find_first_of(path_separator, pos + 1)) == std::string::npos) {
|
|
||||||
pos_n = path.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto diff(pos_n - pos);
|
|
||||||
switch (diff)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
pos_n = std::string::npos;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// Duplicate separators
|
|
||||||
path.erase(pos, 1);
|
|
||||||
pos_n -= 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// Potential marker for current directory
|
|
||||||
if (path[pos + 1] == '.') {
|
|
||||||
path.erase(pos, 2);
|
|
||||||
pos_n -= 2;
|
|
||||||
} else {
|
|
||||||
path_breaks.push_back(pos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// Potential marker for parent directory
|
|
||||||
if (path[pos + 1] == '.' && path[pos + 2] == '.'){
|
|
||||||
if (path_breaks.empty()) {
|
|
||||||
// Ensure we don't override the device name
|
|
||||||
std::string::size_type loc(path.find_first_of(':'));
|
|
||||||
auto req(pos + 3);
|
|
||||||
if (loc == std::string::npos || loc > req) {
|
|
||||||
path.erase(0, req);
|
|
||||||
pos_n -= req;
|
|
||||||
} else {
|
|
||||||
path.erase(loc + 1, req - (loc + 1));
|
|
||||||
pos_n -= req - (loc + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto last(path_breaks.back());
|
|
||||||
auto last_diff((pos + 3) - last);
|
|
||||||
path.erase(last, last_diff);
|
|
||||||
pos_n = last;
|
|
||||||
// Also remove path reference
|
|
||||||
path_breaks.erase(path_breaks.end() - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
path_breaks.push_back(pos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
path_breaks.push_back(pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = pos_n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove trailing seperator
|
|
||||||
if (!path.empty() && path.back() == path_separator) {
|
|
||||||
path.erase(path.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final sanity check for dead paths
|
|
||||||
if ((path.size() == 1 && (path[0] == '.' || path[0] == path_separator))
|
|
||||||
|| (path.size() == 2 && path[0] == '.' && path[1] == '.')) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Entry> FileSystem::ResolvePath(const std::string& path) {
|
std::unique_ptr<Entry> FileSystem::ResolvePath(const std::string& path) {
|
||||||
// Resolve relative paths
|
// Resolve relative paths
|
||||||
std::string normalized_path(CanonicalizePath(path));
|
std::string normalized_path(poly::fs::CanonicalizePath(path));
|
||||||
|
|
||||||
// If no path (starts with a slash) do it module-relative.
|
// If no path (starts with a slash) do it module-relative.
|
||||||
// Which for now, we just make game:.
|
// Which for now, we just make game:.
|
||||||
|
|
|
@ -57,8 +57,6 @@ class FileSystem {
|
||||||
private:
|
private:
|
||||||
std::vector<Device*> devices_;
|
std::vector<Device*> devices_;
|
||||||
std::unordered_map<std::string, std::string> symlinks_;
|
std::unordered_map<std::string, std::string> symlinks_;
|
||||||
|
|
||||||
std::string CanonicalizePath(const std::string& original_path) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
|
@ -29,6 +29,20 @@ GDFXEntry::~GDFXEntry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GDFXEntry* GDFXEntry::GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it)
|
||||||
|
{
|
||||||
|
GDFXEntry* child_entry(nullptr);
|
||||||
|
while (ref_it != children.end()) {
|
||||||
|
if (engine.Match((*ref_it)->name)) {
|
||||||
|
child_entry = (*ref_it);
|
||||||
|
++ref_it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++ref_it;
|
||||||
|
}
|
||||||
|
return child_entry;
|
||||||
|
}
|
||||||
|
|
||||||
GDFXEntry* GDFXEntry::GetChild(const char* name) {
|
GDFXEntry* GDFXEntry::GetChild(const char* name) {
|
||||||
// TODO(benvanik): a faster search
|
// TODO(benvanik): a faster search
|
||||||
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
for (std::vector<GDFXEntry*>::iterator it = children.begin();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
#include "xenia/kernel/fs/entry.h"
|
#include "xenia/kernel/fs/entry.h"
|
||||||
|
#include "poly/fs.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -28,6 +29,10 @@ class GDFXEntry {
|
||||||
GDFXEntry();
|
GDFXEntry();
|
||||||
~GDFXEntry();
|
~GDFXEntry();
|
||||||
|
|
||||||
|
typedef std::vector<GDFXEntry*> child_t;
|
||||||
|
typedef child_t::iterator child_it_t;
|
||||||
|
|
||||||
|
GDFXEntry* GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||||
GDFXEntry* GetChild(const char* name);
|
GDFXEntry* GetChild(const char* name);
|
||||||
|
|
||||||
void Dump(int indent);
|
void Dump(int indent);
|
||||||
|
@ -36,8 +41,7 @@ class GDFXEntry {
|
||||||
X_FILE_ATTRIBUTES attributes;
|
X_FILE_ATTRIBUTES attributes;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
child_t children;
|
||||||
std::vector<GDFXEntry*> children;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GDFX {
|
class GDFX {
|
||||||
|
|
|
@ -100,6 +100,20 @@ STFSEntry::STFSEntry()
|
||||||
update_timestamp(0),
|
update_timestamp(0),
|
||||||
access_timestamp(0) {}
|
access_timestamp(0) {}
|
||||||
|
|
||||||
|
STFSEntry* STFSEntry::GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it)
|
||||||
|
{
|
||||||
|
STFSEntry* child_entry(nullptr);
|
||||||
|
while (ref_it != children.end()) {
|
||||||
|
if (engine.Match((*ref_it)->name)) {
|
||||||
|
child_entry = (*ref_it).get();
|
||||||
|
++ref_it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++ref_it;
|
||||||
|
}
|
||||||
|
return child_entry;
|
||||||
|
}
|
||||||
|
|
||||||
STFSEntry* STFSEntry::GetChild(const char* name) {
|
STFSEntry* STFSEntry::GetChild(const char* name) {
|
||||||
// TODO(benvanik): a faster search
|
// TODO(benvanik): a faster search
|
||||||
for (const auto& entry : children) {
|
for (const auto& entry : children) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "xenia/common.h"
|
#include "xenia/common.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
#include "xenia/kernel/fs/entry.h"
|
#include "xenia/kernel/fs/entry.h"
|
||||||
|
#include "poly/fs.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -131,6 +132,10 @@ class STFSEntry {
|
||||||
public:
|
public:
|
||||||
STFSEntry();
|
STFSEntry();
|
||||||
|
|
||||||
|
typedef std::vector<std::unique_ptr<STFSEntry>> child_t;
|
||||||
|
typedef child_t::iterator child_it_t;
|
||||||
|
|
||||||
|
STFSEntry* GetChild(const poly::fs::WildcardEngine& engine, child_it_t& ref_it);
|
||||||
STFSEntry* GetChild(const char* name);
|
STFSEntry* GetChild(const char* name);
|
||||||
|
|
||||||
void Dump(int indent);
|
void Dump(int indent);
|
||||||
|
@ -141,8 +146,7 @@ class STFSEntry {
|
||||||
size_t size;
|
size_t size;
|
||||||
uint32_t update_timestamp;
|
uint32_t update_timestamp;
|
||||||
uint32_t access_timestamp;
|
uint32_t access_timestamp;
|
||||||
|
child_t children;
|
||||||
std::vector<std::unique_ptr<STFSEntry>> children;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
Loading…
Reference in New Issue