LIB: refactor copyFile

This commit is contained in:
Julian Ospald 2016-04-03 22:36:29 +02:00
parent fa7cab69c6
commit 0a71c3c044
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28

View File

@ -32,6 +32,7 @@ module HSFM.FileSystem.FileOperations where
import Control.Exception import Control.Exception
( (
throw throw
, onException
) )
import Control.Monad import Control.Monad
( (
@ -48,7 +49,6 @@ import Foreign.C.Error
import HPath import HPath
( (
Path Path
, Abs
, Fn , Fn
) )
import qualified HPath as P import qualified HPath as P
@ -186,9 +186,9 @@ copyDir cm from@(_ :/ Dir fromn FileInfo{ fileMode = fmode })
for_ contents $ \f -> for_ contents $ \f ->
case f of case f of
(_ :/ SymLink {}) -> recreateSymlink cm f destdir (_ :/ SymLink {}) -> recreateSymlink cm f destdir (name . file $ f)
(_ :/ Dir {}) -> copyDir cm f destdir (_ :/ Dir {}) -> copyDir cm f destdir
(_ :/ RegFile {}) -> copyFileToDir Replace f destdir (_ :/ RegFile {}) -> copyFile Replace f destdir (name . file $ f)
_ -> return () _ -> return ()
where where
createDestdir destdir fmode' = createDestdir destdir fmode' =
@ -213,15 +213,16 @@ recreateSymlink :: CopyMode
-> AnchoredFile FileInfo -- ^ the old symlink file -> AnchoredFile FileInfo -- ^ the old symlink file
-> AnchoredFile FileInfo -- ^ destination dir of the -> AnchoredFile FileInfo -- ^ destination dir of the
-- new symlink file -- new symlink file
-> Path Fn -- ^ destination file name
-> IO () -> IO ()
recreateSymlink _ AFileInvFN _ = throw InvalidFileName recreateSymlink _ AFileInvFN _ _ = throw InvalidFileName
recreateSymlink _ _ AFileInvFN = throw InvalidFileName recreateSymlink _ _ AFileInvFN _ = throw InvalidFileName
recreateSymlink cm symf@(_ :/ SymLink {}) recreateSymlink _ _ _ InvFN = throw InvalidFileName
symdest@(_ :/ Dir {}) recreateSymlink cm symf@(_ :/ SymLink {}) symdest@(_ :/ Dir {}) fn
= do = do
throwCantOpenDirectory $ fullPath symdest throwCantOpenDirectory $ fullPath symdest
sympoint <- readSymbolicLink (fullPathS $ symf) sympoint <- readSymbolicLink (fullPathS $ symf)
let symname = fullPath symdest P.</> (name . file $ symf) let symname = fullPath symdest P.</> fn
case cm of case cm of
Merge -> delOld symname Merge -> delOld symname
Replace -> delOld symname Replace -> delOld symname
@ -232,24 +233,41 @@ recreateSymlink cm symf@(_ :/ SymLink {})
f <- HSFM.FileSystem.FileType.readFileWithFileInfo symname f <- HSFM.FileSystem.FileType.readFileWithFileInfo symname
unless (failed . file $ f) unless (failed . file $ f)
(easyDelete f) (easyDelete f)
recreateSymlink _ _ _ = throw $ InvalidOperation "wrong input type" recreateSymlink _ _ _ _ = throw $ InvalidOperation "wrong input type"
-- |TODO: handle EAGAIN exception for non-blocking IO -- |TODO: handle EAGAIN exception for non-blocking IO
-- |Low-level function to copy a given file to the given path. The fileMode -- TODO: implement for non-regular file? This would deprecate the logic
-- is preserved. The file is always overwritten if accessible. -- in copyDir
copyFile' :: Path Abs -> Path Abs -> IO () -- |Copies the given file to the given dir with the given filename.
copyFile' from to = do -- Excludes symlinks.
let from' = P.fromAbs from copyFile :: CopyMode
to' = P.fromAbs to -> AnchoredFile FileInfo -- ^ source file
throwCantOpenDirectory $ P.dirname from -> AnchoredFile FileInfo -- ^ destination dir
throwCantOpenDirectory $ P.dirname to -> Path Fn -- ^ destination file name
fromFstatus <- getSymbolicLinkStatus from' -> IO ()
fromContent <- BS.readFile from' copyFile _ AFileInvFN _ _ = throw InvalidFileName
fd <- SPI.createFile to' copyFile _ _ AFileInvFN _ = throw InvalidFileName
(System.Posix.Files.fileMode fromFstatus) copyFile _ _ _ InvFN = throw InvalidFileName
_ <- fdWrite fd fromContent copyFile cm from@(_ :/ RegFile {}) to@(_ :/ Dir {}) fn
SPI.closeFd fd = do
let from' = fullPath from
to' = fullPath to P.</> fn
throwCantOpenDirectory $ fullPath to
case cm of
Strict -> throwFileDoesExist to'
_ -> return ()
throwCantOpenDirectory . P.dirname . fullPath $ from
throwCantOpenDirectory . fullPath $ to
fromFstatus <- getSymbolicLinkStatus (P.fromAbs from')
fromContent <- BS.readFile (P.fromAbs from')
fd <- SPI.createFile (P.fromAbs to')
(System.Posix.Files.fileMode fromFstatus)
_ <- onException (fdWrite fd fromContent) (SPI.closeFd fd)
SPI.closeFd fd
copyFile _ _ _ _ = throw $ InvalidOperation "wrong input type"
-- |Copies the given file to the given file destination, overwriting it. -- |Copies the given file to the given file destination, overwriting it.
@ -267,31 +285,10 @@ overwriteFile from@(_ :/ RegFile {})
throwCantOpenDirectory $ P.dirname from' throwCantOpenDirectory $ P.dirname from'
throwCantOpenDirectory $ P.dirname to' throwCantOpenDirectory $ P.dirname to'
throwSameFile from' to' throwSameFile from' to'
copyFile' from' to' copyFile Replace from to (name . file $ to)
overwriteFile _ _ = throw $ InvalidOperation "wrong input type" overwriteFile _ _ = throw $ InvalidOperation "wrong input type"
-- |Copies the given file to the given dir with the same filename.
-- Excludes symlinks.
copyFileToDir :: CopyMode
-> AnchoredFile FileInfo
-> AnchoredFile FileInfo
-> IO ()
copyFileToDir _ AFileInvFN _ = throw InvalidFileName
copyFileToDir _ _ AFileInvFN = throw InvalidFileName
copyFileToDir cm from@(_ :/ RegFile fn _)
to@(_ :/ Dir {})
= do
let from' = fullPath from
to' = fullPath to P.</> fn
throwCantOpenDirectory $ fullPath to
case cm of
Strict -> throwFileDoesExist to'
_ -> return ()
copyFile' from' to'
copyFileToDir _ _ _ = throw $ InvalidOperation "wrong input type"
-- |Copies a file, directory or symlink. In case of a symlink, it is just -- |Copies a file, directory or symlink. In case of a symlink, it is just
-- recreated, even if it points to a directory. -- recreated, even if it points to a directory.
easyCopy :: CopyMode easyCopy :: CopyMode
@ -300,10 +297,10 @@ easyCopy :: CopyMode
-> IO () -> IO ()
easyCopy cm from@(_ :/ SymLink{}) easyCopy cm from@(_ :/ SymLink{})
to@(_ :/ Dir{}) to@(_ :/ Dir{})
= recreateSymlink cm from to = recreateSymlink cm from to (name . file $ from)
easyCopy cm from@(_ :/ RegFile{}) easyCopy cm from@(_ :/ RegFile{})
to@(_ :/ Dir{}) to@(_ :/ Dir{})
= copyFileToDir cm from to = copyFile cm from to (name . file $ from)
easyCopy cm from@(_ :/ Dir{}) easyCopy cm from@(_ :/ Dir{})
to@(_ :/ Dir{}) to@(_ :/ Dir{})
= copyDir cm from to = copyDir cm from to