Use sendfile for copying and read/write as fallback
This commit is contained in:
parent
ee3ace362b
commit
0fa66cd581
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user