@@ -59,6 +59,9 @@ module System.PosixCompat.Files (
59
59
, accessTime
60
60
, modificationTime
61
61
, statusChangeTime
62
+ , accessTimeHiRes
63
+ , modificationTimeHiRes
64
+ , statusChangeTimeHiRes
62
65
, isBlockDevice
63
66
, isCharacterDevice
64
67
, isNamedPipe
@@ -120,6 +123,7 @@ import Control.Exception (bracket)
120
123
import Control.Monad (liftM , liftM2 )
121
124
import Data.Bits ((.|.) , (.&.) )
122
125
import Data.Int (Int64 )
126
+ import Data.Time.Clock.POSIX (POSIXTime )
123
127
import Foreign.C.Types (CTime (.. ))
124
128
import Prelude hiding (read )
125
129
import System.Directory (Permissions , emptyPermissions )
@@ -129,8 +133,7 @@ import System.Directory (writable, setOwnerWritable)
129
133
import System.Directory (executable , setOwnerExecutable )
130
134
import System.Directory (searchable , setOwnerSearchable )
131
135
import System.Directory (doesFileExist , doesDirectoryExist )
132
- import System.Directory (getModificationTime , renameFile )
133
- import System.IO (IOMode (.. ), openFile , hFileSize , hSetFileSize , hClose )
136
+ import System.IO (IOMode (.. ), openFile , hSetFileSize , hClose )
134
137
import System.IO.Error
135
138
import System.PosixCompat.Types
136
139
import System.Win32.File hiding (getFileType )
@@ -139,7 +142,6 @@ import System.Win32.Time (FILETIME(..), getFileTime, setFileTime)
139
142
140
143
import System.PosixCompat.Internal.Time (
141
144
getClockTime , clockTimeToEpochTime
142
- , modificationTimeToEpochTime
143
145
)
144
146
145
147
#ifdef __GLASGOW_HASKELL__
@@ -267,17 +269,20 @@ fileExist name = liftM2 (||) (doesFileExist name) (doesDirectoryExist name)
267
269
-- stat() support
268
270
269
271
data FileStatus = FileStatus
270
- { deviceID :: DeviceID
271
- , fileID :: FileID
272
- , fileMode :: FileMode
273
- , linkCount :: LinkCount
274
- , fileOwner :: UserID
275
- , fileGroup :: GroupID
276
- , specialDeviceID :: DeviceID
277
- , fileSize :: FileOffset
278
- , accessTime :: EpochTime
279
- , modificationTime :: EpochTime
280
- , statusChangeTime :: EpochTime
272
+ { deviceID :: DeviceID
273
+ , fileID :: FileID
274
+ , fileMode :: FileMode
275
+ , linkCount :: LinkCount
276
+ , fileOwner :: UserID
277
+ , fileGroup :: GroupID
278
+ , specialDeviceID :: DeviceID
279
+ , fileSize :: FileOffset
280
+ , accessTime :: EpochTime
281
+ , modificationTime :: EpochTime
282
+ , statusChangeTime :: EpochTime
283
+ , accessTimeHiRes :: POSIXTime
284
+ , modificationTimeHiRes :: POSIXTime
285
+ , statusChangeTimeHiRes :: POSIXTime
281
286
}
282
287
283
288
isBlockDevice :: FileStatus -> Bool
@@ -312,9 +317,10 @@ getFileStatus :: FilePath -> IO FileStatus
312
317
getFileStatus path = do
313
318
perm <- liftM permsToMode (getPermissions path)
314
319
typ <- getFileType path
315
- size <- if typ == regularFileMode then getFileSize path else return 0
316
- mtime <- liftM modificationTimeToEpochTime (getModificationTime path)
317
320
info <- bracket openPath closeHandle getFileInformationByHandle
321
+ let atime = windowsToPosixTime (bhfiLastAccessTime info)
322
+ mtime = windowsToPosixTime (bhfiLastWriteTime info)
323
+ ctime = windowsToPosixTime (bhfiCreationTime info)
318
324
return $ FileStatus
319
325
{ deviceID = fromIntegral (bhfiVolumeSerialNumber info)
320
326
, fileID = fromIntegral (bhfiFileIndex info)
@@ -323,10 +329,14 @@ getFileStatus path = do
323
329
, fileOwner = 0
324
330
, fileGroup = 0
325
331
, specialDeviceID = 0
326
- , fileSize = size
327
- , accessTime = mtime
328
- , modificationTime = mtime
329
- , statusChangeTime = mtime }
332
+ , fileSize = fromIntegral (bhfiSize info)
333
+ , accessTime = posixTimeToEpochTime atime
334
+ , modificationTime = posixTimeToEpochTime mtime
335
+ , statusChangeTime = posixTimeToEpochTime mtime
336
+ , accessTimeHiRes = atime
337
+ , modificationTimeHiRes = mtime
338
+ , statusChangeTimeHiRes = ctime
339
+ }
330
340
where
331
341
openPath = createFile path
332
342
gENERIC_READ
@@ -336,6 +346,32 @@ getFileStatus path = do
336
346
(sECURITY_ANONYMOUS .|. fILE_FLAG_BACKUP_SEMANTICS)
337
347
Nothing
338
348
349
+ -- | Convert a 'POSIXTime' (synomym for 'Data.Time.Clock.NominalDiffTime')
350
+ -- into an 'EpochTime' (integral number of seconds since epoch). This merely
351
+ -- throws away the fractional part.
352
+ posixTimeToEpochTime :: POSIXTime -> EpochTime
353
+ posixTimeToEpochTime = fromInteger . floor
354
+
355
+ -- three function stolen from System.Directory.Internals.Windows:
356
+
357
+ -- | Difference between the Windows and POSIX epochs in units of 100ns.
358
+ windowsPosixEpochDifference :: Num a => a
359
+ windowsPosixEpochDifference = 116444736000000000
360
+
361
+ -- | Convert from Windows time to POSIX time.
362
+ windowsToPosixTime :: FILETIME -> POSIXTime
363
+ windowsToPosixTime (FILETIME t) =
364
+ (fromIntegral t - windowsPosixEpochDifference) / 10000000
365
+
366
+ {- will be needed to /set/ high res timestamps, not yet supported
367
+
368
+ -- | Convert from POSIX time to Windows time. This is lossy as Windows time
369
+ -- has a resolution of only 100ns.
370
+ posixToWindowsTime :: POSIXTime -> FILETIME
371
+ posixToWindowsTime t = FILETIME $
372
+ truncate (t * 10000000 + windowsPosixEpochDifference)
373
+ -}
374
+
339
375
permsToMode :: Permissions -> FileMode
340
376
permsToMode perms = r .|. w .|. x
341
377
where
@@ -354,10 +390,6 @@ getFileType path =
354
390
if d then return directoryMode
355
391
else unsupported " Unknown file type."
356
392
357
- getFileSize :: FilePath -> IO FileOffset
358
- getFileSize path =
359
- bracket (openFile path ReadMode ) hClose (liftM fromIntegral . hFileSize)
360
-
361
393
getFdStatus :: Fd -> IO FileStatus
362
394
getFdStatus _ = unsupported " getFdStatus"
363
395
0 commit comments