diff --git a/Src/Hyperion-bash/bin/hysh b/Src/Hyperion-bash/bin/hysh index 0e1b051..4e0d50d 100644 --- a/Src/Hyperion-bash/bin/hysh +++ b/Src/Hyperion-bash/bin/hysh @@ -810,6 +810,160 @@ builtinCmds.df = function(...) end end +local function listDir(dir, prefix) + local ok, entries = pcall(syscall.listdir, dir) + if not ok or not entries then return {} end + local results = {} + for _, e in ipairs(entries) do + if prefix == "" or e:sub(1, #prefix) == prefix then + local fullpath = (dir == "/" and "/" or dir.."/")..e + local t = syscall.type(fullpath) + results[#results+1] = t == "directory" and (e.."/") or e + end + end + table.sort(results) + return results +end + +local function listCommands(prefix) + local results = {} + local seen = {} + for name in pairs(builtinCmds) do + if prefix == "" or name:sub(1, #prefix) == prefix then + if not seen[name] then results[#results+1] = name; seen[name] = true end + end + end + local paths = string.split(syscall.getEnviron("PATH") or "/bin/", ":") + for _, p in ipairs(paths) do + local ok, entries = pcall(syscall.listdir, p) + if ok and entries then + for _, e in ipairs(entries) do + local fullpath = (p:sub(-1)=="/" and p or p.."/")..e + local xok = pcall(syscall.access, fullpath, "x") + if xok and (prefix == "" or e:sub(1, #prefix) == prefix) then + if not seen[e] then results[#results+1] = e; seen[e] = true end + end + end + end + end + table.sort(results) + return results +end + +local function commonPrefix(list) + if #list == 0 then return "" end + local pre = list[1] + for i = 2, #list do + local s = list[i] + local j = 1 + while j <= #pre and j <= #s and pre:sub(j,j) == s:sub(j,j) do j = j+1 end + pre = pre:sub(1, j-1) + if pre == "" then return "" end + end + return pre +end + +local function showCompletions(completions) + syscall.write(1, "\n") + local W = 51 + local maxlen = 0 + for _, c in ipairs(completions) do if #c > maxlen then maxlen = #c end end + local colw = maxlen + 2 + local cols = math.max(1, math.floor(W / colw)) + local i = 0 + for _, c in ipairs(completions) do + local padded = c .. string.rep(" ", colw - #c) + syscall.write(1, padded) + i = i + 1 + if i % cols == 0 then syscall.write(1, "\n") end + end + if i % cols ~= 0 then syscall.write(1, "\n") end +end + +local function parseForCompletion(input, cursorPos) + local sofar = input:sub(1, cursorPos - 1) + local tokens = {} + for tok in sofar:gmatch("%S+") do tokens[#tokens+1] = tok end + local partial = sofar:match("%S+$") or "" + local isFirst = (#tokens == 0) or (sofar:sub(-1) ~= " " and #tokens == 1) + + local partialDir, partialBase + if partial:find("/") then + partialDir = partial:match("^(.*/)") or "/" + partialBase = partial:match("[^/]*$") or "" + else + partialDir = nil + partialBase = partial + end + + return tokens, partial, isFirst, partialDir, partialBase +end + +local tabState = { last = nil, idx = 0, list = {} } + +local function doTabComplete(input, cursorPos) + local tokens, partial, isFirst, partialDir, partialBase = parseForCompletion(input, cursorPos) + + local candidates + if isFirst then + if partialDir then + local dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir) + candidates = listDir(dir, partialBase) + for i, c in ipairs(candidates) do candidates[i] = partialDir..c end + else + candidates = listCommands(partialBase) + end + else + local dir, base + if partialDir then + dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir) + base = partialBase + else + dir = syscall.getcwd() + base = partialBase + end + candidates = listDir(dir, base) + if partialDir then + for i, c in ipairs(candidates) do candidates[i] = partialDir..c end + end + end + + if #candidates == 0 then + return input, cursorPos, false + end + + local context = input.."\0"..tostring(cursorPos) + if tabState.last ~= context then + tabState.last = context + tabState.idx = 0 + tabState.list = candidates + end + + if #candidates == 1 then + local completed = candidates[1] + local before = input:sub(1, cursorPos - 1 - #partial) + local after = input:sub(cursorPos) + local newInput = before .. completed .. after + local newCursor = #before + #completed + 1 + tabState.last = nil + return newInput, newCursor, true + end + + local pre = commonPrefix(candidates) + if #pre > #partial then + local before = input:sub(1, cursorPos - 1 - #partial) + local after = input:sub(cursorPos) + local newInput = before .. pre .. after + local newCursor = #before + #pre + 1 + tabState.last = newInput.."\0"..tostring(newCursor) + tabState.list = candidates + return newInput, newCursor, true + else + showCompletions(candidates) + return input, cursorPos, true + end +end + local function getUserInput() syscall.devctl(1,"sfgc",3) syscall.write(1, userhost) @@ -829,6 +983,41 @@ local function getUserInput() local history = 0 local dirty = true + local function getGhostSuffix() + if #input == 0 then return "" end + local _, partial, isFirst, partialDir, partialBase = parseForCompletion(input, cursorPos) + if cursorPos ~= #input + 1 then return "" end + local candidates + if isFirst then + if partialDir then + local dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir) + candidates = listDir(dir, partialBase) + for i, c in ipairs(candidates) do candidates[i] = partialDir..c end + else + candidates = listCommands(partialBase) + end + else + local dir, base + if partialDir then + dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir) + base = partialBase + else + dir = syscall.getcwd() + base = partialBase + end + candidates = listDir(dir, base) + if partialDir then + for i, c in ipairs(candidates) do candidates[i] = partialDir..c end + end + end + if #candidates == 0 then return "" end + local pre = commonPrefix(candidates) + if #pre > #partial then + return pre:sub(#partial + 1) + end + return "" + end + local function redraw() syscall.devctl(1,"spos",curOffsetX,curOffsetY) syscall.write(1, string.sub(input, 1, cursorPos-1)) @@ -841,21 +1030,31 @@ local function getUserInput() syscall.write(1, string.sub(input, cursorPos, cursorPos)) end syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16) - syscall.write(1, string.sub(input, cursorPos+1) .. " ") + local after = string.sub(input, cursorPos+1) + syscall.write(1, after) + local ghost = getGhostSuffix() + if #ghost > 0 then + syscall.devctl(1,"sfgc",14) + syscall.write(1, ghost) + syscall.devctl(1,"sfgc",1) + syscall.write(1, " ") + else + syscall.write(1, " ") + end end while true do local key = syscall.read(0) if key and key ~= "" then - if key=="\19" then if cursorPos>1 then cursorPos=cursorPos-1;dirty=true end - elseif key=="\20" then if cursorPos<=#input then cursorPos=cursorPos+1;dirty=true end - elseif key=="\17" then + if key=="" then if cursorPos>1 then cursorPos=cursorPos-1;dirty=true end + elseif key=="" then if cursorPos<=#input then cursorPos=cursorPos+1;dirty=true end + elseif key=="" then if history<#commandHistory then history=history+1 input=commandHistory[#commandHistory-history+1] cursorPos=#input+1;dirty=true end - elseif key=="\18" then + elseif key=="" then if history>1 then history=history-1 input=commandHistory[#commandHistory-history+1] @@ -863,6 +1062,38 @@ local function getUserInput() elseif history==1 then history=0;input="";cursorPos=1;dirty=true end + elseif key=="" then cursorPos=1;dirty=true + elseif key=="" then cursorPos=#input+1;dirty=true + elseif key=="[3~" then + if cursorPos<=#input then + input=string.sub(input,1,cursorPos-1)..string.sub(input,cursorPos+1) + dirty=true + end + elseif key=="\t" then + local newInput, newCursor, needsRedraw = doTabComplete(input, cursorPos) + if needsRedraw then + input = newInput; cursorPos = newCursor + local posStr = syscall.devctl(1, "gpos") + local sep = posStr:find(";") + local px = tonumber(posStr:sub(1, sep-1)) + local py = tonumber(posStr:sub(sep+1)) + if px > 1 then + syscall.devctl(1,"spos",1,py) + local tsz = syscall.devctl(1,"size") or "51;19" + local tw = tonumber(tsz:match("^(%d+)")) or 51 + syscall.write(1, string.rep(" ", tw)) + syscall.devctl(1,"spos",1,py) + end + syscall.devctl(1,"sfgc",3); syscall.write(1, userhost) + syscall.devctl(1,"sfgc",1); syscall.write(1, ":") + syscall.devctl(1,"sfgc",10); syscall.write(1, syscall.getcwd()) + syscall.devctl(1,"sfgc",1); syscall.write(1, "$ ") + posStr = syscall.devctl(1, "gpos") + sep = posStr:find(";") + curOffsetX = tonumber(posStr:sub(1, sep-1)) + curOffsetY = tonumber(posStr:sub(sep+1)) + dirty = true + end elseif key=="\b" then if cursorPos>1 then input=string.sub(input,1,cursorPos-2)..string.sub(input,cursorPos) @@ -873,7 +1104,7 @@ local function getUserInput() syscall.devctl(1,"spos",curOffsetX,curOffsetY) syscall.write(1, input.." \n") return input - else + elseif #key == 1 and key:byte(1) >= 32 and key:byte(1) < 127 then input=string.sub(input,1,cursorPos-1)..key..string.sub(input,cursorPos) cursorPos=cursorPos+1;dirty=true end diff --git a/Src/Hyperion-bash/bin/micro b/Src/Hyperion-bash/bin/micro index 3a21d9d..c73d68c 100644 --- a/Src/Hyperion-bash/bin/micro +++ b/Src/Hyperion-bash/bin/micro @@ -223,7 +223,7 @@ local function prompt(label, default) tbg(16); tfg(1) local key = syscall.read(0) if not key or key == "" then sleep(0.02) - elseif key == "\27" then return nil + elseif key == "" then return nil elseif key == "\n" then return inp elseif key == "\b" then if #inp > 0 then inp = inp:sub(1,-2) end else @@ -359,31 +359,29 @@ while running do local key = syscall.read(0) if key and key ~= "" then local b = key:byte(1) - if key == "\17" then moveCursorUp(map); dirty=true - elseif key == "\18" then moveCursorDown(map); dirty=true - elseif key == "\19" then - if cx > 1 then cx=cx-1 - elseif cy > 1 then cy=cy-1; cx=#lines[cy]+1 end - dirty=true - elseif key == "\20" then + if key == "" then moveCursorUp(map); dirty=true + elseif key == "" then moveCursorDown(map); dirty=true + elseif key == "" then if cx <= #lines[cy] then cx=cx+1 elseif cy < #lines then cy=cy+1; cx=1 end dirty=true + elseif key == "" then + if cx > 1 then cx=cx-1 + elseif cy > 1 then cy=cy-1; cx=#lines[cy]+1 end + dirty=true + elseif key == "" then cx=1; dirty=true + elseif key == "" then cx=#lines[cy]+1; dirty=true + elseif key == "[5~" then for _=1,ROWS do moveCursorUp(map) end; dirty=true + elseif key == "[6~" then for _=1,ROWS do moveCursorDown(map) end; dirty=true + elseif key == "[3~" then delRight() elseif key == "\n" then newline() elseif key == "\b" then delLeft() elseif key == "\t" then for _=1,4 do insChar(" ") end - elseif b == 1 then cx=1; dirty=true - elseif b == 2 then - for _=1,ROWS do moveCursorUp(map) end; dirty=true - elseif b == 4 then delRight() - elseif b == 5 then cx=#lines[cy]+1; dirty=true elseif b == 6 then local p=prompt("Find: ",sPat); dirty=true if p then sPat=p; sLine=0; findNext() end elseif b == 7 then goToLine() elseif b == 11 then cutLine() - elseif b == 12 then - for _=1,ROWS do moveCursorDown(map) end; dirty=true elseif b == 14 then if sPat=="" then local p=prompt("Find: ",""); dirty=true diff --git a/Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod b/Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod index 4a86f4a..8b586e1 100644 --- a/Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod +++ b/Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod @@ -1,4 +1,4 @@ --- :Minify:-- +--:Minify:-- local kernel = ... local apis = kernel.apis local native = apis.peripheral @@ -317,7 +317,18 @@ kernel.processes.cctmond = function() local eventType = event[1] local charOrKey = event[3] - -- Update modifier keys + local ctrlKeyMap = { + [apis.keys.a]=1, [apis.keys.b]=2, [apis.keys.c]=3, + [apis.keys.d]=4, [apis.keys.e]=5, [apis.keys.f]=6, + [apis.keys.g]=7, [apis.keys.h]=8, [apis.keys.i]=9, + [apis.keys.j]=10, [apis.keys.k]=11, [apis.keys.l]=12, + [apis.keys.m]=13, [apis.keys.n]=14, [apis.keys.o]=15, + [apis.keys.p]=16, [apis.keys.q]=17, [apis.keys.r]=18, + [apis.keys.s]=19, [apis.keys.t]=20, [apis.keys.u]=21, + [apis.keys.v]=22, [apis.keys.w]=23, [apis.keys.x]=24, + [apis.keys.y]=25, [apis.keys.z]=26, + } + if eventType == "keyPressed" then if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then ctrl = true @@ -325,11 +336,31 @@ kernel.processes.cctmond = function() alt = true end - -- Handle Ctrl+C - if ctrl and charOrKey == apis.keys.c then - for _, task in ipairs(syscall.getTasks()) do - syscall.sigsend(task, 1) -- SIGINT + if ctrl then + local ctrlByte = ctrlKeyMap[charOrKey] + if ctrlByte then + if ctrlByte == 3 then + for _, task in ipairs(syscall.getTasks()) do + syscall.sigsend(task, 1) + end + else + fifo.push(string.char(ctrlByte)) + end end + else + local specialKeyMap = { + [apis.keys.up] = "", + [apis.keys.down] = "", + [apis.keys.right] = "", + [apis.keys.left] = "", + [apis.keys.home] = "", + [apis.keys["end"]] = "", + [apis.keys.pageUp] = "[5~", + [apis.keys.pageDown] = "[6~", + [apis.keys.delete] = "[3~", + } + local special = specialKeyMap[charOrKey] + if special then fifo.push(special) end end elseif eventType == "keyReleased" then diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod index e8d7307..fd63bc9 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod @@ -113,57 +113,23 @@ end local SAFE_COMPONENT_PATTERN = "^[A-Za-z0-9_.+%-%@%(%)%[%]]+$" -local function normalizePath(path) - local task = kernel.currentTask - local cwd = task.cwd or "/" - - if path:sub(1, 1) ~= "/" then - path = cwd .. "/" .. path +local function tokenizePath(path) + local isAbsolute = (path:sub(1,1) == "/") + local tokens = {} + for comp in (path .. "/"):gmatch("([^/]*)/") do + table.insert(tokens, comp) end + return isAbsolute, tokens +end - local stack = {} - local i = 1 - local len = #path - while i <= len do - local j = path:find("/", i, true) - local comp - if j then - comp = path:sub(i, j - 1) - i = j + 1 - else - comp = path:sub(i) - i = len + 1 - end - - comp = comp:match("^%s*(.-)%s*$") - - if comp == "" or comp == "." then - elseif comp == ".." then - if #stack > 0 then - table.remove(stack) - end - else - comp = comp:lower() - if not comp:match(SAFE_COMPONENT_PATTERN) then - error("EINVAL: illegal characters in path component: " .. comp, 2) - end - if comp == ".meta" then - error("EINVAL: reserved path component: " .. comp, 2) - end - table.insert(stack, comp) - end +local function validateComponent(comp) + local lower = comp:lower() + if not lower:match(SAFE_COMPONENT_PATTERN) then + error("EINVAL: illegal characters in path component: " .. comp, 3) end - - local result = "/" .. table.concat(stack, "/") - - local root = task and task.root - if root and root ~= "/" then - if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then - result = root - end + if lower == ".meta" then + error("EINVAL: reserved path component: .meta", 3) end - - return result end function vfs.splitPath(path) @@ -222,47 +188,205 @@ local function readMetaEntry(disk, parentDiskPath, filename) end local MAX_SYMLINK = 16 -local function resolveSymlinks(path, noFollow, _depth) - _depth = _depth or 0 - if _depth > MAX_SYMLINK then error("ELOOP") end - path = normalizePath(path) - local parts = {} - for p in path:gmatch("[^/]+") do table.insert(parts, p) end +local function namei(path, noFollow, symDepth) + symDepth = symDepth or 0 + if symDepth > MAX_SYMLINK then error("ELOOP") end - local resolved = "" + local task = kernel.currentTask + local euid = (task and (task.euid or task.uid)) or kernel.uid + local groups = (task and task.groups) or kernel.groups or {} + local root = (task and task.root) or "/" + local cwd = (task and task.cwd) or "/" - for i, part in ipairs(parts) do - local candidate = resolved == "" and ("/" .. part) or (resolved .. "/" .. part) + if root ~= "/" and root:sub(-1) == "/" then root = root:sub(1,-2) end - if noFollow and i == #parts then - resolved = candidate - break - end - - local disk, parentDisk = resolveMount(resolved == "" and "/" or resolved) - local entry = readMetaEntry(disk, parentDisk, part) - - if entry and entry.etype == 0x01 then - local target = entry.cmeta - if target:sub(1,1) ~= "/" then - target = (resolved == "" and "/" or resolved) .. "/" .. target + local function canTraverse(entry) + if euid == 0 then return true end + if not entry then return true end + local bits = entry.perms + if euid == entry.owner and bit_is_set(bits, 9) then return true end + if entry.group then + for _, gid in ipairs(groups) do + if gid == entry.group and bit_is_set(bits, 8) then return true end end - if i < #parts then - target = target .. "/" .. table.concat(parts, "/", i+1, #parts) - end - return resolveSymlinks(normalizePath(target), noFollow, _depth + 1) end - - resolved = candidate + return bit_is_set(bits, 7) end - if resolved == "" then resolved = "/" end - return resolved + local isAbsolute, tokens = tokenizePath(path) + + local stack = {} + + if isAbsolute then + stack = {} + else + for seg in cwd:gmatch("[^/]+") do table.insert(stack, seg) end + end + + local i = 1 + while i <= #tokens do + local comp = tokens[i] + i = i + 1 + + comp = comp:match("^%s*(.-)%s*$") + + if comp == "" or comp == "." then + elseif comp == ".." then + local currentPath = "/" .. table.concat(stack, "/") + + local jailStack = {} + if root ~= "/" then + for seg in root:gmatch("[^/]+") do table.insert(jailStack, seg) end + end + + if #stack <= #jailStack then + stack = {} + for _, seg in ipairs(jailStack) do table.insert(stack, seg) end + else + local exitName = stack[#stack] + local parentPath = "/" .. table.concat(stack, "/", 1, #stack - 1) + if parentPath == "/" then parentPath = "/" end + + local okM, diskM, dpM = pcall(resolveMount, parentPath == "" and "/" or parentPath) + if okM and diskM then + local entry = readMetaEntry(diskM, dpM, exitName) + if entry then + if entry.etype ~= 0x00 then + error("ENOTDIR: not a directory: " .. currentPath) + end + if not canTraverse(entry) then + error("EACCES: permission denied traversing " .. currentPath) + end + else + local okD, diskD, dpD = pcall(resolveMount, currentPath) + if okD and diskD then + local dtype = diskD:type(dpD) + if dtype ~= nil and dtype ~= "directory" then + error("ENOTDIR: not a directory: " .. currentPath) + end + end + end + end + + table.remove(stack) + end + + else + validateComponent(comp) + local lname = comp:lower() + + local curPath = "/" .. table.concat(stack, "/") + + local okM, diskM, dpM = pcall(resolveMount, curPath == "/" and "/" or curPath) + local entry = nil + if okM and diskM then + entry = readMetaEntry(diskM, dpM, lname) + end + + local isFinal = (i > #tokens) + + if entry and entry.etype == 0x01 then + if isFinal and noFollow then + table.insert(stack, lname) + else + symDepth = symDepth + 1 + if symDepth > MAX_SYMLINK then error("ELOOP") end + + local target = entry.cmeta + if not target or target == "" then + error("ENOENT: empty symlink target") + end + + local symIsAbs, symTokens = tokenizePath(target) + + if symIsAbs then + stack = {} + if root ~= "/" then + for seg in root:gmatch("[^/]+") do table.insert(stack, seg) end + end + end + + local fresh = {} + for j = 1, i - 2 do table.insert(fresh, tokens[j]) end + local insertAt = #fresh + 1 + for _, t in ipairs(symTokens) do table.insert(fresh, t) end + for j = i, #tokens do table.insert(fresh, tokens[j]) end + tokens = fresh + i = insertAt + end + else + table.insert(stack, lname) + + if not isFinal then + local newPath = "/" .. table.concat(stack, "/") + local okD, diskD, dpD = pcall(resolveMount, newPath) + if okD and diskD then + local dtype = diskD:type(dpD) + if dtype ~= nil and dtype ~= "directory" then + error("ENOTDIR: not a directory: " .. newPath) + end + end + if not canTraverse(entry) then + error("EACCES: permission denied traversing " .. newPath) + end + end + end + end + end + + local result = "/" .. table.concat(stack, "/") + + if root ~= "/" then + if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then + result = root + end + end + + return result +end + +local function normalizePath(path) + local task = kernel.currentTask + local cwd = (task and task.cwd) or "/" + local root = (task and task.root) or "/" + if root ~= "/" and root:sub(-1) == "/" then root = root:sub(1,-2) end + + local isAbsolute, tokens = tokenizePath(path) + local stack = {} + + if not isAbsolute then + for seg in cwd:gmatch("[^/]+") do table.insert(stack, seg) end + end + + local jailStack = {} + if root ~= "/" then + for seg in root:gmatch("[^/]+") do table.insert(jailStack, seg) end + end + + for _, comp in ipairs(tokens) do + comp = comp:match("^%s*(.-)%s*$") + if comp == "" or comp == "." then + elseif comp == ".." then + if #stack > #jailStack then + table.remove(stack) + end + else + table.insert(stack, comp:lower()) + end + end + + local result = "/" .. table.concat(stack, "/") + if root ~= "/" then + if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then + result = root + end + end + return result end local function resolvePath(path, noFollow) - local real = resolveSymlinks(path, noFollow) + local real = namei(path, noFollow) local disk, diskPath = resolveMount(real) if kernel.config.logPathResolution then kernel.log("resolvePath '"..path.."' -> '"..real.."' diskPath '"..diskPath.."'") @@ -271,24 +395,23 @@ local function resolvePath(path, noFollow) end local function getFileMeta(path, noFollow) - local real = resolveSymlinks(path, noFollow) + local real = namei(path, noFollow) - local parts = {} - for p in real:gmatch("[^/]+") do table.insert(parts, p) end + if real == "/" then + return { etype = 0x00, owner = 0, group = 0, perms = 63, cmeta = "" } + end - local default = { etype = 0x00, owner = 0, group = 0, perms = 63, cmeta = "" } - if #parts == 0 then return default end + local parent, name = real:match("^(.*)/([^/]+)$") + if not parent or parent == "" then parent = "/" end - local parentNorm = "/" .. table.concat(parts, "/", 1, #parts - 1) - if parentNorm == "" then parentNorm = "/" end - local disk, parentDiskPath = resolveMount(parentNorm) - local entry = readMetaEntry(disk, parentDiskPath, parts[#parts]) + local disk, parentDiskPath = resolveMount(parent) + local entry = readMetaEntry(disk, parentDiskPath, name) if entry then return entry end - return default + return { etype = 0x00, owner = 0, group = 0, perms = 63, cmeta = "" } end local function writeMetaEntry(path, name, entry, noFollow) - local real = resolveSymlinks(path, noFollow) + local real = namei(path, noFollow) local disk, diskPath = resolveMount(real) local mp @@ -668,7 +791,7 @@ function vfs.mkdir(path) end function vfs.remove(path) - local norm = resolveSymlinks(path, true) + local norm = namei(path, true) local parent = norm:match("^(.*)/[^/]+$") or "/" if parent == "" then parent = "/" end local parentMeta = getFileMeta(parent) @@ -681,7 +804,7 @@ function vfs.remove(path) end if meta.etype == 0x01 then - local norm = resolveSymlinks(path, true) + local norm = namei(path, true) local parent = norm:match("^(.*)/[^/]+$") or "/" if parent == "" then parent = "/" end local name = norm:match("[^/]+$") @@ -747,7 +870,7 @@ function vfs.access(path, mode) end local function updateMeta(path, fn, noFollow) - local real = resolveSymlinks(path, noFollow) + local real = namei(path, noFollow) local norm = real local parent = norm:match("^(.*)/[^/]+$") or "/" if parent == "" then parent = "/" end diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod deleted file mode 100644 index 9c82644..0000000 --- a/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod +++ /dev/null @@ -1,5 +0,0 @@ ---:Minify:-- -local kernel = ... -kernel.vfs.open("/dev/tty/1","r") -kernel.vfs.open("/dev/tty/1","w") -kernel.vfs.open("/dev/null","w") \ No newline at end of file