/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
base/stat.jl
623 строки
20 KB
Max Horn
docs: improve 'See also' in many docstrings (#60858)
29 янв 2026, 23:34
Не верифицирован
29 янв 2026, 23:34
29706fd
Код
Авторство
О чём код?
# This file is a part of Julia. License is MIT: https://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 """ StatStruct A struct which stores information about a file. Usually constructed by calling [`stat`](@ref) on a path. This struct is used internally as the foundation of a number of utility functions. Some return specific parts of the information stored in it directly, such as [`filesize`](@ref), [`mtime`](@ref) and [`ctime`](@ref). Others add some logic on top using bit-manipulation, such as [`isfifo`](@ref), [`ischardev`](@ref), and [`issetuid`](@ref). The following fields of this struct are considered public API: | Name | Type | Description | |:--------|:--------------------------------|:-------------------------------------------------------------------| | desc | `Union{String, Base.OS_HANDLE}` | The path or OS file descriptor | | size | `Int64` | The size (in bytes) of the file | | device | `UInt` | ID of the device that contains the file | | inode | `UInt` | The inode number of the file | | mode | `UInt` | The protection mode of the file | | nlink | `Int` | The number of hard links to the file | | uid | `UInt` | The user id of the owner of the file | | gid | `UInt` | The group id of the file owner | | rdev | `UInt` | If this file refers to a device, the ID of the device it refers to | | blksize | `Int64` | The file-system preferred block size for the file | | blocks | `Int64` | The number of 512-byte blocks allocated | | mtime | `Float64` | Unix timestamp of when the file was last modified | | ctime | `Float64` | Unix timestamp of when the file's metadata was changed | See also [`stat`](@ref). """ struct StatStruct desc :: Union{String, OS_HANDLE} # for show method, not included in equality or hash device :: UInt inode :: UInt mode :: UInt nlink :: Int uid :: UInt gid :: UInt rdev :: UInt size :: Int64 blksize :: Int64 blocks :: Int64 mtime :: Float64 ctime :: Float64 ioerrno :: Int32 end @eval function Base.:(==)(x::StatStruct, y::StatStruct) # do not include `desc` in equality or hash $(let ex = true for fld in fieldnames(StatStruct)[2:end] ex = :(getfield(x, $(QuoteNode(fld))) === getfield(y, $(QuoteNode(fld))) && $ex) end Expr(:return, ex) end) end @eval function Base.hash(obj::StatStruct, h::UInt) $(quote $(Any[:(h = hash(getfield(obj, $(QuoteNode(fld))), h)) for fld in fieldnames(StatStruct)[2:end]]...) return h end) end StatStruct() = StatStruct("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Base.UV_ENOENT) StatStruct(buf::Union{Memory{UInt8},Vector{UInt8},Ptr{UInt8}}, ioerrno::Int32) = StatStruct("", buf, ioerrno) StatStruct(desc::Union{AbstractString, OS_HANDLE}, buf::Union{Memory{UInt8},Vector{UInt8},Ptr{UInt8}}, ioerrno::Int32) = StatStruct( desc isa OS_HANDLE ? desc : String(desc), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_dev, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_ino, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_mode, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_nlink, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_uid, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_gid, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt32) : ccall(:jl_stat_rdev, UInt32, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt64) : ccall(:jl_stat_size, UInt64, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt64) : ccall(:jl_stat_blksize, UInt64, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(UInt64) : ccall(:jl_stat_blocks, UInt64, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(Float64) : ccall(:jl_stat_mtime, Float64, (Ptr{UInt8},), buf), ioerrno != 0 ? zero(Float64) : ccall(:jl_stat_ctime, Float64, (Ptr{UInt8},), buf), ioerrno ) function iso_datetime_with_relative(t, tnow) 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)) if tdiff != 0 # find first unit difference plural = tdiff == 1 ? "" : "s" when = secdiff < 0 ? "ago" : "in the future" return "$str ($tdiff $name$plural $when)" end end return "$str (just now)" end function getusername(uid::Unsigned) pwd = Libc.getpwuid(uid, false) pwd === nothing && return isempty(pwd.username) && return return pwd.username end function getgroupname(gid::Unsigned) gp = Libc.getgrgid(gid, false) gp === nothing && return isempty(gp.groupname) && return return gp.groupname end function show_statstruct(io::IO, st::StatStruct, oneline::Bool) print(io, oneline ? "StatStruct(" : "StatStruct for ") show(io, st.desc) code = st.ioerrno if code != 0 print(io, oneline ? " " : "\n ") print(io, Base.uverrorname(code), ": ", Base.struverror(code)) else oneline || print(io, "\n ") print(io, " size: ", st.size, " bytes") oneline || print(io, "\n") print(io, " device: ", st.device) oneline || print(io, "\n ") print(io, " inode: ", st.inode) oneline || print(io, "\n ") print(io, " mode: 0o", string(filemode(st), base = 8, pad = 6), " (", filemode_string(st), ")") oneline || print(io, "\n ") print(io, " nlink: ", st.nlink) oneline || print(io, "\n ") print(io, " uid: $(st.uid)") username = getusername(st.uid) username === nothing || print(io, " (", username, ")") oneline || print(io, "\n ") print(io, " gid: ", st.gid) groupname = getgroupname(st.gid) groupname === nothing || print(io, " (", groupname, ")") oneline || print(io, "\n ") print(io, " rdev: ", st.rdev) oneline || print(io, "\n ") print(io, " blksz: ", st.blksize) oneline || print(io, "\n") print(io, " blocks: ", st.blocks) tnow = round(UInt, time()) oneline || print(io, "\n ") print(io, " mtime: ", iso_datetime_with_relative(st.mtime, tnow)) oneline || print(io, "\n ") print(io, " ctime: ", iso_datetime_with_relative(st.ctime, tnow)) end oneline && print(io, ")") return nothing end show(io::IO, st::StatStruct) = show_statstruct(io, st, true) show(io::IO, ::MIME"text/plain", st::StatStruct) = show_statstruct(io, st, false) # stat & lstat functions checkstat(s::StatStruct) = Int(s.ioerrno) in (0, Base.UV_ENOENT, Base.UV_ENOTDIR, Base.UV_EINVAL) ? s : _uv_error(string("stat(", repr(s.desc), ")"), s.ioerrno) macro stat_call(sym, arg1type, arg) return quote stat_buf = fill!(Memory{UInt8}(undef, Int(ccall(:jl_sizeof_stat, Int32, ()))), 0x00) r = ccall($(Expr(:quote, sym)), Int32, ($(esc(arg1type)), Ptr{UInt8}), $(esc(arg)), stat_buf) return checkstat(StatStruct($(esc(arg)), stat_buf, r)) end end stat(fd::OS_HANDLE) = @stat_call jl_fstat OS_HANDLE fd function stat(path::AbstractString) # @info "stat($(repr(path)))" exception=(ErrorException("Fake error for backtrace printing"),stacktrace()) @stat_call jl_stat Cstring path end function lstat(path::AbstractString) # @info "lstat($(repr(path)))" exception=(ErrorException("Fake error for backtrace printing"),stacktrace()) @stat_call jl_lstat Cstring path end if RawFD !== OS_HANDLE global stat(fd::RawFD) = stat(Libc._get_osfhandle(fd)) end """ stat(path) stat(path_elements...) Return a structure whose fields contain information about the file. If multiple arguments are given, they are joined by [`joinpath`](@ref). The fields of the structure are: | Name | Type | Description | |:--------|:--------------------------------|:-------------------------------------------------------------------| | desc | `Union{String, Base.OS_HANDLE}` | The path or OS file descriptor | | size | `Int64` | The size (in bytes) of the file | | device | `UInt` | ID of the device that contains the file | | inode | `UInt` | The inode number of the file | | mode | `UInt` | The protection mode of the file | | nlink | `Int` | The number of hard links to the file | | uid | `UInt` | The user id of the owner of the file | | gid | `UInt` | The group id of the file owner | | rdev | `UInt` | If this file refers to a device, the ID of the device it refers to | | blksize | `Int64` | The file-system preferred block size for the file | | blocks | `Int64` | The number of 512-byte blocks allocated | | mtime | `Float64` | Unix timestamp of when the file was last modified | | ctime | `Float64` | Unix timestamp of when the file's metadata was changed | """ stat(path) = (path2 = joinpath(path); path2 isa typeof(path) ? error("stat not implemented for $(typeof(path))") : stat(path2)) stat(path...) = stat(joinpath(path...)) """ lstat(path) lstat(path_elements...) Like [`stat`](@ref), but for symbolic links gets the info for the link itself rather than the file it refers to. This function must be called on a file path rather than a file object or a file descriptor. """ lstat(path) = (path2 = joinpath(path); path2 isa typeof(path) ? error("lstat not implemented for $(typeof(path))") : lstat(path2)) lstat(path...) = lstat(joinpath(path...)) # some convenience functions const filemode_table = ( [ (S_IFLNK, "l"), (S_IFSOCK, "s"), # Must appear before IFREG and IFDIR as IFSOCK == IFREG | IFDIR (S_IFREG, "-"), (S_IFBLK, "b"), (S_IFDIR, "d"), (S_IFCHR, "c"), (S_IFIFO, "p") ], [ (S_IRUSR, "r"), ], [ (S_IWUSR, "w"), ], [ (S_IXUSR|S_ISUID, "s"), (S_ISUID, "S"), (S_IXUSR, "x") ], [ (S_IRGRP, "r"), ], [ (S_IWGRP, "w"), ], [ (S_IXGRP|S_ISGID, "s"), (S_ISGID, "S"), (S_IXGRP, "x") ], [ (S_IROTH, "r"), ], [ (S_IWOTH, "w"), ], [ (S_IXOTH|S_ISVTX, "t"), (S_ISVTX, "T"), (S_IXOTH, "x") ] ) """ filemode(path) filemode(path_elements...) filemode(stat_struct) Return the mode of the file located at `path`, or the mode indicated by the file descriptor `stat_struct`. Equivalent to `stat(path).mode` or `stat_struct.mode`. """ filemode(st::StatStruct) = st.mode filemode_string(st::StatStruct) = filemode_string(st.mode) function filemode_string(mode) str = IOBuffer() for table in filemode_table complete = true for (bit, char) in table if mode & bit == bit write(str, char) complete = false break end end complete && write(str, "-") end return unsafe_takestring!(str) end """ filesize(path) filesize(path_elements...) filesize(stat_struct) Return the size of the file located at `path`, or the size indicated by file descriptor `stat_struct`. Equivalent to `stat(path).size` or `stat_struct.size`. """ filesize(st::StatStruct) = st.size """ mtime(path) mtime(path_elements...) mtime(stat_struct) Return the unix timestamp of when the file at `path` was last modified, or the last modified timestamp indicated by the file descriptor `stat_struct`. Equivalent to `stat(path).mtime` or `stat_struct.mtime`. """ mtime(st::StatStruct) = st.mtime """ ctime(path) ctime(path_elements...) ctime(stat_struct) Return the unix timestamp of when the metadata of the file at `path` was last modified, or the last modified metadata timestamp indicated by the file descriptor `stat_struct`. Equivalent to `stat(path).ctime` or `stat_struct.ctime`. """ ctime(st::StatStruct) = st.ctime # mode type predicates """ ispath(path)::Bool ispath(path_elements...)::Bool Return `true` if a valid filesystem entity exists at `path`, otherwise returns `false`. This is the generalization of [`isfile`](@ref), [`isdir`](@ref) etc. """ ispath(st::StatStruct) = st.ioerrno == 0 function ispath(path::String) # We use `access()` and `F_OK` to determine if a given path exists. `F_OK` comes from `unistd.h`. F_OK = 0x00 r = ccall(:jl_fs_access, Cint, (Cstring, Cint), path, F_OK) if !(r in (0, Base.UV_ENOENT, Base.UV_ENOTDIR, Base.UV_EINVAL)) uv_error(string("ispath(", repr(path), ")"), r) end return r == 0 end ispath(path::AbstractString) = ispath(String(path)::String) """ isfifo(path)::Bool isfifo(path_elements...)::Bool isfifo(stat_struct)::Bool Return `true` if the file at `path` or file descriptor `stat_struct` is FIFO, `false` otherwise. """ isfifo(st::StatStruct) = filemode(st) & 0xf000 == 0x1000 """ ischardev(path)::Bool ischardev(path_elements...)::Bool ischardev(stat_struct)::Bool Return `true` if the path `path` or file descriptor `stat_struct` refer to a character device, `false` otherwise. """ ischardev(st::StatStruct) = filemode(st) & 0xf000 == 0x2000 """ isdir(path)::Bool isdir(path_elements...)::Bool Return `true` if `path` points to a directory, `false` otherwise. See also [`isfile`](@ref), [`ispath`](@ref). # Examples ```jldoctest julia> isdir(homedir()) true julia> isdir("not/a/directory") false ``` """ isdir(st::StatStruct) = filemode(st) & 0xf000 == 0x4000 """ isblockdev(path)::Bool isblockdev(path_elements...)::Bool isblockdev(stat_struct)::Bool Return `true` if the path `path` or file descriptor `stat_struct` refer to a block device, `false` otherwise. """ isblockdev(st::StatStruct) = filemode(st) & 0xf000 == 0x6000 """ isfile(path)::Bool isfile(path_elements...)::Bool Return `true` if `path` points to a regular file, `false` otherwise. See also [`isdir`](@ref), [`ispath`](@ref). # Examples ```jldoctest julia> isfile(homedir()) false julia> filename = "test_file.txt"; julia> write(filename, "Hello world!"); julia> isfile(filename) true julia> rm(filename); julia> isfile(filename) false ``` """ isfile(st::StatStruct) = filemode(st) & 0xf000 == 0x8000 """ islink(path)::Bool islink(path_elements...)::Bool Return `true` if `path` points to a symbolic link, `false` otherwise. """ islink(st::StatStruct) = filemode(st) & 0xf000 == 0xa000 """ issocket(path)::Bool issocket(path_elements...)::Bool Return `true` if `path` points to a socket, `false` otherwise. """ issocket(st::StatStruct) = filemode(st) & 0xf000 == 0xc000 # mode permission predicates """ issetuid(path)::Bool issetuid(path_elements...)::Bool issetuid(stat_struct)::Bool Return `true` if the file at `path` or file descriptor `stat_struct` have the setuid flag set, `false` otherwise. """ issetuid(st::StatStruct) = (filemode(st) & 0o4000) > 0 """ issetgid(path)::Bool issetgid(path_elements...)::Bool issetgid(stat_struct)::Bool Return `true` if the file at `path` or file descriptor `stat_struct` have the setgid flag set, `false` otherwise. """ issetgid(st::StatStruct) = (filemode(st) & 0o2000) > 0 """ issticky(path)::Bool issticky(path_elements...)::Bool issticky(stat_struct)::Bool Return `true` if the file at `path` or file descriptor `stat_struct` have the sticky bit set, `false` otherwise. """ issticky(st::StatStruct) = (filemode(st) & 0o1000) > 0 """ uperm(path) uperm(path_elements...) uperm(stat_struct) Return a bitfield of the owner permissions for the file at `path` or file descriptor `stat_struct`. | Value | Description | |:------|:-------------------| | 01 | Execute Permission | | 02 | Write Permission | | 04 | Read Permission | The fact that a bitfield is returned means that if the permission is read+write, the bitfield is "110", which maps to the decimal value of 0+2+4=6. This is reflected in the printing of the returned `UInt8` value. See also [`gperm`](@ref), [`operm`](@ref). ```jldoctest julia> touch("dummy_file"); # Create test-file without contents julia> uperm("dummy_file") 0x06 julia> bitstring(ans) "00000110" julia> has_read_permission(path) = uperm(path) & 0b00000100 != 0; # Use bit mask to check specific bit julia> has_read_permission("dummy_file") true julia> rm("dummy_file") # Clean up test-file ``` """ uperm(st::StatStruct) = UInt8((filemode(st) >> 6) & 0x7) """ gperm(path) gperm(path_elements...) gperm(stat_struct) Like [`uperm`](@ref) but gets the permissions of the group owning the file. See also [`operm`](@ref). """ gperm(st::StatStruct) = UInt8((filemode(st) >> 3) & 0x7) """ operm(path) operm(path_elements...) operm(stat_struct) Like [`uperm`](@ref) but gets the permissions for people who neither own the file nor are a member of the group owning the file. See also [`gperm`](@ref). """ 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 function samefile(a::StatStruct, b::StatStruct) ispath(a) && ispath(b) && a.device == b.device && a.inode == b.inode end """ samefile(path_a, path_b) Check if the paths `path_a` and `path_b` refer to the same existing file or directory. """ samefile(a::AbstractString, b::AbstractString) = samefile(stat(a), stat(b)) """ ismount(path)::Bool ismount(path_elements...)::Bool Return `true` if `path` is a mount point, `false` otherwise. """ 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