packages feed

sendfile 0.1 → 0.2

raw patch · 5 files changed

+110/−66 lines, 5 files

Files

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