Extract high resolution timestamps from FileStatus
authorMarios Titas <redneb@gmx.com>
Wed, 13 Jun 2012 06:52:03 +0000 (02:52 -0400)
committerPaolo Capriotti <p.capriotti@gmail.com>
Tue, 17 Jul 2012 15:42:13 +0000 (16:42 +0100)
Signed-off-by: Paolo Capriotti <p.capriotti@gmail.com>
System/Posix/Files.hsc
System/Posix/Files/ByteString.hsc
System/Posix/Files/Common.hsc
configure.ac
tests/fileStatus.hs
tests/fileStatusByteString.hs
unix.cabal

index 5916d1a..cb9663c 100644 (file)
@@ -57,6 +57,7 @@ module System.Posix.Files (
     deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,
     specialDeviceID, fileSize, accessTime, modificationTime,
     statusChangeTime,
+    accessTimeHiRes, modificationTimeHiRes, statusChangeTimeHiRes,
     isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,
     isDirectory, isSymbolicLink, isSocket,
 
index 5853ab9..cb183ff 100644 (file)
@@ -55,6 +55,7 @@ module System.Posix.Files.ByteString (
     deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,
     specialDeviceID, fileSize, accessTime, modificationTime,
     statusChangeTime,
+    accessTimeHiRes, modificationTimeHiRes, statusChangeTimeHiRes,
     isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,
     isDirectory, isSymbolicLink, isSocket,
 
index 2894244..01f9fb3 100644 (file)
@@ -54,6 +54,7 @@ module System.Posix.Files.Common (
     deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,
     specialDeviceID, fileSize, accessTime, modificationTime,
     statusChangeTime,
+    accessTimeHiRes, modificationTimeHiRes, statusChangeTimeHiRes,
     isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,
     isDirectory, isSymbolicLink, isSocket,
 
@@ -71,6 +72,8 @@ import System.Posix.Error
 import System.Posix.Types
 import System.IO.Unsafe
 import Data.Bits
+import Data.Time.Clock.POSIX
+import Data.Ratio
 import System.Posix.Internals
 import Foreign hiding (unsafePerformIO)
 import Foreign.C
@@ -233,10 +236,16 @@ specialDeviceID  :: FileStatus -> DeviceID
 fileSize         :: FileStatus -> FileOffset
 -- | Time of last access.
 accessTime       :: FileStatus -> EpochTime
+-- | Time of last access in sub-second resolution.
+accessTimeHiRes  :: FileStatus -> POSIXTime
 -- | Time of last modification.
 modificationTime :: FileStatus -> EpochTime
+-- | Time of last modification in sub-second resolution.
+modificationTimeHiRes :: FileStatus -> POSIXTime
 -- | Time of last status change (i.e. owner, group, link count, mode, etc.).
 statusChangeTime :: FileStatus -> EpochTime
+-- | Time of last status change (i.e. owner, group, link count, mode, etc.) in sub-second resolution.
+statusChangeTimeHiRes :: FileStatus -> POSIXTime
 
 deviceID (FileStatus stat) = 
   unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_dev)
@@ -261,6 +270,75 @@ modificationTime (FileStatus stat) =
 statusChangeTime (FileStatus stat) =
   unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_ctime)
 
+accessTimeHiRes (FileStatus stat) =
+  unsafePerformIO $ withForeignPtr stat $ \stat -> do
+    sec  <- (#peek struct stat, st_atime) stat :: IO EpochTime
+#ifdef HAVE_STRUCT_STAT_ST_ATIM
+    nsec <- (#peek struct stat, st_atim.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_ATIMESPEC
+    nsec <- (#peek struct stat, st_atimespec.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_ATIMENSEC
+    nsec <- (#peek struct stat, st_atimensec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_ATIME_N
+    nsec <- (#peek struct stat, st_atime_n) stat :: IO (#type int)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_UATIME
+    usec <- (#peek struct stat, st_uatime) stat :: IO (#type int)
+    let frac = toInteger usec % 10^6
+#else
+    let frac = 0
+#endif
+    return $ fromRational $ toRational sec + frac
+
+modificationTimeHiRes (FileStatus stat) =
+  unsafePerformIO $ withForeignPtr stat $ \stat -> do
+    sec  <- (#peek struct stat, st_mtime) stat :: IO EpochTime
+#ifdef HAVE_STRUCT_STAT_ST_MTIM
+    nsec <- (#peek struct stat, st_mtim.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_MTIMESPEC
+    nsec <- (#peek struct stat, st_mtimespec.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_MTIMENSEC
+    nsec <- (#peek struct stat, st_mtimensec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_MTIME_N
+    nsec <- (#peek struct stat, st_mtime_n) stat :: IO (#type int)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_UMTIME
+    usec <- (#peek struct stat, st_umtime) stat :: IO (#type int)
+    let frac = toInteger usec % 10^6
+#else
+    let frac = 0
+#endif
+    return $ fromRational $ toRational sec + frac
+
+statusChangeTimeHiRes (FileStatus stat) =
+  unsafePerformIO $ withForeignPtr stat $ \stat -> do
+    sec  <- (#peek struct stat, st_ctime) stat :: IO EpochTime
+#ifdef HAVE_STRUCT_STAT_ST_CTIM
+    nsec <- (#peek struct stat, st_ctim.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_CTIMESPEC
+    nsec <- (#peek struct stat, st_ctimespec.tv_nsec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_CTIMENSEC
+    nsec <- (#peek struct stat, st_ctimensec) stat :: IO (#type long)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_CTIME_N
+    nsec <- (#peek struct stat, st_ctime_n) stat :: IO (#type int)
+    let frac = toInteger nsec % 10^9
+#elif HAVE_STRUCT_STAT_ST_UCTIME
+    usec <- (#peek struct stat, st_uctime) stat :: IO (#type int)
+    let frac = toInteger usec % 10^6
+#else
+    let frac = 0
+#endif
+    return $ fromRational $ toRational sec + frac
+
 -- | Checks if this file is a block device.
 isBlockDevice     :: FileStatus -> Bool
 -- | Checks if this file is a character device.
index ebf708d..9461452 100644 (file)
@@ -34,6 +34,22 @@ AC_CHECK_FUNCS([ptsname])
 AC_CHECK_FUNCS([setitimer])
 AC_CHECK_FUNCS([readdir_r])
 
+AC_CHECK_MEMBERS([struct stat.st_atim])
+AC_CHECK_MEMBERS([struct stat.st_mtim])
+AC_CHECK_MEMBERS([struct stat.st_ctim])
+AC_CHECK_MEMBERS([struct stat.st_atimespec])
+AC_CHECK_MEMBERS([struct stat.st_mtimespec])
+AC_CHECK_MEMBERS([struct stat.st_ctimespec])
+AC_CHECK_MEMBERS([struct stat.st_atimensec])
+AC_CHECK_MEMBERS([struct stat.st_mtimensec])
+AC_CHECK_MEMBERS([struct stat.st_ctimensec])
+AC_CHECK_MEMBERS([struct stat.st_atime_n])
+AC_CHECK_MEMBERS([struct stat.st_mtime_n])
+AC_CHECK_MEMBERS([struct stat.st_ctime_n])
+AC_CHECK_MEMBERS([struct stat.st_uatime])
+AC_CHECK_MEMBERS([struct stat.st_umtime])
+AC_CHECK_MEMBERS([struct stat.st_uctime])
+
 # Additional temp functions
 AC_CHECK_FUNCS([mkstemps mkdtemp])
 
index e1d1661..262d396 100644 (file)
@@ -83,7 +83,7 @@ getStatus f = do
 
   return (fs, ls)
 
--- Yay for 17-element tuples!
+-- Yay for 20-element tuples!
 statusElements fs = (,)
   (deviceID fs
   ,fileMode fs
@@ -93,8 +93,11 @@ statusElements fs = (,)
   ,specialDeviceID fs
   ,fileSize fs
   ,accessTime fs
+  ,accessTimeHiRes fs
   ,modificationTime fs
+  ,modificationTimeHiRes fs
   ,statusChangeTime fs
+  ,statusChangeTimeHiRes fs
   )
   (isBlockDevice fs
   ,isCharacterDevice fs
index 35d52d8..ec492b3 100644 (file)
@@ -82,7 +82,7 @@ getStatus f = do
 
   return (fs, ls)
 
--- Yay for 17-element tuples!
+-- Yay for 20-element tuples!
 statusElements fs = (,)
   (deviceID fs
   ,fileMode fs
@@ -92,8 +92,11 @@ statusElements fs = (,)
   ,specialDeviceID fs
   ,fileSize fs
   ,accessTime fs
+  ,accessTimeHiRes fs
   ,modificationTime fs
+  ,modificationTimeHiRes fs
   ,statusChangeTime fs
+  ,statusChangeTimeHiRes fs
   )
   (isBlockDevice fs
   ,isCharacterDevice fs
index 59fe0ad..e425f5e 100644 (file)
@@ -78,7 +78,8 @@ Library
         System.Posix.Terminal.Common
 
     build-depends:      base >= 4.2 && < 4.7,
-                        bytestring >= 0.9.2.0 && < 0.11
+                        bytestring >= 0.9.2.0 && < 0.11,
+                        time
     extensions: CPP, ForeignFunctionInterface, EmptyDataDecls
     if impl(ghc >= 7.1)
         extensions: NondecreasingIndentation