rumpk/libs/membrane/fs/sfs_user.nim

249 lines
7.3 KiB
Nim

# Membrane SFS - Sovereign Filesystem (Userland Edition)
# Phase 37.2: The Glass Vault - Userland Architecture
#
# This is the CORRECT location for filesystem logic.
# Kernel is just a Block Valve - no FS logic there.
import ../blk
import ../libc
const
SFS_MAGIC* = 0x32534653'u32 # "SFS2" little endian
SEC_SB = 0'u64
SEC_BAM = 1'u64
SEC_DIR = 2'u64
CHUNK_SIZE = 508
EOF_MARKER = 0xFFFFFFFF'u32
DIR_ENTRY_SIZE = 64
MAX_FILENAME = 32
type
DirEntry* = object
filename*: array[32, char]
start_sector*: uint32
size_bytes*: uint32
reserved*: array[24, byte]
var sfs_mounted: bool = false
var io_buffer: array[512, byte]
proc print(s: cstring) =
discard libc.write(1, cast[pointer](s), csize_t(s.len))
proc print(s: string) =
if s.len > 0:
discard libc.write(1, cast[pointer](unsafeAddr s[0]), csize_t(s.len))
# =========================================================
# Helpers
# =========================================================
proc sfs_alloc_sector(): uint32 =
## Allocate a free sector using the Block Allocation Map
discard blk_read(SEC_BAM, addr io_buffer[0])
for i in 0..<512:
if io_buffer[i] != 0xFF:
for b in 0..7:
if (io_buffer[i] and byte(1 shl b)) == 0:
let sec = uint32(i * 8 + b)
# Mark as allocated
io_buffer[i] = io_buffer[i] or byte(1 shl b)
discard blk_write(SEC_BAM, addr io_buffer[0])
return sec
return 0 # Disk full
# =========================================================
# SFS API (Userland)
# =========================================================
proc sfs_mount*(): bool =
## Mount the SFS filesystem
print("[SFS-U] Mounting Userland Filesystem...\n")
discard blk_read(SEC_SB, addr io_buffer[0])
# Check magic: "SFS2"
if io_buffer[0] == byte('S') and io_buffer[1] == byte('F') and
io_buffer[2] == byte('S') and io_buffer[3] == byte('2'):
print("[SFS-U] Mount SUCCESS. Version 2 (Userland).\n")
sfs_mounted = true
return true
else:
print("[SFS-U] Mount FAILED. Invalid Magic.\n")
return false
proc sfs_is_mounted*(): bool = sfs_mounted
proc sfs_list*(): seq[string] =
## List all files in the filesystem
result = @[]
if not sfs_mounted: return
discard blk_read(SEC_DIR, addr io_buffer[0])
for offset in countup(0, 511, DIR_ENTRY_SIZE):
if io_buffer[offset] != 0:
var name = ""
for i in 0..<MAX_FILENAME:
let c = char(io_buffer[offset + i])
if c == '\0': break
name.add(c)
result.add(name)
proc get_vfs_listing*(): seq[string] =
return sfs_list()
proc sfs_write*(filename: string, data: pointer, data_len: int): int =
## Write a file to the filesystem
## Returns: bytes written or negative error
if not sfs_mounted: return -1
discard blk_read(SEC_DIR, addr io_buffer[0])
var dir_offset = -1
# Find existing file or free slot
for offset in countup(0, 511, DIR_ENTRY_SIZE):
if io_buffer[offset] != 0:
var entry_name = ""
for i in 0..<MAX_FILENAME:
if io_buffer[offset + i] == 0: break
entry_name.add(char(io_buffer[offset + i]))
if entry_name == filename:
dir_offset = offset
break
elif dir_offset == -1:
dir_offset = offset
if dir_offset == -1:
print("[SFS-U] Error: Directory Full.\n")
return -2
# Allocate first sector
var first_sector = sfs_alloc_sector()
if first_sector == 0:
print("[SFS-U] Error: Disk Full.\n")
return -3
# Write data in chunks
var remaining = data_len
var data_ptr = 0
var current_sector = first_sector
while remaining > 0:
var sector_buf: array[512, byte]
let chunk_size = if remaining > CHUNK_SIZE: CHUNK_SIZE else: remaining
copyMem(addr sector_buf[0],
cast[pointer](cast[int](data) + data_ptr),
chunk_size)
remaining -= chunk_size
data_ptr += chunk_size
# Determine next sector
var next_sector = EOF_MARKER
if remaining > 0:
next_sector = sfs_alloc_sector()
if next_sector == 0:
next_sector = EOF_MARKER
remaining = 0
# Write next pointer at end of sector
sector_buf[508] = byte(next_sector and 0xFF)
sector_buf[509] = byte((next_sector shr 8) and 0xFF)
sector_buf[510] = byte((next_sector shr 16) and 0xFF)
sector_buf[511] = byte((next_sector shr 24) and 0xFF)
discard blk_write(uint64(current_sector), addr sector_buf[0])
if next_sector == EOF_MARKER: break
current_sector = next_sector
# Update directory entry
discard blk_read(SEC_DIR, addr io_buffer[0])
for i in 0..<MAX_FILENAME:
if i < filename.len:
io_buffer[dir_offset + i] = byte(filename[i])
else:
io_buffer[dir_offset + i] = 0
io_buffer[dir_offset + 32] = byte(first_sector and 0xFF)
io_buffer[dir_offset + 33] = byte((first_sector shr 8) and 0xFF)
io_buffer[dir_offset + 34] = byte((first_sector shr 16) and 0xFF)
io_buffer[dir_offset + 35] = byte((first_sector shr 24) and 0xFF)
let sz = uint32(data_len)
io_buffer[dir_offset + 36] = byte(sz and 0xFF)
io_buffer[dir_offset + 37] = byte((sz shr 8) and 0xFF)
io_buffer[dir_offset + 38] = byte((sz shr 16) and 0xFF)
io_buffer[dir_offset + 39] = byte((sz shr 24) and 0xFF)
discard blk_write(SEC_DIR, addr io_buffer[0])
discard blk_sync()
print("[SFS-U] Write Complete: " & $data_len & " bytes.\n")
return data_len
proc sfs_read*(filename: string, dest: pointer, max_len: int): int =
## Read a file from the filesystem
## Returns: bytes read or negative error
if not sfs_mounted: return -1
discard blk_read(SEC_DIR, addr io_buffer[0])
var start_sector = 0'u32
var file_size = 0'u32
var found = false
for offset in countup(0, 511, DIR_ENTRY_SIZE):
if io_buffer[offset] != 0:
var entry_name = ""
for i in 0..<MAX_FILENAME:
if io_buffer[offset + i] == 0: break
entry_name.add(char(io_buffer[offset + i]))
if entry_name == filename:
start_sector = uint32(io_buffer[offset + 32]) or
(uint32(io_buffer[offset + 33]) shl 8) or
(uint32(io_buffer[offset + 34]) shl 16) or
(uint32(io_buffer[offset + 35]) shl 24)
file_size = uint32(io_buffer[offset + 36]) or
(uint32(io_buffer[offset + 37]) shl 8) or
(uint32(io_buffer[offset + 38]) shl 16) or
(uint32(io_buffer[offset + 39]) shl 24)
found = true
break
if not found: return -1
# Read chain
var current_sector = start_sector
var dest_addr = cast[int](dest)
var remaining = int(file_size)
if remaining > max_len: remaining = max_len
var total_read = 0
while remaining > 0 and current_sector != EOF_MARKER and current_sector != 0:
var sector_buf: array[512, byte]
discard blk_read(uint64(current_sector), addr sector_buf[0])
let payload_size = min(remaining, CHUNK_SIZE)
copyMem(cast[pointer](dest_addr), addr sector_buf[0], payload_size)
dest_addr += payload_size
remaining -= payload_size
total_read += payload_size
# Next sector pointer
current_sector = uint32(sector_buf[508]) or
(uint32(sector_buf[509]) shl 8) or
(uint32(sector_buf[510]) shl 16) or
(uint32(sector_buf[511]) shl 24)
return total_read