[Add] Implment scp for remote file copy.
This commit is contained in:
		
							parent
							
								
									4f5436f376
								
							
						
					
					
						commit
						3fbacd4a99
					
				
							
								
								
									
										8
									
								
								assets/scripts/bin/scp.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								assets/scripts/bin/scp.lua
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
local source = arg[1]
 | 
			
		||||
local destination = arg[2]
 | 
			
		||||
 | 
			
		||||
if not source or not destination then
 | 
			
		||||
  return "usage: scp source destination"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return bettola.scp(context, source, destination)
 | 
			
		||||
@ -117,30 +117,6 @@ std::string CommandProcessor::write_file(const std::string& path, const std::str
 | 
			
		||||
  return api::write_file(*this, path, content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find a VFS node by it's absolute path. */
 | 
			
		||||
vfs_node* find_node_by_path(vfs_node* root, const std::string& path) {
 | 
			
		||||
  if(path == "/") {
 | 
			
		||||
    return root;
 | 
			
		||||
  }
 | 
			
		||||
  vfs_node* current = root;
 | 
			
		||||
  std::stringstream ss(path);
 | 
			
		||||
  std::string segment;
 | 
			
		||||
 | 
			
		||||
  /* Discard the first empty segment that comes form the leading '/'. */
 | 
			
		||||
  if(path[0] == '/') {
 | 
			
		||||
    std::getline(ss, segment, '/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while(std::getline(ss, segment, '/')) {
 | 
			
		||||
    if(current->type == DIR_NODE && current->children.count(segment)) {
 | 
			
		||||
      current = current->children[segment];
 | 
			
		||||
    } else {
 | 
			
		||||
      return nullptr; /* Path segmenet not found. */
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return current;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string CommandProcessor::read_file(const std::string& path) {
 | 
			
		||||
  vfs_node* root = get_session_machine()->vfs_root;
 | 
			
		||||
  vfs_node* node = find_node_by_path(root, path);
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
#include <sol/call.hpp>
 | 
			
		||||
#include <sol/types.hpp>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
@ -130,4 +131,94 @@ std::string close_terminal(CommandProcessor& context) {
 | 
			
		||||
  return "__CLOSE_CONNECTION__";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ScpPath {
 | 
			
		||||
  std::string host;
 | 
			
		||||
  std::string path;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ScpPath parse_scp_path(const std::string& arg) {
 | 
			
		||||
  size_t colon_pos = arg.find(':');
 | 
			
		||||
  if(colon_pos != std::string::npos) {
 | 
			
		||||
    return {arg.substr(0, colon_pos), arg.substr(colon_pos+1)};
 | 
			
		||||
  } else {
 | 
			
		||||
    return {"", arg};
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string scp(CommandProcessor& context, const std::string& source_arg,
 | 
			
		||||
                const std::string& dest_arg) {
 | 
			
		||||
  ScpPath source_path = parse_scp_path(source_arg);
 | 
			
		||||
  ScpPath dest_path = parse_scp_path(dest_arg);
 | 
			
		||||
  Machine* session_machine = context.get_session_machine();
 | 
			
		||||
  INetworkBridge* bridge = context.get_network_bridge();
 | 
			
		||||
 | 
			
		||||
  Machine* source_machine = source_path.host.empty()
 | 
			
		||||
    ? session_machine : bridge->get_machine_by_ip(source_path.host);
 | 
			
		||||
 | 
			
		||||
  Machine* dest_machine = dest_path.host.empty()
 | 
			
		||||
    ? session_machine : bridge->get_machine_by_ip(dest_path.host);
 | 
			
		||||
 | 
			
		||||
  if(!source_machine) {
 | 
			
		||||
    return "scp: " + source_path.host + ": Name or service not known";
 | 
			
		||||
  }
 | 
			
		||||
  if(!dest_machine) {
 | 
			
		||||
    if(source_machine != session_machine) bridge->release_machine(source_machine->id);
 | 
			
		||||
    return "scp: " + dest_path.host + ": Name or service not known";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Simplified to use only absolute paths for now. */
 | 
			
		||||
  vfs_node* source_node = find_node_by_path(source_machine->vfs_root, source_path.path);
 | 
			
		||||
 | 
			
		||||
  if(!source_node || source_node->type != FILE_NODE) {
 | 
			
		||||
    if(source_machine != session_machine) bridge->release_machine(source_machine->id);
 | 
			
		||||
    if(dest_machine != session_machine) bridge->release_machine(dest_machine->id);
 | 
			
		||||
    return "scp: " + source_path.path + ": No such file or directory";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  vfs_node* dest_node = find_node_by_path(dest_machine->vfs_root, dest_path.path);
 | 
			
		||||
  vfs_node* dest_dir = nullptr;
 | 
			
		||||
  std::string dest_filename;
 | 
			
		||||
 | 
			
		||||
  if(dest_node && dest_node->type == DIR_NODE) {
 | 
			
		||||
    dest_dir = dest_node;
 | 
			
		||||
    dest_filename = source_node->name;
 | 
			
		||||
  } else {
 | 
			
		||||
    size_t last_slash = dest_path.path.find_last_of('/');
 | 
			
		||||
    if(last_slash != std::string::npos) {
 | 
			
		||||
      std::string parent_path = dest_path.path.substr(0, last_slash);
 | 
			
		||||
      if(parent_path.empty()) parent_path = "/";
 | 
			
		||||
      dest_dir = find_node_by_path(dest_machine->vfs_root, parent_path);
 | 
			
		||||
      dest_filename = dest_path.path.substr(last_slash+1);
 | 
			
		||||
    } else {
 | 
			
		||||
      dest_dir = dest_machine->vfs_root;
 | 
			
		||||
      dest_filename = dest_path.path;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(!dest_dir) {
 | 
			
		||||
    if(source_machine != session_machine) bridge->release_machine(source_machine->id);
 | 
			
		||||
    if(dest_machine != session_machine) bridge->release_machine(dest_machine->id);
 | 
			
		||||
    return "scp: " + dest_path.path + ": No such file or directory";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(dest_dir->children.count(dest_filename)) {
 | 
			
		||||
    vfs_node* existing_node = dest_dir->children[dest_filename];
 | 
			
		||||
    if(existing_node->type == DIR_NODE) {
 | 
			
		||||
      if(source_machine != session_machine) bridge->release_machine(source_machine->id);
 | 
			
		||||
      if(dest_machine != session_machine) bridge->release_machine(dest_machine->id);
 | 
			
		||||
      return "scp: " + dest_path.path + ": Is a directory";
 | 
			
		||||
    }
 | 
			
		||||
    existing_node->content = source_node->content;
 | 
			
		||||
  } else {
 | 
			
		||||
    vfs_node* new_file = new_node(dest_filename, FILE_NODE, dest_dir);
 | 
			
		||||
    new_file->content = source_node->content;
 | 
			
		||||
    dest_dir->children[dest_filename] = new_file;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(source_machine != session_machine) bridge->release_machine(source_machine->id);
 | 
			
		||||
  if(dest_machine != session_machine) bridge->release_machine(dest_machine->id);
 | 
			
		||||
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace api */
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,8 @@ std::string write_file(CommandProcessor& context, const std::string& filename,
 | 
			
		||||
                       const std::string& content);
 | 
			
		||||
std::string ls(CommandProcessor& context);
 | 
			
		||||
std::string cd(CommandProcessor& context, const std::string& path);
 | 
			
		||||
std::string scp(CommandProcessor& context, const std::string& source,
 | 
			
		||||
                const std::string& destination);
 | 
			
		||||
 | 
			
		||||
/* NETWORK ACTIONS. */
 | 
			
		||||
std::string ssh(CommandProcessor& context, const std::string& ip);
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ LuaProcessor::LuaProcessor(CommandProcessor& context) {
 | 
			
		||||
  bettola_api.set_function("write_file",      &api::write_file);
 | 
			
		||||
  bettola_api.set_function("get_current_dir", &api::get_current_dir);
 | 
			
		||||
  bettola_api.set_function("cd",              &api::cd);
 | 
			
		||||
  bettola_api.set_function("scp",             &api::scp);
 | 
			
		||||
  bettola_api.set_function("close_terminal",  &api::close_terminal);
 | 
			
		||||
  bettola_api.set_function("ssh",             &api::ssh);
 | 
			
		||||
  bettola_api.set_function("nmap",            &api::nmap);
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#include "vfs.h"
 | 
			
		||||
 | 
			
		||||
/* Create a new node. */
 | 
			
		||||
@ -31,3 +33,27 @@ void delete_vfs_tree(vfs_node* node) {
 | 
			
		||||
  }
 | 
			
		||||
  delete node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find a VFS node by it's absolute path. */
 | 
			
		||||
vfs_node* find_node_by_path(vfs_node* root, const std::string& path) {
 | 
			
		||||
  if(path == "/") {
 | 
			
		||||
    return root;
 | 
			
		||||
  }
 | 
			
		||||
  vfs_node* current = root;
 | 
			
		||||
  std::stringstream ss(path);
 | 
			
		||||
  std::string segment;
 | 
			
		||||
 | 
			
		||||
  /* Discard the first empty segment that comes form the leading '/'. */
 | 
			
		||||
  if(path[0] == '/') {
 | 
			
		||||
    std::getline(ss, segment, '/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while(std::getline(ss, segment, '/')) {
 | 
			
		||||
    if(current->type == DIR_NODE && current->children.count(segment)) {
 | 
			
		||||
      current = current->children[segment];
 | 
			
		||||
    } else {
 | 
			
		||||
      return nullptr; /* Path segmenet not found. */
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return current;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,4 +30,5 @@ struct vfs_node {
 | 
			
		||||
vfs_node* new_node(std::string name, vfs_node_type type, vfs_node* parent);
 | 
			
		||||
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);
 | 
			
		||||
void delete_vfs_tree(vfs_node* node);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user