mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-10 13:40:16 +00:00
merge
This commit is contained in:
parent
19347fa6c6
commit
266b6ff6e1
76
src/io.h
76
src/io.h
@ -10,21 +10,36 @@
|
||||
#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 = (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 {
|
||||
PY_CLASS(FileIO, io, FileIO)
|
||||
@ -36,7 +51,8 @@ struct FileIO {
|
||||
bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; }
|
||||
|
||||
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());
|
||||
if(!fp) vm->IOError(strerror(errno));
|
||||
}
|
||||
@ -110,17 +126,24 @@ inline void add_module_os(VM* vm){
|
||||
|
||||
// Working directory is shared by all VMs!!
|
||||
vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){
|
||||
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){
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
helper_process_isolated(vm, path);
|
||||
std::filesystem::current_path(path);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
helper_process_isolated(vm, path);
|
||||
|
||||
std::filesystem::directory_iterator di;
|
||||
try{
|
||||
di = std::filesystem::directory_iterator(path);
|
||||
@ -131,28 +154,40 @@ inline void add_module_os(VM* vm){
|
||||
vm->IOError(Str(msg).lstrip());
|
||||
}
|
||||
List ret;
|
||||
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);
|
||||
});
|
||||
|
||||
vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
helper_process_isolated(vm, path);
|
||||
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
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());
|
||||
helper_process_isolated(vm, path);
|
||||
|
||||
std::cout << path.string().c_str() << "\n";
|
||||
|
||||
bool ok = std::filesystem::create_directory(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
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());
|
||||
helper_process_isolated(vm, path);
|
||||
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
if(!ok) vm->IOError("Operation failed.");
|
||||
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){
|
||||
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);
|
||||
return VAR(exists);
|
||||
});
|
||||
|
||||
@ -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
|
||||
@ -1334,11 +1334,7 @@ inline void VM::post_init(){
|
||||
|
||||
if(enable_os){
|
||||
add_module_io(this);
|
||||
if (isolated_os) {
|
||||
add_module_isolated_os(this);
|
||||
} else {
|
||||
add_module_os(this);
|
||||
}
|
||||
add_module_requests(this);
|
||||
_import_handler = _default_import_handler;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user