summaryrefslogtreecommitdiff
path: root/Utility/InodeCache.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Utility/InodeCache.hs')
-rw-r--r--Utility/InodeCache.hs94
1 files changed, 94 insertions, 0 deletions
diff --git a/Utility/InodeCache.hs b/Utility/InodeCache.hs
new file mode 100644
index 000000000..46ca87bd9
--- /dev/null
+++ b/Utility/InodeCache.hs
@@ -0,0 +1,94 @@
+{- Caching a file's inode, size, and modification time to see when it's changed.
+ -
+ - Copyright 2013 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Utility.InodeCache where
+
+import Common
+import System.PosixCompat.Types
+import Utility.QuickCheck
+
+data InodeCachePrim = InodeCachePrim FileID FileOffset EpochTime
+ deriving (Show, Eq, Ord)
+
+newtype InodeCache = InodeCache InodeCachePrim
+ deriving (Show)
+
+{- Inode caches can be compared in two different ways, either weakly
+ - or strongly. -}
+data InodeComparisonType = Weakly | Strongly
+ deriving (Eq, Ord)
+
+{- Strong comparison, including inodes. -}
+compareStrong :: InodeCache -> InodeCache -> Bool
+compareStrong (InodeCache x) (InodeCache y) = x == y
+
+{- Weak comparison of the inode caches, comparing the size and mtime,
+ - but not the actual inode. Useful when inodes have changed, perhaps
+ - due to some filesystems being remounted. -}
+compareWeak :: InodeCache -> InodeCache -> Bool
+compareWeak (InodeCache (InodeCachePrim _ size1 mtime1)) (InodeCache (InodeCachePrim _ size2 mtime2)) =
+ size1 == size2 && mtime1 == mtime2
+
+compareBy :: InodeComparisonType -> InodeCache -> InodeCache -> Bool
+compareBy Strongly = compareStrong
+compareBy Weakly = compareWeak
+
+{- For use in a Map; it's determined at creation time whether this
+ - uses strong or weak comparison for Eq. -}
+data InodeCacheKey = InodeCacheKey InodeComparisonType InodeCachePrim
+ deriving (Ord)
+
+instance Eq InodeCacheKey where
+ (InodeCacheKey ctx x) == (InodeCacheKey cty y) =
+ compareBy (maximum [ctx,cty]) (InodeCache x ) (InodeCache y)
+
+inodeCacheToKey :: InodeComparisonType -> InodeCache -> InodeCacheKey
+inodeCacheToKey ct (InodeCache prim) = InodeCacheKey ct prim
+
+inodeCacheToMtime :: InodeCache -> EpochTime
+inodeCacheToMtime (InodeCache (InodeCachePrim _ _ mtime)) = mtime
+
+showInodeCache :: InodeCache -> String
+showInodeCache (InodeCache (InodeCachePrim inode size mtime)) = unwords
+ [ show inode
+ , show size
+ , show mtime
+ ]
+
+readInodeCache :: String -> Maybe InodeCache
+readInodeCache s = case words s of
+ (inode:size:mtime:_) ->
+ let prim = InodeCachePrim
+ <$> readish inode
+ <*> readish size
+ <*> readish mtime
+ in InodeCache <$> prim
+ _ -> Nothing
+
+genInodeCache :: FilePath -> IO (Maybe InodeCache)
+genInodeCache f = catchDefaultIO Nothing $ toInodeCache <$> getFileStatus f
+
+toInodeCache :: FileStatus -> Maybe InodeCache
+toInodeCache s
+ | isRegularFile s = Just $ InodeCache $ InodeCachePrim
+ (fileID s)
+ (fileSize s)
+ (modificationTime s)
+ | otherwise = Nothing
+
+instance Arbitrary InodeCache where
+ arbitrary =
+ let prim = InodeCachePrim
+ <$> arbitrary
+ <*> arbitrary
+ <*> arbitrary
+ in InodeCache <$> prim
+
+prop_read_show_inodecache :: InodeCache -> Bool
+prop_read_show_inodecache c = case readInodeCache (showInodeCache c) of
+ Nothing -> False
+ Just c' -> compareStrong c c'