rumpk/core/fs/tar.nim

223 lines
6.1 KiB
Nim

# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: ROMFS (Static Tar Loader)
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# Rumpk L1: Sovereign VFS (Indexing TarFS)
{.push stackTrace: off, lineTrace: off.}
import std/tables
# Kernel Imports
proc kprint(s: cstring) {.importc, cdecl.}
proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint_hex(n: uint64) {.importc, cdecl.}
type
TarHeader* = array[512, byte]
FileEntry = object
offset*: uint64
size*: uint64
is_sfs*: bool
FileHandle = object
path*: string
offset*: uint64
is_sfs*: bool
is_ram*: bool
VFSInitRD* = object
start_addr*: uint64
end_addr*: uint64
index*: Table[string, FileEntry]
ram_data*: Table[string, seq[byte]]
fds*: Table[int, FileHandle]
next_fd*: int
var vfs*: VFSInitRD
proc vfs_init*(s: pointer, e: pointer) =
vfs.start_addr = cast[uint64](s)
vfs.end_addr = cast[uint64](e)
vfs.index = initTable[string, FileEntry]()
vfs.ram_data = initTable[string, seq[byte]]()
vfs.fds = initTable[int, FileHandle]()
vfs.next_fd = 3
# kprint("[VFS] InitRD Start: "); kprint_hex(vfs.start_addr); kprintln("")
# kprint("[VFS] InitRD End: "); kprint_hex(vfs.end_addr); kprintln("")
var p = vfs.start_addr
while p < vfs.end_addr:
let h = cast[ptr TarHeader](p)
if h[][0] == byte(0): break
# kprint("[VFS] Raw Header: ")
# for i in 0..15:
# kprint_hex(uint64(h[][i]))
# kprint(" ")
# kprintln("")
# Extract and normalize name directly from header
var name_len = 0
while name_len < 100 and h[][name_len] != 0:
inc name_len
var start_idx = 0
if name_len >= 2 and h[][0] == byte('.') and h[][1] == byte('/'):
start_idx = 2
elif name_len >= 1 and h[][0] == byte('/'):
start_idx = 1
let clean_len = name_len - start_idx
var clean = ""
if clean_len > 0:
clean = newString(clean_len)
# Copy directly from header memory
for i in 0..<clean_len:
clean[i] = char(h[][start_idx + i])
if clean.len > 0:
# Extract size (octal string)
var size: uint64 = 0
for i in 124..134:
let b = h[][i]
if b >= byte('0') and b <= byte('7'):
size = (size shl 3) or uint64(b - byte('0'))
vfs.index[clean] = FileEntry(offset: p + 512'u64, size: size, is_sfs: false)
# Move to next header
let padded_size = (size + 511'u64) and not 511'u64
p += 512'u64 + padded_size
else:
p += 512'u64 # Skip invalid/empty
proc vfs_open*(path: string, flags: int32 = 0): int =
var start_idx = 0
if path.len > 0 and path[0] == '/':
start_idx = 1
let clean_len = path.len - start_idx
var clean = ""
if clean_len > 0:
clean = newString(clean_len)
for i in 0..<clean_len:
clean[i] = path[start_idx + i]
# 1. Check RamFS
if vfs.ram_data.hasKey(clean):
let fd = vfs.next_fd
vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: false, is_ram: true)
vfs.next_fd += 1
return fd
# 2. Check TarFS
if vfs.index.hasKey(clean):
let entry = vfs.index[clean]
let fd = vfs.next_fd
vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: entry.is_sfs,
is_ram: false)
vfs.next_fd += 1
return fd
# 3. Create if O_CREAT (bit 6 in POSIX)
if (flags and 64) != 0:
vfs.ram_data[clean] = @[]
let fd = vfs.next_fd
vfs.fds[fd] = FileHandle(path: clean, offset: 0, is_sfs: false, is_ram: true)
vfs.next_fd += 1
return fd
return -1
proc vfs_read_file*(path: string): string =
var start_idx = 0
if path.len > 0 and path[0] == '/':
start_idx = 1
let clean_len = path.len - start_idx
var clean = ""
if clean_len > 0:
clean = newString(clean_len)
for i in 0..<clean_len:
clean[i] = path[start_idx + i]
if vfs.ram_data.hasKey(clean):
let data = vfs.ram_data[clean]
if data.len == 0: return ""
var s = newString(data.len)
copyMem(addr s[0], unsafeAddr data[0], data.len)
return s
if vfs.index.hasKey(clean):
let entry = vfs.index[clean]
if entry.is_sfs: return ""
var s = newString(int(entry.size))
if entry.size > 0:
copyMem(addr s[0], cast[pointer](entry.offset), int(entry.size))
return s
return ""
proc vfs_read_at*(path: string, buf: pointer, count: uint64, offset: uint64): int64 =
if vfs.ram_data.hasKey(path):
let data = addr vfs.ram_data[path]
if offset >= uint64(data[].len): return 0
let available = uint64(data[].len) - offset
let actual = min(count, available)
if actual > 0:
copyMem(buf, addr data[][int(offset)], int(actual))
return int64(actual)
if not vfs.index.hasKey(path): return -1
let entry = vfs.index[path]
if entry.is_sfs: return -1 # Routed via SFS
var actual = uint64(count)
if offset >= entry.size: return 0
if offset + count > entry.size:
actual = entry.size - offset
copyMem(buf, cast[pointer](entry.offset + offset), int(actual))
return int64(actual)
proc vfs_write_at*(path: string, buf: pointer, count: uint64, offset: uint64): int64 =
# Promote to RamFS if on TarFS (CoW)
if not vfs.ram_data.hasKey(path):
if vfs.index.hasKey(path):
let entry = vfs.index[path]
var content = newSeq[byte](int(entry.size))
if entry.size > 0:
copyMem(addr content[0], cast[pointer](entry.offset), int(entry.size))
vfs.ram_data[path] = content
else:
vfs.ram_data[path] = @[]
let data = addr vfs.ram_data[path]
let min_size = int(offset + count)
if data[].len < min_size:
data[].setLen(min_size)
copyMem(addr data[][int(offset)], buf, int(count))
return int64(count)
# Removed ion_vfs_* in favor of vfs.nim dispatcher
proc vfs_get_names*(): seq[string] =
var names = initTable[string, bool]()
for name, _ in vfs.index: names[name] = true
for name, _ in vfs.ram_data: names[name] = true
result = @[]
for name, _ in names: result.add(name)
proc vfs_register_sfs*(name: string, size: uint64) {.exportc, cdecl.} =
vfs.index[name] = FileEntry(offset: 0, size: size, is_sfs: true)
{.pop.}