Use sendfile for copying and read/write as fallback

This commit is contained in:
Julian Ospald 2016-05-18 03:47:39 +02:00
parent ee3ace362b
commit 0fa66cd581
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
2 changed files with 32 additions and 4 deletions

View File

@ -35,6 +35,7 @@ library
, deepseq , deepseq
, exceptions , exceptions
, hspec , hspec
, simple-sendfile >= 0.2.22
, unix >= 2.5 , unix >= 2.5
, unix-bytestring , unix-bytestring
, utf8-string , utf8-string

View File

@ -107,6 +107,8 @@ import Data.Word
import Foreign.C.Error import Foreign.C.Error
( (
eEXIST eEXIST
, eINVAL
, eNOSYS
, eNOTEMPTY , eNOTEMPTY
, eXDEV , eXDEV
) )
@ -136,6 +138,14 @@ import System.IO.Error
catchIOError catchIOError
, ioeGetErrorType , ioeGetErrorType
) )
import System.Linux.Sendfile
(
sendfileFd
)
import Network.Sendfile
(
FileRange(..)
)
import System.Posix.ByteString import System.Posix.ByteString
( (
exclusive exclusive
@ -341,7 +351,7 @@ recreateSymlink symsource newsym
-- - `SameFile` if source and destination are the same file (`HPathIOException`) -- - `SameFile` if source and destination are the same file (`HPathIOException`)
-- - `AlreadyExists` if destination already exists -- - `AlreadyExists` if destination already exists
-- --
-- Note: calls `read`/`write` -- Note: calls `sendfile` and possibly `read`/`write` as fallback
copyFile :: Path Abs -- ^ source file copyFile :: Path Abs -- ^ source file
-> Path Abs -- ^ destination file -> Path Abs -- ^ destination file
-> IO () -> IO ()
@ -369,7 +379,7 @@ copyFile from to = do
-- - `InvalidArgument` if source file is wrong type (directory) -- - `InvalidArgument` if source file is wrong type (directory)
-- - `SameFile` if source and destination are the same file (`HPathIOException`) -- - `SameFile` if source and destination are the same file (`HPathIOException`)
-- --
-- Note: calls `read`/`write` -- Note: calls `sendfile` and possibly `read`/`write` as fallback
copyFileOverwrite :: Path Abs -- ^ source file copyFileOverwrite :: Path Abs -- ^ source file
-> Path Abs -- ^ destination file -> Path Abs -- ^ destination file
-> IO () -> IO ()
@ -397,9 +407,26 @@ _copyFile :: [SPDF.Flags]
-> IO () -> IO ()
_copyFile sflags dflags from to _copyFile sflags dflags from to
= =
-- TODO: add sendfile support -- from sendfile(2) manpage:
void $ readWriteCopy (fromAbs from) (fromAbs to) -- Applications may wish to fall back to read(2)/write(2) in the case
-- where sendfile() fails with EINVAL or ENOSYS.
withAbsPath to $ \to' -> withAbsPath from $ \from' ->
catchErrno [eINVAL, eNOSYS]
(sendFileCopy from' to')
(void $ readWriteCopy from' to')
where where
-- this is low-level stuff utilizing sendfile(2) for speed
sendFileCopy source dest =
bracket (SPDT.openFd source SPI.ReadOnly sflags Nothing)
SPI.closeFd
$ \sfd -> do
fileM <- System.Posix.Files.ByteString.fileMode
<$> getFdStatus sfd
bracketeer (SPDT.openFd dest SPI.WriteOnly
dflags $ Just fileM)
SPI.closeFd
(\fd -> SPI.closeFd fd >> deleteFile to)
$ \dfd -> sendfileFd dfd sfd EntireFile (return ())
-- low-level copy operation utilizing read(2)/write(2) -- low-level copy operation utilizing read(2)/write(2)
-- in case `sendFileCopy` fails/is unsupported -- in case `sendFileCopy` fails/is unsupported
readWriteCopy :: ByteString -> ByteString -> IO Int readWriteCopy :: ByteString -> ByteString -> IO Int