Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add disk stat functions #42248

Merged
merged 18 commits into from
Oct 30, 2021
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,7 @@ export
chown,
cp,
ctime,
diskstat,
download,
filemode,
filesize,
Expand Down
70 changes: 70 additions & 0 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export
chown,
cp,
cptree,
diskstat,
hardlink,
mkdir,
mkpath,
Expand Down Expand Up @@ -1168,3 +1169,72 @@ function chown(path::AbstractString, owner::Integer, group::Integer=-1)
err < 0 && uv_error("chown($(repr(path)), $owner, $group)", err)
path
end


# typedef struct uv_statfs_s {
# uint64_t f_type;
# uint64_t f_bsize; <- block size
# uint64_t f_blocks; <- total blocks
# uint64_t f_bfree;
# uint64_t f_bavail; <- available blocks
# uint64_t f_files;
# uint64_t f_ffree;
# uint64_t f_spare[4];
# } uv_statfs_t;
# See also
li1 marked this conversation as resolved.
Show resolved Hide resolved
# - http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_statfs (libuv function docs)
# - http://docs.libuv.org/en/v1.x/fs.html#c.uv_statfs_t (libuv docs of the returned struct)
struct StatFS
ftype::UInt64
bsize::UInt64
blocks::UInt64
bfree::UInt64
bavail::UInt64
files::UInt64
ffree::UInt64
fspare1::UInt128
fspare2::UInt128
li1 marked this conversation as resolved.
Show resolved Hide resolved
end

"""
DiskStat

li1 marked this conversation as resolved.
Show resolved Hide resolved
Stores the total size, available space, and currently used space of the disk in bytes.
Populate by calling `diskstat`.
"""
struct DiskStat
total::Int
available::Int
used::Int
li1 marked this conversation as resolved.
Show resolved Hide resolved
end

"""
diskstat(path=pwd())

Returns statistics in bytes about the disk that contains the file or directory pointed at by
`path`. If no argument is passed, statistics about the disk that contains the current
working directory are returned.

!!! compat "Julia 1.8"
This method was added in Julia 1.8.
"""
function diskstat(path::AbstractString=pwd())
ispath(path) || throw(ArgumentError("'$path' is not a file or directory."))
li1 marked this conversation as resolved.
Show resolved Hide resolved

# Call libuv's cross-platform statfs implementation
li1 marked this conversation as resolved.
Show resolved Hide resolved
req = Ref{NTuple{Int(_sizeof_uv_fs), UInt8}}()
err = ccall(:uv_fs_statfs, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}),
C_NULL, req, path, C_NULL)
err < 0 && uv_error("statfs($(repr(path)))", err)
statfs_ptr = ccall(:jl_uv_fs_t_ptr, Ptr{Nothing}, (Ptr{Cvoid},), req)

stats = unsafe_load(reinterpret(Ptr{StatFS}, statfs_ptr))
li1 marked this conversation as resolved.
Show resolved Hide resolved
total = Int(stats.bsize * stats.blocks)
available = Int(stats.bsize * stats.bavail)
li1 marked this conversation as resolved.
Show resolved Hide resolved
disk_stats = DiskStat(total, available, total - available)

# Cleanup
uv_fs_req_cleanup(req)
li1 marked this conversation as resolved.
Show resolved Hide resolved

return disk_stats
end
9 changes: 9 additions & 0 deletions test/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1692,3 +1692,12 @@ end
@test !isnothing(Base.Filesystem.getgroupname(s.gid))
end
end

@testset "diskstat() works" begin
dstat = diskstat()
li1 marked this conversation as resolved.
Show resolved Hide resolved

# Sanity check assuming disk is smaller than 32TB
TB = 2^41
@test dstat.total < 32TB
li1 marked this conversation as resolved.
Show resolved Hide resolved
@test dstat.used + dstat.available == dstat.total
end