formating better for spm packages
This commit is contained in:
268
Src/hysh/data/bin/chmod
Normal file
268
Src/hysh/data/bin/chmod
Normal file
@@ -0,0 +1,268 @@
|
||||
--:Minify:--
|
||||
local name = syscall.getTask(syscall.getpid()).name
|
||||
local cloptions = { R = false, help = false }
|
||||
local args = {}
|
||||
|
||||
for _, v in ipairs({ ... }) do
|
||||
if v:sub(1, 2) == "--" then
|
||||
local opt = v:sub(3)
|
||||
if cloptions[opt] == nil then
|
||||
print(name .. ": unrecognized option '" .. v .. "'")
|
||||
print("try '" .. name .. " --help' for more information.")
|
||||
syscall.exit(1); return
|
||||
end
|
||||
cloptions[opt] = true
|
||||
elseif v:sub(1, 1) == "-" then
|
||||
for i = 2, #v do
|
||||
local opt = v:sub(i, i)
|
||||
if cloptions[opt] == nil then
|
||||
print(name .. ": invalid option '-" .. opt .. "'")
|
||||
print("try '" .. name .. " --help' for more information.")
|
||||
syscall.exit(1); return
|
||||
end
|
||||
cloptions[opt] = true
|
||||
end
|
||||
else
|
||||
table.insert(args, v)
|
||||
end
|
||||
end
|
||||
|
||||
if cloptions.help then
|
||||
print("Usage: " .. name .. " [OPTION]... MODE FILE...")
|
||||
print("Change the file mode bits of each FILE to MODE.")
|
||||
print("")
|
||||
print("MODE may be octal (e.g. 755) or symbolic (e.g. u+x, go-w, a=r).")
|
||||
print("")
|
||||
print("Octal bit layout (Hyperion):")
|
||||
print(" owner: r=32 w=16 x=512 group: r=8 w=4 x=256")
|
||||
print(" world: r=2 w=1 x=128 suid=64")
|
||||
print(" Common: 644=rw-r--r-- 755=rwxr-xr-x 700=rwx------")
|
||||
print("")
|
||||
print("Symbolic: [ugoa][+-=][rwxs] (comma-separated list)")
|
||||
print("")
|
||||
print("Options:")
|
||||
print(" -R change files and directories recursively")
|
||||
print(" --help display this help and exit")
|
||||
return
|
||||
end
|
||||
|
||||
if #args < 2 then
|
||||
print(name .. ": missing operand")
|
||||
print("try '" .. name .. " --help' for more information.")
|
||||
syscall.exit(1); return
|
||||
end
|
||||
|
||||
local modeArg = args[1]
|
||||
|
||||
local P = {
|
||||
OWNER_R = 32, OWNER_W = 16, OWNER_X = 512,
|
||||
GROUP_R = 8, GROUP_W = 4, GROUP_X = 256,
|
||||
WORLD_R = 2, WORLD_W = 1, WORLD_X = 128,
|
||||
SUID = 64,
|
||||
}
|
||||
|
||||
local function bit_is_set(num, bit)
|
||||
return math.floor(num / (2 ^ bit)) % 2 == 1
|
||||
end
|
||||
|
||||
local function parseOctal(s)
|
||||
local n = tonumber(s, 8)
|
||||
if not n then return nil end
|
||||
|
||||
local result = 0
|
||||
if bit_is_set(n, 8) then result = result + P.OWNER_R end -- 0400
|
||||
if bit_is_set(n, 7) then result = result + P.OWNER_W end -- 0200
|
||||
if bit_is_set(n, 6) then result = result + P.OWNER_X end -- 0100
|
||||
|
||||
if bit_is_set(n, 5) then result = result + P.GROUP_R end -- 040
|
||||
if bit_is_set(n, 4) then result = result + P.GROUP_W end -- 020
|
||||
if bit_is_set(n, 3) then result = result + P.GROUP_X end -- 010
|
||||
|
||||
if bit_is_set(n, 2) then result = result + P.WORLD_R end -- 004
|
||||
if bit_is_set(n, 1) then result = result + P.WORLD_W end -- 002
|
||||
if bit_is_set(n, 0) then result = result + P.WORLD_X end -- 001
|
||||
|
||||
if bit_is_set(n, 11) then result = result + P.SUID end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function applySymbolic(modeStr, existingPerms)
|
||||
local perms = existingPerms
|
||||
|
||||
for clause in (modeStr .. ","):gmatch("([^,]+),") do
|
||||
local who_str, rest = clause:match("^([ugoa]*)([+%-=].+)$")
|
||||
if not who_str then
|
||||
print(name .. ": invalid mode: '" .. clause .. "'")
|
||||
syscall.exit(1); return nil
|
||||
end
|
||||
if who_str == "" or who_str == "a" then who_str = "ugo" end
|
||||
|
||||
local op = rest:sub(1, 1)
|
||||
local bits_str = rest:sub(2)
|
||||
|
||||
local mask = 0
|
||||
for i = 1, #bits_str do
|
||||
local c = bits_str:sub(i, i)
|
||||
for j = 1, #who_str do
|
||||
local w = who_str:sub(j, j)
|
||||
if c == "r" then
|
||||
if w == "u" then mask = mask + P.OWNER_R
|
||||
elseif w == "g" then mask = mask + P.GROUP_R
|
||||
elseif w == "o" then mask = mask + P.WORLD_R end
|
||||
elseif c == "w" then
|
||||
if w == "u" then mask = mask + P.OWNER_W
|
||||
elseif w == "g" then mask = mask + P.GROUP_W
|
||||
elseif w == "o" then mask = mask + P.WORLD_W end
|
||||
elseif c == "x" then
|
||||
if w == "u" then mask = mask + P.OWNER_X
|
||||
elseif w == "g" then mask = mask + P.GROUP_X
|
||||
elseif w == "o" then mask = mask + P.WORLD_X end
|
||||
elseif c == "s" then
|
||||
if w == "u" then mask = mask + P.SUID end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if op == "+" then
|
||||
perms = perms + (mask - (perms % (mask + 1) - perms % mask > 0 and 0 or 0))
|
||||
|
||||
perms = perms - (perms % 1)
|
||||
local function bor(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 or b > 0 do
|
||||
if (a % 2 == 1) or (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
perms = bor(perms, mask)
|
||||
elseif op == "-" then
|
||||
local function band(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 and b > 0 do
|
||||
if (a % 2 == 1) and (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
local function bxor(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 or b > 0 do
|
||||
if (a % 2 == 1) ~= (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
perms = bxor(perms, band(perms, mask))
|
||||
elseif op == "=" then
|
||||
local clearMask = 0
|
||||
for j = 1, #who_str do
|
||||
local w = who_str:sub(j, j)
|
||||
if w == "u" then clearMask = clearMask + P.OWNER_R + P.OWNER_W + P.OWNER_X + P.SUID
|
||||
elseif w == "g" then clearMask = clearMask + P.GROUP_R + P.GROUP_W + P.GROUP_X
|
||||
elseif w == "o" then clearMask = clearMask + P.WORLD_R + P.WORLD_W + P.WORLD_X end
|
||||
end
|
||||
local function bxor(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 or b > 0 do
|
||||
if (a % 2 == 1) ~= (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
local function band(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 and b > 0 do
|
||||
if (a % 2 == 1) and (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
local function bor(a, b)
|
||||
local result, bit = 0, 1
|
||||
while a > 0 or b > 0 do
|
||||
if (a % 2 == 1) or (b % 2 == 1) then result = result + bit end
|
||||
a = math.floor(a / 2); b = math.floor(b / 2); bit = bit * 2
|
||||
end
|
||||
return result
|
||||
end
|
||||
perms = bxor(perms, band(perms, clearMask))
|
||||
perms = bor(perms, mask)
|
||||
else
|
||||
print(name .. ": invalid operator in mode: '" .. clause .. "'")
|
||||
syscall.exit(1); return nil
|
||||
end
|
||||
end
|
||||
|
||||
return perms
|
||||
end
|
||||
|
||||
local function resolveMode(modeStr, existingPerms)
|
||||
if modeStr:match("^[0-7]+$") then
|
||||
local p = parseOctal(modeStr)
|
||||
if p then return p end
|
||||
end
|
||||
|
||||
return applySymbolic(modeStr, existingPerms)
|
||||
end
|
||||
|
||||
local function chmodPath(path)
|
||||
local stat, err = pcall(syscall.stat, path)
|
||||
local existingPerms = 0
|
||||
if stat then
|
||||
local s = syscall.stat(path)
|
||||
existingPerms = s and s.perms or 0
|
||||
end
|
||||
|
||||
local newPerms = resolveMode(modeArg, existingPerms)
|
||||
if newPerms == nil then return false end
|
||||
|
||||
local ok, cerr = pcall(syscall.chmod, path, newPerms)
|
||||
if not ok then
|
||||
local msg = tostring(cerr)
|
||||
if msg:find("EACCES") or msg:find("EPERM") then
|
||||
msg = "permission denied"
|
||||
elseif msg:find("ENOENT") then
|
||||
msg = "no such file or directory"
|
||||
end
|
||||
print(name .. ": cannot change permissions of '" .. path .. "': " .. msg)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function chmodRecursive(path)
|
||||
if not chmodPath(path) then return end
|
||||
if syscall.type(path) == "directory" then
|
||||
local ok, list = pcall(syscall.listdir, path)
|
||||
if ok then
|
||||
for _, entry in ipairs(list) do
|
||||
local child = path
|
||||
if child:sub(-1) ~= "/" then child = child .. "/" end
|
||||
chmodRecursive(child .. entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cwd = syscall.getcwd()
|
||||
local function absPath(p)
|
||||
if p:sub(1,1) ~= "/" then p = cwd .. "/" .. p end
|
||||
return p
|
||||
end
|
||||
|
||||
local exitCode = 0
|
||||
for i = 2, #args do
|
||||
local path = absPath(args[i])
|
||||
if not syscall.exists(path) then
|
||||
print(name .. ": cannot access '" .. args[i] .. "': No such file or directory")
|
||||
exitCode = 1
|
||||
elseif cloptions.R then
|
||||
chmodRecursive(path)
|
||||
else
|
||||
if not chmodPath(path) then exitCode = 1 end
|
||||
end
|
||||
end
|
||||
|
||||
syscall.exit(exitCode)
|
||||
Reference in New Issue
Block a user