summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-06-12 13:43:16 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-06-12 13:54:08 -0400
commit624a9aba5adf8df8f0d9583454bf808842c3e15c (patch)
tree1cfbed8db158ad1e2d9b902cd8082f14a2e13fd9
parent34c9eab951a73f06de70170cc2c2d40ce490ea70 (diff)
finish fixing windows timezone madness
Rather than calculating the TSDelta once, and caching it, this now reads the inode sential file's InodeCache file once, and then each time a new InodeCache is generated, looks at the sentinal file to get the current delta. This way, if the time zone changes while git-annex is running, it will adapt. This adds some inneffiency, but only on Windows, and only 1 stat per new file added. The worst innefficiency is that `git annex status` and `git annex sync` will now (on Windows) stat the inode sentinal file once per file in the repo. It would be more efficient to use getCurrentTimeZone, rather than needing to stat the sentinal file. This should be easy to do, once the time package gets my bugfix patch. This commit was sponsored by Jürgen Lüters.
-rw-r--r--Annex/Content/Direct.hs4
-rw-r--r--Annex/Direct.hs3
-rw-r--r--Command/Add.hs2
-rw-r--r--Utility/InodeCache.hs53
-rw-r--r--debian/changelog1
-rw-r--r--doc/bugs/Windows_file_timestamp_timezone_madness.mdwn3
6 files changed, 40 insertions, 26 deletions
diff --git a/Annex/Content/Direct.hs b/Annex/Content/Direct.hs
index 2d271eee4..b249e0557 100644
--- a/Annex/Content/Direct.hs
+++ b/Annex/Content/Direct.hs
@@ -175,9 +175,9 @@ sameInodeCache file old = go =<< withTSDelta (liftIO . genInodeCache file)
{- Checks if a FileStatus matches the recorded InodeCache of a file. -}
sameFileStatus :: Key -> FileStatus -> Annex Bool
-sameFileStatus key status = withTSDelta $ \delta -> do
+sameFileStatus key status = do
old <- recordedInodeCache key
- let curr = toInodeCache delta status
+ curr <- withTSDelta $ \delta -> liftIO $ toInodeCache delta status
case (old, curr) of
(_, Just c) -> elemInodeCaches c old
([], Nothing) -> return True
diff --git a/Annex/Direct.hs b/Annex/Direct.hs
index e3dbfb6d8..5442113af 100644
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -56,8 +56,9 @@ stageDirect = do
go (file, Just sha, Just mode) = withTSDelta $ \delta -> do
shakey <- catKey sha mode
mstat <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file
+ mcache <- liftIO $ maybe (pure Nothing) (toInodeCache delta) mstat
filekey <- isAnnexLink file
- case (shakey, filekey, mstat, toInodeCache delta =<< mstat) of
+ case (shakey, filekey, mstat, mcache) of
(_, Just key, _, _)
| shakey == filekey -> noop
{- A changed symlink. -}
diff --git a/Command/Add.hs b/Command/Add.hs
index fc55eb655..ae895464e 100644
--- a/Command/Add.hs
+++ b/Command/Add.hs
@@ -155,7 +155,7 @@ ingest (Just source) = withTSDelta $ \delta -> do
backend <- chooseBackend $ keyFilename source
k <- genKey source backend
ms <- liftIO $ catchMaybeIO $ getFileStatus $ contentLocation source
- let mcache = toInodeCache delta =<< ms
+ mcache <- maybe (pure Nothing) (liftIO . toInodeCache delta) ms
case (mcache, inodeCache source) of
(_, Nothing) -> go k mcache ms
(Just newc, Just c) | compareStrong c newc -> go k mcache ms
diff --git a/Utility/InodeCache.hs b/Utility/InodeCache.hs
index b0718e0be..b3534487d 100644
--- a/Utility/InodeCache.hs
+++ b/Utility/InodeCache.hs
@@ -107,15 +107,17 @@ readInodeCache s = case words s of
genInodeCache :: FilePath -> TSDelta -> IO (Maybe InodeCache)
genInodeCache f delta = catchDefaultIO Nothing $
- toInodeCache delta <$> getFileStatus f
-
-toInodeCache :: TSDelta -> FileStatus -> Maybe InodeCache
-toInodeCache (TSDelta delta) s
- | isRegularFile s = Just $ InodeCache $ InodeCachePrim
- (fileID s)
- (fileSize s)
- (modificationTime s + delta)
- | otherwise = Nothing
+ toInodeCache delta =<< getFileStatus f
+
+toInodeCache :: TSDelta -> FileStatus -> IO (Maybe InodeCache)
+toInodeCache (TSDelta getdelta) s
+ | isRegularFile s = do
+ delta <- getdelta
+ return $ Just $ InodeCache $ InodeCachePrim
+ (fileID s)
+ (fileSize s)
+ (modificationTime s + delta)
+ | otherwise = pure Nothing
{- Some filesystem get new random inodes each time they are mounted.
- To detect this and other problems, a sentinal file can be created.
@@ -130,12 +132,13 @@ data SentinalFile = SentinalFile
{- On Windows, the mtime of a file appears to change when the time zone is
- changed. To deal with this, a TSDelta can be used; the delta is added to
- the mtime when generating an InodeCache. The current delta can be found
- - by looking at the SentinalFile. -}
-newtype TSDelta = TSDelta EpochTime
- deriving (Show)
+ - by looking at the SentinalFile. Effectively, this makes all InodeCaches
+ - use the same time zone that was in use when the sential file was
+ - originally written. -}
+newtype TSDelta = TSDelta (IO EpochTime)
noTSDelta :: TSDelta
-noTSDelta = TSDelta 0
+noTSDelta = TSDelta (pure 0)
writeSentinalFile :: SentinalFile -> IO ()
writeSentinalFile s = do
@@ -147,16 +150,15 @@ data SentinalStatus = SentinalStatus
{ sentinalInodesChanged :: Bool
, sentinalTSDelta :: TSDelta
}
- deriving (Show)
{- Checks if the InodeCache of the sentinal file is the same
- as it was when it was originally created.
-
- - On Windows, there's no change even when there is a nonzero
- - TSDelta between the original and current InodeCaches.
+ - On Windows, time stamp differences are ignored, since they change
+ - with the timezone.
-
- - If the sential does not exist, returns a dummy value indicating
- - that it's apparently changed.
+ - When the sential file does not exist, InodeCaches canot reliably be
+ - compared, so the assumption is that there is has been a change.
-}
checkSentinalFile :: SentinalFile -> IO SentinalStatus
checkSentinalFile s = do
@@ -172,14 +174,21 @@ checkSentinalFile s = do
loadoldcache = catchDefaultIO Nothing $
readInodeCache <$> readFile (sentinalCacheFile s)
gennewcache = genInodeCache (sentinalFile s) noTSDelta
- calc (InodeCache (InodeCachePrim inode1 size1 mtime1)) (InodeCache (InodeCachePrim inode2 size2 mtime2)) =
+ calc (InodeCache (InodeCachePrim oldinode oldsize oldmtime)) (InodeCache (InodeCachePrim newinode newsize newmtime)) =
SentinalStatus (not unchanged) tsdelta
where
#ifdef mingw32_HOST_OS
- unchanged = inode1 == inode2 && size1 == size2
- tsdelta = TSDelta (mtime1 - mtime2)
+ unchanged = oldinode == newinode && oldsize == newsize
+ tsdelta = TSDelta $ do
+ -- Run when generating an InodeCache,
+ -- to get the current delta.
+ mnew <- gennewcache
+ return $ case mnew of
+ Just (InodeCache (InodeCachePrim _ _ currmtime)) ->
+ oldmtime - currmtime
+ Nothing -> 0
#else
- unchanged = inode1 == inode2 && size1 == size2 && mtime1 == mtime2
+ unchanged = oldinode == newinode && oldsize == newsize && oldmtime == newmtime
tsdelta = noTSDelta
#endif
dummy = SentinalStatus True noTSDelta
diff --git a/debian/changelog b/debian/changelog
index 9b9f93d9c..5b5274ea3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -11,6 +11,7 @@ git-annex (5.20140607) UNRELEASED; urgency=medium
Linux's caching of higher res timestamps while a FAT is mounted, caused
direct mode repositories on FAT to seem to have modified files after
they were unmounted and remounted.
+ * Deal with Windows's horrible handling of time zone changes.
-- Joey Hess <joeyh@debian.org> Mon, 09 Jun 2014 14:44:09 -0400
diff --git a/doc/bugs/Windows_file_timestamp_timezone_madness.mdwn b/doc/bugs/Windows_file_timestamp_timezone_madness.mdwn
index a90c58f24..fb0b08d9d 100644
--- a/doc/bugs/Windows_file_timestamp_timezone_madness.mdwn
+++ b/doc/bugs/Windows_file_timestamp_timezone_madness.mdwn
@@ -14,3 +14,6 @@ Unfortunately, Data.Time.LocalTime.getCurrentTimeZone doesn't seem to really
work on windows. It always returns a time zone 60 minutes from UTS in my tests,
no matter what the zone really is. I need to test this more widely and file
a GHC bug if appropriate.
+
+> [[fixed|done]], avoiding using getCurrentTime for now, although I have a
+> patch to fix it too. --[[Joey]]