fixed a fd double-close

This commit is contained in:
Joey Hess 2015-11-13 15:43:09 -04:00
parent b0155d9093
commit 389c6c7d37
Failed to extract signature

View file

@ -39,7 +39,7 @@ import System.Directory
type LockFile = FilePath type LockFile = FilePath
data LockHandle = LockHandle FilePath Fd SideLockHandle data LockHandle = LockHandle FilePath FileStatus SideLockHandle
type SideLockHandle = Maybe Posix.LockHandle type SideLockHandle = Maybe Posix.LockHandle
@ -100,17 +100,17 @@ tryLock lockfile = trySideLock lockfile $ \sidelock -> do
setFileMode tmp (combineModes readModes) setFileMode tmp (combineModes readModes)
hPutStr h . show =<< mkPidLock hPutStr h . show =<< mkPidLock
hClose h hClose h
st <- getFileStatus tmp
let failedlock = do let failedlock = do
nukeFile tmp nukeFile tmp
maybe noop Posix.dropLock sidelock maybe noop Posix.dropLock sidelock
return Nothing return Nothing
let tooklock fd = return $ Just $ LockHandle lockfile fd sidelock let tooklock = return $ Just $ LockHandle lockfile st sidelock
mfd <- linkToLock sidelock tmp lockfile ifM (linkToLock sidelock tmp lockfile)
case mfd of ( do
Just fd -> do
nukeFile tmp nukeFile tmp
tooklock fd tooklock
Nothing -> do , do
v <- readPidLock lockfile v <- readPidLock lockfile
hn <- getHostName hn <- getHostName
case v of case v of
@ -121,9 +121,9 @@ tryLock lockfile = trySideLock lockfile $ \sidelock -> do
-- we know that the pidlock is -- we know that the pidlock is
-- stale, and can take it over. -- stale, and can take it over.
rename tmp lockfile rename tmp lockfile
fd <- openFd lockfile ReadOnly Nothing defaultFileFlags tooklock
tooklock fd
_ -> failedlock _ -> failedlock
)
-- Linux's open(2) man page recommends linking a pid lock into place, -- Linux's open(2) man page recommends linking a pid lock into place,
-- as the most portable atomic operation that will fail if -- as the most portable atomic operation that will fail if
@ -141,21 +141,16 @@ tryLock lockfile = trySideLock lockfile $ \sidelock -> do
-- can't do anything about such a lying filesystem. -- can't do anything about such a lying filesystem.
-- At least the side lock file will prevent git-annex's running on the same -- At least the side lock file will prevent git-annex's running on the same
-- host from running concurrently even on such a lying filesystem. -- host from running concurrently even on such a lying filesystem.
linkToLock :: SideLockHandle -> FilePath -> FilePath -> IO (Maybe Fd) linkToLock :: SideLockHandle -> FilePath -> FilePath -> IO Bool
linkToLock Nothing _ _ = return Nothing linkToLock Nothing _ _ = return False
linkToLock (Just _) src dest = do linkToLock (Just _) src dest = do
_ <- tryIO $ createLink src dest _ <- tryIO $ createLink src dest
ifM (catchDefaultIO False checklink) ifM (catchBoolIO checklink)
( catchDefaultIO Nothing $ do ( catchBoolIO $ do
srccontent <- readFile src srccontent <- readFile src
h <- openFile dest ReadMode destcontent <- readFile dest
destcontent <- hGetContents h return (srccontent == destcontent)
if srccontent /= destcontent , return False
then do
hClose h
return Nothing
else Just <$> handleToFd h
, return Nothing
) )
where where
checklink = do checklink = do
@ -192,13 +187,12 @@ waitLock (Seconds timeout) lockfile = go timeout
error $ "Gave up waiting for possibly stale pid lock file " ++ lockfile error $ "Gave up waiting for possibly stale pid lock file " ++ lockfile
dropLock :: LockHandle -> IO () dropLock :: LockHandle -> IO ()
dropLock (LockHandle lockfile fd sidelock) = do dropLock (LockHandle lockfile _ sidelock) = do
-- Drop side lock first, at which point the pid lock will be -- Drop side lock first, at which point the pid lock will be
-- considered stale. -- considered stale.
-- The side lock file cannot be deleted because another process may -- The side lock file cannot be deleted because another process may
-- have it open and be waiting to lock it. -- have it open and be waiting to lock it.
maybe noop Posix.dropLock sidelock maybe noop Posix.dropLock sidelock
closeFd fd
nukeFile lockfile nukeFile lockfile
getLockStatus :: LockFile -> IO LockStatus getLockStatus :: LockFile -> IO LockStatus
@ -213,10 +207,9 @@ checkLocked lockfile = conv <$> getLockStatus lockfile
-- Checks that the lock file still exists, and is the same file that was -- Checks that the lock file still exists, and is the same file that was
-- locked to get the LockHandle. -- locked to get the LockHandle.
checkSaneLock :: LockFile -> LockHandle -> IO Bool checkSaneLock :: LockFile -> LockHandle -> IO Bool
checkSaneLock lockfile (LockHandle _ fd _) = checkSaneLock lockfile (LockHandle _ st _) =
go =<< catchMaybeIO (getFileStatus lockfile) go =<< catchMaybeIO (getFileStatus lockfile)
where where
go Nothing = return False go Nothing = return False
go (Just st) = do go (Just st') = do
fdst <- getFdStatus fd return $ deviceID st == deviceID st' && fileID st == fileID st'
return $ deviceID fdst == deviceID st && fileID fdst == fileID st