mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-10 21:50:19 +00:00
merge
This commit is contained in:
parent
16086a346f
commit
3ad9525a14
5
src/io.h
5
src/io.h
@ -31,11 +31,12 @@ struct FileIO {
|
|||||||
|
|
||||||
Str file;
|
Str file;
|
||||||
Str mode;
|
Str mode;
|
||||||
FILE* fp;
|
FILE* fp= nullptr;
|
||||||
|
|
||||||
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));}
|
||||||
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));
|
||||||
}
|
}
|
||||||
@ -125,7 +126,7 @@ inline void add_module_os(VM* vm){
|
|||||||
di = std::filesystem::directory_iterator(path);
|
di = std::filesystem::directory_iterator(path);
|
||||||
}catch(std::filesystem::filesystem_error& e){
|
}catch(std::filesystem::filesystem_error& e){
|
||||||
std::string msg = e.what();
|
std::string msg = e.what();
|
||||||
auto pos = msg.find_last_of(":");
|
auto pos = msg.find_last_of(':');
|
||||||
if(pos != std::string::npos) msg = msg.substr(pos + 1);
|
if(pos != std::string::npos) msg = msg.substr(pos + 1);
|
||||||
vm->IOError(Str(msg).lstrip());
|
vm->IOError(Str(msg).lstrip());
|
||||||
}
|
}
|
||||||
|
|||||||
142
src/isolated_io.h
Normal file
142
src/isolated_io.h
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@ -1333,7 +1333,11 @@ inline void VM::post_init(){
|
|||||||
|
|
||||||
if(enable_os){
|
if(enable_os){
|
||||||
add_module_io(this);
|
add_module_io(this);
|
||||||
add_module_os(this);
|
if (isolated_os) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/vm.h
15
src/vm.h
@ -25,6 +25,8 @@ namespace pkpy{
|
|||||||
#define POPX() (s_data.popx())
|
#define POPX() (s_data.popx())
|
||||||
#define STACK_VIEW(n) (s_data.view(n))
|
#define STACK_VIEW(n) (s_data.view(n))
|
||||||
|
|
||||||
|
typedef std::function<Bytes(const Str & name)> ReadFileCwdFunc;
|
||||||
|
|
||||||
#define DEF_NATIVE_2(ctype, ptype) \
|
#define DEF_NATIVE_2(ctype, ptype) \
|
||||||
template<> inline ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
|
template<> inline ctype py_cast<ctype>(VM* vm, PyObject* obj) { \
|
||||||
vm->check_non_tagged_type(obj, vm->ptype); \
|
vm->check_non_tagged_type(obj, vm->ptype); \
|
||||||
@ -98,7 +100,7 @@ struct FrameId{
|
|||||||
Frame* operator->() const { return &data->operator[](index); }
|
Frame* operator->() const { return &data->operator[](index); }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void(*PrintFunc)(VM*, const Str&);
|
typedef std::function<void(VM*, const Str&)> PrintFunc;
|
||||||
|
|
||||||
class VM {
|
class VM {
|
||||||
VM* vm; // self reference for simplify code
|
VM* vm; // self reference for simplify code
|
||||||
@ -123,7 +125,7 @@ public:
|
|||||||
|
|
||||||
PrintFunc _stdout;
|
PrintFunc _stdout;
|
||||||
PrintFunc _stderr;
|
PrintFunc _stderr;
|
||||||
Bytes (*_import_handler)(const Str& name);
|
std::function<Bytes(const Str&)> _import_handler;
|
||||||
|
|
||||||
// for quick access
|
// for quick access
|
||||||
Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
|
Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str;
|
||||||
@ -133,9 +135,14 @@ public:
|
|||||||
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
||||||
Type tp_dict, tp_property, tp_star_wrapper;
|
Type tp_dict, tp_property, tp_star_wrapper;
|
||||||
|
|
||||||
const bool enable_os;
|
std::function<bool(std::string)> check_is_invalid_io_path = [](const std::string&){return false;};
|
||||||
|
std::string _lowest_isolated_cwd_path; // should be absolute, only used in isolated_io.h
|
||||||
|
|
||||||
VM(bool enable_os=true) : heap(this), enable_os(enable_os) {
|
const bool enable_os;
|
||||||
|
const bool isolated_os;
|
||||||
|
|
||||||
|
VM(bool enable_os=true, bool isolated_os=false):
|
||||||
|
heap(this), enable_os(enable_os), isolated_os(isolated_os) {
|
||||||
this->vm = this;
|
this->vm = this;
|
||||||
_stdout = [](VM* vm, const Str& s) { std::cout << s; };
|
_stdout = [](VM* vm, const Str& s) { std::cout << s; };
|
||||||
_stderr = [](VM* vm, const Str& s) { std::cerr << s; };
|
_stderr = [](VM* vm, const Str& s) { std::cerr << s; };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user