module Development.Shake.FileTime(
FileTime, fileTimeNone,
getModTimeError, getModTimeMaybe
) where
import Development.Shake.Classes
import General.String
import Data.Char
import Data.Int
import Data.Word
import Numeric
#if defined(PORTABLE)
import System.IO.Error
import Control.Exception
import System.Directory
import Data.Time
import System.Time
#elif defined(mingw32_HOST_OS)
import qualified Data.ByteString.Char8 as BS
import Foreign
import Foreign.C.Types
import Foreign.C.String
#else
import System.IO.Error
import Control.Exception
import System.Posix.Files.ByteString
#endif
newtype FileTime = FileTime Int32
deriving (Typeable,Eq,Hashable,Binary,NFData)
instance Show FileTime where
show (FileTime x) = "0x" ++ replicate (length s 8) '0' ++ map toUpper s
where s = showHex (fromIntegral x :: Word32) ""
fileTime :: Int32 -> FileTime
fileTime x = FileTime $ if x == maxBound then maxBound 1 else x
fileTimeNone :: FileTime
fileTimeNone = FileTime maxBound
getModTimeError :: String -> BSU -> IO FileTime
getModTimeError msg x = do
res <- getModTimeMaybe x
case res of
Nothing -> error $ msg ++ "\n " ++ unpackU x
Just x -> return x
getModTimeMaybe :: BSU -> IO (Maybe FileTime)
#if defined(PORTABLE)
getModTimeMaybe x = handleJust (\e -> if isDoesNotExistError e then Just () else Nothing) (const $ return Nothing) $ do
time <- getModificationTime $ unpackU x
return $ Just $ extractFileTime time
class ExtractFileTime a where extractFileTime :: a -> FileTime
instance ExtractFileTime ClockTime where extractFileTime (TOD t _) = fileTime $ fromIntegral t
instance ExtractFileTime UTCTime where extractFileTime = fileTime . floor . fromRational . toRational . utctDayTime
#elif defined(mingw32_HOST_OS)
getModTimeMaybe x = BS.useAsCString (unpackU_ x) $ \file ->
alloca_WIN32_FILE_ATTRIBUTE_DATA $ \fad -> do
res <- c_getFileAttributesExA file 0 fad
if res then
fmap (Just . fileTime) $ peekLastWriteTimeLow fad
else if requireU x then withCWString (unpackU x) $ \file -> do
res <- c_getFileAttributesExW file 0 fad
if res then fmap (Just . fileTime) $ peekLastWriteTimeLow fad else return Nothing
else
return Nothing
foreign import stdcall unsafe "Windows.h GetFileAttributesExA" c_getFileAttributesExA :: Ptr CChar -> Int32 -> Ptr WIN32_FILE_ATTRIBUTE_DATA -> IO Bool
foreign import stdcall unsafe "Windows.h GetFileAttributesExW" c_getFileAttributesExW :: Ptr CWchar -> Int32 -> Ptr WIN32_FILE_ATTRIBUTE_DATA -> IO Bool
data WIN32_FILE_ATTRIBUTE_DATA
alloca_WIN32_FILE_ATTRIBUTE_DATA :: (Ptr WIN32_FILE_ATTRIBUTE_DATA -> IO a) -> IO a
alloca_WIN32_FILE_ATTRIBUTE_DATA act = allocaBytes size_WIN32_FILE_ATTRIBUTE_DATA act
where size_WIN32_FILE_ATTRIBUTE_DATA = 36
peekLastWriteTimeLow :: Ptr WIN32_FILE_ATTRIBUTE_DATA -> IO Int32
peekLastWriteTimeLow p = peekByteOff p index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime
where index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime = 20
#else
getModTimeMaybe x = handleJust (\e -> if isDoesNotExistError e then Just () else Nothing) (const $ return Nothing) $ do
s <- getFileStatus $ unpackU_ x
return $ Just $ fileTime $ extractFileTime s
extractFileTime :: FileStatus -> Int32
#ifndef MIN_VERSION_unix
#define MIN_VERSION_unix(a,b,c) 0
#endif
#if MIN_VERSION_unix(2,6,0)
extractFileTime x = ceiling $ modificationTimeHiRes x * 1e4
#else
extractFileTime x = fromIntegral $ fromEnum $ modificationTime x
#endif
#endif