Filesystem Structure

Directory layout and SafeFS API

Root Directory Layout

/
├── apps/                    # Installed applications
│   └── com.developer.app/   # App directory (reverse domain naming)
│       ├── manifest.lua     # App manifest (required)
│       ├── icon.png         # App icon (optional, PNG or BMP)
│       └── src/             # Source code directory
│           └── init.lua     # Entry point (or as specified in manifest)
│
├── home/                    # User home directory (~)
│   └── Documents/           # User documents
│
├── keys/                    # Developer signing keys (LAM)
│   └── developer_name/      # Per-developer key storage
│       ├── public.key       # ED25519 public key (base64)
│       └── secret.key       # ED25519 secret key (base64)
│
├── os/                      # Operating system files
│   ├── init.lua             # OS initialization
│   ├── postinit.lua         # Post-initialization (starts apps)
│   ├── libs/                # System libraries
│   │   ├── Application.lua  # App framework
│   │   ├── safefs.lua       # SafeFS implementation
│   │   ├── run.lua          # App launcher
│   │   ├── scheduler.lua    # Process scheduler
│   │   ├── sys.lua          # System APIs
│   │   ├── dialogs.lua      # Dialog system
│   │   ├── LAM.lua          # Application manager
│   │   ├── Hook.lua         # Event hook system
│   │   ├── Image.lua        # Image handling
│   │   ├── PNG.lua          # PNG decoder
│   │   └── ...
│   ├── public/              # Public OS resources
│   │   └── res/             # Resources (backgrounds, etc.)
│   └── res/                 # System resources
│       └── default.bmp      # Default app icon
│
├── proc/                    # Process information (virtual)
│   └── <pid>/               # Per-process directory
│       └── process          # Contains app path
│
└── scripts/                 # Shell scripts (.lua)

Path Shortcuts

Shortcut Expands To Description
~ /home User home directory
$ /apps/com.dev.app Current app's directory (in shell)
. Current directory Relative to CWD
.. Parent directory Go up one level

SafeFS (Sandboxed Filesystem)

SafeFS provides a secure, sandboxed filesystem interface for applications. It restricts access based on the app's declared permissions and allowedPaths in the manifest.

Getting SafeFS

Apps with the "filesystem" permission receive a fs object in their sandbox:

-- In app code
if fs then
    local content, err = fs:read("/home/Documents/file.txt")
end

SafeFS Methods

Reading Files

-- Read entire file contents
local content, err = fs:read(path)

-- Check if file/directory exists
local exists = fs:exists(path)

-- Get file information
local info, err = fs:stat(path)
-- Returns: { size = number, type = "file"|"directory", ... }

Writing Files

-- Write content to file (creates or overwrites)
local success, err = fs:write(path, content)

-- Append to file
local success, err = fs:append(path, content)

Directory Operations

-- List directory contents
local entries, err = fs:list(path)
-- Returns array of: { name = string, type = "file"|"directory" }

-- Create directory
local success, err = fs:mkdir(path)

-- Remove file or empty directory
local success, err = fs:remove(path)

Path Operations

-- Join path components
local fullPath = fs:join("/home", "Documents", "file.txt")
-- Returns: "/home/Documents/file.txt"

-- Get parent directory
local parent = fs:dirname("/home/Documents/file.txt")
-- Returns: "/home/Documents"

-- Get filename
local name = fs:basename("/home/Documents/file.txt")
-- Returns: "file.txt"

-- Get file extension
local ext = fs:extension("file.txt")
-- Returns: "txt"

Access Control

SafeFS enforces two levels of access control:

1. Permission Check

The app must have "filesystem" in its permissions array:

-- manifest.lua
return {
    permissions = { "filesystem" };
}

2. Path Restrictions

If allowedPaths is specified, access is restricted to matching paths:

-- manifest.lua
return {
    allowedPaths = {
        "/home/*";      -- Access to all of /home
        "/apps/*";      -- Access to all apps
    };
}

Path pattern syntax:

Access Denied Behavior

When access is denied, SafeFS returns nil and an error message:

local content, err = fs:read("/etc/secret")
if not content then
    print("Access denied: " .. err)
end

Example Usage

-- Read a configuration file
local config, err = fs:read("~/config.lua")
if config then
    -- Parse config...
end

-- Save user data
local data = "user preferences here"
local ok, err = fs:write("~/Documents/prefs.txt", data)
if not ok then
    print("Failed to save: " .. err)
end

-- List home directory
local files, err = fs:list("~")
if files then
    for _, entry in ipairs(files) do
        print(entry.name .. " (" .. entry.type .. ")")
    end
end

-- Create a directory structure
fs:mkdir("~/Documents/MyDir")

-- Check before overwriting
if fs:exists("~/Documents/important.txt") then
    print("File already exists!")
end

Direct Ramdisk Access

Apps with the "ramdisk" permission can bypass SafeFS and use low-level functions:

-- Only with "ramdisk" permission - bypasses all security!
local handle = CRamdiskOpen("/path/to/file", "r")
local content = CRamdiskRead(handle)
CRamdiskClose(handle)
Warning: Direct ramdisk access bypasses all security checks. Only use for system-level applications that require unrestricted access.