sendfile 0.1 → 0.2
raw patch · 5 files changed
+110/−66 lines, 5 files
Files
- csrc/sendfile_linux.c +9/−14
- csrc/sendfile_win32.c +20/−14
- sendfile.cabal +18/−15
- src/SendFile.hs +19/−3
- src/SendFile/Internal.hsc +44/−20
csrc/sendfile_linux.c view
@@ -6,21 +6,17 @@ #include <sys/sendfile.h> #include <sys/stat.h> -/* return value is system error code */-int c_sendfile_linux(int out_fd, char* in_fp) {- int in_fd;- struct stat in_stat;-- in_fd = open(in_fp, O_RDONLY);+/* return value is an errno code or 0 if there is no error */+int c_sendfile_linux(const int out_fd, const char* in_fp, const long _offset, const long _count) {+ off_t offset = _offset;+ size_t count = _count;+ int in_fd = open(in_fp, O_RDONLY);+ if(in_fd == -1) { return errno; }-- if(fstat(in_fd, &in_stat) == -1) {- return errno;- }-- if(sendfile(out_fd, in_fd, NULL, in_stat.st_size) == -1) {+ + if(sendfile(out_fd, in_fd, &offset, count) == -1) { return errno; } @@ -28,7 +24,6 @@ return errno; } - /* if no errors, return 0 to indicate no errors */+ /* return 0 to indicate no errors */ return 0; }-
csrc/sendfile_win32.c view
@@ -3,25 +3,31 @@ #include <windows.h> #include <mswsock.h> -/* return value is system error code defined here:+/* return value is 0 if there is no error otherwise it is a system error code defined here: * http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx */-int c_sendfile_win32(int out_fd, char* in_fp) {- HANDLE in_hdl =- CreateFile(- in_fp,- GENERIC_READ,- FILE_SHARE_READ,- NULL,- OPEN_EXISTING,- FILE_FLAG_SEQUENTIAL_SCAN,- NULL- );+int c_sendfile_win32(const int out_fd, const char* in_fp, const long _offset, const long _count) {+ LONG offset = _offset;+ DWORD count = _count;+ HANDLE in_hdl = CreateFile(+ in_fp,+ GENERIC_READ,+ FILE_SHARE_READ,+ NULL,+ OPEN_EXISTING,+ FILE_FLAG_SEQUENTIAL_SCAN,+ NULL+ );+ if(in_hdl == INVALID_HANDLE_VALUE) { return GetLastError(); } - if(! TransmitFile(out_fd, in_hdl, 0, 0, NULL, NULL, TF_USE_KERNEL_APC)) {+ if(SetFilePointer(in_hdl, offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {+ return GetLastError();+ }+ + if(! TransmitFile(out_fd, in_hdl, count, 0, NULL, NULL, TF_USE_KERNEL_APC)) { return WSAGetLastError(); } @@ -29,6 +35,6 @@ return GetLastError(); } - /* if no errors, return 0 to indicate no errors */+ /* return 0 to indicate no errors */ return 0; }
sendfile.cabal view
@@ -1,8 +1,14 @@ name: sendfile-version: 0.1+version: 0.2 stability: experimental synopsis: A portable sendfile library description: A library which exposes zero-copy sendfile functionality in a portable way. If a platform does not support sendfile, a fallback implementation in haskell is provided.+ .+ Currently supported platforms:+ * Windows 2000+ (Native)+ * Linux 2.6+ (Native)+ * Everything else (Haskell)+ license: BSD3 license-file: LICENSE author: Matthew Elder <matt@mattelder.org>@@ -20,27 +26,24 @@ hs-source-dirs: src exposed-modules: SendFile- SendFile.Internal++ other-modules: SendFile.Internal build-depends: base >= 3 && < 5,- bytestring >= 0.9.1.4 && < 0.10, network >= 2 && < 3 - if flag(portable)- cc-options: -DPORTABLE_SENDFILE+ if os(windows) && !flag(portable)+ cc-options: -DWIN32_SENDFILE+ c-sources: csrc/sendfile_win32.c+ extra-libraries: kernel32, mswsock else- if os(windows)- cc-options: -DWIN32_SENDFILE- c-sources: csrc/sendfile_win32.c- extra-libraries: kernel32, mswsock+ if os(linux) && !flag(portable)+ cc-options: -DLINUX_SENDFILE+ c-sources: csrc/sendfile_linux.c else- if os(linux)- cc-options: -DLINUX_SENDFILE- c-sources: csrc/sendfile_linux.c- else- cc-options: -DPORTABLE_SENDFILE+ cc-options: -DPORTABLE_SENDFILE+ build-depends: bytestring >= 0.9.1.4 && < 0.10 source-repository head type: darcs location: http://patch-tag.com/r/sendfile/pullrepo-
src/SendFile.hs view
@@ -1,17 +1,33 @@ module SendFile (+ fileSize, sendFile,+ sendFile', sendFileMode ) where import qualified SendFile.Internal import System.IO (Handle(..)) --- | A cross-platform wrapper for sendfile -- this implements an available operating-system call if supported, otherwise it falls back to a portable haskell implementation. It takes a Handle which it will first flush before handing it to the operating system to perform the transmission.+-- | Get the size of a file.+fileSize :: FilePath -- ^ The path of the file+ -> IO Int -- ^ The size of the file (in bytes)+fileSize = SendFile.Internal.fileSize++-- | A cross-platform wrapper for sendfile -- this implements an available operating-system call if supported, otherwise it falls back to a portable haskell implementation. It will flush the output Handle before handing it to the operating system for transmission. sendFile :: Handle -- ^ The output Handle -> FilePath -- ^ The path where the input file resides- -> IO () -- ^ Whether or not the transmission was successful+ -> IO () sendFile = SendFile.Internal.sendFile --- | Returns the mode that sendfile was compiled with. Mainly for debugging use. Possible values are 'WIN32_SENDFILE' and 'PORTABLE_SENDFILE'.+-- | Like sendFile except that it additionally allows you to specify an offset and count. The behavior of reading beyond the end of the file is undefined.+sendFile' :: Handle -- ^ The output Handle+ -> FilePath -- ^ The path where the input file resides+ -> Int -- ^ The starting offset of the file (in bytes)+ -> Int -- ^ The number of bytes to read+ -> IO ()+sendFile' = SendFile.Internal.sendFile'++-- | Returns the mode that sendfile was compiled with. Mainly for debugging use. Possible values are 'WIN32_SENDFILE', 'LINUX_SENDFILE', and 'PORTABLE_SENDFILE'. sendFileMode :: String -- ^ The mode that sendfile was compiled with sendFileMode = SendFile.Internal.sendFileMode+
src/SendFile/Internal.hsc view
@@ -1,14 +1,22 @@ {-# LANGUAGE CPP, ForeignFunctionInterface #-} module SendFile.Internal (+ fileSize, sendFile,+ sendFile', sendFileMode ) where- -import Data.ByteString.Char8-import Prelude hiding (readFile)-import System.IO (Handle(..), hFlush) -#if defined(WIN32_SENDFILE) && !defined(PORTABLE_SENDFILE)+import System.IO (+ Handle(..),+ IOMode(..),+ SeekMode(..),+ hFileSize,+ hFlush,+ hSeek,+ withBinaryFile+ )++#if defined(WIN32_SENDFILE) import Foreign.C import GHC.IOBase (haFD) import GHC.Handle (withHandle_)@@ -16,22 +24,23 @@ sendFileMode :: String sendFileMode = "WIN32_SENDFILE" -sendFile :: Handle -> FilePath -> IO ()-sendFile outh infp = do+sendFile' :: Handle -> FilePath -> Int -> Int -> IO ()+sendFile' outh infp offset count = do -- flush outh before handing it sendFile hFlush outh withHandle_ "sendFile" outh $ \outh' -> do withCString infp $ \in_fp -> do let out_fd = haFD outh'- err <- c_sendfile_win32 out_fd in_fp+ err <- c_sendfile_win32 out_fd in_fp (fromIntegral offset) (fromIntegral count) if err == 0 then return () else fail ("system error " ++ show err) foreign import ccall- c_sendfile_win32 :: CInt -> CString -> IO Int-#else-# if defined(LINUX_SENDFILE) && !defined(PORTABLE_SENDFILE)+ c_sendfile_win32 :: CInt -> CString -> CLong -> CLong -> IO Int+#endif++#if defined(LINUX_SENDFILE) import Foreign.C import GHC.IOBase (haFD) import GHC.Handle (withHandle_)@@ -39,29 +48,44 @@ sendFileMode :: String sendFileMode = "LINUX_SENDFILE" -sendFile :: Handle -> FilePath -> IO ()-sendFile outh infp = do+sendFile' :: Handle -> FilePath -> Int -> Int -> IO ()+sendFile' outh infp offset count = do -- flush outh before handing it sendFile hFlush outh withHandle_ "sendFile" outh $ \outh' -> do withCString infp $ \in_fp -> do let out_fd = haFD outh'- err <- c_sendfile_linux out_fd in_fp+ err <- c_sendfile_linux out_fd in_fp (fromIntegral offset) (fromIntegral count) if err == 0 then return () else fail ("errno " ++ show err) foreign import ccall- c_sendfile_linux :: CInt -> CString -> IO Int-# else+ c_sendfile_linux :: CInt -> CString -> CLong -> CLong -> IO Int+#endif++#if defined(PORTABLE_SENDFILE)+import Prelude hiding (readFile)+import Data.ByteString.Char8+ sendFileMode :: String sendFileMode = "PORTABLE_SENDFILE" -- FIXME: possibly immature / inefficient implementation-sendFile :: Handle -> FilePath -> IO ()-sendFile outh infp = do- hPutStr outh =<< readFile infp+sendFile' :: Handle -> FilePath -> Int -> Int -> IO ()+sendFile' outh infp offset count =+ withBinaryFile infp ReadMode $ \inh -> do+ hSeek inh AbsoluteSeek (fromIntegral offset)+ hPutStr outh =<< hGet inh count+ hFlush outh return ()-# endif #endif++fileSize :: FilePath -> IO Int+fileSize fp = fmap fromIntegral (withBinaryFile fp ReadMode hFileSize)++sendFile :: Handle -> FilePath -> IO ()+sendFile outh infp = do+ count <- fileSize infp+ sendFile' outh infp 0 count