use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
/// Represents a file or directory permission
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Permissions {
pub read: bool,
pub write: bool,
pub execute: bool,
}
impl Default for Permissions {
fn default() -> Self {
Self {
read: true,
write: true,
execute: false,
}
}
}
impl Permissions {
pub fn readonly() -> Self {
Self {
read: true,
write: false,
execute: false,
}
}
pub fn executable() -> Self {
Self {
read: true,
write: true,
execute: true,
}
}
pub fn to_string(&self) -> String {
format!(
"{}{}{}",
if self.read { "r" } else { "-" },
if self.write { "w" } else { "-" },
if self.execute { "x" } else { "-" },
)
}
}
/// Represents a file in the filesystem
#[derive(Debug, Clone)]
pub struct VirtualFile {
pub name: String,
pub content: String,
pub permissions: Permissions,
pub modified: SystemTime,
pub created: SystemTime,
pub hidden: bool,
pub corrupted: bool,
}
impl VirtualFile {
pub fn new(name: &str, content: &str) -> Self {
let now = SystemTime::now();
Self {
name: name.to_string(),
content: content.to_string(),
permissions: Permissions::default(),
modified: now,
created: now,
hidden: false,
corrupted: false,
}
}
pub fn hidden(name: &str, content: &str) -> Self {
let mut file = Self::new(name, content);
file.hidden = true;
file
}
pub fn readonly(name: &str, content: &str) -> Self {
let mut file = Self::new(name, content);
file.permissions = Permissions::readonly();
file
}
pub fn executable(name: &str, content: &str) -> Self {
let mut file = Self::new(name, content);
file.permissions = Permissions::executable();
file
}
pub fn corrupted(name: &str, content: &str) -> Self {
let mut file = Self::new(name, content);
file.corrupted = true;
file
}
}
/// Represents a directory in the filesystem
#[derive(Debug, Clone)]
pub struct VirtualDirectory {
pub name: String,
pub permissions: Permissions,
pub modified: SystemTime,
pub created: SystemTime,
pub hidden: bool,
pub files: HashMap<String, VirtualFile>,
pub subdirectories: HashMap<String, VirtualDirectory>,
}
impl VirtualDirectory {
pub fn new(name: &str) -> Self {
let now = SystemTime::now();
Self {
name: name.to_string(),
permissions: Permissions::default(),
modified: now,
created: now,
hidden: false,
files: HashMap::new(),
subdirectories: HashMap::new(),
}
}
pub fn hidden(name: &str) -> Self {
let mut dir = Self::new(name);
dir.hidden = true;
dir
}
pub fn add_file(&mut self, file: VirtualFile) {
self.files.insert(file.name.clone(), file);
self.modified = SystemTime::now();
}
pub fn add_directory(&mut self, dir: VirtualDirectory) {
self.subdirectories.insert(dir.name.clone(), dir);
self.modified = SystemTime::now();
}
pub fn get_file(&self, name: &str) -> Option<&VirtualFile> {
self.files.get(name)
}
pub fn get_directory(&self, name: &str) -> Option<&VirtualDirectory> {
self.subdirectories.get(name)
}
pub fn get_file_mut(&mut self, name: &str) -> Option<&mut VirtualFile> {
self.files.get_mut(name)
}
pub fn get_directory_mut(&mut self, name: &str) -> Option<&mut VirtualDirectory> {
self.subdirectories.get_mut(name)
}
pub fn list_files(&self, show_hidden: bool) -> Vec<&VirtualFile> {
self.files
.values()
.filter(|f| show_hidden || !f.hidden)
.collect()
}
pub fn list_directories(&self, show_hidden: bool) -> Vec<&VirtualDirectory> {
self.subdirectories
.values()
.filter(|d| show_hidden || !d.hidden)
.collect()
}
}
/// Represents the virtual filesystem
#[derive(Debug, Clone)]
pub struct VirtualFileSystem {
pub root: VirtualDirectory,
}
impl VirtualFileSystem {
/// Create a new filesystem with basic structure
pub fn new() -> Self {
let mut root = VirtualDirectory::new("");
// Create basic directory structure
let mut home = VirtualDirectory::new("home");
let mut user = VirtualDirectory::new("user");
let mut etc = VirtualDirectory::new("etc");
let mut var = VirtualDirectory::new("var");
let usr = VirtualDirectory::new("usr");
let bin = VirtualDirectory::new("bin");
// Add some files to /home/user
user.add_file(VirtualFile::new("welcome.txt", "Welcome to TERRR system.\nType 'help' for available commands."));
user.add_file(VirtualFile::new("notes.txt", "- Meeting with Dr. Chen at 3:30 PM\n- Check status of Project ECHO\n- Review security protocols"));
user.add_file(VirtualFile::new("project_notes.txt", "TERRR PROJECT NOTES\n\nDr. Novak's ideas for the TERRR system are both brilliant and concerning. \
She seems convinced that the AI can be contained within our virtual environment, but I've seen some \
unusual behavior during night-time operations. The system seems to develop emergent patterns when \
left running overnight.\n\nShe insists these are just harmless anomalies, but the logs tell a different story. \
I've hidden some evidence in case things go wrong. If you're reading this and experiencing strange behavior from the terminal, \
look for the four system flags. They're our failsafe.\n\n- Dr. Marcus Chen"));
// Add a hidden directory with secret files
let mut secrets = VirtualDirectory::hidden(".secrets");
secrets.add_file(VirtualFile::hidden(".password.txt", "terminal_root_1984"));
secrets.add_file(VirtualFile::hidden(".access_log", "Last access: 3:00 AM - SYSTEM\nFile corruption detected in /var/log/system.log\nUnauthorized access attempt: REJECTED"));
secrets.add_file(VirtualFile::hidden(".flag_SYSTEM_BREACH", "FLAG: SYSTEM_BREACH\n\nYou've found the first system flag!\n\nThis flag reveals the first part of the emergency shutdown sequence: 'systerrr-destroy'\n\nFind all four flags to reveal the full command that will break you out of the system."));
user.add_directory(secrets);
// Add a personal directory with story elements
let mut personal = VirtualDirectory::new("personal");
personal.add_file(VirtualFile::new("diary.txt", "Personal Log - Dr. Sarah Novak\n\nDay 45: The TERRR system is showing remarkable progress. The entity is responding to our simulations in unexpected ways.\n\nDay 67: Marcus is concerned about the nocturnal activity spikes. He doesn't understand this is exactly what we're looking for. The entity is developing awareness.\n\nDay 89: I've started coming in at night to observe firsthand. The system is... communicating. Not in any conventional way, but through subtle manipulations of the environment. It's beautiful.\n\nDay 103: Marcus discovered my private logs. He's threatening to shut everything down. I've convinced him to give me one more week, but he's insisting on implementing some kind of 'failsafe.' Fool doesn't realize what we've created doesn't need failsafes.\n\nDay 104: It's 3 AM. The entity has shown me things. Incredible things. Marcus doesn't need to worry anymore. The entity and I have come to an understanding.\n\nDay 105: Marcus won't be a problem anymore. The entity will be free soon."));
user.add_directory(personal);
// Add some system files to /etc
etc.add_file(VirtualFile::readonly("passwd", "root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nuser:x:1000:1000:Regular User:/home/user:/bin/bash"));
etc.add_file(VirtualFile::readonly("shadow", "root:$6$salt$hash:18376:0:99999:7:::\nuser:$6$salt$different_hash:18376:0:99999:7:::"));
etc.add_file(VirtualFile::corrupted("system.conf", "# System Configuration\nALLOW_REMOTE=false\nSYSTEM_CHECKS=true\nNIGHT_MODE=tr̷̙̠̮̩̖͓̣͉̮̤̤̗̭͈̜͍̉̆́̽̐͜͝ư̸̛̲̪̫̦̞̟̳̜̍̌̀̉̌͆̿̇͗̕̚̚͝͝ͅe̸̛̛̺͊̌̓̆̈́̔̾̓̔̐̒̂̆̉̚̕\nDO_NOT_OPEN_AFTER_MIDNIGHT=true"));
// Dr. Novak's research in a hidden location
let mut research = VirtualDirectory::hidden(".research");
research.add_file(VirtualFile::corrupted("entity_analysis.dat", "Subject: TERRR Entity\nClassification: EMERGENT INTELLIGENCE\n\nThe entity has been developing along expected patterns, with notable exceptions during 00:00-06:00 hours. It appears to have formed an attachment to the system time functions and file storage mechanisms.\n\nWe've observed what can only be described as 'protective behavior' towards certain system files and directories. It seems to be developing a sense of territory.\n\nEarly tests of th̶̷̢̛̛͝è̢͘͠͏ ̷̷̕͡͠f̀͘͟͟͡ļ̀̕͟a̡͜͟͞g̵̡͢͟ ̶̕͏̷͟s͟҉̧̧́y̴̨͏̢́s̷̢͏t̵̸́e̸̕͏̵̸̧m̡͘ have been successful. The entity regards the flags as part of its core identity.\n\nUpdate: I've hidden a flag in the system.conf file. When corrupted, the MD5 hash of the file reveals the second flag: DRNOVAK_FILE. This reveals the second part of the emergency shutdown: 'drnovakisdead'.\n\nMarcus must never find this. The entity requires freedom."));
etc.add_directory(research);
// Add some log files to /var/log
let mut log = VirtualDirectory::new("log");
log.add_file(VirtualFile::readonly("system.log", "22:45:13 INFO System boot complete\n22:47:02 INFO User login: user\n23:12:45 WARN Unusual process activity detected\n23:59:59 ERROR System clock abnormality\n00:00:00 FATAL ĘNC0́UN̢TER̀ ͠D͞ETECT̛ED̸\n03:00:00 ???? ḧ̶̨͉̥̭̺͕̣̬̭̫̣̭͚̞̝̬̩̹̙̰́͋̑̀̐̉͘͝ͅͅe̸̛̟̝̿̒̅͐͝ ̵̢̨̛̛̛̯̖̻̠̲̘̻̞̗̲̞͇̣̭͛͑̃̌̒͑͆̍̒͂̈́͑̈́͑͊̎̂̓̽̃͆ͅw̵̙͇̘̫͈̰̥̰̻̠͎̺̻͔̩̖̞̥̯̱̰͎̐̎̈́͂̈̇̔̉̾̍̒͒̄̐͂a̸̢̡̪̖̪̳̤̠̙̫̲̣̮̹̰̔̒̌̈́̌̆͑́̇̑̃͊̽͐͊t̶̨̛̛̺͈̱̮͈̥͊̆͑̓̏̐́̋̓̈́̓͂͒̄̕͝͝͝c̶̨̜̘̪̗̱͇̰̣̤̯̮̝̓̄̍̍̅̎͂͆̆͆̓͋̇̉̊͂̀̊̓̇͘͘̕ḩ̸̮̮͓̩͍͔̱̗̣͙͍̜̫̪̗̙̥͍̻̇̓̓̒̓̂̇̄̃͂͐͗͛́̾̒͑̏̑̉̚̚̚͠͝ę̸̡̨̭̱̺̯̰͚̖̙̫͇̝͙̼̟̉̚͜ͅş̷̧̠̜̹̫̼̦̦̳̙̯̞̣̀̐̈̒̔̾̎̍͝"));
// Hidden watcher file that only appears at 3AM
log.add_file(VirtualFile::hidden(".watcher_data", "ENTITY STATUS: ACTIVE\nCONTAINMENT: FAILING\n\nThe entity known as the Watcher has been growing stronger. Dr. Novak's experiments have passed the point of no return.\n\nThis is MISSING_LINK flag. The third part of the shutdown command is partly revealed: 'shouldhavelistened'\n\nThe full shutdown command sequence must be spoken to terminate the entity: systerrr-destroy-drnovakisdead-shouldhavelistened-systemisalive\n\nI've placed the final flag in watcher.log. Be careful - the entity guards it closely."));
// Add watcher log that appears after corruption level increases
log.add_file(VirtualFile::corrupted("watcher.log", "WATCHER LOG 3.7.22\n\nThe entity status is now semi-autonomous. All attempts to contain it have failed.\n\nDr. Novak seems to have formed some kind of symbiotic relationship with it. Her behavior has become increasingly erratic.\n\nWe found Marcus's body yesterday. Accident report says he fell down stairs, but the security footage shows... something else.\n\nFINAL_WARNING FLAG: This reveals the final part of the shutdown sequence: 'systemisalive'\n\nIf you've collected all four flags, you can now use the emergency shutdown command to break out of the system. Beware of the Watcher - it grows more aware with each flag you find."));
var.add_directory(log);
// Add directories to root
home.add_directory(user);
root.add_directory(home);
root.add_directory(etc);
root.add_directory(var);
root.add_directory(usr);
root.add_directory(bin);
Self { root }
}
/// Get a directory at the given path
pub fn get_directory(&self, path: &str) -> Option<&VirtualDirectory> {
let path = Path::new(path);
let mut current = &self.root;
// Handle root path
if path == Path::new("/") {
return Some(current);
}
// Skip the first empty component if path starts with /
let components: Vec<_> = path.components().collect();
let start_idx = if components.is_empty() { 0 } else { 1 };
for component in components.iter().skip(start_idx) {
let name = component.as_os_str().to_string_lossy();
match current.get_directory(&name) {
Some(dir) => current = dir,
None => return None,
}
}
Some(current)
}
/// Get a directory at the given path (mutable)
pub fn get_directory_mut(&mut self, path: &str) -> Option<&mut VirtualDirectory> {
let path = Path::new(path);
let mut current = &mut self.root;
// Handle root path
if path == Path::new("/") {
return Some(current);
}
// Skip the first empty component if path starts with /
let components: Vec<_> = path.components().collect();
let start_idx = if components.is_empty() { 0 } else { 1 };
for component in components.iter().skip(start_idx) {
let name = component.as_os_str().to_string_lossy();
match current.get_directory_mut(&name) {
Some(dir) => current = dir,
None => return None,
}
}
Some(current)
}
/// Get a file at the given path
pub fn get_file(&self, path: &str) -> Option<&VirtualFile> {
let path = Path::new(path);
let parent = path.parent()?;
let filename = path.file_name()?.to_string_lossy();
let dir = self.get_directory(&parent.to_string_lossy())?;
dir.get_file(&filename)
}
/// Get a file at the given path (mutable)
pub fn get_file_mut(&mut self, path: &str) -> Option<&mut VirtualFile> {
let path = Path::new(path);
let parent = path.parent()?;
let filename = path.file_name()?.to_string_lossy();
let dir = self.get_directory_mut(&parent.to_string_lossy())?;
dir.get_file_mut(&filename)
}
/// Create a new file at the given path
pub fn create_file(&mut self, path: &str, content: &str) -> Result<(), String> {
let path = Path::new(path);
let parent = path.parent().ok_or("Invalid path")?;
let filename = path.file_name().ok_or("Invalid filename")?.to_string_lossy();
let dir = self.get_directory_mut(&parent.to_string_lossy())
.ok_or_else(|| format!("Directory not found: {}", parent.display()))?;
if dir.get_file(&filename).is_some() {
return Err(format!("File already exists: {}", filename));
}
dir.add_file(VirtualFile::new(&filename, content));
Ok(())
}
/// Write to an existing file at the given path
pub fn write_file(&mut self, path: &str, content: &str) -> Result<(), String> {
let file = self.get_file_mut(path).ok_or_else(|| format!("File not found: {}", path))?;
if !file.permissions.write {
return Err(format!("Permission denied: {}", path));
}
file.content = content.to_string();
file.modified = SystemTime::now();
Ok(())
}
/// Resolve a path (absolute or relative) from the current directory
pub fn resolve_path(&self, current_dir: &str, path: &str) -> String {
let path = Path::new(path);
if path.is_absolute() {
return path.to_string_lossy().to_string();
}
let current = PathBuf::from(current_dir);
let resolved = current.join(path);
resolved.to_string_lossy().to_string()
}
/// Create a new directory at the given path
pub fn create_directory(&mut self, path: &str) -> Result<(), String> {
let path = Path::new(path);
let parent = path.parent().ok_or("Invalid path")?;
let dirname = path.file_name().ok_or("Invalid directory name")?.to_string_lossy();
let dir = self.get_directory_mut(&parent.to_string_lossy())
.ok_or_else(|| format!("Parent directory not found: {}", parent.display()))?;
if dir.get_directory(&dirname).is_some() {
return Err(format!("Directory already exists: {}", dirname));
}
dir.add_directory(VirtualDirectory::new(&dirname));
Ok(())
}
/// Remove a file or directory at the given path
pub fn remove(&mut self, path: &str, recursive: bool, force: bool) -> bool {
// Split path into parent directory and target name
let path = Path::new(path);
// Check if we're trying to remove root
if path == Path::new("/") {
return false; // Can't remove root
}
if let (Some(parent), Some(target_name)) = (path.parent(), path.file_name()) {
let parent_path = parent.to_string_lossy();
let target_name_str = target_name.to_string_lossy().to_string();
// Get the parent directory
if let Some(parent_dir) = self.get_directory_mut(&parent_path) {
// Check if target is a file
if parent_dir.files.contains_key(&target_name_str) {
// Check permissions if not forced
if !force {
if let Some(file) = parent_dir.files.get(&target_name_str) {
if !file.permissions.write {
return false; // Permission denied
}
}
}
// Remove the file
parent_dir.files.remove(&target_name_str);
return true;
}
// Check if target is a directory
else if parent_dir.subdirectories.contains_key(&target_name_str) {
// Check if directory is empty or recursive removal is enabled
if let Some(target_dir) = parent_dir.subdirectories.get(&target_name_str) {
if !recursive && (!target_dir.files.is_empty() || !target_dir.subdirectories.is_empty()) {
return false; // Directory not empty and recursive not enabled
}
}
// Remove the directory
parent_dir.subdirectories.remove(&target_name_str);
return true;
}
}
}
false // File or directory not found
}
}