[Add] Implement VFS permissions and ls -l

This commit is contained in:
Ritchie Cunningham 2025-11-04 21:11:43 +00:00
parent d3b5139e89
commit 6618b0e0a2
9 changed files with 150 additions and 45 deletions

View File

@ -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

View File

@ -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. */

View File

@ -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);
};

View File

@ -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:

View File

@ -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);

View File

@ -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;

View 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;
}

View File

@ -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);

View File

@ -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) {