[Add] Implement VFS permissions and ls -l
This commit is contained in:
parent
d3b5139e89
commit
6618b0e0a2
@ -2,4 +2,61 @@
|
||||
--
|
||||
-- Iterate over the 'children' map exposed via C++.
|
||||
|
||||
return bettola.ls(context)
|
||||
local function format_permissions(perms)
|
||||
local rwx = { "-", "-", "-", "-", "-", "-","-", "-", "-" }
|
||||
if(perms & 0x100) ~= 0 then rwx[1] = "r" end -- Owner read.
|
||||
if(perms & 0x080) ~= 0 then rwx[2] = "w" end -- Owner write.
|
||||
if(perms & 0x040) ~= 0 then rwx[3] = "x" end -- Owner execute.
|
||||
if(perms & 0x020) ~= 0 then rwx[4] = "r" end -- Group read.
|
||||
if(perms & 0x010) ~= 0 then rwx[5] = "w" end -- Group write.
|
||||
if(perms & 0x008) ~= 0 then rwx[6] = "x" end -- Group execute.
|
||||
if(perms & 0x004) ~= 0 then rwx[7] = "r" end -- Other read.
|
||||
if(perms & 0x002) ~= 0 then rwx[8] = "w" end -- Other write.
|
||||
if(perms & 0x001) ~= 0 then rwx[9] = "x" end -- Other execute.
|
||||
return table.concat(rwx)
|
||||
end
|
||||
|
||||
local function get_file_size(node)
|
||||
if node.type == 0 then -- FILE_NODE.
|
||||
return #node.content
|
||||
else
|
||||
return 0 -- Dirs don't have content size in this context.
|
||||
end
|
||||
end
|
||||
|
||||
local function ls_long_format(dir)
|
||||
local output = {}
|
||||
for name, node in pairs(dir.children) do
|
||||
local line_type = (node.type == 1) and "d" or "-"
|
||||
local perms = format_permissions(node.permissions)
|
||||
local owner = node.owner_id
|
||||
local group = node.group_id
|
||||
local size = get_file_size(node)
|
||||
table.insert(output, string.format("%s%s %d %d %5d %s", line_type, perms, owner, group, size, name))
|
||||
end
|
||||
table.sort(output)
|
||||
return table.concat(output, "\n")
|
||||
end
|
||||
|
||||
local function ls_short_format(dir)
|
||||
local output = {}
|
||||
for name, node in pairs(dir.children) do
|
||||
local display_name = name
|
||||
if node.type == 1 then -- DIR_NODE
|
||||
display_name = display_name .. "/"
|
||||
elseif node.type == 2 then --EXEC_NODE
|
||||
display_name = display_name .. "*"
|
||||
end
|
||||
table.insert(output, display_name)
|
||||
end
|
||||
table.sort(output)
|
||||
return table.concat(output, "\t") -- Tab separated short format.
|
||||
end
|
||||
|
||||
local current_dir = bettola.get_current_dir(context);
|
||||
|
||||
if arg[1] == "-l" then
|
||||
return ls_long_format(current_dir)
|
||||
else
|
||||
return ls_short_format(current_dir)
|
||||
end
|
||||
|
||||
@ -30,7 +30,10 @@ DatabaseManager::DatabaseManager(const std::string& db_path) :
|
||||
"parent_id INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"content TEXT"
|
||||
"content TEXT,"
|
||||
"owner_id INTEGER NOT NULL,"
|
||||
"group_id INTEGER NOT NULL,"
|
||||
"permissions INTEGER NOT NULL"
|
||||
");";
|
||||
_db << "CREATE TABLE IF NOT EXISTS services ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
@ -62,19 +65,24 @@ bool DatabaseManager::create_player(const std::string& username, const std::stri
|
||||
_player_repository->set_home_machine_id(player_id, machine_id);
|
||||
|
||||
/* Create the root dir for the new machine's VFS. */
|
||||
long long root_id = _vfs_repository->create_node(machine_id, nullptr, "/", DIR_NODE);
|
||||
long long root_id = _vfs_repository->create_node(machine_id, nullptr, "/", DIR_NODE,
|
||||
"", player_id, player_id, 0755);
|
||||
|
||||
/* Create default subdirs. */
|
||||
_vfs_repository->create_node(machine_id, &root_id, "home", DIR_NODE);
|
||||
_vfs_repository->create_node(machine_id, &root_id, "etc", DIR_NODE);
|
||||
_vfs_repository->create_node(machine_id, &root_id, "home", DIR_NODE,
|
||||
"", player_id, player_id, 0755);
|
||||
_vfs_repository->create_node(machine_id, &root_id, "etc", DIR_NODE,
|
||||
"", player_id, player_id, 0755);
|
||||
|
||||
/* Create /bin and get it's ID */
|
||||
long long bin_id = _vfs_repository->create_node(machine_id, &root_id, "bin", DIR_NODE);
|
||||
long long bin_id = _vfs_repository->create_node(machine_id, &root_id, "bin", DIR_NODE,
|
||||
"", player_id, player_id, 0755);
|
||||
|
||||
/* Copy scripts from template into new machine's /bin */
|
||||
vfs_node* template_bin = vfs_template->children["bin"];
|
||||
for(auto const& [name, node] : template_bin->children) {
|
||||
_vfs_repository->create_node(machine_id, &bin_id, name, node->type, node->content);
|
||||
_vfs_repository->create_node(machine_id, &bin_id, name, node->type, node->content,
|
||||
player_id, player_id, 0755);
|
||||
}
|
||||
|
||||
/* Add default SSH service. */
|
||||
|
||||
@ -4,30 +4,41 @@ VFSRepository::VFSRepository(sqlite::database& db) : _db(db) {}
|
||||
|
||||
long long VFSRepository::create_node(long long machine_id, long long* parent_id,
|
||||
const std::string& name, vfs_node_type type,
|
||||
const std::string& content) {
|
||||
const std::string& content,
|
||||
uint32_t owner_id, uint32_t group_id,
|
||||
uint16_t permissions) {
|
||||
if(parent_id) {
|
||||
_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) "
|
||||
"VALUES (?, ?, ?, ?, ?);"
|
||||
<< machine_id << *parent_id << name << type << content;
|
||||
_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content, "
|
||||
"owner_id, group_id, permissions) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?);"
|
||||
<< machine_id << *parent_id << name << type << content << owner_id
|
||||
<< group_id << permissions;
|
||||
} else {
|
||||
_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) "
|
||||
"VALUES (?, NULL, ?, ?, ?);"
|
||||
<< machine_id << name << type << content;
|
||||
_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content, "
|
||||
"owner_id, group_id, permissions) "
|
||||
"VALUES (?, NULL, ?, ?, ?, ?, ?, ?);"
|
||||
<< machine_id << name << type << content
|
||||
<< owner_id << group_id << permissions;
|
||||
}
|
||||
return _db.last_insert_rowid();
|
||||
}
|
||||
|
||||
std::vector<vfs_node*> VFSRepository::get_nodes_for_machine(long long machine_id) {
|
||||
std::vector<vfs_node*> nodes;
|
||||
_db << "SELECT id, parent_id, name, type, content FROM vfs_nodes WHERE machine_id = ?;"
|
||||
_db << "SELECT id, parent_id, name, type, content, owner_id, group_id, permissions "
|
||||
"FROM vfs_nodes WHERE machine_id = ?;"
|
||||
<< machine_id
|
||||
>> [&](long long id, long long parent_id, std::string name, int type, std::string content) {
|
||||
>> [&](long long id, long long parent_id, std::string name, int type,
|
||||
std::string content, uint32_t owner_id, uint32_t group_id, uint16_t permissions) {
|
||||
vfs_node* node = new vfs_node();
|
||||
node->id = id;
|
||||
node->parent_id = parent_id;
|
||||
node->name = name;
|
||||
node->type = (vfs_node_type) type;
|
||||
node->content = content;
|
||||
node->owner_id = owner_id;
|
||||
node->group_id = group_id;
|
||||
node->permissions = permissions;
|
||||
|
||||
nodes.push_back(node);
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -12,7 +13,10 @@ public:
|
||||
|
||||
long long create_node(long long machine_id, long long* parent_id,
|
||||
const std::string& name, vfs_node_type type,
|
||||
const std::string& content = "");
|
||||
const std::string& content = "",
|
||||
uint32_t owner_id = 0, uint32_t group_id = 0,
|
||||
uint16_t permissions = 0755);
|
||||
|
||||
std::vector<vfs_node*> get_nodes_for_machine(long long machine_id);
|
||||
|
||||
private:
|
||||
|
||||
@ -30,7 +30,10 @@ LuaProcessor::LuaProcessor(Session& context) {
|
||||
"name", &vfs_node::name,
|
||||
"type", &vfs_node::type,
|
||||
"children", &vfs_node::children,
|
||||
"content", &vfs_node::content);
|
||||
"content", &vfs_node::content,
|
||||
"owner_id", &vfs_node::owner_id,
|
||||
"group_id", &vfs_node::group_id,
|
||||
"permissions", &vfs_node::permissions);
|
||||
|
||||
/* Expose CommandProcessor to Lua. DON'T ALLOW SCRIPTS TO CREATE IT THOUGH! */
|
||||
_lua.new_usertype<Session>("Session", sol::no_constructor);
|
||||
|
||||
@ -15,7 +15,10 @@ vfs_node* copy_vfs_node(vfs_node* original, vfs_node* new_parent) {
|
||||
}
|
||||
|
||||
/* Create the new node and copy its properties. */
|
||||
vfs_node* new_copy = new_node(original->name, original->type, new_parent);
|
||||
vfs_node* new_copy = new_node(original->name, original->type, new_parent,
|
||||
original->owner_id, original->group_id,
|
||||
original->permissions);
|
||||
|
||||
new_copy->content = original->content;
|
||||
|
||||
/* Recursively copy all children. */
|
||||
@ -30,7 +33,7 @@ MachineManager::MachineManager(DatabaseManager* db_manager) :
|
||||
_db_manager(db_manager) {
|
||||
/* Create template VFS that holds shared, read-only directories. */
|
||||
_vfs_template_root = new_node("/", DIR_NODE, nullptr);
|
||||
vfs_node* bin = new_node("bin", DIR_NODE, _vfs_template_root);
|
||||
vfs_node* bin = new_node("bin", DIR_NODE, _vfs_template_root, 0, 0, 0755); /* System owned. */
|
||||
_vfs_template_root->children["bin"] = bin;
|
||||
|
||||
/* Load all scripts from assets/scripts/bin into the VFS. */
|
||||
@ -42,7 +45,7 @@ MachineManager::MachineManager(DatabaseManager* db_manager) :
|
||||
buffer << t.rdbuf();
|
||||
std::string filename_with_ext = entry.path().filename().string();
|
||||
std::string filename = filename_with_ext.substr(0, filename_with_ext.find_last_of('.'));
|
||||
vfs_node* script_node = new_node(filename, EXEC_NODE, bin);
|
||||
vfs_node* script_node = new_node(filename, EXEC_NODE, bin, 0, 0, 0755); /* System owned. */
|
||||
script_node->content = util::xor_string(buffer.str());
|
||||
bin->children[filename] = script_node;
|
||||
fprintf(stderr, "Loaded executable: /bin/%s\n", filename.c_str());
|
||||
@ -58,24 +61,28 @@ Machine* MachineManager::create_machine(uint32_t id, const std::string& hostname
|
||||
const std::string& system_type) {
|
||||
auto* new_machine = new Machine(id, hostname);
|
||||
|
||||
vfs_node* root = new_node("/", DIR_NODE, nullptr);
|
||||
vfs_node* root = new_node("/", DIR_NODE, nullptr, 0, 0, 0755); /* Root owned by system (0). */
|
||||
|
||||
/* Create directories for this specific VFS. */
|
||||
vfs_node* home = new_node("home", DIR_NODE, root);
|
||||
vfs_node* home = new_node("home", DIR_NODE, root, id, id, 0755); /* Owned by player. */
|
||||
vfs_node* user = new_node("user", DIR_NODE, home);
|
||||
home->children["user"] = user;
|
||||
vfs_node* readme = new_node("readme.txt", FILE_NODE, user);
|
||||
vfs_node* readme = new_node("readme.txt", FILE_NODE, user, id, id, 0644); /* Owned by player. */
|
||||
readme->content = "Welcome to your new virtual machine.";
|
||||
user->children["readme.txt"] = readme;
|
||||
|
||||
/* Link to the shared directories from the template. */
|
||||
root->children["bin"] = copy_vfs_node(_vfs_template_root->children["bin"], root);
|
||||
/* Ensure copied bin directory has the correct owner/group/permissions. */
|
||||
root->children["bin"]->owner_id = 0; /* System owned. */
|
||||
root->children["bin"]->group_id = 0;
|
||||
root->children["bin"]->permissions = 0755;
|
||||
|
||||
/* Assign the VFS to the new machine. */
|
||||
new_machine->vfs_root = root;
|
||||
|
||||
if(system_type == "npc") {
|
||||
vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root);
|
||||
vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root, 0, 0, 0644);
|
||||
npc_file->content = "This guy sucks nuts!";
|
||||
root->children["npc_system.txt"] = npc_file;
|
||||
|
||||
|
||||
@ -3,11 +3,15 @@
|
||||
#include "vfs.h"
|
||||
|
||||
/* Create a new node. */
|
||||
vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent) {
|
||||
vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent,
|
||||
uint32_t owner_id, uint32_t group_id, uint16_t permissions) {
|
||||
vfs_node* node = new vfs_node();
|
||||
node->name = name;
|
||||
node->type = type;
|
||||
node->parent = parent;
|
||||
node->owner_id = owner_id;
|
||||
node->group_id = group_id;
|
||||
node->permissions = permissions;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@ -20,6 +21,10 @@ struct vfs_node {
|
||||
std::string name;
|
||||
vfs_node_type type;
|
||||
|
||||
uint32_t owner_id;
|
||||
uint32_t group_id;
|
||||
uint16_t permissions;
|
||||
|
||||
/* Files. */
|
||||
std::string content;
|
||||
|
||||
@ -28,7 +33,8 @@ struct vfs_node {
|
||||
vfs_node* parent;
|
||||
};
|
||||
|
||||
vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent);
|
||||
vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent,
|
||||
uint32_t owner_id = 0, uint32_t group_id = 0, uint16_t permissions=0755);
|
||||
vfs_node* find_node_by_id(vfs_node* root, long long id);
|
||||
std::string get_full_path(vfs_node* node);
|
||||
vfs_node* find_node_by_path(vfs_node* root, const std::string& path);
|
||||
|
||||
@ -304,7 +304,8 @@ void NetworkManager::release_machine(long long machine_id) {
|
||||
void NetworkManager::_recursive_save_vfs(long long machine_id, vfs_node* node, long long* parent_id) {
|
||||
long long current_node_id = _db_manager->vfs().create_node(machine_id, parent_id,
|
||||
node->name, node->type,
|
||||
node->content);
|
||||
node->content, node->owner_id,
|
||||
node->group_id, node->permissions);
|
||||
|
||||
if(node->type == DIR_NODE) {
|
||||
for(auto const& [name, child] : node->children) {
|
||||
@ -347,15 +348,19 @@ void NetworkManager::_seed_npc_machines(void) {
|
||||
long long machine_id = _db_manager->machines().create({}, def.hostname, def.ip);
|
||||
|
||||
/* Create a basic VFS for the NPC machines. */
|
||||
long long root_id = _db_manager->vfs().create_node(machine_id, nullptr, "/", DIR_NODE);
|
||||
long long root_id = _db_manager->vfs().create_node(machine_id, nullptr, "/", DIR_NODE,
|
||||
"", 0, 0, 0755); /* System owned. */
|
||||
|
||||
_db_manager->vfs().create_node(machine_id, &root_id, "etc", DIR_NODE);
|
||||
_db_manager->vfs().create_node(machine_id, &root_id, "etc", DIR_NODE,
|
||||
"", 0, 0, 0755); /*System owned. */
|
||||
|
||||
long long bin_id = _db_manager->vfs().create_node(machine_id, &root_id, "bin", DIR_NODE);
|
||||
long long bin_id = _db_manager->vfs().create_node(machine_id, &root_id, "bin", DIR_NODE,
|
||||
"", 0, 0, 0755); /* System owned. */
|
||||
|
||||
vfs_node* template_bin = _machine_manager.get_vfs_template()->children["bin"];
|
||||
for(auto const& [name, node] : template_bin->children) {
|
||||
_db_manager->vfs().create_node(machine_id, &bin_id, name, node->type, node->content);
|
||||
_db_manager->vfs().create_node(machine_id, &bin_id, name, node->type, node->content,
|
||||
0, 0, 0755); /* System owned. */
|
||||
}
|
||||
|
||||
for(const auto& service : def.services) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user