Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/HiddenFiles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ include("docs.jl")

@static if Sys.isunix()
include("utils/zfs.jl")
if iszfs() # @static breaks here # ZFS

function _ishidden_zfs(f::AbstractString, rp::AbstractString)
error("not yet implemented")
_ishidden_zfs(f::AbstractString, rp::AbstractString) = error("not yet implemented")
_ishidden = _ishidden_zfs
end

# Trivial Unix check
_isdotfile(f::AbstractString) = startswith(basename(f), '.')
# Check dotfiles, but also account for ZFS
_ishidden_unix(f::AbstractString, rp::AbstractString) = _isdotfile(rp) || (iszfs() && _ishidden_zfs("", ""))
_ishidden_unix(f::AbstractString, rp::AbstractString) = _isdotfile(rp) || (iszfs() && _ishidden_zfs(f, rp))

@static if Sys.isbsd() # BDS-related; this is true for macOS as well
# https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/chflags.2.html
Expand Down
13 changes: 11 additions & 2 deletions src/docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@ See also: [`_ishidden_unix`](@ref), [`_ishidden_windows`](@ref), [`_ishidden_mac
_ishidden

### ZFS ###
"This function is not yet implemented"
iszfs
"""
```julia
_iszfs(f::AbstractString) -> Bool
```

Determines if the file system that `f` exists on is ZFS.

!!! note
This is only implemented for Unix-like systems, as I have not seen ZFS for Windows.
"""
_iszfs

"This function is not yet implemented"
_ishidden_zfs
Expand Down
96 changes: 93 additions & 3 deletions src/utils/zfs.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,95 @@
function iszfs()
# TODO
return false
# TODO: Correct < 1.6 error codes

# https://lists.freebsd.org/pipermail/freebsd-hackers/2018-February/052295.html
const SUN_ZFS_SUPER_MAGIC = 0x1b
const BSD_ZFS_SUPER_MAGIC = 0xde # Obtained from testing
# https://reviews.freebsd.org/rS320069
const LINUX_ZFS_SUPER_MAGIC = 0x2fc12fc1

const ZFS_SUPER_MAGICS = (SUN_ZFS_SUPER_MAGIC, BSD_ZFS_SUPER_MAGIC, LINUX_ZFS_SUPER_MAGIC)

@static if VERSION ≥ v"1.6"
@static if VERSION < v"1.8"
# Adapted from Julia 1.8's diskstat: https://github.com/JuliaLang/julia/pull/42248
# C calls for UV statfs requires Julia 1.6
# http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_statfs
struct DiskStat
ftype::UInt64
bsize::UInt64
blocks::UInt64
bfree::UInt64
bavail::UInt64
files::UInt64
ffree::UInt64
fspare::NTuple{4, UInt64} # reserved
end
function statfs(f::AbstractString)
buf = Vector{UInt8}(undef, ccall(:jl_sizeof_uv_fs_t, Int32, ()))
i = ccall(:uv_fs_statfs, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}),
C_NULL, buf, f, C_NULL)
i < 0 && Base.uv_error("statfs($(repr(f)))", i)
p = ccall(:jl_uv_fs_t_ptr, Ptr{UInt32}, (Ptr{Cvoid},), buf)

return unsafe_load(reinterpret(Ptr{DiskStat}, p))
end
else
statfs = diskstat
end

function _iszfs(f::AbstractString)
s = statfs(f)
@info s.ftype
return s.ftype ∈ ZFS_SUPER_MAGICS
end
else
# If Julia version < 1.6, we have to write our own, not very nice solution

# It occurred to me that UInt8 wasn't always enough to store the f_type (eda1c22)
const STATFS_BUF_ELTYPE = UInt32
const SIZEOF_STATFS_BUF_ELTYPE = Int8(sizeof(STATFS_BUF_ELTYPE))

@static if Sys.isapple()
# macOS: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/statfs.2.html
const SIZEOF_STATFS = cld(2168, SIZEOF_STATFS_BUF_ELTYPE)
const F_TYPE_OFFSET = cld(0x3d, SIZEOF_STATFS_BUF_ELTYPE)
const F_FSSUBTYPE_OFFSET = cld(0x45, SIZEOF_STATFS_BUF_ELTYPE)

function _iszfs(f::AbstractString)
buf = Vector{STATFS_BUF_ELTYPE}(undef, SIZEOF_STATFS)
# statfs(const char *path, struct statfs *buf);
i = ccall(:statfs, Int, (Cstring, Ptr{Cvoid}), f, buf)
i < 0 && Base.uv_error("statfs($(repr(f)))", i)
@info buf[F_TYPE_OFFSET], buf[F_FSSUBTYPE_OFFSET], buf, f
return buf[F_TYPE_OFFSET] ∈ ZFS_SUPER_MAGICS || buf[F_FSSUBTYPE_OFFSET] ∈ ZFS_SUPER_MAGICS
end
elseif Sys.isbsd()
# https://www.freebsd.org/cgi/man.cgi?query=statfs&sektion=2
const SIZEOF_STATFS = cld(2344, SIZEOF_STATFS_BUF_ELTYPE)
const F_TYPE_OFFSET = cld(0x05, SIZEOF_STATFS_BUF_ELTYPE)

function _iszfs(f::AbstractString)
buf = Vector{STATFS_BUF_ELTYPE}(undef, SIZEOF_STATFS)
# statfs(const char *path, struct statfs *buf);
i = ccall(:statfs, Int, (Cstring, Ptr{Cvoid}), f, buf)
i < 0 && Base.uv_error("statfs($(repr(f)))", i)
@info buf[F_TYPE_OFFSET], buf, f
return buf[F_TYPE_OFFSET] ∈ ZFS_SUPER_MAGICS
end
elseif Sys.isunix()
# Linux: https://man7.org/linux/man-pages/man2/statfs.2.html
const SIZEOF_STATFS = cld(120, SIZEOF_STATFS_BUF_ELTYPE)
const F_TYPE_OFFSET = cld(0x01, SIZEOF_STATFS_BUF_ELTYPE)

function _iszfs(f::AbstractString)
buf = Vector{STATFS_BUF_ELTYPE}(undef, SIZEOF_STATFS)
# statfs(const char *path, struct statfs *buf);
i = ccall(:statfs, Int, (Cstring, Ptr{Cvoid}), f, buf)
i < 0 && Base.uv_error("statfs($(repr(f)))", i)
@info buf[F_TYPE_OFFSET], buf, f
return buf[F_TYPE_OFFSET] ∈ ZFS_SUPER_MAGICS
end
else
_iszfs(_f::AbstractString) = error("Cannot call statfs for non-Unix operating systems")
end
end