[commit: packages/Cabal] ghc-head: getModTime: Convert Windows time to POSIX seconds. (f45552f)
git at git.haskell.org
git at git.haskell.org
Wed Oct 16 06:33:17 UTC 2013
Repository : ssh://git@git.haskell.org/Cabal
On branch : ghc-head
Link : http://git.haskell.org/packages/Cabal.git/commitdiff/f45552f6a4403e8632a5406b4dc47040102d8a20
>---------------------------------------------------------------
commit f45552f6a4403e8632a5406b4dc47040102d8a20
Author: Mikhail Glushenkov <mikhail.glushenkov at gmail.com>
Date: Sat Oct 12 13:55:28 2013 +0200
getModTime: Convert Windows time to POSIX seconds.
Fixes #1538.
(cherry picked from commit 6ce9ca28079e9ce0f6fe96e05deece5a1ca430a0)
>---------------------------------------------------------------
f45552f6a4403e8632a5406b4dc47040102d8a20
cabal-install/Distribution/Client/Compat/Time.hs | 71 ++++++++++++++--------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/cabal-install/Distribution/Client/Compat/Time.hs b/cabal-install/Distribution/Client/Compat/Time.hs
index 9913af5..e105691 100644
--- a/cabal-install/Distribution/Client/Compat/Time.hs
+++ b/cabal-install/Distribution/Client/Compat/Time.hs
@@ -16,19 +16,24 @@ import System.Time (ClockTime(..), getClockTime
#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)
+import Data.Bits ((.|.), bitSize, unsafeShiftL)
+import Data.Int (Int32)
+import Data.Word (Word64)
+import Foreign (allocaBytes, peekByteOff)
+import System.IO.Error (mkIOError, doesNotExistErrorType)
+import System.Win32.Types (BOOL, DWORD, LPCTSTR, LPVOID, withTString)
-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
+foreign import stdcall "windows.h GetFileAttributesExW"
+ c_getFileAttributesEx :: LPCTSTR -> Int32 -> LPVOID -> IO BOOL
+
+getFileAttributesEx :: String -> LPVOID -> IO BOOL
+getFileAttributesEx path lpFileInformation =
+ withTString path $ \c_path ->
+ c_getFileAttributesEx c_path getFileExInfoStandard lpFileInformation
+
+getFileExInfoStandard :: Int32
+getFileExInfoStandard = 0
size_WIN32_FILE_ATTRIBUTE_DATA :: Int
size_WIN32_FILE_ATTRIBUTE_DATA = 36
@@ -36,6 +41,9 @@ size_WIN32_FILE_ATTRIBUTE_DATA = 36
index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime :: Int
index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime = 20
+index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwHighDateTime :: Int
+index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwHighDateTime = 24
+
#else
#if MIN_VERSION_base(4,5,0)
@@ -60,21 +68,32 @@ getModTime :: FilePath -> IO EpochTime
#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.Client.Compat.Time.getModTime"
- Nothing (Just path)
- ioError err
- else do
- dword <- peekByteOff info
- index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime
- -- TODO: Convert Windows seconds to POSIX seconds. ATM we don't care
- -- since we only use the value for comparisons.
- return $! fromIntegral (dword :: Word32)
+getModTime path = allocaBytes size_WIN32_FILE_ATTRIBUTE_DATA $ \info -> do
+ res <- getFileAttributesEx path info
+ if not res
+ then do
+ let err = mkIOError doesNotExistErrorType
+ "Distribution.Client.Compat.Time.getModTime"
+ Nothing (Just path)
+ ioError err
+ else do
+ dwLow <- peekByteOff info
+ index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime
+ dwHigh <- peekByteOff info
+ index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwHighDateTime
+ return $! windowsTimeToPOSIXSeconds dwLow dwHigh
+ where
+ windowsTimeToPOSIXSeconds :: DWORD -> DWORD -> EpochTime
+ windowsTimeToPOSIXSeconds dwLow dwHigh =
+ let wINDOWS_TICK = 10000000
+ sEC_TO_UNIX_EPOCH = 11644473600
+ qwTime = (fromIntegral dwHigh `unsafeShiftL` bitSize dwHigh)
+ .|. (fromIntegral dwLow)
+ res = ((qwTime :: Word64) `div` wINDOWS_TICK)
+ - sEC_TO_UNIX_EPOCH
+ -- TODO: What if the result is not representable as POSIX seconds?
+ -- Probably fine to return garbage.
+ in fromIntegral res
#else
-- Directly against the unix library.
More information about the ghc-commits
mailing list