diff --git a/base/filesystem.jl b/base/filesystem.jl index 9ef4dfa332c42..9b64317e36f71 100644 --- a/base/filesystem.jl +++ b/base/filesystem.jl @@ -11,14 +11,12 @@ const S_IFREG = 0o100000 # regular file const S_IFIFO = 0o010000 # fifo (named pipe) const S_IFLNK = 0o120000 # symbolic link const S_IFSOCK = 0o140000 # socket file +const S_IFMT = 0o170000 const S_ISUID = 0o4000 # set UID bit const S_ISGID = 0o2000 # set GID bit const S_ENFMT = S_ISGID # file locking enforcement const S_ISVTX = 0o1000 # sticky bit -const S_IREAD = 0o0400 # Unix V7 synonym for S_IRUSR -const S_IWRITE = 0o0200 # Unix V7 synonym for S_IWUSR -const S_IEXEC = 0o0100 # Unix V7 synonym for S_IXUSR const S_IRWXU = 0o0700 # mask for owner permissions const S_IRUSR = 0o0400 # read by owner diff --git a/base/stat.jl b/base/stat.jl index f3b8b1b506818..380316df0f2b4 100644 --- a/base/stat.jl +++ b/base/stat.jl @@ -62,63 +62,56 @@ StatStruct(desc::Union{AbstractString, OS_HANDLE}, buf::Union{Vector{UInt8},Ptr{ function show(io::IO, st::StatStruct) compact = get(io, :compact, true) function iso_datetime_with_relative(t, tnow) - sprint() do iob2 - print(iob2, Libc.strftime("%FT%T%z", t)) - secdiff = t - tnow - for (d, name) in ((24*60*60,"day"),(60*60,"hour"),(60,"minute"),(1,"second")) - tdiff = round(Int, div(abs(secdiff), d)) - (tdiff == 0 && name != "second") && continue # find first unit difference - if tdiff == 0 && name == "second" - print(iob2, " (just now)") - break - end - plural = tdiff == 1 ? "" : "s" - when = secdiff < 0 ? "ago" : "in the future" - print(iob2, " ($(tdiff) $(name)$(plural) $(when))") + str = Libc.strftime("%FT%T%z", t) + secdiff = t - tnow + for (d, name) in ((24*60*60,"day"),(60*60,"hour"),(60,"minute"),(1,"second")) + tdiff = round(Int, div(abs(secdiff), d)) + (tdiff == 0 && name != "second") && continue # find first unit difference + if tdiff == 0 && name == "second" + str *= " (just now)" break end + plural = tdiff == 1 ? "" : "s" + when = secdiff < 0 ? "ago" : "in the future" + str *= " ($(tdiff) $(name)$(plural) $(when))" + break end end - str = if compact - sprint() do iob - print(iob, "$(st.desc)") - print(iob, " size: $(st.size) bytes") - print(iob, " device: $(st.device)") - print(iob, " inode: $(st.inode)") - print(iob, " mode: 0o$(string(filemode(st), base = 8, pad = 6)) ($(filemode_string(st)))") - print(iob, " nlink: $(st.nlink)") - username = Base.getusername(st.uid) - isnothing(username) ? print(iob, " uid: $(st.uid)") : print(iob, " uid: $(st.uid) ($username)") - groupname = Base.getgroupname(st.gid) - isnothing(groupname) ? print(iob, " gid: $(st.gid)") : print(iob, " gid: $(st.gid) ($groupname)") - print(iob, " rdev: $(st.rdev)") - print(iob, " blksize: $(st.blksize)") - print(iob, " blocks: $(st.blocks)") - tnow = Libc.TimeVal().sec - print(iob, " mtime: $(iso_datetime_with_relative(st.mtime, tnow))") - println(iob, " ctime: $(iso_datetime_with_relative(st.ctime, tnow))") - end + if compact + print(io, "$(st.desc)") + print(io, " size: $(st.size) bytes") + print(io, " device: $(st.device)") + print(io, " inode: $(st.inode)") + print(io, " mode: 0o$(string(filemode(st), base = 8, pad = 6)) ($(filemode_string(st)))") + print(io, " nlink: $(st.nlink)") + username = Base.getusername(st.uid) + isnothing(username) ? print(io, " uid: $(st.uid)") : print(io, " uid: $(st.uid) ($username)") + groupname = Base.getgroupname(st.gid) + isnothing(groupname) ? print(io, " gid: $(st.gid)") : print(io, " gid: $(st.gid) ($groupname)") + print(io, " rdev: $(st.rdev)") + print(io, " blksize: $(st.blksize)") + print(io, " blocks: $(st.blocks)") + tnow = Libc.TimeVal().sec + print(io, " mtime: $(iso_datetime_with_relative(st.mtime, tnow))") + println(io, " ctime: $(iso_datetime_with_relative(st.ctime, tnow))") else - sprint() do iob - println(iob, "StatStruct for $(st.desc)") - println(iob, " size: $(st.size) bytes") - println(iob, " device: $(st.device)") - println(iob, " inode: $(st.inode)") - println(iob, " mode: 0o$(string(filemode(st), base = 8, pad = 6)) ($(filemode_string(st)))") - println(iob, " nlink: $(st.nlink)") - username = Base.getusername(st.uid) - isnothing(username) ? println(iob, " uid: $(st.uid)") : println(iob, " uid: $(st.uid) ($username)") - groupname = Base.getgroupname(st.gid) - isnothing(groupname) ? println(iob, " gid: $(st.gid)") : println(iob, " gid: $(st.gid) ($groupname)") - println(iob, " rdev: $(st.rdev)") - println(iob, "blksize: $(st.blksize)") - println(iob, " blocks: $(st.blocks)") - tnow = Libc.TimeVal().sec - println(iob, " mtime: $(iso_datetime_with_relative(st.mtime, tnow))") - println(iob, " ctime: $(iso_datetime_with_relative(st.ctime, tnow))") - end + println(io, "StatStruct for $(st.desc)") + println(io, " size: $(st.size) bytes") + println(io, " device: $(st.device)") + println(io, " inode: $(st.inode)") + println(io, " mode: 0o$(string(filemode(st), base = 8, pad = 6)) ($(filemode_string(st)))") + println(io, " nlink: $(st.nlink)") + username = Base.getusername(st.uid) + isnothing(username) ? println(io, " uid: $(st.uid)") : println(io, " uid: $(st.uid) ($username)") + groupname = Base.getgroupname(st.gid) + isnothing(groupname) ? println(io, " gid: $(st.gid)") : println(io, " gid: $(st.gid) ($groupname)") + println(io, " rdev: $(st.rdev)") + println(io, "blksize: $(st.blksize)") + println(io, " blocks: $(st.blocks)") + tnow = Libc.TimeVal().sec + println(io, " mtime: $(iso_datetime_with_relative(st.mtime, tnow))") + println(io, " ctime: $(iso_datetime_with_relative(st.ctime, tnow))") end - print(io, str) end # stat & lstat functions @@ -218,18 +211,17 @@ function filemode_string(mode) (S_ISVTX, "T"), (S_IXOTH, "x")) ) - str = sprint() do iob - for table in filemode_table - complete = true - for (bit, char) in table - if mode & bit == bit - print(iob, char) - complete = false - break - end + str = "" + for table in filemode_table + complete = true + for (bit, char) in table + if mode & bit == bit + str *= char + complete = false + break end - complete && print(iob, "-") end + complete && (str *= "-") end return str end @@ -451,3 +443,92 @@ function ismount(path...) (s1.inode == s2.inode) && return true false end + +mutable struct Cpasswd + pw_name::Ptr{Cchar} # username + pw_passwd::Ptr{Cchar} # user password + pw_uid::Cuint # user ID + pw_gid::Cuint # group ID + pw_gecos::Ptr{Cchar} # user information + pw_dir::Ptr{Cchar} # home directory + pw_shell::Ptr{Cchar} # shell program + Cpasswd() = new() +end +struct Passwd + name::String + passwd::String + uid::Int + gid::Int + gecos::String + dir::String + shell::String +end +function getpwuid(uid) + pd = Cpasswd() + pwdptr = pointer_from_objref(pd) + tempPwdPtr = pointer_from_objref(Cpasswd()) + buf = Array{Cchar}(undef, 200) + bufsize = sizeof(buf) + ret = ccall(:getpwuid_r, Cint, (Cuint, Ptr{Cpasswd}, Ptr{UInt8}, Csize_t, Ptr{Cpasswd}), uid, pwdptr, buf, bufsize, tempPwdPtr) + ret != 0 && error("getpwuid_r error") + out = Passwd( + pd.pw_name == C_NULL ? "" : unsafe_string(pd.pw_name), + pd.pw_passwd == C_NULL ? "" : unsafe_string(pd.pw_passwd), + pd.pw_uid, + pd.pw_gid, + pd.pw_gecos == C_NULL ? "" : unsafe_string(pd.pw_gecos), + pd.pw_dir == C_NULL ? "" : unsafe_string(pd.pw_dir), + pd.pw_shell == C_NULL ? "" : unsafe_string(pd.pw_shell) + ) + return out +end + +function getusername(uid::Union{UInt32, UInt64}) + if Sys.iswindows() + return nothing + else + pwd = getpwuid(uid) + isempty(pwd.name) && return + return pwd.name + end +end + +mutable struct Cgroup + gr_name::Ptr{Cchar} # group name + gr_passwd::Ptr{Cchar} # group password + gr_gid::Cuint # group ID + gr_mem::Ptr{Ptr{Cchar}} # group members + Cgroup() = new() +end +struct Group + name::String + passwd::String + gid::Int + mem::Vector{String} +end +function getpwuid(gid) + gp = Cgroup() + gpptr = pointer_from_objref(gp) + tempGpPtr = pointer_from_objref(Cgroup()) + buf = Array{Cchar}(undef, 200) + bufsize = sizeof(buf) + ret = ccall(:getgrgid_r, Cint, (Cuint, Ptr{Cgroup}, Ptr{UInt8}, Csize_t, Ptr{Cgroup}), gid, gpptr, buf, bufsize, tempGpPtr) + ret != 0 && error("getpwuid_r error") + out = Group( + gp.gr_name == C_NULL ? "" : unsafe_string(gp.gr_name), + gp.gr_passwd == C_NULL ? "" : unsafe_string(gp.gr_passwd), + gp.gr_gid, + gp.gr_mem == C_NULL ? "" : [""] # TODO: Actually populate + ) + return out +end + +function getgroupname(gid::Union{UInt32, UInt64}) + if Sys.iswindows() + return nothing + else + gp = getpwuid(gid) + isempty(gp.name) && return + return gp.name + end +end diff --git a/base/util.jl b/base/util.jl index 876caec857de4..503ba5c390e1c 100644 --- a/base/util.jl +++ b/base/util.jl @@ -622,39 +622,3 @@ function runtests(tests = ["all"]; ncores::Int = ceil(Int, Sys.CPU_THREADS::Int "including error messages above and the output of versioninfo():\n$(read(buf, String))") end end - -# stat.jl helpers which require methods that are loaded later - -function getusername(uid::Union{UInt32, UInt64}) - if Sys.islinux() - name = strip(read(pipeline(`getent passwd "$(Int(uid))"`,`cut -d: -f1`), String)) - isempty(name) && return - return name - elseif Sys.isapple() - lines = read(`dscl . -list /Users UniqueID`, String) - isempty(lines) && return - lines = split(lines, "\n") - for line in lines - parts = split(line, " ", keepempty=false) - tryparse(Int, last(parts)) == Int(uid) && return first(parts) - end - end - nothing -end - -function getgroupname(gid::Union{UInt32, UInt64}) - if Sys.islinux() - name = strip(read(pipeline(`getent group "$(Int(gid))"`,`cut -d: -f1`), String)) - isempty(name) && return - return name - elseif Sys.isapple() - lines = read(`dscl . -list /groups PrimaryGroupID`, String) - isempty(lines) && return - lines = split(lines, "\n") - for line in lines - parts = split(line, " ", keepempty=false) - tryparse(Int, last(parts)) == gid && return first(parts) - end - end - nothing -end