This commit is contained in:
spaceeye 2023-06-11 18:44:32 +03:00
parent 19347fa6c6
commit 266b6ff6e1
3 changed files with 61 additions and 167 deletions

View File

@ -10,21 +10,36 @@
#include <cstdio> #include <cstdio>
namespace pkpy{ namespace pkpy{
inline std::filesystem::path get_rel(const VM* vm, const std::filesystem::path & rel) {
return rel.lexically_relative(vm->_lowest_isolated_cwd_path);
}
inline bool check_if_path_is_isolated(const std::string & path_to_check_str,
const std::string & toplevel_path_str) {
//.lexically_normal() expands somepath/somdir/.. to somepath/
auto toplevel_path = std::filesystem::path(toplevel_path_str).lexically_normal();
auto path_to_check = (toplevel_path / std::filesystem::path(path_to_check_str)).lexically_normal();
//toplevel_path is part of toplevel_path, so if toplevel_path is less than path_to_check, then toplevel_path is certainly not a part of it
if (path_to_check < toplevel_path) {return false;}
if (path_to_check == toplevel_path) {return true;}
while (true) {
auto temp = path_to_check.parent_path();
if (path_to_check == temp) { break;}
path_to_check = temp;
if (path_to_check < toplevel_path) {return false;}
if (path_to_check == toplevel_path) {return true;}
}
return false;
}
static inline void helper_process_isolated(VM *vm, std::filesystem::path & path) {
if (!vm->isolated_os) { return;}
path = std::filesystem::path(vm->_lowest_isolated_cwd_path) / path;
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {vm->IOError(Str("Invalid path."));}
}
inline Bytes _default_import_handler(const Str& name){
std::filesystem::path path(name.sv());
bool exists = std::filesystem::exists(path);
if(!exists) return Bytes();
std::string cname = name.str();
FILE* fp = fopen(cname.c_str(), "rb");
if(!fp) return Bytes();
fseek(fp, 0, SEEK_END);
std::vector<char> buffer(ftell(fp));
fseek(fp, 0, SEEK_SET);
fread(buffer.data(), 1, buffer.size(), fp);
fclose(fp);
return Bytes(std::move(buffer));
};
struct FileIO { struct FileIO {
PY_CLASS(FileIO, io, FileIO) PY_CLASS(FileIO, io, FileIO)
@ -36,7 +51,8 @@ struct FileIO {
bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; } bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; }
FileIO(VM* vm, std::string file, std::string mode): file(file), mode(mode) { FileIO(VM* vm, std::string file, std::string mode): file(file), mode(mode) {
if (vm->check_is_invalid_io_path(file)) {vm->IOError(strerror(errno));} if (vm->isolated_os && !check_if_path_is_isolated(file, vm->_lowest_isolated_cwd_path)) {vm->IOError(strerror(errno));}
if (vm->isolated_os) {file = vm->_lowest_isolated_cwd_path / std::filesystem::path(file);}
fp = fopen(file.c_str(), mode.c_str()); fp = fopen(file.c_str(), mode.c_str());
if(!fp) vm->IOError(strerror(errno)); if(!fp) vm->IOError(strerror(errno));
} }
@ -110,17 +126,24 @@ inline void add_module_os(VM* vm){
// Working directory is shared by all VMs!! // Working directory is shared by all VMs!!
vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){ vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){
return VAR(std::filesystem::current_path().string()); if (!vm->isolated_os) {
return VAR(std::filesystem::current_path().string());
} else {
return VAR(get_rel(vm, std::filesystem::current_path()).string());//TODO BUG! while technically correct, cwd needs to change to a file path upon executing
}
}); });
vm->bind_func<1>(mod, "chdir", [](VM* vm, ArgsView args){ vm->bind_func<1>(mod, "chdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
helper_process_isolated(vm, path);
std::filesystem::current_path(path); std::filesystem::current_path(path);
return vm->None; return vm->None;
}); });
vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){ vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
helper_process_isolated(vm, path);
std::filesystem::directory_iterator di; std::filesystem::directory_iterator di;
try{ try{
di = std::filesystem::directory_iterator(path); di = std::filesystem::directory_iterator(path);
@ -131,28 +154,40 @@ inline void add_module_os(VM* vm){
vm->IOError(Str(msg).lstrip()); vm->IOError(Str(msg).lstrip());
} }
List ret; List ret;
for(auto& p: di) ret.push_back(VAR(p.path().filename().string())); if (!vm->isolated_os) {
for (auto &p: di) ret.push_back(VAR(p.path().filename().string()));
} else {
for(auto& p: di) ret.push_back(VAR(get_rel(vm, p.path()).filename().string()));
}
return VAR(ret); return VAR(ret);
}); });
vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){ vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
helper_process_isolated(vm, path);
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("Operation failed.");
return vm->None; return vm->None;
}); });
vm->bind_func<1>(mod, "mkdir", [](VM* vm, ArgsView args){ vm->bind_func<1>(mod, "mkdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
helper_process_isolated(vm, path);
std::cout << path.string().c_str() << "\n";
bool ok = std::filesystem::create_directory(path); bool ok = std::filesystem::create_directory(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("Operation failed.");
return vm->None; return vm->None;
}); });
vm->bind_func<1>(mod, "rmdir", [](VM* vm, ArgsView args){ vm->bind_func<1>(mod, "rmdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
helper_process_isolated(vm, path);
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("Operation failed.");
return vm->None; return vm->None;
}); });
@ -166,6 +201,11 @@ inline void add_module_os(VM* vm){
vm->bind_func<1>(path_obj, "exists", [](VM* vm, ArgsView args){ vm->bind_func<1>(path_obj, "exists", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
if (vm->isolated_os) {
path = vm->_lowest_isolated_cwd_path / path;
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {return VAR(false);}
}
bool exists = std::filesystem::exists(path); bool exists = std::filesystem::exists(path);
return VAR(exists); return VAR(exists);
}); });

View File

@ -1,142 +0,0 @@
#pragma once
#include "ceval.h"
#include "cffi.h"
#include "common.h"
#if PK_ENABLE_OS
#include <filesystem>
#include <cstdio>
namespace pkpy {
inline std::filesystem::path get_rel(const VM* vm, const std::filesystem::path & rel) {
return rel.lexically_relative(vm->_lowest_isolated_cwd_path);
}
inline bool check_if_path_is_isolated(const std::string & path_to_check_str,
const std::string & toplevel_path_str) {
//.lexically_normal() expands somepath/somdir/.. to somepath/
auto toplevel_path = std::filesystem::path(toplevel_path_str).lexically_normal();
auto path_to_check = std::filesystem::path(toplevel_path_str+path_to_check_str).lexically_normal();
//toplevel_path is part of toplevel_path, so if toplevel_path is less than path_to_check, then toplevel_path is certainly not a part of it
if (path_to_check < toplevel_path) {return false;}
if (path_to_check == toplevel_path) {return true;}
while (true) {
auto temp = path_to_check.parent_path();
if (path_to_check == temp) { break;}
path_to_check = temp;
if (path_to_check < toplevel_path) {return false;}
if (path_to_check == toplevel_path) {return true;}
}
return false;
}
inline void add_module_isolated_os(VM *vm) {
if (vm->_lowest_isolated_cwd_path.empty()) {
throw std::invalid_argument("vm->_lowest_isolated_cwd_path is empty. Change it to a path of VM's allowed operation.");
}
if (!std::filesystem::exists(vm->_lowest_isolated_cwd_path)) {
throw std::invalid_argument("vm->_lowest_isolated_cwd_path doesn't exist.");
}
PyObject* mod = vm->new_module("os");
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(vm->tp_object, {});
mod->attr().set("path", path_obj);
vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){
return VAR(get_rel(vm, std::filesystem::current_path()).string());
});
vm->bind_func<1>(mod, "chdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {
std::filesystem::current_path(vm->_lowest_isolated_cwd_path);
return vm->None;
}
std::filesystem::current_path(vm->_lowest_isolated_cwd_path / path);
return vm->None;
});
vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {vm->IOError(Str("Invalid path."));}
path = vm->_lowest_isolated_cwd_path / path;
std::filesystem::directory_iterator di;
try{
di = std::filesystem::directory_iterator(path);
}catch(std::filesystem::filesystem_error& e){
std::string msg = e.what();
auto pos = msg.find_last_of(':');
if(pos != std::string::npos) msg = msg.substr(pos + 1);
vm->IOError(Str(msg).lstrip());
}
List ret;
for(auto& p: di) ret.push_back(VAR(get_rel(vm, p.path()).filename().string()));
return VAR(ret);
});
vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {vm->IOError(Str("Operation failed."));}
path = vm->_lowest_isolated_cwd_path / path;
bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("Operation failed.");
return vm->None;
});
vm->bind_func<1>(mod, "mkdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {vm->IOError(Str("Operation failed."));}
path = vm->_lowest_isolated_cwd_path / path;
bool ok = std::filesystem::create_directory(path);
if(!ok) vm->IOError("Operation failed.");
return vm->None;
});
vm->bind_func<1>(mod, "rmdir", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
if (!check_if_path_is_isolated(path, vm->_lowest_isolated_cwd_path)) {vm->IOError(Str("Operation failed."));}
path = vm->_lowest_isolated_cwd_path / path;
bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("Operation failed.");
return vm->None;
});
vm->bind_func<-1>(path_obj, "join", [](VM* vm, ArgsView args){
std::filesystem::path path;
for(int i=0; i<args.size(); i++){
path /= CAST(Str&, args[i]).sv();
}
return VAR(path.string());
});
vm->bind_func<1>(path_obj, "exists", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
path = vm->_lowest_isolated_cwd_path / path;
bool exists = std::filesystem::exists(path);
return VAR(exists);
});
vm->bind_func<1>(path_obj, "basename", [](VM* vm, ArgsView args){
std::filesystem::path path(CAST(Str&, args[0]).sv());
return VAR(path.filename().string());
});
}
}// namespace pkpy
#else
namespace pkpy{
inline void add_module_isolated_os(void* vm){}
} // namespace pkpy
#endif

View File

@ -1334,11 +1334,7 @@ inline void VM::post_init(){
if(enable_os){ if(enable_os){
add_module_io(this); add_module_io(this);
if (isolated_os) { add_module_os(this);
add_module_isolated_os(this);
} else {
add_module_os(this);
}
add_module_requests(this); add_module_requests(this);
_import_handler = _default_import_handler; _import_handler = _default_import_handler;
} }