--: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]... OWNER[:GROUP] FILE...")
    print("       " .. name .. " [OPTION]... :GROUP FILE...")
    print("Change the owner and/or group of each FILE.")
    print("OWNER and GROUP may be names or numeric IDs.")
    print("")
    print("Options:")
    print("  -R          operate on 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 spec = args[1]
local ownerStr, groupStr

if spec:sub(1,1) == ":" then
    groupStr = spec:sub(2)
else
    local colon = spec:find(":", 1, true)
    if colon then
        ownerStr = spec:sub(1, colon - 1)
        groupStr = spec:sub(colon + 1)
        if groupStr == "" then groupStr = nil end
    else
        ownerStr = spec
    end
end

local function resolveUid(s)
    if not s or s == "" then return nil end
    local n = tonumber(s)
    if n then return n end
    local uid = syscall.getuidbyname and syscall.getuidbyname(s)
    if uid then return uid end
    print(name .. ": invalid user: '" .. s .. "'")
    syscall.exit(1)
end

local function resolveGid(s)
    if not s or s == "" then return nil end
    local n = tonumber(s)
    if n then return n end
    local uid = syscall.getuidbyname and syscall.getuidbyname(s)
    if uid then
        local pwent = syscall.getpasswd(uid)
        if pwent then return pwent.gid end
    end
    print(name .. ": invalid group: '" .. s .. "'")
    syscall.exit(1)
end

local newUid = resolveUid(ownerStr)
local newGid = resolveGid(groupStr)

if newUid == nil and newGid == nil then
    print(name .. ": no owner or group specified")
    syscall.exit(1); return
end

local function chownPath(path)
    local stat = syscall.stat(path)
    if not stat then
        print(name .. ": cannot stat '" .. path .. "': No such file or directory")
        return false
    end
    local uid = newUid ~= nil and newUid or stat.owner
    local gid = newGid ~= nil and newGid or stat.group
    local ok, err = pcall(syscall.chown, path, uid, gid)
    if not ok then
        print(name .. ": cannot change owner of '" .. path .. "': " .. tostring(err))
        return false
    end
    return true
end

local function chownRecursive(path)
    if not chownPath(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
                chownRecursive(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
        chownRecursive(path)
    else
        if not chownPath(path) then exitCode = 1 end
    end
end

syscall.exit(exitCode)
