Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F125893
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/file-system.cpp b/util/file-system.cpp
index d50d13b0..9bb9a8b2 100644
--- a/util/file-system.cpp
+++ b/util/file-system.cpp
@@ -1,757 +1,757 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
/* FIXME: replace with <winalleg.h> */
#ifdef _WIN32
#define BITMAP dummyBITMAP
#include <windows.h>
#undef BITMAP
#endif
#endif
#include <algorithm>
#include "funcs.h"
#include "file-system.h"
#include "thread.h"
#include "system.h"
#include "globals.h"
#include <dirent.h>
#include <sstream>
#include <exception>
#include <string>
#include <fstream>
#include <ostream>
#ifndef USE_ALLEGRO
/* some sfl symbols conflict with allegro */
#include "sfl/sfl.h"
#include "sfl/sfldir.h"
#endif
#ifdef _WIN32
#define _WIN32_IE 0x400
#include <shlobj.h>
#endif
using namespace std;
/* some filesystem access can only be done by one thread at a time. specifically, sfl
* has its own allocator that is meant to be used in a single-threaded manner.
* rather than try to add locks to sfl we just wrap all sfl calls with a lock.
*
* initialize() must be called to initialize this lock
*/
// Util::Thread::Lock lock;
namespace Path{
/* remove extra path separators (/) */
string sanitize(string path){
size_t double_slash = path.find("//");
while (double_slash != string::npos){
path.erase(double_slash, 1);
double_slash = path.find("//");
}
return path;
}
static int invert(int c){
if (c == '\\'){
return '/';
}
return c;
}
std::string invertSlashes(string str){
transform(str.begin(), str.end(), str.begin(), invert);
return str;
}
const string & Path::path() const {
return mypath;
}
bool Path::isEmpty() const {
return mypath.empty();
}
Path::~Path(){
}
Path::Path(){
}
Path::Path(const std::string & path):
mypath(sanitize(invertSlashes(path))){
}
Path::Path(const Path & path):
mypath(sanitize(invertSlashes(path.path()))){
}
RelativePath::RelativePath(){
}
RelativePath::RelativePath(const std::string & path):
Path(path){
if (! path.empty() && path[0] == '/'){
ostringstream out;
out << "Relative path '" << path << "' cannot start with a /. Only absolute paths can start with /";
throw Storage::IllegalPath(__FILE__, __LINE__, out.str());
}
}
/* a/b/c/d -> b/c/d */
std::string stripFirstDir(const std::string & str){
if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
std::string temp = str;
size_t rem = temp.find("/");
if (rem != std::string::npos){
return str.substr(rem+1,str.size());
}
rem = temp.find("\\");
if( rem != std::string::npos ){
return str.substr(rem+1,str.size());
}
}
return str;
}
static vector<string> splitPath(string path){
vector<string> all;
if (path.size() > 0 && path[0] == '/'){
all.push_back("/");
}
size_t found = path.find('/');
while (found != string::npos){
if (found > 0){
all.push_back(path.substr(0, found));
}
path.erase(0, found + 1);
found = path.find('/');
}
if (path.size() != 0){
all.push_back(path);
}
return all;
}
static string joinPath(const vector<string> & paths){
ostringstream out;
bool first = true;
for (vector<string>::const_iterator it = paths.begin(); it != paths.end(); it++){
if (!first){
out << '/';
}
out << *it;
first = false;
}
return out.str();
}
/* a/b/c/d -> a/b/c
* a/b/c/d/ -> a/b/c
*/
static string dirname(string path){
vector<string> paths = splitPath(path);
if (paths.size() > 1){
paths.pop_back();
return joinPath(paths);
} else if (paths.size() == 1){
if (paths[0] == "/"){
return "/";
}
return ".";
} else {
return ".";
}
/*
while (path.size() > 0 && path[path.size() - 1] == '/'){
path.erase(path.size() - 1);
}
if (path.find("/") != string::npos ||
path.find("\\") != string::npos){
size_t rem = path.find_last_of("/");
if (rem != string::npos){
return path.substr(0, rem + 1);
}
rem = path.find_last_of("\\");
if (rem != string::npos){
return path.substr(0, rem + 1);
}
}
return "";
*/
}
RelativePath::RelativePath(const RelativePath & path):
Path(path){
}
RelativePath RelativePath::removeFirstDirectory() const {
return RelativePath(stripFirstDir(path()));
}
bool RelativePath::isFile() const {
vector<string> paths = splitPath(path());
return paths.size() == 1;
}
RelativePath RelativePath::firstDirectory() const {
vector<string> paths = splitPath(path());
if (paths.size() > 1){
return RelativePath(paths[0]);
}
return RelativePath();
}
RelativePath RelativePath::getDirectory() const {
return RelativePath(dirname(path()));
}
RelativePath RelativePath::getFilename() const {
return RelativePath(stripDir(path()));
}
bool RelativePath::operator<(const RelativePath & path) const {
return this->path() < path.path();
}
bool RelativePath::operator==(const RelativePath & path) const {
return this->path() == path.path();
}
RelativePath RelativePath::join(const RelativePath & him) const {
return RelativePath(path() + "/" + him.path());
}
RelativePath & RelativePath::operator=(const RelativePath & copy){
setPath(copy.path());
return *this;
}
AbsolutePath::AbsolutePath(){
}
AbsolutePath::AbsolutePath(const std::string & path):
Path(path){
}
AbsolutePath::AbsolutePath(const AbsolutePath & path):
Path(path){
}
AbsolutePath & AbsolutePath::operator=(const AbsolutePath & copy){
setPath(copy.path());
return *this;
}
bool AbsolutePath::operator==(const AbsolutePath & path) const {
return this->path() == path.path();
}
bool AbsolutePath::operator<(const AbsolutePath & path) const {
return this->path() < path.path();
}
AbsolutePath AbsolutePath::getDirectory() const {
return AbsolutePath(dirname(path()));
}
AbsolutePath AbsolutePath::getFilename() const {
return AbsolutePath(stripDir(path()));
}
AbsolutePath AbsolutePath::join(const RelativePath & path) const {
return AbsolutePath(this->path() + "/" + path.path());
}
InsensitivePath::InsensitivePath(const Path & what):
Path(what){
}
bool InsensitivePath::operator==(const Path & path) const {
return Util::upperCaseAll(this->path()) == Util::upperCaseAll(path.path());
}
std::string removeExtension(const std::string & str){
if (str.find(".") != std::string::npos){
return str.substr(0, str.find_last_of("."));
}
return str;
}
/* a/b/c/d -> d */
std::string stripDir(const std::string & str){
- if (str.find("/") != std::string::npos || str.find( "\\") != std::string::npos){
+ if (str.find("/") != std::string::npos || str.find("\\") != std::string::npos){
std::string temp = str;
size_t rem = temp.find_last_of( "/" );
if (rem != std::string::npos){
return str.substr(rem+1,str.size());
}
rem = temp.find_last_of( "\\" );
if( rem != std::string::npos ){
return str.substr(rem+1,str.size());
}
}
return str;
}
/* a/b/c/d -> a/b/c/ */
std::string stripFilename(const std::string & str){
std::string temp = str;
if( str.find( "/") != std::string::npos || str.find( "\\") != std::string::npos ){
size_t rem = temp.find_last_of( "/" );
if( rem != std::string::npos ){
return str.substr(0,rem+1);
}
rem = temp.find_last_of( "\\" );
if( rem != std::string::npos ){
return str.substr(0,rem+1);
}
}
return "";
}
}
namespace Storage{
Exception::Exception(const std::string & where, int line, const std::string & file):
Exc::Base(where, line),
reason(file){
}
Exception::Exception(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exc::Base(where, line, nested),
reason(file){
}
Exception::Exception(const Exception & copy):
Exc::Base(copy),
reason(copy.reason){
}
Exception::~Exception() throw (){
}
const std::string Exception::getReason() const {
return reason;
}
NotFound::NotFound(const std::string & where, int line, const std::string & file):
Exception(where, line, file){
}
NotFound::NotFound(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file){
}
NotFound::NotFound(const NotFound & copy):
Exception(copy){
}
NotFound::~NotFound() throw (){
}
IllegalPath::IllegalPath(const std::string & where, int line, const std::string & file):
Exception(where, line, file){
}
IllegalPath::IllegalPath(const std::string & where, int line, const Exc::Base & nested, const std::string & file):
Exception(where, line, nested, file){
}
IllegalPath::IllegalPath(const IllegalPath & copy):
Exception(copy){
}
IllegalPath::~IllegalPath() throw(){
}
System::System(){
}
System::~System(){
}
Util::ReferenceCount<System> self;
System & instance(){
if (self != NULL){
return *self;
}
self = new Filesystem(Util::getDataPath2());
return *self;
}
System & setInstance(const Util::ReferenceCount<System> & what){
self = what;
return *self;
}
/* will read upto 'length' bytes unless a null byte is seen first */
string EndianReader::readStringX(int length){
ostringstream out;
uint8_t letter = readByte1();
while (letter != 0 && length > 0){
out << letter;
letter = readByte1();
length -= 1;
}
return out.str();
}
/* unconditionally reads 'length' bytes */
std::string EndianReader::readString2(int length){
ostringstream out;
vector<uint8_t> bytes = readBytes(length);
for (vector<uint8_t>::iterator it = bytes.begin(); it != bytes.end(); it++){
char byte = *it;
if (byte == 0){
break;
}
out << *it;
}
return out.str();
}
void EndianReader::seekEnd(streamoff where){
stream.seekg(where, ios::end);
}
void EndianReader::seek(streampos where){
stream.seekg(where);
}
int EndianReader::position(){
return stream.tellg();
}
void EndianReader::readBytes(uint8_t * out, int length){
stream.read((char*) out, length);
}
vector<uint8_t> EndianReader::readBytes(int length){
vector<uint8_t> bytes;
for (int i = 0; i < length; i++){
uint8_t byte = 0;
stream.read((char*) &byte, 1);
if (stream.eof()){
throw Eof();
} else {
}
bytes.push_back(byte);
}
return bytes;
}
}
Filesystem::Filesystem(const AbsolutePath & path):
dataPath(path){
}
#ifdef _WIN32
Filesystem::AbsolutePath Filesystem::userDirectory(){
ostringstream str;
char path[MAX_PATH];
SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
str << path << "/paintown/";
return Filesystem::AbsolutePath(str.str());
}
Filesystem::AbsolutePath Filesystem::configFile(){
ostringstream str;
char path[MAX_PATH];
SHGetSpecialFolderPathA(0, path, CSIDL_APPDATA, false);
str << path << "/paintown_configuration.txt";
return Filesystem::AbsolutePath(str.str());
}
#else
Filesystem::AbsolutePath Filesystem::configFile(){
ostringstream str;
/* what if HOME isn't set? */
str << getenv("HOME") << "/.paintownrc";
return Filesystem::AbsolutePath(str.str());
}
Filesystem::AbsolutePath Filesystem::userDirectory(){
ostringstream str;
char * home = getenv("HOME");
if (home == NULL){
str << "/tmp/paintown";
} else {
str << home << "/.paintown/";
}
return Filesystem::AbsolutePath(str.str());
}
#endif
Filesystem::AbsolutePath Filesystem::lookup(const RelativePath path){
vector<Filesystem::AbsolutePath> places;
#define push(x) try{ places.push_back(x); } catch (const Storage::IllegalPath & fail){ }
push(dataPath.join(path));
push(userDirectory().join(path));
push(Filesystem::AbsolutePath(path.path()));
#undef push
/* start error stuff early */
ostringstream out;
out << "Cannot find " << path.path() << ". I looked in ";
bool first = true;
for (vector<Filesystem::AbsolutePath>::iterator it = places.begin(); it != places.end(); it++){
Filesystem::AbsolutePath & final = *it;
if (::System::readable(final.path())){
return final;
}
if (!first){
out << ", ";
} else {
first = false;
}
out << "'" << final.path() << "'";
}
// out << "Cannot find " << path.path() << ". I looked in '" << dataPath.join(path).path() << "', '" << userDirectory().join(path).path() << "', and '" << path.path() << "'";
throw NotFound(__FILE__, __LINE__, out.str());
#if 0
/* first try the main data directory */
Filesystem::AbsolutePath final = dataPath.join(path);
if (::System::readable(final.path())){
return final;
}
/* then try the user directory, like ~/.paintown */
final = userDirectory().join(path);
if (::System::readable(final.path())){
return final;
}
/* then just look in the cwd */
if (::System::readable(path.path())){
return Filesystem::AbsolutePath(path.path());
}
ostringstream out;
out << "Cannot find " << path.path() << ". I looked in '" << dataPath.join(path).path() << "', '" << userDirectory().join(path).path() << "', and '" << path.path() << "'";
throw NotFound(__FILE__, __LINE__, out.str());
#endif
}
Filesystem::AbsolutePath Filesystem::lookupInsensitive(const Filesystem::AbsolutePath & directory, const Filesystem::RelativePath & path){
if (path.path() == ""){
throw NotFound(__FILE__, __LINE__, "Given empty path to lookup");
}
if (path.path() == "."){
return directory;
}
if (path.path() == ".."){
return directory.getDirectory();
}
if (path.isFile()){
vector<AbsolutePath> all = getFiles(directory, "*", true);
for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
AbsolutePath & check = *it;
if (InsensitivePath(check.getFilename()) == path){
return check;
}
}
ostringstream out;
out << "Cannot find " << path.path() << " in " << directory.path();
throw NotFound(__FILE__, __LINE__, out.str());
} else {
return lookupInsensitive(lookupInsensitive(directory, path.firstDirectory()), path.removeFirstDirectory());
}
}
vector<Filesystem::AbsolutePath> Filesystem::findDirectoriesIn(const Filesystem::AbsolutePath & path){
vector<Filesystem::AbsolutePath> dirs;
DIR * dir = opendir(path.path().c_str());
if (dir == NULL){
return dirs;
}
struct dirent * entry = readdir(dir);
while (entry != NULL){
if (string(entry->d_name) != "." && string(entry->d_name) != ".."){
string total = path.path() + "/" + entry->d_name;
if (::System::isDirectory(total)){
dirs.push_back(AbsolutePath(total));
}
}
entry = readdir(dir);
}
closedir(dir);
return dirs;
}
vector<Filesystem::AbsolutePath> Filesystem::findDirectories(const RelativePath & path){
typedef vector<AbsolutePath> Paths;
Paths dirs;
Paths main_dirs = findDirectoriesIn(dataPath.join(path));
Paths user_dirs = findDirectoriesIn(userDirectory().join(path));
Paths here_dirs = findDirectoriesIn(Filesystem::AbsolutePath(path.path()));
dirs.insert(dirs.end(), main_dirs.begin(), main_dirs.end());
dirs.insert(dirs.end(), user_dirs.begin(), user_dirs.end());
dirs.insert(dirs.end(), here_dirs.begin(), here_dirs.end());
return dirs;
}
/* a/b/c/ -> a/b/c */
static string removeTrailingSlash(string str){
while (str.size() > 0 && str[str.size() - 1] == '/'){
str = str.erase(str.size() - 1);
}
return str;
}
vector<Filesystem::AbsolutePath> Filesystem::getFiles(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
#ifdef USE_ALLEGRO
struct al_ffblk info;
vector<AbsolutePath> files;
if ( al_findfirst( (dataPath.path() + "/" + find).c_str(), &info, FA_ALL ) != 0 ){
return files;
}
files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
while ( al_findnext( &info ) == 0 ){
files.push_back(AbsolutePath(dataPath.path() + "/" + string(info.name)));
}
al_findclose( &info );
return files;
#else
Util::Thread::ScopedLock scoped(lock);
vector<AbsolutePath> files;
DIRST sflEntry;
// bool ok = open_dir(&sflEntry, removeTrailingSlash(dataPath.path()).c_str());
bool ok = open_dir(&sflEntry, dataPath.path().c_str());
if (!ok){
return files;
}
while (ok){
if (file_matches(sflEntry.file_name, find.c_str())){
files.push_back(AbsolutePath(dataPath.path() + "/" + string(sflEntry.file_name)));
}
ok = read_dir(&sflEntry);
}
close_dir(&sflEntry);
// Global::debug(0) << "Warning: Filesystem::getFiles() is not implemented yet for SDL" << endl;
return files;
#endif
}
template <class X>
static void append(vector<X> & destination, const vector<X> & source){
/*
for (typename vector<X>::const_iterator it = source.begin(); it != source.end(); it++){
destination.push_back(*it);
}
*/
copy(source.begin(), source.end(), back_insert_iterator<vector<X> >(destination));
}
vector<Filesystem::AbsolutePath> Filesystem::getAllDirectories(const AbsolutePath & path){
vector<AbsolutePath> all = findDirectoriesIn(path);
vector<AbsolutePath> final;
append(final, all);
for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
vector<AbsolutePath> more = getAllDirectories(*it);
append(final, more);
}
return final;
}
vector<Filesystem::AbsolutePath> Filesystem::getFilesRecursive(const AbsolutePath & dataPath, const string & find, bool caseInsensitive){
if (!exists(dataPath)){
return vector<AbsolutePath>();
}
vector<AbsolutePath> directories = getAllDirectories(dataPath);
directories.push_back(dataPath);
vector<AbsolutePath> files;
for (vector<AbsolutePath>::iterator it = directories.begin(); it != directories.end(); it++){
vector<AbsolutePath> found = getFiles(*it, find, caseInsensitive);
append(files, found);
}
return files;
}
/*
std::string find(const std::string path){
if (path.length() == 0){
throw NotFound("No path given");
}
if (path[0] == '/'){
string str(path);
str.erase(0, 1);
string out = lookup(str);
if (System::isDirectory(out)){
return sanitize(out + "/");
}
return sanitize(out);
}
string out = lookup(path);
if (System::isDirectory(out)){
return sanitize(out + "/");
}
return sanitize(out);
}
*/
Filesystem::AbsolutePath Filesystem::find(const RelativePath & path){
if (path.isEmpty()){
throw NotFound(__FILE__, __LINE__, "No path given");
}
AbsolutePath out = lookup(path);
if (::System::isDirectory(out.path())){
return AbsolutePath(out.path() + "/");
}
return AbsolutePath(out.path());
}
Filesystem::AbsolutePath Filesystem::findInsensitive(const RelativePath & path){
try{
/* try sensitive lookup first */
return lookup(path);
} catch (const NotFound & fail){
}
/* get the base directory */
AbsolutePath directory = lookup(path.getDirectory());
return lookupInsensitive(directory, path.getFilename());
}
bool Filesystem::exists(const RelativePath & path){
try{
AbsolutePath absolute = find(path);
return true;
} catch (const NotFound & found){
return false;
}
}
bool Filesystem::exists(const AbsolutePath & path){
return ::System::readable(path.path());
}
Filesystem::RelativePath Filesystem::cleanse(const AbsolutePath & path){
string str = path.path();
if (str.find(dataPath.path()) == 0){
str.erase(0, dataPath.path().length());
} else if (str.find(userDirectory().path()) == 0){
str.erase(0, userDirectory().path().length());
}
return RelativePath(str);
}
diff --git a/util/nacl/network-system.cpp b/util/nacl/network-system.cpp
index 94d34b84..f395d086 100644
--- a/util/nacl/network-system.cpp
+++ b/util/nacl/network-system.cpp
@@ -1,808 +1,894 @@
#ifdef NACL
/* documentation for ppapi
* http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/inherits.html
*/
/* issues with getting data
* 1. the function that starts the game is called from the main chrome thread
* which starts from a javascript call to module.PostMessage('run').
* ...
*
*/
#include <unistd.h>
#include <errno.h>
#include "network-system.h"
#include <sstream>
#include <fstream>
#include "../funcs.h"
#include "../debug.h"
+#include "../sfl/sfl.h"
#include <ppapi/c/pp_errors.h>
#include <ppapi/cpp/url_loader.h>
#include <ppapi/cpp/url_request_info.h>
#include <ppapi/cpp/url_response_info.h>
#include <ppapi/c/ppb_url_request_info.h>
#include <ppapi/cpp/completion_callback.h>
using std::string;
using std::map;
using std::vector;
using std::ostringstream;
using std::ifstream;
namespace Nacl{
static const char * CONTEXT = "nacl";
typedef Path::AbsolutePath AbsolutePath;
typedef Path::RelativePath RelativePath;
enum RequestType{
Exists
};
struct Request{
RequestType type;
AbsolutePath absolute;
RelativePath relative;
bool complete;
bool success;
};
Request operation;
struct NaclRequest{
virtual ~NaclRequest(){
}
virtual void start() = 0;
};
struct NaclRequestOpen: public NaclRequest {
NaclRequestOpen(pp::Instance * instance, const string & url, Manager * manager):
request(instance),
loader(instance),
url(url),
manager(manager){
request.SetURL(url);
request.SetMethod("GET");
// request.SetProperty(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS, pp::Var((bool) PP_TRUE));
}
void start(){
Global::debug(2) << "Request open for url " << url << std::endl;
pp::CompletionCallback callback(&NaclRequestOpen::onFinish, this);
int32_t ok = loader.Open(request, callback);
Global::debug(2) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
// Global::debug(0) << "Call on main thread" << std::endl;
// core->CallOnMainThread(0, callback, ok);
callback.Run(ok);
}
// Global::debug(1) << "Callback running" << std::endl;
}
static void onFinish(void * me, int32_t result){
NaclRequestOpen * self = (NaclRequestOpen*) me;
self->finish(result);
}
void finish(int32_t result);
pp::URLRequestInfo request;
pp::URLLoader loader;
string url;
Manager * manager;
};
struct NaclRequestExists: public NaclRequest {
NaclRequestExists(pp::Instance * instance, const string & url, Manager * manager):
request(instance),
loader(instance),
url(url),
manager(manager){
request.SetURL(url);
request.SetMethod("GET");
}
void start(){
pp::CompletionCallback callback(&NaclRequestExists::onFinish, this);
int32_t ok = loader.Open(request, callback);
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
}
static void onFinish(void * me, int32_t result){
NaclRequestExists * self = (NaclRequestExists*) me;
self->finish(result);
}
void finish(int32_t result);
pp::URLRequestInfo request;
pp::URLLoader loader;
string url;
Manager * manager;
};
class FileHandle{
public:
FileHandle():
buffer(NULL){
}
~FileHandle(){
delete[] buffer;
}
class Reader{
public:
static const int PAGE_SIZE = 1024 * 32;
struct Page{
Page():
buffer(NULL),
size(0),
next(NULL){
buffer = new char[PAGE_SIZE];
}
char * buffer;
int size;
Page * next;
~Page(){
delete[] buffer;
delete next;
}
};
Reader(pp::CompletionCallback finish, pp::URLLoader & loader, FileHandle * handle, pp::Core * core):
finish(finish),
loader(loader),
handle(handle),
core(core),
tries(0){
current = &page;
}
int getSize(){
Page * use = &page;
int total = 0;
while (use != NULL){
total += use->size;
use = use->next;
}
return total;
}
void copy(char * buffer){
Page * use = &page;
while (use != NULL){
memcpy(buffer, use->buffer, use->size);
buffer += use->size;
use = use->next;
}
}
void read(){
pp::CompletionCallback callback(&Reader::onRead, this);
if (current->size == PAGE_SIZE){
Page * next = new Page();
current->next = next;
current = next;
}
int32_t ok = loader.ReadResponseBody(current->buffer + current->size, PAGE_SIZE - current->size, callback);
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
}
static void onRead(void * self, int32_t result){
Reader * reader = (Reader*) self;
reader->didRead(result);
}
void didRead(int32_t result){
Global::debug(2) << "Read " << result << " bytes" << std::endl;
current->size += result;
if (result > 0){
tries = 0;
read();
} else {
if (tries >= 3){
handle->readDone(this);
} else {
tries += 1;
pp::CompletionCallback callback(&Reader::doRead, this);
core->CallOnMainThread((tries - 1) * 25, callback, 0);
}
}
}
static void doRead(void * self, int32_t result){
Reader * reader = (Reader*) self;
reader->read();
}
pp::CompletionCallback finish;
pp::URLLoader & loader;
Page page;
Page * current;
FileHandle * handle;
pp::Core * core;
int tries;
};
void readAll(pp::CompletionCallback finish, pp::Core * core, pp::URLLoader & loader){
reader = new Reader(finish, loader, this, core);
reader->read();
}
void readDone(Reader * reader){
length = reader->getSize();
Global::debug(2) << "Done reading, got " << length << " bytes" << std::endl;
position = 0;
buffer = new char[length];
reader->copy(buffer);
reader->finish.Run(0);
}
int read(void * buffer, size_t count){
size_t bytes = position + count < length ? count : (length - position);
memcpy(buffer, this->buffer + position, bytes);
position += bytes;
return bytes;
}
off_t seek(off_t offset, int whence){
switch (whence){
case SEEK_SET: {
position = offset;
break;
}
case SEEK_CUR: {
position += offset;
break;
}
case SEEK_END: {
position = length - offset;
break;
}
}
return position;
}
off_t position;
off_t length;
char * buffer;
Util::ReferenceCount<Reader> reader;
};
class Manager{
public:
Manager(pp::Instance * instance, pp::Core * core):
instance(instance),
core(core),
factory(this){
}
pp::Instance * instance;
pp::Core * core;
Util::ReferenceCount<NaclRequest> request;
pp::CompletionCallbackFactory<Manager> factory;
struct OpenFileData{
const char * path;
Util::ReferenceCount<FileHandle> file;
};
struct ExistsData{
const char * path;
bool exists;
};
OpenFileData openFileData;
ExistsData existsData;
Util::Thread::LockObject lock;
volatile bool done;
Util::ReferenceCount<FileHandle> openFile(const char * path){
Global::debug(1, CONTEXT) << "open " << path << std::endl;
Util::Thread::ScopedLock scoped(lock);
done = false;
openFileData.path = path;
pp::CompletionCallback callback(&Manager::doOpenFile, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return openFileData.file;
}
bool exists(const string & path){
Global::debug(1, CONTEXT) << "exists " << path << std::endl;
Util::Thread::ScopedLock scoped(lock);
done = false;
existsData.exists = false;
existsData.path = path.c_str();
pp::CompletionCallback callback(&Manager::doExists, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return existsData.exists;
}
static void doExists(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->continueExists();
}
void continueExists(){
request = new NaclRequestExists(instance, existsData.path, this);
request->start();
}
void success(NaclRequestExists & exists){
existsData.exists = true;
requestComplete();
}
void failure(NaclRequestExists & exists){
existsData.exists = false;
requestComplete();
}
/* called by the main thread */
static void doOpenFile(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->continueOpenFile();
}
void continueOpenFile(){
request = new NaclRequestOpen(instance, openFileData.path, this);
request->start();
}
void requestComplete(){
/* destroy request on the main thread */
request = NULL;
lock.lockAndSignal(done, true);
}
void success(NaclRequestOpen & open){
pp::URLResponseInfo info = open.loader.GetResponseInfo();
if (info.GetStatusCode() == 200){
/*
int64_t received = 0;
int64_t total = 0;
if (open.loader.GetDownloadProgress(&received, &total)){
Global::debug(0) << "Downloaded " << received << " total " << total << std::endl;
}
*/
Util::ReferenceCount<FileHandle> handle = new FileHandle();
pp::CompletionCallback callback(&Manager::completeRead, this);
openFileData.file = handle;
handle->readAll(callback, core, open.loader);
/*
openFileData.file = nextFileDescriptor();
fileTable[openFileData.file] = new FileHandle(request.convert<NaclRequestOpen>());
readEntireFile(fileTable[openFileData.file]);
*/
} else {
Global::debug(1) << "Could not open file" << std::endl;
requestComplete();
}
}
static void completeRead(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->requestComplete();
}
void failure(NaclRequestOpen & open){
requestComplete();
}
};
void NaclRequestOpen::finish(int32_t result){
if (result == 0){
manager->success(*this);
} else {
manager->failure(*this);
}
}
void NaclRequestExists::finish(int32_t result){
if (result == 0){
pp::URLResponseInfo info = loader.GetResponseInfo();
if (info.GetStatusCode() == 200){
manager->success(*this);
} else {
manager->failure(*this);
}
} else {
manager->failure(*this);
}
}
+static void testMatchFile();
+
NetworkSystem::NetworkSystem(pp::Instance * instance, pp::Core * core):
instance(instance),
core(core){
+ // testMatchFile();
}
NetworkSystem::~NetworkSystem(){
}
AbsolutePath NetworkSystem::find(const RelativePath & path){
AbsolutePath all = Util::getDataPath2().join(path);
if (exists(all)){
return all;
}
throw Storage::NotFound(__FILE__, __LINE__, path.path());
}
RelativePath NetworkSystem::cleanse(const AbsolutePath & path){
string str = path.path();
if (str.find(Util::getDataPath2().path()) == 0){
str.erase(0, Util::getDataPath2().path().length());
} else if (str.find(userDirectory().path()) == 0){
str.erase(0, userDirectory().path().length());
}
return RelativePath(str);
}
bool NetworkSystem::exists(const RelativePath & path){
try{
AbsolutePath absolute = find(path);
return true;
} catch (const Storage::NotFound & found){
return false;
}
}
bool NetworkSystem::exists(const AbsolutePath & path){
Util::Thread::ScopedLock scoped(lock);
if (existsCache.find(path) != existsCache.end()){
return existsCache[path];
}
Manager manager(instance, core);
bool what = manager.exists(path.path());
existsCache[path] = what;
return what;
}
string NetworkSystem::readFileAsString(const AbsolutePath & path){
if (!exists(path)){
ostringstream fail;
fail << "Could not read " << path.path();
throw Filesystem::NotFound(__FILE__, __LINE__, fail.str());
}
ostringstream buffer;
ifstream input(path.path().c_str());
char stuff[1024];
while (input.good()){
input.read(stuff, sizeof(stuff) - 1);
- stuff[sizeof(stuff) - 1] = '\0';
+ int in = input.gcount();
+ stuff[in] = '\0';
buffer << stuff;
}
return buffer.str();
}
static vector<string> split(string input, char splitter){
vector<string> all;
size_t found = input.find(splitter);
while (found != string::npos){
all.push_back(input.substr(0, found));
input.erase(0, found + 1);
found = input.find(splitter);
}
if (input.size() != 0){
all.push_back(input);
}
return all;
}
vector<AbsolutePath> NetworkSystem::readDirectory(const AbsolutePath & dataPath){
/* assume existence of 'directory.txt' in the given directory */
AbsolutePath fullPath = dataPath.join(RelativePath("directory.txt"));
string all = readFileAsString(fullPath);
vector<string> files = split(all, '\n');
vector<AbsolutePath> paths;
for (vector<string>::iterator it = files.begin(); it != files.end(); it++){
string what = *it;
- paths.push_back(dataPath.join(RelativePath(what)));
+ if (what != ""){
+ paths.push_back(dataPath.join(RelativePath(what)));
+ }
}
return paths;
}
-/* check if 'foo/bar/baz.txt' matches *.txt */
static bool matchFile(const AbsolutePath & path, const string & find, bool insensitive = false){
+ return false;
+ /*
+ string file = path.path();
+ for (unsigned int index = 0; index < find.size(); index += 1){
+ if (index >= file.size()){
+ return false;
+ }
+ char find_letter = find[find.size() - index - 1];
+ char file_letter = file[file.size() - index - 1];
+ if (insensitive){
+ if (tolower(find_letter) != tolower(file_letter)){
+ return false;
+ }
+ } else {
+ if (find_letter != file_letter){
+ return false;
+ }
+ }
+ }
+
+ return true;
+ */
+}
+
+/* check if 'foo/bar/baz.txt' matches *.txt */
+static bool matchFile2(const AbsolutePath & path, const string & find, bool insensitive = false){
string file = path.getFilename().path();
+ Global::debug(0) << "Find " << find << " in " << path.path() << " insensitive? " << insensitive << std::endl;
unsigned int index = 0;
while (index < file.size()){
if (index >= find.size()){
return false;
}
if (find[index] == '*'){
return true;
}
if (insensitive){
if (tolower(find[index]) != tolower(file[index])){
return false;
}
} else {
if (find[index] != file[index]){
return false;
}
}
index += 1;
}
return true;
}
+static void testMatchFile(){
+#define test_match(check, against, insensitive) if (!matchFile(Filesystem::AbsolutePath(check), against, insensitive)){ Global::debug(0) << "Test failed, expected a match: file " << check << " find " << against << std::endl; }
+#define test_no_match(check, against, insensitive) if (matchFile(Filesystem::AbsolutePath(check), against, insensitive)){ Global::debug(0) << "Test failed, expected no match: file " << check << " find " << against << std::endl; }
+
+ test_match("foo", "foo", false);
+ test_match("fOo", "foO", true);
+ test_match("bar/foo", "foo", false);
+ test_match("bar/fOo", "foO", true);
+ test_match("bar/baz/foo.txt", "baz/foo.txt", false);
+ test_match("foobar.txt", "*.txt", false);
+ test_match("bar/foobar.txt", "*.txt", false);
+ test_no_match("fuz", "foo", false);
+ test_no_match("foo/bar.txt", "foo", false);
+ test_no_match("buz/foobar.txt", "bar/*.txt", false);
+
+#undef test_match
+#undef test_no_match
+}
+
std::vector<AbsolutePath> NetworkSystem::getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
vector<AbsolutePath> files = readDirectory(dataPath);
vector<AbsolutePath> paths;
for (vector<AbsolutePath>::iterator it = files.begin(); it != files.end(); it++){
AbsolutePath check = *it;
- if (matchFile(check, find)){
+ if (file_matches(check.getFilename().path().c_str(), find.c_str())){
paths.push_back(check);
}
}
return paths;
}
std::vector<AbsolutePath> NetworkSystem::getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
vector<AbsolutePath> files = readDirectory(dataPath);
vector<AbsolutePath> paths;
for (vector<AbsolutePath>::iterator it = files.begin(); it != files.end(); it++){
AbsolutePath check = *it;
if (matchFile(check, find)){
paths.push_back(check);
}
vector<AbsolutePath> more = getFilesRecursive(check, find, caseInsensitive);
paths.insert(paths.end(), more.begin(), more.end());
}
return paths;
}
AbsolutePath NetworkSystem::configFile(){
return AbsolutePath("paintownrc");
}
AbsolutePath NetworkSystem::userDirectory(){
return AbsolutePath("paintown-user");
}
std::vector<AbsolutePath> NetworkSystem::findDirectories(const RelativePath & path){
vector<AbsolutePath> files = readDirectory(find(path));
vector<AbsolutePath> paths;
for (vector<AbsolutePath>::iterator it = files.begin(); it != files.end(); it++){
AbsolutePath check = *it;
try{
/* if we can read directory contents then its a directory */
vector<AbsolutePath> more = readDirectory(check);
paths.push_back(check);
} catch (const Filesystem::NotFound & fail){
}
}
return paths;
}
AbsolutePath NetworkSystem::findInsensitive(const RelativePath & path){
try{
/* try sensitive lookup first */
return find(path);
} catch (const Filesystem::NotFound & fail){
}
/* get the base directory */
AbsolutePath directory = find(path.getDirectory());
return lookupInsensitive(directory, path.getFilename());
}
+/*
AbsolutePath NetworkSystem::lookupInsensitive(const AbsolutePath & directory, const RelativePath & path){
vector<AbsolutePath> files = readDirectory(directory);
vector<AbsolutePath> paths;
for (vector<AbsolutePath>::iterator it = files.begin(); it != files.end(); it++){
AbsolutePath check = *it;
if (matchFile(check, path.path(), true)){
return check;
}
}
ostringstream out;
out << "Cannot find " << path.path() << " in " << directory.path();
throw Filesystem::NotFound(__FILE__, __LINE__, out.str());
}
+*/
+
+Filesystem::AbsolutePath NetworkSystem::lookupInsensitive(const Filesystem::AbsolutePath & directory, const Filesystem::RelativePath & path){
+ if (path.path() == ""){
+ throw Filesystem::NotFound(__FILE__, __LINE__, "Given empty path to lookup");
+ }
+ if (path.path() == "."){
+ return directory;
+ }
+ if (path.path() == ".."){
+ return directory.getDirectory();
+ }
+ if (path.isFile()){
+ vector<AbsolutePath> all = getFiles(directory, "*", true);
+ for (vector<AbsolutePath>::iterator it = all.begin(); it != all.end(); it++){
+ AbsolutePath & check = *it;
+ if (InsensitivePath(check.getFilename()) == path){
+ return check;
+ }
+ }
+
+ ostringstream out;
+ out << "Cannot find " << path.path() << " in " << directory.path();
+ throw Filesystem::NotFound(__FILE__, __LINE__, out.str());
+ } else {
+ return lookupInsensitive(lookupInsensitive(directory, path.firstDirectory()), path.removeFirstDirectory());
+ }
+}
int nextFileDescriptor(){
static int next = 3;
int n = next;
next += 1;
return n;
}
int NetworkSystem::libcOpen(const char * path, int mode, int params){
Manager manager(instance, core);
Util::ReferenceCount<FileHandle> handle = manager.openFile(path);
if (handle == NULL){
return -1;
}
Util::Thread::ScopedLock scoped(lock);
int file = nextFileDescriptor();
fileTable[file] = handle;
return file;
}
ssize_t NetworkSystem::libcRead(int fd, void * buffer, size_t count){
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return EBADF;
}
Util::ReferenceCount<FileHandle> handle = fileTable[fd];
if (handle == NULL){
Global::debug(0) << "Handle is null!!" << std::endl;
}
return handle->read(buffer, count);
}
int NetworkSystem::libcClose(int fd){
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return -1;
/* set errno to EBADF */
}
fileTable.erase(fileTable.find(fd));
return 0;
}
off_t NetworkSystem::libcLseek(int fd, off_t offset, int whence){
Global::debug(2, CONTEXT) << "seek fd " << fd << " offset " << offset << " whence " << whence << std::endl;
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return -1;
}
Util::ReferenceCount<FileHandle> handle = fileTable[fd];
return handle->seek(offset, whence);
}
}
/* NOTE FIXME Missing I/O in Native Client */
Nacl::NetworkSystem & getSystem(){
return (Nacl::NetworkSystem&) Storage::instance();
}
extern "C" {
/* http://sourceware.org/binutils/docs-2.21/ld/Options.html#index-g_t_002d_002dwrap_003d_0040var_007bsymbol_007d-261
* --wrap=symbol
* Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol.
*/
int __wrap_open(const char * path, int mode, int params){
return getSystem().libcOpen(path, mode, params);
}
ssize_t __wrap_read(int fd, void * buf, size_t count){
return getSystem().libcRead(fd, buf, count);
}
extern int __real_close(int fd);
int __wrap_close(int fd){
/* we may be given a file descriptor that we do not own, probably
* because some file descriptors are really tied to sockets so
* if we don't own the fd then pass it to the real close function.
*/
int ok = getSystem().libcClose(fd);
if (ok == -1){
return __real_close(fd);
}
return ok;
}
off_t __wrap_lseek(int fd, off_t offset, int whence){
return getSystem().libcLseek(fd, offset, whence);
}
int pipe (int filedes[2]){
return -1;
}
int mkdir (const char *filename, mode_t mode){
return -1;
}
-int access(const char *filename, int how){
+int __wrap_access(const char *filename, int mode){
+ Global::debug(0) << "Access for " << filename << std::endl;
+ if (mode == R_OK){
+ return getSystem().exists(Filesystem::AbsolutePath(filename));
+ }
return -1;
}
char * getcwd (char *buffer, size_t size){
return NULL;
}
-int lstat (const char *path, struct stat *buf){
+int __wrap_lstat (const char *path, struct stat *buf){
+ Global::debug(0) << "Lstat for " << path << std::endl;
return -1;
}
int rmdir (const char *filename){
return -1;
}
int chdir (const char *filename){
return -1;
}
int setuid (uid_t newuid){
return 0;
}
int seteuid (uid_t uid){
return 0;
}
uid_t geteuid (void){
return NULL;
}
int setgid (gid_t gid){
return 0;
}
gid_t getgid (void){
return NULL;
}
int setegid (gid_t gid){
return 0;
}
gid_t getegid (void){
return NULL;
}
char * getlogin (void){
return NULL;
}
uid_t getuid(void){
return NULL;
}
struct passwd * getpwuid (uid_t uid){
return NULL;
}
struct passwd * getpwnam (const char *name){
return NULL;
}
struct group * getgrnam(const char *name){
return NULL;
}
struct group * getgrgid(gid_t gid){
return NULL;
}
int link (const char *oldname, const char *newname){
return -1;
}
int unlink (const char *filename){
return -1;
}
int kill(pid_t pid, int sig){
return -1;
}
}
#endif
diff --git a/util/nacl/network-system.h b/util/nacl/network-system.h
index 851c9848..0f2804a4 100644
--- a/util/nacl/network-system.h
+++ b/util/nacl/network-system.h
@@ -1,68 +1,69 @@
#ifndef _paintown_network_system_h
#define _paintown_network_system_h
#ifdef NACL
#include <map>
#include <string>
#include <vector>
#include "../file-system.h"
#include "../thread.h"
#include "../pointer.h"
namespace pp{
class Instance;
class Core;
}
namespace Nacl{
typedef Path::AbsolutePath AbsolutePath;
typedef Path::RelativePath RelativePath;
+typedef Path::InsensitivePath InsensitivePath;
class Manager;
class FileHandle;
class NetworkSystem: public Storage::System {
public:
NetworkSystem(pp::Instance * instance, pp::Core * core);
virtual ~NetworkSystem();
virtual AbsolutePath find(const RelativePath & path);
virtual RelativePath cleanse(const AbsolutePath & path);
virtual bool exists(const RelativePath & path);
virtual bool exists(const AbsolutePath & path);
virtual std::vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
virtual std::vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
virtual AbsolutePath configFile();
virtual AbsolutePath userDirectory();
virtual std::vector<AbsolutePath> findDirectories(const RelativePath & path);
virtual AbsolutePath findInsensitive(const RelativePath & path);
virtual AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path);
public:
int libcOpen(const char * path, int mode, int params);
ssize_t libcRead(int fd, void * buf, size_t count);
int libcClose(int fd);
off_t libcLseek(int fd, off_t offset, int whence);
protected:
std::string readFileAsString(const AbsolutePath & path);
std::vector<AbsolutePath> readDirectory(const AbsolutePath & dataPath);
protected:
pp::Instance * instance;
pp::Core * core;
/* only one thread at a time to access the network system */
Util::Thread::LockObject lock;
// Util::ReferenceCount<Manager> manager;
std::map<AbsolutePath, bool> existsCache;
std::map<int, Util::ReferenceCount<FileHandle> > fileTable;
};
}
#endif
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:03 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68266
Default Alt Text
(48 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline