diff --git a/System/Posix/Files.hsc b/System/Posix/Files.hsc index 7587718..7d95a2e 100644 --- a/System/Posix/Files.hsc +++ b/System/Posix/Files.hsc @@ -62,6 +62,15 @@ module System.Posix.Files ( fileBlockSize, fileBlocks, + -- * Extended file status + StatxFlags(..), + defaultStatxFlags, + StatxMask(..), + defaultStatxMask, + ExtendedFileStatus(..), + fileSizeX, + fileGroupX, + -- * Creation createNamedPipe, createDevice, diff --git a/System/Posix/Files/ByteString.hsc b/System/Posix/Files/ByteString.hsc index 1c7b5a0..b5e34f3 100644 --- a/System/Posix/Files/ByteString.hsc +++ b/System/Posix/Files/ByteString.hsc @@ -49,8 +49,14 @@ module System.Posix.Files.ByteString ( -- * File status FileStatus, + StatxFlags(..), + defaultStatxFlags, + StatxMask(..), + defaultStatxMask, + ExtendedFileStatus(..), -- ** Obtaining file status getFileStatus, getFdStatus, getSymbolicLinkStatus, + getExtendedFileStatus, -- ** Querying file status deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup, specialDeviceID, fileSize, accessTime, modificationTime, @@ -184,6 +190,17 @@ getFileStatus path = do throwErrnoPathIfMinus1Retry_ "getFileStatus" path (c_stat s p) return (FileStatus fp) +-- | @getExtendedFileStatus path@ gets the @FileStatus@ information (user ID, +-- size, access times, etc.) for the file @path@. +-- +-- Note: calls @statx@. +getExtendedFileStatus :: Maybe Fd -- ^ Optional directory file descriptor + -> RawFilePath -- ^ Pathname to open + -> StatxFlags + -> StatxMask + -> IO ExtendedFileStatus +getExtendedFileStatus mfd path flags masks = withFilePath path $ \s -> getExtendedFileStatus_ mfd s flags masks + -- | Acts as 'getFileStatus' except when the 'RawFilePath' refers to a symbolic -- link. In that case the @FileStatus@ information of the symbolic link itself -- is returned instead of that of the file it points to. diff --git a/System/Posix/Files/Common.hsc b/System/Posix/Files/Common.hsc index b03859a..851ec78 100644 --- a/System/Posix/Files/Common.hsc +++ b/System/Posix/Files/Common.hsc @@ -1,4 +1,5 @@ {-# LANGUAGE CApiFFI #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE Trustworthy #-} ----------------------------------------------------------------------------- @@ -60,6 +61,17 @@ module System.Posix.Files.Common ( fileBlockSize, fileBlocks, + -- * Extended file status + StatxFlags(..), + defaultStatxFlags, + StatxMask(..), + defaultStatxMask, + ExtendedFileStatus(..), + getExtendedFileStatus_, + fileSizeX, + fileGroupX, + fileOwnerX, + -- * Setting file sizes setFdSize, @@ -688,3 +700,109 @@ getFdPathVar (Fd fd) v = foreign import ccall unsafe "fpathconf" c_fpathconf :: CInt -> CInt -> IO CLong + + + -- ----------------------------------------------------------------------------- +-- statx +-- +data StatxFlags = + StatxFlags { + emptyPath :: Bool + , noAutoMount :: Bool + , symlinkNoFollow :: Bool + } + deriving (Read, Show, Eq, Ord) + + +defaultStatxFlags :: StatxFlags +defaultStatxFlags = + StatxFlags { + emptyPath = False, + noAutoMount = False, + symlinkNoFollow = False + } + +data StatxMask = + StatxMask { + statx_type :: Bool + , statx_mode :: Bool + , statx_nlink :: Bool + , statx_uid :: Bool + , statx_gid :: Bool + , statx_atime :: Bool + , statx_mtime :: Bool + , statx_ctime :: Bool + , statx_ino :: Bool + , statx_size :: Bool + , statx_blocks :: Bool + , statx_btime :: Bool + } + deriving (Read, Show, Eq, Ord) + + +defaultStatxMask :: StatxMask +defaultStatxMask = + StatxMask { + statx_type = False + , statx_mode = False + , statx_nlink = False + , statx_uid = False + , statx_gid = False + , statx_atime = False + , statx_mtime = False + , statx_ctime = False + , statx_ino = False + , statx_size = False + , statx_blocks = False + , statx_btime = False + } + +newtype ExtendedFileStatus = ExtendedFileStatus (ForeignPtr CStatx) -- ^ The constructor is considered internal and may change. + +fileOwnerX :: ExtendedFileStatus -> UserID +fileGroupX :: ExtendedFileStatus -> GroupID +fileSizeX :: ExtendedFileStatus -> FileOffset + +fileOwnerX (ExtendedFileStatus statx) = + unsafePerformIO $ withForeignPtr statx $ (#peek struct statx, stx_uid) +fileGroupX (ExtendedFileStatus statx) = + unsafePerformIO $ withForeignPtr statx $ (#peek struct statx, stx_gid) +fileSizeX (ExtendedFileStatus statx) = + unsafePerformIO $ withForeignPtr statx $ (#peek struct statx, stx_size) + +data {-# CTYPE "struct statx" #-} CStatx + +foreign import ccall unsafe "statx" + c_statx :: CInt -> CFilePath -> CInt -> CInt -> Ptr CStatx -> IO CInt + + +getExtendedFileStatus_ :: Maybe Fd -- ^ Optional directory file descriptor + -> CString -- ^ Pathname to open + -> StatxFlags + -> StatxMask + -> IO ExtendedFileStatus +getExtendedFileStatus_ fdMay str StatxFlags{..} StatxMask{..} = do + fp <- mallocForeignPtrBytes (#const sizeof(struct statx)) + withForeignPtr fp $ \p -> + throwErrnoIfMinus1Retry_ "getExtendedFileStatus_" (c_statx c_fd str flags masks p) + return (ExtendedFileStatus fp) + where + c_fd = maybe (#const AT_FDCWD) (\ (Fd fd) -> fd) fdMay + flags = + (if emptyPath then (#const AT_EMPTY_PATH) else 0) .|. + (if noAutoMount then (#const AT_NO_AUTOMOUNT) else 0) .|. + (if symlinkNoFollow then (#const AT_SYMLINK_NOFOLLOW) else 0) + masks = + (if statx_type then (#const STATX_TYPE) else 0) .|. + (if statx_mode then (#const STATX_MODE) else 0) .|. + (if statx_nlink then (#const STATX_NLINK) else 0) .|. + (if statx_uid then (#const STATX_UID) else 0) .|. + (if statx_gid then (#const STATX_GID) else 0) .|. + (if statx_atime then (#const STATX_ATIME) else 0) .|. + (if statx_mtime then (#const STATX_MTIME) else 0) .|. + (if statx_ctime then (#const STATX_CTIME) else 0) .|. + (if statx_ino then (#const STATX_INO) else 0) .|. + (if statx_size then (#const STATX_SIZE) else 0) .|. + (if statx_blocks then (#const STATX_BLOCKS) else 0) .|. + (if statx_btime then (#const STATX_BTIME) else 0) + diff --git a/configure.ac b/configure.ac index d7d09a5..d7c40b2 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,11 @@ AC_CHECK_FUNCS([chown fchdir fchmod]) AC_CHECK_TYPE([struct rlimit],[AC_DEFINE([HAVE_STRUCT_RLIMIT],[1],[HAVE_STRUCT_RLIMIT])],[],[#include ]) +# check for statx +AC_CHECK_FUNC([statx], [AC_DEFINE([HAVE_STATX_FUN],[1],[HAVE_STATX_FUN])],[],[#include ]) +AC_CHECK_TYPE([struct statx],[AC_DEFINE([HAVE_STRUCT_STATX],[1],[HAVE_STRUCT_STATX])],[],[#include ]) +AS_IF([test "x$HAVE_STRUCT_STATX" = "x1" && test "x$HAVE_STATX_FUN" = "x1"], [AC_DEFINE([HAVE_STATX],[1],[HAVE_STATX])]) + AC_MSG_CHECKING(for F_GETLK from fcntl.h) AC_EGREP_CPP(yes, [