Skip to content

Commit c89b440

Browse files
bfrkjacobstanley
andauthored
partial support for high resolution timestamps, drop definition of FileID (#45)
* support for reading high resolution timestamps This should also improve efficiency, since we no longer call the portable functions from the directory package. While we're at it, we now also take the file size directly from the Windows file handle meta data. * remove redefinition of System.Posix.Types.FileID * bump version to 0.5.2.1 to avoid mixup with official 0.5.2 * unix-compat-0.5.3 Co-authored-by: Jacob Stanley <[email protected]>
1 parent 9a6758e commit c89b440

File tree

4 files changed

+61
-51
lines changed

4 files changed

+61
-51
lines changed

src/System/PosixCompat/Files.hsc

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ module System.PosixCompat.Files (
5959
, accessTime
6060
, modificationTime
6161
, statusChangeTime
62+
, accessTimeHiRes
63+
, modificationTimeHiRes
64+
, statusChangeTimeHiRes
6265
, isBlockDevice
6366
, isCharacterDevice
6467
, isNamedPipe
@@ -120,6 +123,7 @@ import Control.Exception (bracket)
120123
import Control.Monad (liftM, liftM2)
121124
import Data.Bits ((.|.), (.&.))
122125
import Data.Int (Int64)
126+
import Data.Time.Clock.POSIX (POSIXTime)
123127
import Foreign.C.Types (CTime(..))
124128
import Prelude hiding (read)
125129
import System.Directory (Permissions, emptyPermissions)
@@ -129,8 +133,7 @@ import System.Directory (writable, setOwnerWritable)
129133
import System.Directory (executable, setOwnerExecutable)
130134
import System.Directory (searchable, setOwnerSearchable)
131135
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)
134137
import System.IO.Error
135138
import System.PosixCompat.Types
136139
import System.Win32.File hiding (getFileType)
@@ -139,7 +142,6 @@ import System.Win32.Time (FILETIME(..), getFileTime, setFileTime)
139142

140143
import System.PosixCompat.Internal.Time (
141144
getClockTime, clockTimeToEpochTime
142-
, modificationTimeToEpochTime
143145
)
144146

145147
#ifdef __GLASGOW_HASKELL__
@@ -267,17 +269,20 @@ fileExist name = liftM2 (||) (doesFileExist name) (doesDirectoryExist name)
267269
-- stat() support
268270

269271
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
281286
}
282287

283288
isBlockDevice :: FileStatus -> Bool
@@ -312,9 +317,10 @@ getFileStatus :: FilePath -> IO FileStatus
312317
getFileStatus path = do
313318
perm <- liftM permsToMode (getPermissions path)
314319
typ <- getFileType path
315-
size <- if typ == regularFileMode then getFileSize path else return 0
316-
mtime <- liftM modificationTimeToEpochTime (getModificationTime path)
317320
info <- bracket openPath closeHandle getFileInformationByHandle
321+
let atime = windowsToPosixTime (bhfiLastAccessTime info)
322+
mtime = windowsToPosixTime (bhfiLastWriteTime info)
323+
ctime = windowsToPosixTime (bhfiCreationTime info)
318324
return $ FileStatus
319325
{ deviceID = fromIntegral (bhfiVolumeSerialNumber info)
320326
, fileID = fromIntegral (bhfiFileIndex info)
@@ -323,10 +329,14 @@ getFileStatus path = do
323329
, fileOwner = 0
324330
, fileGroup = 0
325331
, 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+
}
330340
where
331341
openPath = createFile path
332342
gENERIC_READ
@@ -336,6 +346,32 @@ getFileStatus path = do
336346
(sECURITY_ANONYMOUS .|. fILE_FLAG_BACKUP_SEMANTICS)
337347
Nothing
338348

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+
339375
permsToMode :: Permissions -> FileMode
340376
permsToMode perms = r .|. w .|. x
341377
where
@@ -354,10 +390,6 @@ getFileType path =
354390
if d then return directoryMode
355391
else unsupported "Unknown file type."
356392

357-
getFileSize :: FilePath -> IO FileOffset
358-
getFileSize path =
359-
bracket (openFile path ReadMode) hClose (liftM fromIntegral . hFileSize)
360-
361393
getFdStatus :: Fd -> IO FileStatus
362394
getFdStatus _ = unsupported "getFdStatus"
363395

src/System/PosixCompat/Internal/Time.hs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ module System.PosixCompat.Internal.Time (
77
ClockTime
88
, getClockTime
99
, clockTimeToEpochTime
10-
, ModificationTime
11-
, modificationTimeToEpochTime
1210
) where
1311

1412
import System.Posix.Types (EpochTime)
@@ -20,15 +18,9 @@ import System.Time (ClockTime(TOD), getClockTime)
2018
clockTimeToEpochTime :: ClockTime -> EpochTime
2119
clockTimeToEpochTime (TOD s _) = fromInteger s
2220

23-
type ModificationTime = ClockTime
24-
25-
modificationTimeToEpochTime :: ModificationTime -> EpochTime
26-
modificationTimeToEpochTime = clockTimeToEpochTime
27-
2821
#else
2922

30-
import Data.Time.Clock (UTCTime)
31-
import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime, utcTimeToPOSIXSeconds)
23+
import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime)
3224

3325
type ClockTime = POSIXTime
3426

@@ -38,9 +30,4 @@ getClockTime = getPOSIXTime
3830
clockTimeToEpochTime :: ClockTime -> EpochTime
3931
clockTimeToEpochTime = fromInteger . floor
4032

41-
type ModificationTime = UTCTime
42-
43-
modificationTimeToEpochTime :: UTCTime -> EpochTime
44-
modificationTimeToEpochTime = clockTimeToEpochTime . utcTimeToPOSIXSeconds
45-
4633
#endif

src/System/PosixCompat/Types.hs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,21 @@ On Windows 'UserID', 'GroupID' and 'LinkCount' are missing, so they are
88
redefined by this module.
99
-}
1010
module System.PosixCompat.Types (
11+
module System.Posix.Types
1112
#ifdef mingw32_HOST_OS
12-
module AllPosixTypesButFileID
13-
, FileID
1413
, UserID
1514
, GroupID
1615
, LinkCount
17-
#else
18-
module System.Posix.Types
1916
#endif
2017
) where
2118

2219
#ifdef mingw32_HOST_OS
2320
-- Since CIno (FileID's underlying type) reflects <sys/type.h> ino_t,
2421
-- which mingw defines as short int (int16), it must be overriden to
2522
-- match the size of windows fileIndex (word64).
26-
import System.Posix.Types as AllPosixTypesButFileID hiding (FileID)
27-
28-
import Data.Word (Word32, Word64)
23+
import System.Posix.Types
2924

30-
newtype FileID = FileID Word64
31-
deriving (Eq, Ord, Enum, Bounded, Integral, Num, Real)
32-
instance Show FileID where show (FileID x) = show x
33-
instance Read FileID where readsPrec i s = [ (FileID x, s')
34-
| (x,s') <- readsPrec i s]
25+
import Data.Word (Word32)
3526

3627
newtype UserID = UserID Word32
3728
deriving (Eq, Ord, Enum, Bounded, Integral, Num, Real)

unix-compat.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: unix-compat
2-
version: 0.5.2
2+
version: 0.5.3
33
synopsis: Portable POSIX-compatibility layer.
44
description: This package provides portable implementations of parts
55
of the unix package. This package re-exports the unix

0 commit comments

Comments
 (0)