[commit: packages/Cabal] ghc-head: Work around the low clock resolution problem of 'getModificationTime'. (a8609ae)

git at git.haskell.org git at git.haskell.org
Mon Aug 26 23:23:04 CEST 2013


Repository : ssh://git@git.haskell.org/Cabal

On branch  : ghc-head
Link       : http://git.haskell.org/?p=packages/Cabal.git;a=commit;h=a8609aeb9fd8e57ebda2d9607aa5a1d089ecbd04

>---------------------------------------------------------------

commit a8609aeb9fd8e57ebda2d9607aa5a1d089ecbd04
Author: Mikhail Glushenkov <the.dead.shall.rise at gmail.com>
Date:   Mon Apr 29 21:42:31 2013 +0200

    Work around the low clock resolution problem of 'getModificationTime'.
    
    See http://hackage.haskell.org/trac/ghc/ticket/7473 .


>---------------------------------------------------------------

a8609aeb9fd8e57ebda2d9607aa5a1d089ecbd04
 cabal-install/Distribution/Compat/Time.hs |   70 ++++++++++++++++++++++++-----
 1 file changed, 59 insertions(+), 11 deletions(-)

diff --git a/cabal-install/Distribution/Compat/Time.hs b/cabal-install/Distribution/Compat/Time.hs
index 63a24c2..be217dc 100644
--- a/cabal-install/Distribution/Compat/Time.hs
+++ b/cabal-install/Distribution/Compat/Time.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE CPP, ForeignFunctionInterface #-}
 module Distribution.Compat.Time (EpochTime, getModTime, getFileAge, getCurTime)
        where
 
@@ -13,20 +13,68 @@ import System.Time (ClockTime(..), getClockTime
                    ,diffClockTimes, normalizeTimeDiff, tdDay)
 #endif
 
--- | The number of seconds since the UNIX epoch
+#if defined mingw32_HOST_OS
+
+import Data.Int         (Int32)
+import Data.Word        (Word32)
+import Foreign          (Ptr, allocaBytes, peekByteOff)
+import Foreign.C.Types  (CChar(..))
+import Foreign.C.String (withCString)
+import System.IO.Error  (mkIOError, doesNotExistErrorType)
+
+type WIN32_FILE_ATTRIBUTE_DATA = Ptr ()
+type LPCSTR = Ptr CChar
+
+foreign import stdcall "Windows.h GetFileAttributesExA"
+  c_getFileAttributesEx :: LPCSTR -> Int32
+                           -> WIN32_FILE_ATTRIBUTE_DATA -> IO Bool
+
+size_WIN32_FILE_ATTRIBUTE_DATA :: Int
+size_WIN32_FILE_ATTRIBUTE_DATA = 36
+
+index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime :: Int
+index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime = 20
+
+#else
+
+import Foreign.C.Types    (CTime(..))
+import System.Posix.Files (getFileStatus, modificationTime)
+
+#endif
+
+-- | The number of seconds since the UNIX epoch.
 type EpochTime = Int64
 
--- FIXME: 'getModificationTime' has a very low (second-level) resolution in all
--- released GHCs, which is bad for our purposes.
--- See hackage.haskell.org/trac/ghc/ticket/7473
--- We should copy the file modification utils that Shake uses.
+-- | Return modification time of given file. Works around the low clock
+-- resolution problem that 'getModificationTime' has on GHC < 7.8.
+--
+-- This is a modified version of the code originally written for OpenShake by
+-- Neil Mitchell. See module Development.Shake.FileTime.
 getModTime :: FilePath -> IO EpochTime
-getModTime path =  do
-#if MIN_VERSION_directory(1,2,0)
-  (truncate . utcTimeToPOSIXSeconds) `fmap` getModificationTime path
+
+#if defined mingw32_HOST_OS
+
+-- Directly against the Win32 API.
+getModTime path = withCString path $ \file ->
+  allocaBytes size_WIN32_FILE_ATTRIBUTE_DATA $ \info -> do
+    res <- c_getFileAttributesEx file 0 info
+    if not res
+      then do
+        let err = mkIOError doesNotExistErrorType
+                  "Distribution.Compat.Time.getModTime"
+                  Nothing (Just path)
+        ioError err
+      else do
+        dword <- peekByteOff info
+                 index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime
+        return $! fromIntegral (dword :: Word32)
 #else
-  (TOD s _) <- getModificationTime path
-  return $! fromIntegral s
+
+-- Directly against the unix library.
+getModTime path = do
+    (CTime i) <- fmap modificationTime $ getFileStatus path
+    -- CTime is Int32 in base < 4.6, but Int64 in base >= 4.6.
+    return (fromIntegral i)
 #endif
 
 -- | Return age of given file in days.





More information about the ghc-commits mailing list