stat.jl
# This file is a part of Julia. License is MIT: http://julialang.org/license
# filesystem operations
export
ctime,
filemode,
filesize,
gperm,
isblockdev,
ischardev,
isdir,
isfifo,
isfile,
islink,
ismount,
ispath,
issetgid,
issetuid,
issocket,
issticky,
lstat,
mtime,
operm,
stat,
uperm
immutable StatStruct
device :: UInt
inode :: UInt
mode :: UInt
nlink :: Int
uid :: UInt
gid :: UInt
rdev :: UInt
size :: Int64
blksize :: Int64
blocks :: Int64
mtime :: Float64
ctime :: Float64
end
StatStruct() = StatStruct(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
StatStruct(buf::Union{Vector{UInt8},Ptr{UInt8}}) = StatStruct(
ccall(:jl_stat_dev, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_ino, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_mode, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_nlink, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_uid, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_gid, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_rdev, UInt32, (Ptr{UInt8},), buf),
ccall(:jl_stat_size, UInt64, (Ptr{UInt8},), buf),
ccall(:jl_stat_blksize, UInt64, (Ptr{UInt8},), buf),
ccall(:jl_stat_blocks, UInt64, (Ptr{UInt8},), buf),
ccall(:jl_stat_mtime, Float64, (Ptr{UInt8},), buf),
ccall(:jl_stat_ctime, Float64, (Ptr{UInt8},), buf),
)
show(io::IO, st::StatStruct) = print(io, "StatStruct(mode=$(oct(filemode(st),6)), size=$(filesize(st)))")
# stat & lstat functions
const stat_buf = Array(UInt8, ccall(:jl_sizeof_stat, Int32, ()))
macro stat_call(sym, arg1type, arg)
quote
fill!(stat_buf,0)
r = ccall($(Expr(:quote,sym)), Int32, ($arg1type, Ptr{UInt8}), $(esc(arg)), stat_buf)
r==0 || r==Base.UV_ENOENT || r==Base.UV_ENOTDIR || throw(UVError("stat",r))
st = StatStruct(stat_buf)
if ispath(st) != (r==0)
error("stat returned zero type for a valid path")
end
st
end
end
stat(fd::RawFD) = @stat_call jl_fstat Int32 fd.fd
stat(fd::Integer) = @stat_call jl_fstat Int32 fd
stat(path::AbstractString) = @stat_call jl_stat Cstring path
lstat(path::AbstractString) = @stat_call jl_lstat Cstring path
stat(path...) = stat(joinpath(path...))
lstat(path...) = lstat(joinpath(path...))
# some convenience functions
filemode(st::StatStruct) = st.mode
filesize(st::StatStruct) = st.size
mtime(st::StatStruct) = st.mtime
ctime(st::StatStruct) = st.ctime
# mode type predicates
ispath(st::StatStruct) = filemode(st) & 0xf000 != 0x0000
isfifo(st::StatStruct) = filemode(st) & 0xf000 == 0x1000
ischardev(st::StatStruct) = filemode(st) & 0xf000 == 0x2000
isdir(st::StatStruct) = filemode(st) & 0xf000 == 0x4000
isblockdev(st::StatStruct) = filemode(st) & 0xf000 == 0x6000
isfile(st::StatStruct) = filemode(st) & 0xf000 == 0x8000
islink(st::StatStruct) = filemode(st) & 0xf000 == 0xa000
issocket(st::StatStruct) = filemode(st) & 0xf000 == 0xc000
# mode permission predicates
issetuid(st::StatStruct) = (filemode(st) & 0o4000) > 0
issetgid(st::StatStruct) = (filemode(st) & 0o2000) > 0
issticky(st::StatStruct) = (filemode(st) & 0o1000) > 0
uperm(st::StatStruct) = UInt8((filemode(st) >> 6) & 0x7)
gperm(st::StatStruct) = UInt8((filemode(st) >> 3) & 0x7)
operm(st::StatStruct) = UInt8((filemode(st) ) & 0x7)
# mode predicate methods for file names
for f in Symbol[
:ispath
:isfifo
:ischardev
:isdir
:isblockdev
:isfile
:issocket
:issetuid
:issetgid
:issticky
:uperm
:gperm
:operm
:filemode
:filesize
:mtime
:ctime
]
@eval ($f)(path...) = ($f)(stat(path...))
end
islink(path...) = islink(lstat(path...))
# samefile can be used for files and directories: #11145#issuecomment-99511194
samefile(a::StatStruct, b::StatStruct) = a.device==b.device && a.inode==b.inode
function samefile(a::AbstractString, b::AbstractString)
infoa = stat(a)
infob = stat(b)
if ispath(infoa) && ispath(infob)
samefile(infoa, infob)
else
return false
end
end
function ismount(path...)
path = joinpath(path...)
isdir(path) || return false
s1 = lstat(path)
# Symbolic links cannot be mount points
islink(s1) && return false
parent_path = joinpath(path, "..")
s2 = lstat(parent_path)
# If a directory and its parent are on different devices, then the
# directory must be a mount point
(s1.device != s2.device) && return true
(s1.inode == s2.inode) && return true
false
end