update memory
Написал алгоритм сжатия совместимый с UTF-8. Не очень эффективный, экономит 10-15% на тексте. Добавил генератор стартовой памяти, убран хардкод из MMC
This commit is contained in:
439
atlas_os/MMC.lua
439
atlas_os/MMC.lua
@@ -9,6 +9,169 @@ local SEG_SIZE = 8192
|
|||||||
local MAX_INODES = 64
|
local MAX_INODES = 64
|
||||||
local ROOT_INO = 1
|
local ROOT_INO = 1
|
||||||
|
|
||||||
|
local _unpack = table.unpack or unpack
|
||||||
|
|
||||||
|
-- === LZ4 compression (pure Lua) ===
|
||||||
|
|
||||||
|
function lz4Compress(data)
|
||||||
|
local n = #data
|
||||||
|
if n == 0 then return "" end
|
||||||
|
local ht, res, ip, anchor = {}, {}, 1, 1
|
||||||
|
local hashSize = 4096
|
||||||
|
local function hash4(p)
|
||||||
|
return (((data:byte(p) * 256 + data:byte(p + 1)) * 256 + data:byte(p + 2)) * 256 + data:byte(p + 3)) % hashSize
|
||||||
|
end
|
||||||
|
while ip + 3 <= n do
|
||||||
|
local h = hash4(ip)
|
||||||
|
local ref = ht[h]
|
||||||
|
ht[h] = ip
|
||||||
|
if ref and ip - ref <= 65535 and data:byte(ref) == data:byte(ip)
|
||||||
|
and data:byte(ref + 1) == data:byte(ip + 1)
|
||||||
|
and data:byte(ref + 2) == data:byte(ip + 2)
|
||||||
|
and data:byte(ref + 3) == data:byte(ip + 3) then
|
||||||
|
local ml = 4
|
||||||
|
while ip + ml <= n and data:byte(ref + ml) == data:byte(ip + ml) do ml = ml + 1 end
|
||||||
|
local litLen = ip - anchor
|
||||||
|
local matchLen = ml - 4
|
||||||
|
local tokLit = litLen < 15 and litLen or 15
|
||||||
|
local tokMatch = matchLen < 15 and matchLen or 15
|
||||||
|
res[#res + 1] = string.char(tokLit * 16 + tokMatch)
|
||||||
|
if litLen >= 15 then
|
||||||
|
local e = litLen - 15
|
||||||
|
while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end
|
||||||
|
res[#res + 1] = string.char(e)
|
||||||
|
end
|
||||||
|
if litLen > 0 then res[#res + 1] = data:sub(anchor, ip - 1) end
|
||||||
|
local off = ip - ref
|
||||||
|
res[#res + 1] = string.char(off % 256)
|
||||||
|
res[#res + 1] = string.char(math.floor(off / 256))
|
||||||
|
if matchLen >= 15 then
|
||||||
|
local e = matchLen - 15
|
||||||
|
while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end
|
||||||
|
res[#res + 1] = string.char(e)
|
||||||
|
end
|
||||||
|
ip = ip + ml
|
||||||
|
anchor = ip
|
||||||
|
else
|
||||||
|
ip = ip + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local last = n - anchor + 1
|
||||||
|
if last > 0 then
|
||||||
|
local tokLit = last < 15 and last or 15
|
||||||
|
res[#res + 1] = string.char(tokLit * 16)
|
||||||
|
if last >= 15 then
|
||||||
|
local e = last - 15
|
||||||
|
while e >= 255 do res[#res + 1] = string.char(255); e = e - 255 end
|
||||||
|
res[#res + 1] = string.char(e)
|
||||||
|
end
|
||||||
|
res[#res + 1] = data:sub(anchor, n)
|
||||||
|
end
|
||||||
|
return table.concat(res)
|
||||||
|
end
|
||||||
|
|
||||||
|
function lz4Decompress(compressed)
|
||||||
|
local pos, out, oi = 1, {}, 1
|
||||||
|
local n = #compressed
|
||||||
|
while pos <= n do
|
||||||
|
local token = compressed:byte(pos); pos = pos + 1
|
||||||
|
local litLen = math.floor(token / 16)
|
||||||
|
if litLen == 15 then
|
||||||
|
local s
|
||||||
|
repeat s = compressed:byte(pos); pos = pos + 1; litLen = litLen + s until s < 255
|
||||||
|
end
|
||||||
|
for _ = 1, litLen do out[oi] = compressed:byte(pos); oi = oi + 1; pos = pos + 1 end
|
||||||
|
if pos > n then break end
|
||||||
|
local off = compressed:byte(pos) + compressed:byte(pos + 1) * 256; pos = pos + 2
|
||||||
|
local matchLen = (token % 16) + 4
|
||||||
|
if matchLen == 19 then
|
||||||
|
local s
|
||||||
|
repeat s = compressed:byte(pos); pos = pos + 1; matchLen = matchLen + s until s < 255
|
||||||
|
end
|
||||||
|
local mp = oi - off
|
||||||
|
for _ = 1, matchLen do out[oi] = out[mp]; oi = oi + 1; mp = mp + 1 end
|
||||||
|
end
|
||||||
|
return string.char(_unpack(out))
|
||||||
|
end
|
||||||
|
|
||||||
|
local b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
local b64dec = {}
|
||||||
|
for i = 1, 64 do b64dec[b64:sub(i, i)] = i - 1 end
|
||||||
|
|
||||||
|
function encode(s)
|
||||||
|
local out, i, n = {}, 1, #s
|
||||||
|
while i <= n do
|
||||||
|
local a, b, c = s:byte(i), s:byte(i + 1), s:byte(i + 2)
|
||||||
|
out[#out + 1] = b64:sub(math.floor(a / 4) + 1, math.floor(a / 4) + 1)
|
||||||
|
out[#out + 1] = b64:sub((a % 4) * 16 + math.floor((b or 0) / 16) + 1, (a % 4) * 16 + math.floor((b or 0) / 16) + 1)
|
||||||
|
if i + 1 > n then
|
||||||
|
out[#out + 1] = "="
|
||||||
|
else
|
||||||
|
out[#out + 1] = b64:sub(((b or 0) % 16) * 4 + math.floor((c or 0) / 64) + 1, ((b or 0) % 16) * 4 + math.floor((c or 0) / 64) + 1)
|
||||||
|
end
|
||||||
|
if i + 2 > n then
|
||||||
|
out[#out + 1] = "="
|
||||||
|
else
|
||||||
|
out[#out + 1] = b64:sub(((c or 0) % 64) + 1, ((c or 0) % 64) + 1)
|
||||||
|
end
|
||||||
|
i = i + 3
|
||||||
|
end
|
||||||
|
return table.concat(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
function decode(str)
|
||||||
|
local out, i, n = {}, 1, #str
|
||||||
|
while i <= n and str:sub(i, i) ~= "=" do
|
||||||
|
local a = b64dec[str:sub(i, i)] or 0
|
||||||
|
local b = b64dec[str:sub(i + 1, i + 1)] or 0
|
||||||
|
local c = b64dec[str:sub(i + 2, i + 2)] or 0
|
||||||
|
local d = b64dec[str:sub(i + 3, i + 3)] or 0
|
||||||
|
out[#out + 1] = string.char(a * 4 + math.floor(b / 16))
|
||||||
|
if str:sub(i + 2, i + 2) ~= "=" then
|
||||||
|
out[#out + 1] = string.char((b % 16) * 16 + math.floor(c / 4))
|
||||||
|
end
|
||||||
|
if str:sub(i + 3, i + 3) ~= "=" then
|
||||||
|
out[#out + 1] = string.char((c % 4) * 64 + d)
|
||||||
|
end
|
||||||
|
i = i + 4
|
||||||
|
end
|
||||||
|
return table.concat(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function escRaw(s)
|
||||||
|
s = s:gsub("\x01", "\x01\x01")
|
||||||
|
s = s:gsub("\n", "\x01n")
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unescRaw(s)
|
||||||
|
local out, i, n = {}, 1, #s
|
||||||
|
while i <= n do
|
||||||
|
local b = s:byte(i)
|
||||||
|
if b == 1 then
|
||||||
|
i = i + 1
|
||||||
|
out[#out + 1] = s:byte(i) == 1 and "\x01" or "\n"
|
||||||
|
else
|
||||||
|
out[#out + 1] = s:sub(i, i)
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return table.concat(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
function compressStr(s)
|
||||||
|
local lz = encode(lz4Compress(s))
|
||||||
|
if #lz < #s then return lz end
|
||||||
|
return "\x01" .. escRaw(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
function decompressStr(c)
|
||||||
|
if c:byte(1) == 1 then return unescRaw(c:sub(2)) end
|
||||||
|
return lz4Decompress(decode(c))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ================================
|
||||||
|
|
||||||
local function parseMsg(msg)
|
local function parseMsg(msg)
|
||||||
local p = msg:find("|")
|
local p = msg:find("|")
|
||||||
return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil
|
return p and msg:sub(1, p - 1) or msg, p and msg:sub(p + 1) or nil
|
||||||
@@ -29,7 +192,7 @@ local files = {}
|
|||||||
local users = {}
|
local users = {}
|
||||||
local sb = { seg_size = SEG_SIZE, max_inodes = MAX_INODES, root_ino = ROOT_INO }
|
local sb = { seg_size = SEG_SIZE, max_inodes = MAX_INODES, root_ino = ROOT_INO }
|
||||||
|
|
||||||
local function fsSerialize()
|
function fsSerialize()
|
||||||
local lines = {}
|
local lines = {}
|
||||||
lines[#lines + 1] = "V|1"
|
lines[#lines + 1] = "V|1"
|
||||||
lines[#lines + 1] = "S|" .. sb.seg_size .. "|" .. sb.max_inodes .. "|" .. sb.root_ino
|
lines[#lines + 1] = "S|" .. sb.seg_size .. "|" .. sb.max_inodes .. "|" .. sb.root_ino
|
||||||
@@ -47,7 +210,7 @@ local function fsSerialize()
|
|||||||
end
|
end
|
||||||
lines[#lines + 1] = "D|" .. ino.ino .. "|" .. table.concat(entries, "|")
|
lines[#lines + 1] = "D|" .. ino.ino .. "|" .. table.concat(entries, "|")
|
||||||
elseif ino.typ == "f" and files[ino.ino] then
|
elseif ino.typ == "f" and files[ino.ino] then
|
||||||
lines[#lines + 1] = "F|" .. ino.ino .. "|" .. files[ino.ino]
|
lines[#lines + 1] = "Z|" .. ino.ino .. "|" .. files[ino.ino]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -96,15 +259,15 @@ local function fsDeserialize(str)
|
|||||||
end
|
end
|
||||||
dirs[ino] = entries
|
dirs[ino] = entries
|
||||||
end
|
end
|
||||||
elseif typ == "F" then
|
elseif typ == "Z" then
|
||||||
local parts = split(rest, "|")
|
local parts = split(rest, "|")
|
||||||
if #parts >= 2 then
|
if #parts >= 2 then
|
||||||
local ino = tonumber(parts[1])
|
local ino = tonumber(parts[1])
|
||||||
local content = parts[2] or ""
|
local b64 = parts[2] or ""
|
||||||
for i = 3, #parts do
|
for i = 3, #parts do
|
||||||
content = content .. "|" .. parts[i]
|
b64 = b64 .. "|" .. parts[i]
|
||||||
end
|
end
|
||||||
files[ino] = content
|
files[ino] = b64
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -161,8 +324,8 @@ local function processReq(req)
|
|||||||
local ino = findInodeByPath(path)
|
local ino = findInodeByPath(path)
|
||||||
if not ino then return "ERR|" .. seqStr .. "ENOENT" end
|
if not ino then return "ERR|" .. seqStr .. "ENOENT" end
|
||||||
if ino.typ ~= "f" then return "ERR|" .. seqStr .. "EISDIR" end
|
if ino.typ ~= "f" then return "ERR|" .. seqStr .. "EISDIR" end
|
||||||
local content = files[ino.ino] or ""
|
local raw = decompressStr(files[ino.ino]) or ""
|
||||||
local data = content:sub(offset + 1, offset + len)
|
local data = raw:sub(offset + 1, offset + len)
|
||||||
return "OK|" .. seqStr .. data
|
return "OK|" .. seqStr .. data
|
||||||
|
|
||||||
elseif op == "LS" then
|
elseif op == "LS" then
|
||||||
@@ -197,187 +360,110 @@ local function processReq(req)
|
|||||||
return "ERR|" .. seqStr .. "EINVAL"
|
return "ERR|" .. seqStr .. "EINVAL"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function defaultFS()
|
-- Exported FS API for external tools (generators, tests)
|
||||||
|
FS = {}
|
||||||
|
|
||||||
|
function FS.init()
|
||||||
inodes = {}
|
inodes = {}
|
||||||
dirs = {}
|
dirs = {}
|
||||||
files = {}
|
files = {}
|
||||||
users = {}
|
users = {}
|
||||||
|
sb = { seg_size = SEG_SIZE, max_inodes = MAX_INODES, root_ino = ROOT_INO }
|
||||||
|
inodes[1] = { ino = 1, typ = "d", mode = "755", uid = 0, gid = 0, size = 0, mtime = 0 }
|
||||||
|
dirs[1] = { { name = ".", ino = 1 }, { name = "..", ino = 1 } }
|
||||||
|
end
|
||||||
|
|
||||||
users[0] = { uid = 0, name = "root", gid = 0, home = "/", hash = "-" }
|
function FS.addUser(uid, name, gid, home, hash)
|
||||||
users[100] = { uid = 100, name = "captain", gid = 10, home = "/home/captain", hash = "-" }
|
users[uid] = { uid = uid, name = name, gid = gid, home = home, hash = hash or "-" }
|
||||||
|
end
|
||||||
|
|
||||||
local function mkIno(num, typ, mode, uid, gid, size)
|
function FS.resolve(path)
|
||||||
inodes[num] = { ino = num, typ = typ, mode = mode, uid = uid, gid = gid, size = size or 0, mtime = 0 }
|
return findInodeByPath(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
function FS.serialize()
|
||||||
|
return fsSerialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
function FS.deserialize(str)
|
||||||
|
return fsDeserialize(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
function FS.mkdir(path, mode, uid, gid)
|
||||||
|
local parentPath, name = path:match("^(.*)/([^/]+)$")
|
||||||
|
if not name then
|
||||||
|
parentPath, name = "/", path:match("^/?(.+)$") or path
|
||||||
end
|
end
|
||||||
|
local parent = findInodeByPath(parentPath)
|
||||||
local function mkDir(num, entries)
|
if not parent then return nil, "parent not found" end
|
||||||
dirs[num] = entries
|
if parent.typ ~= "d" then return nil, "not a directory" end
|
||||||
|
local ino
|
||||||
|
for i = 1, MAX_INODES do
|
||||||
|
if not inodes[i] then ino = i; break end
|
||||||
end
|
end
|
||||||
|
if not ino then return nil, "no free inodes" end
|
||||||
|
inodes[ino] = { ino = ino, typ = "d", mode = mode or "755", uid = uid or 0, gid = gid or 0, size = 0, mtime = 0 }
|
||||||
|
dirs[ino] = { { name = ".", ino = ino }, { name = "..", ino = parent.ino } }
|
||||||
|
table.insert(dirs[parent.ino], { name = name, ino = ino })
|
||||||
|
return ino
|
||||||
|
end
|
||||||
|
|
||||||
local function mkFile(num, content)
|
function FS.mkfile(path, content, mode, uid, gid)
|
||||||
files[num] = content or ""
|
local parentPath, name = path:match("^(.*)/([^/]+)$")
|
||||||
local sz = #(content or "")
|
if not name then
|
||||||
if inodes[num] then inodes[num].size = sz end
|
parentPath, name = "/", path:match("^/?(.+)$") or path
|
||||||
end
|
end
|
||||||
|
local parent = findInodeByPath(parentPath)
|
||||||
|
if not parent then return nil, "parent not found" end
|
||||||
|
if parent.typ ~= "d" then return nil, "not a directory" end
|
||||||
|
local ino
|
||||||
|
for i = 1, MAX_INODES do
|
||||||
|
if not inodes[i] then ino = i; break end
|
||||||
|
end
|
||||||
|
if not ino then return nil, "no free inodes" end
|
||||||
|
content = content or ""
|
||||||
|
inodes[ino] = { ino = ino, typ = "f", mode = mode or "644", uid = uid or 0, gid = gid or 0, size = #content, mtime = 0 }
|
||||||
|
files[ino] = compressStr(content)
|
||||||
|
table.insert(dirs[parent.ino], { name = name, ino = ino })
|
||||||
|
return ino
|
||||||
|
end
|
||||||
|
|
||||||
mkIno(1, "d", "755", 0, 0, 0)
|
function FS.write(path, content)
|
||||||
mkDir(1, { { name = ".", ino = 1 }, { name = "..", ino = 1 }, { name = "home", ino = 2 }, { name = "etc", ino = 4 } })
|
local ino = findInodeByPath(path)
|
||||||
|
if not ino then return nil, "not found" end
|
||||||
|
if ino.typ ~= "f" then return nil, "not a file" end
|
||||||
|
content = content or ""
|
||||||
|
files[ino.ino] = compressStr(content)
|
||||||
|
inodes[ino.ino].size = #content
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
mkIno(2, "d", "755", 0, 0, 0)
|
function FS.read(path)
|
||||||
mkDir(2, { { name = ".", ino = 2 }, { name = "..", ino = 1 }, { name = "captain", ino = 5 } })
|
local ino = findInodeByPath(path)
|
||||||
|
if not ino then return nil, "not found" end
|
||||||
|
if ino.typ ~= "f" then return nil, "not a file" end
|
||||||
|
return decompressStr(files[ino.ino])
|
||||||
|
end
|
||||||
|
|
||||||
mkIno(5, "d", "700", 100, 10, 0)
|
function FS.ls(path)
|
||||||
mkDir(5, { { name = ".", ino = 5 }, { name = "..", ino = 2 }, { name = "readme.txt", ino = 3 } })
|
local ino = findInodeByPath(path or "/")
|
||||||
|
if not ino then return nil, "not found" end
|
||||||
|
if ino.typ ~= "d" then return nil, "not a directory" end
|
||||||
|
local result = {}
|
||||||
|
for _, e in ipairs(dirs[ino.ino]) do
|
||||||
|
result[#result + 1] = e.name
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
mkIno(3, "f", "644", 100, 10, 0)
|
function FS.stat(path)
|
||||||
mkFile(3, "Welcome to AtlasOS v2.0!\n")
|
local ino = findInodeByPath(path)
|
||||||
|
if not ino then return nil, "not found" end
|
||||||
mkIno(4, "d", "755", 0, 0, 0)
|
local result = {}
|
||||||
mkDir(4, { { name = ".", ino = 4 }, { name = "..", ino = 1 }, { name = "man", ino = 6 } })
|
for k, v in pairs(ino) do
|
||||||
|
result[k] = v
|
||||||
mkIno(6, "d", "755", 0, 0, 0)
|
end
|
||||||
mkDir(6, {
|
return result
|
||||||
{ name = ".", ino = 6 }, { name = "..", ino = 4 },
|
|
||||||
{ name = "help", ino = 7 }, { name = "echo", ino = 8 },
|
|
||||||
{ name = "clear", ino = 9 }, { name = "color", ino = 10 },
|
|
||||||
{ name = "status", ino = 11 }, { name = "ls", ino = 12 },
|
|
||||||
{ name = "cat", ino = 13 }, { name = "cd", ino = 14 },
|
|
||||||
{ name = "stat", ino = 15 }, { name = "man", ino = 16 },
|
|
||||||
})
|
|
||||||
|
|
||||||
mkIno(7, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(7, [[NAME
|
|
||||||
help - display help information
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
help
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Show a list of all available commands with their usage
|
|
||||||
and description.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(8, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(8, [[NAME
|
|
||||||
echo - display a line of text
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
echo <text>
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Write the given text to the terminal output.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(9, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(9, [[NAME
|
|
||||||
clear - clear the terminal screen
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
clear
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Clear all text from the terminal display.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(10, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(10, [[NAME
|
|
||||||
color - set terminal text color
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
color <R> <G> <B>
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Change the text color for subsequent output.
|
|
||||||
Each value must be 0-255 (red, green, blue).
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(11, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(11, [[NAME
|
|
||||||
status - show system status
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
status
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Display system information including current user,
|
|
||||||
working directory, and memory usage.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(12, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(12, [[NAME
|
|
||||||
ls - list directory contents
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
ls [-la] [path]
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
List contents of a directory. If no path is given,
|
|
||||||
list the current directory.
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-a Include hidden entries (. and ..)
|
|
||||||
-l Long format (detailed listing)
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(13, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(13, [[NAME
|
|
||||||
cat - concatenate and display files
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
cat <path>
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Read a file and display its contents on the terminal.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(14, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(14, [[NAME
|
|
||||||
cd - change the working directory
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
cd [path]
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Change the current working directory. If no path
|
|
||||||
is given, go to root (/). Supports both absolute
|
|
||||||
and relative paths.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(15, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(15, [[NAME
|
|
||||||
stat - show file metadata
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
stat <path>
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Display metadata for a file or directory, including
|
|
||||||
inode number, type, permissions, owner, group, size,
|
|
||||||
and modification time.
|
|
||||||
]])
|
|
||||||
|
|
||||||
mkIno(16, "f", "644", 0, 0, 0)
|
|
||||||
mkFile(16, [[NAME
|
|
||||||
man - display manual page
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
man <command>
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Display the manual page for a command. Manual pages
|
|
||||||
are stored in /etc/man/.
|
|
||||||
|
|
||||||
EXAMPLE
|
|
||||||
man ls
|
|
||||||
man cat
|
|
||||||
|
|
||||||
SEE ALSO
|
|
||||||
help
|
|
||||||
]])
|
|
||||||
|
|
||||||
local str = fsSerialize()
|
|
||||||
out[5] = str
|
|
||||||
out[6] = 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local fsLoaded = false
|
local fsLoaded = false
|
||||||
@@ -393,7 +479,8 @@ function upd()
|
|||||||
fsLoaded = true
|
fsLoaded = true
|
||||||
else
|
else
|
||||||
fsLoaded = true
|
fsLoaded = true
|
||||||
defaultFS()
|
FS.init()
|
||||||
|
FS.addUser(0, "root", 0, "/", "-")
|
||||||
writePending = true
|
writePending = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
211
atlas_os/tools/example.txt
Normal file
211
atlas_os/tools/example.txt
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
Это читайте, мужик молодец
|
||||||
|
|
||||||
|
Добро пожаловать в официальный перевод полного руководства по Neurotrauma!
|
||||||
|
|
||||||
|
Если в данный момент вы находитесь в экстренной медицинской ситуации и рядом нет медицинских работников, немедленно перейдите в раздел первой помощи.
|
||||||
|
|
||||||
|
Если вы испытываете беспокойство или необычные симптомы, немедленно обратитесь к ближайшему медицинскому специалисту.
|
||||||
|
|
||||||
|
Помните! Всегда носите шлем!
|
||||||
|
|
||||||
|
Понимание того, как функционирует человеческий организм - или как в нем происходят сбои - может занять некоторое время.
|
||||||
|
Цель этого руководства - предоставить начинающим врачам важнейшую информацию, пока они не накопят достаточно опыта.
|
||||||
|
|
||||||
|
Врачи всегда должны иметь при себе медицинский сканер - вы не узнаете, что именно вызывает все симптомы у вашего пациента, пока не просканируете его (или не будете обладать обширными знаниями)!
|
||||||
|
|
||||||
|
Упаковываем аптечку первой помощи
|
||||||
|
Аптечка первой помощи для экспедиции
|
||||||
|
должна содержать следующее (более подходящие вещи находятся слева):
|
||||||
|
|
||||||
|
Эластичный бинт или обычный
|
||||||
|
Шовный материал
|
||||||
|
По крайне мере 1 жгут
|
||||||
|
Пакет с кровью (предпочтительно O-), Раствор Рингера, физраствор или адреналин
|
||||||
|
Каликсанид
|
||||||
|
Антипарализант
|
||||||
|
|
||||||
|
Рекомендуется также взять с собой в экспедицию следующее:
|
||||||
|
|
||||||
|
Полностью укомплектованный хирургический набор -> более подробно в 13: Хирургические процедуры и вы
|
||||||
|
Эндоваскулярный баллон
|
||||||
|
Медицинский стент
|
||||||
|
Гипс
|
||||||
|
|
||||||
|
Эти предметы могут спасти жизнь пациента при катастрофическом не перекрывающемся кровотечении из шеи или аорты, требующем немедленного хирургического вмешательства.
|
||||||
|
|
||||||
|
Аптечка первой помощи при несчастных случаях на подлодке
|
||||||
|
должна содержать следующее (более подходящие вещи находятся слева):
|
||||||
|
|
||||||
|
Эластичный бинт или обычный
|
||||||
|
Шовный материал
|
||||||
|
По крайне мере 1 жгут
|
||||||
|
Пакет с кровью (предпочтительно O-), Раствор Рингера, физраствор или адреналин
|
||||||
|
Дефибриллятор
|
||||||
|
Гипс
|
||||||
|
|
||||||
|
Мод Neurotrauma: 1:Оказание первой помощи
|
||||||
|
Непосредственные опасности
|
||||||
|
отсортированы от наиболее до наименее серьезных
|
||||||
|
|
||||||
|
Разрыв аорты
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
|
||||||
|
Опиоид
|
||||||
|
Скальпель
|
||||||
|
Эндоваскулярный баллон
|
||||||
|
Медицинский стент
|
||||||
|
Шовный материал
|
||||||
|
|
||||||
|
Опиоид
|
||||||
|
Скальпель
|
||||||
|
Эндоваскулярный баллон
|
||||||
|
Медицинский стент
|
||||||
|
Шовный материал
|
||||||
|
|
||||||
|
Мрачный
|
||||||
|
|
||||||
|
Кровотечение из сонной артерии
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Операция
|
||||||
|
Операция
|
||||||
|
Мрачный
|
||||||
|
|
||||||
|
В огне
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Огнетушитель, вода или любой водолазный костюм
|
||||||
|
См. ожог
|
||||||
|
Зависит от того, как долго пациент горел
|
||||||
|
|
||||||
|
Артериальное кровотечение
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Жгут
|
||||||
|
Операция
|
||||||
|
Тревожный
|
||||||
|
|
||||||
|
Остановка сердца
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
СЛР или дефибриллятор
|
||||||
|
СЛР или дефибриллятор
|
||||||
|
Данная болезнь является признаком чего-то худшего
|
||||||
|
|
||||||
|
Остановка дыхания
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
СЛР
|
||||||
|
СЛР
|
||||||
|
Данная болезнь является признаком чего-то худшего
|
||||||
|
|
||||||
|
Припадок
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Удаление из небезопасной среды
|
||||||
|
Лечение первопричин
|
||||||
|
Данная болезнь является признаком чего-то худшего
|
||||||
|
|
||||||
|
Рвота кровью
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Внутривенные жидкости
|
||||||
|
Операция
|
||||||
|
Данная болезнь является признаком чего-то худшего
|
||||||
|
|
||||||
|
Переломы
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Бинт + гипс
|
||||||
|
Остеосинтетическая операция
|
||||||
|
Выживите
|
||||||
|
|
||||||
|
Ожоги
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Эластичный бинт или обычный
|
||||||
|
Эластичный бинт или обычный, антибиотическая мазь в тяжёлых случаях
|
||||||
|
Частый источник заражения
|
||||||
|
|
||||||
|
Раны (укусы, огнестрельные раны, рваные раны)
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Шовный материал
|
||||||
|
Шовный материал
|
||||||
|
Потенциальный источник заражения
|
||||||
|
|
||||||
|
Вывихи
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Эластичный бинт или обычный
|
||||||
|
Удары гаечным ключом (используйте в качестве лечения, как бинт)
|
||||||
|
(сначала нужно ввести опиаты)
|
||||||
|
Мучительная боль
|
||||||
|
|
||||||
|
Травма от удара тупым предметом
|
||||||
|
Оказание первой помощи
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Эластичный бинт или обычный
|
||||||
|
Операция с полустерильными плоскогубцами
|
||||||
|
Не проходит без первой помощи или лечения
|
||||||
|
|
||||||
|
После оказания себе первой помощи обратитесь к врачу, как только сможете
|
||||||
|
Мод Neurotrauma: 2:Симптомы и причины
|
||||||
|
В ПРОЦЕССЕ ДОРАБОТКИ!!!
|
||||||
|
|
||||||
|
В приведенной выше таблице вы можете найти симптом, который у вас может быть или вам интересно узнать, и посетить соответствующую главу данного руководства.
|
||||||
|
Мод Neurotrauma: 3: Мозг
|
||||||
|
Состояния и симптомы заболеваний головного мозга
|
||||||
|
отсортированы от наиболее до наименее тяжелых
|
||||||
|
|
||||||
|
Нейротравма
|
||||||
|
Первая помощь
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Вызвано
|
||||||
|
Вызывает
|
||||||
|
Отсутствует
|
||||||
|
Маннитол (требуется длительное время)
|
||||||
|
Главный антагонист. Вызвано низким притоком кислорода к мозгу. Непременная смерть при длительном кислородном голодании.
|
||||||
|
Гипоксемия, инсульт
|
||||||
|
Потеря сознания, остановка дыхания, смерть
|
||||||
|
|
||||||
|
Инсульт(в оф. переводе мода "удар")
|
||||||
|
Первая помощь
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Вызвано
|
||||||
|
Вызывает
|
||||||
|
Отсутствует
|
||||||
|
Операция
|
||||||
|
Инсульт следует лечить как можно скорее, чтобы свести к минимуму риск смерти.
|
||||||
|
Гипертония
|
||||||
|
Нейротравма, кома, судороги, боль, головная боль
|
||||||
|
|
||||||
|
Кома
|
||||||
|
Первая помощь
|
||||||
|
Лечение
|
||||||
|
Прогноз
|
||||||
|
Вызвано
|
||||||
|
Вызывает
|
||||||
|
Отсутствует
|
||||||
|
Авто пульс и много времени
|
||||||
|
Основные причины следует лечить как можно скорее, иначе пациент может впасть в стойкое вегетативное состояние.
|
||||||
|
Остановка сердца, инсульт, ацидоз
|
||||||
|
Остановка сердца, остановка дыхания, потеря сознания
|
||||||
|
|
||||||
|
Рвота кровью
|
||||||
140
atlas_os/tools/generate_init_fs.lua
Normal file
140
atlas_os/tools/generate_init_fs.lua
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
-- generate_init_fs.lua
|
||||||
|
-- Генерирует начальный образ SEG0 с man-страницами в /etc/man/
|
||||||
|
-- Использует экспортированное FS API из MMC.lua
|
||||||
|
-- Запуск: lua tools/generate_init_fs.lua > tools/init.amem
|
||||||
|
|
||||||
|
local base = arg and arg[0] and arg[0]:match("(.+)/") or "."
|
||||||
|
dofile(base .. "/../MMC.lua")
|
||||||
|
|
||||||
|
FS.init()
|
||||||
|
|
||||||
|
FS.addUser(0, "root", 0, "/", "-")
|
||||||
|
FS.addUser(100, "captain", 10, "/home/captain", "-")
|
||||||
|
|
||||||
|
FS.mkdir("/home", "755", 0, 0)
|
||||||
|
FS.mkdir("/home/captain", "700", 100, 10)
|
||||||
|
FS.mkfile("/home/captain/readme.txt", "Welcome to AtlasOS v2.0!\n", "644", 100, 10)
|
||||||
|
FS.mkdir("/etc", "755", 0, 0)
|
||||||
|
FS.mkdir("/etc/man", "755", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/help", [[NAME
|
||||||
|
help - display help information
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
help
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Show a list of all available commands with their usage
|
||||||
|
and description.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/echo", [[NAME
|
||||||
|
echo - display a line of text
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
echo <text>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Write the given text to the terminal output.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/clear", [[NAME
|
||||||
|
clear - clear the terminal screen
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
clear
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Clear all text from the terminal display.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/color", [[NAME
|
||||||
|
color - set terminal text color
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
color <R> <G> <B>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Change the text color for subsequent output.
|
||||||
|
Each value must be 0-255 (red, green, blue).
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/status", [[NAME
|
||||||
|
status - show system status
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
status
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Display system information including current user,
|
||||||
|
working directory, and memory usage.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/ls", [[NAME
|
||||||
|
ls - list directory contents
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
ls [-la] [path]
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
List contents of a directory. If no path is given,
|
||||||
|
list the current directory.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-a Include hidden entries (. and ..)
|
||||||
|
-l Long format (detailed listing)
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/cat", [[NAME
|
||||||
|
cat - concatenate and display files
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
cat <path>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Read a file and display its contents on the terminal.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/cd", [[NAME
|
||||||
|
cd - change the working directory
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
cd [path]
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Change the current working directory. If no path
|
||||||
|
is given, go to root (/). Supports both absolute
|
||||||
|
and relative paths.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/stat", [[NAME
|
||||||
|
stat - show file metadata
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
stat <path>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Display metadata for a file or directory, including
|
||||||
|
inode number, type, permissions, owner, group, size,
|
||||||
|
and modification time.
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
FS.mkfile("/etc/man/man", [[NAME
|
||||||
|
man - display manual page
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
man <command>
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Display the manual page for a command. Manual pages
|
||||||
|
are stored in /etc/man/.
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
man ls
|
||||||
|
man cat
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
help
|
||||||
|
]], "644", 0, 0)
|
||||||
|
|
||||||
|
print(FS.serialize())
|
||||||
6
atlas_os/tools/make_init_memory.sh
Executable file
6
atlas_os/tools/make_init_memory.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# make_init_memory.sh
|
||||||
|
# Генерирует стартовый образ памяти SEG0 и сохраняет в init.amem
|
||||||
|
|
||||||
|
lua generate_init_fs.lua > init.amem
|
||||||
|
echo "init.amem создан ($(wc -c < init.amem) байт)"
|
||||||
Reference in New Issue
Block a user