packages feed

btrfs-0.1.2.3: examples/btrfs-split.hs

import System.Environment (getArgs, getProgName)
import System.Exit (exitFailure)
import System.IO (stderr, hPutStrLn)
import Text.Read (readMaybe)
import Text.Printf (printf)
import Control.Exception (bracket)
import Data.Function (fix)
import Control.Monad (when)
import System.Posix

import System.Linux.Btrfs (cloneRangeFd)

main :: IO ()
main = do
    args <- getArgs
    case args of
        [srcPath, sizeS, prefix] | Just size <- readMaybe sizeS, size > 0 ->
            withReadFd srcPath $ \srcFd -> do
                stat <- getFdStatus srcFd
                let totSize = fromIntegral $ fileSize stat
                    mode = fileMode stat
                    lastN = (totSize - 1) `div` size
                    formatStr = "%0" ++ show (length (show lastN)) ++ "d"
                flip fix (0 :: Int, 0) $ \loop (n, offset) -> do
                    let filename = prefix ++ printf formatStr n
                        size' = min size (totSize - offset)
                    withWriteFd filename mode $ \dstFd ->
                        cloneRangeFd srcFd offset size' dstFd 0
                    let offset' = offset + size'
                    when (offset' < totSize) $ loop (n + 1, offset')
        _ -> do
            prog <- getProgName
            hPutStrLn stderr "Invalid command line arguments"
            hPutStrLn stderr $ "Usage: " ++ prog ++ " FILE SIZE PREFIX"
            exitFailure

withReadFd :: FilePath -> (Fd -> IO r) -> IO r
withReadFd path action =
    bracket
        (openFd path ReadOnly Nothing defaultFileFlags {nonBlock = True})
        closeFd action

withWriteFd :: FilePath -> FileMode -> (Fd -> IO r) -> IO r
withWriteFd path mode action =
    bracket
        (openFd path WriteOnly (Just mode) defaultFileFlags {trunc = True})
        closeFd action