module System.RawDevice.File
( RawDevice
, makeRawDevice
, blocksInDevice
, finalizeDevice
, newDevice
, devBufferRead
, devBufferWrite
) where
import Control.Exception(assert)
import System.IO(SeekMode(AbsoluteSeek), hFileSize)
import System.Directory(doesFileExist)
import System.Posix.IO(openFd, closeFd, defaultFileFlags,
OpenMode(..), fdWrite, fdSeek)
import Data.Integral ( INInt, intToINInt, fromIntegral'' )
import System.RawDevice.Base ( DiskAddress, bytesPerBlock, locationOfBlock, BufferBlockHandle,checkBufferBlockHandleSize )
import Binary(openBinIO, copyBytes, seekBin, resetBin)
import System.Posix.Internals (fdGetMode, FDType(RegularFile))
import System.Posix.Files(unionFileModes, ownerReadMode, ownerWriteMode, groupReadMode)
import System.Posix.Types (Fd(Fd))
import qualified GHC.Handle
import GHC.IOBase
data RawDevice = RawDevice {rawDevPath :: FilePath
,rawDevHandle :: Fd
}
instance Ord RawDevice where
compare (RawDevice{rawDevPath=f1}) (RawDevice{rawDevPath=f2})
= compare f1 f2
instance Eq RawDevice where
(==) (RawDevice{rawDevPath=f1}) (RawDevice{rawDevPath=f2})
= f1 == f2
instance Show RawDevice where
show rd = "dev_" ++ rawDevPath rd
fdToHandle2 :: Fd -> IO Handle
fdToHandle2 (Fd fd) = do
let fd' = fromIntegral'' fd
mode <- fdGetMode fd'
let fd_str = "<file descriptor: " ++ show fd' ++ ">"
h <- GHC.Handle.fdToHandle' fd' (Just RegularFile) False fd_str mode True
return h
makeRawDevice :: Maybe RawDevice
-> FilePath
-> IO RawDevice
makeRawDevice _ path = do
fd <- openFd path ReadWrite Nothing defaultFileFlags
return $
RawDevice { rawDevPath = path
, rawDevHandle = fd
}
newDevice :: Maybe RawDevice
-> FilePath
-> INInt
-> IO RawDevice
newDevice _ path fileLen = do
existsP <- doesFileExist path
fd <- if existsP
then openFd path ReadWrite Nothing defaultFileFlags
else openFd path
ReadWrite
(Just (foldl1 unionFileModes [ ownerReadMode
, ownerWriteMode
, groupReadMode]))
defaultFileFlags
fdSeek fd AbsoluteSeek (fromIntegral'' $ fileLen * (intToINInt bytesPerBlock) 1)
fdWrite fd "!"
return $
RawDevice { rawDevPath = path
, rawDevHandle = fd
}
blocksInDevice :: RawDevice
-> IO DiskAddress
blocksInDevice (RawDevice{rawDevHandle=fd}) = do
h <- fdToHandle2 fd
s <- hFileSize h
return $ fromIntegral'' $ s `div` (toInteger bytesPerBlock)
finalizeDevice :: RawDevice -> IO ()
finalizeDevice (RawDevice{rawDevHandle=h }) = closeFd h
devBufferRead :: RawDevice
-> DiskAddress
-> BufferBlockHandle s
-> IO ()
devBufferRead (RawDevice{rawDevHandle=h}) blockNum buffer = do
() <- assert (blockNum >= 0) $ return ()
checkBufferBlockHandleSize buffer
fileHandle <- openBinIO h
seekBin fileHandle (locationOfBlock (abs blockNum))
resetBin buffer
copyBytes fileHandle
buffer bytesPerBlock
devBufferWrite :: RawDevice
-> DiskAddress
-> BufferBlockHandle s
-> IO ()
devBufferWrite (RawDevice{rawDevHandle=h}) blockNum buffer = do
() <- assert (blockNum >= 0) $ return ()
checkBufferBlockHandleSize buffer
fileHandle <- openBinIO h
seekBin fileHandle (locationOfBlock (abs blockNum))
resetBin buffer
copyBytes buffer
fileHandle bytesPerBlock