module System.TPFS.Block (
BlockIndex,
blockIndexToAddress,
addressToBlockIndex,
addressToBlockIndexAndOffset,
divBlocks,
readBlock,
writeBlock
) where
import Data.Binary
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import System.TPFS.Device
import System.TPFS.Filesystem
import System.TPFS.Header
type BlockIndex = Word64
blockIndexToAddress :: Header
-> BlockIndex
-> Address
blockIndexToAddress hdr idx = blockOffset hdr + fromIntegral (blockSize hdr) * fromIntegral (idx 1)
addressToBlockIndex :: Header
-> Address
-> BlockIndex
addressToBlockIndex hdr a
= toZero $ fromIntegral (quot (a blockOffset hdr) (fromIntegral $ blockSize hdr)) + 1
where toZero x | x < 1 = 0
| otherwise = x
addressToBlockIndexAndOffset :: Header
-> Address
-> (BlockIndex, Word64)
addressToBlockIndexAndOffset hdr a
| a >= blockOffset hdr = (fromIntegral q + 1, fromIntegral r)
| otherwise = undefined
where (q, r) = quotRem (a blockOffset hdr) (fromIntegral $ blockSize hdr)
divBlocks :: Integral i => i -> Header -> i
i `divBlocks` hdr
| r == 0 = q
| otherwise = q + 1
where (q, r) = i `quotRem` fromIntegral (blockSize hdr 16)
readBlock :: Device m h
=> Filesystem m h
-> BlockIndex
-> m ByteString
readBlock fs idx = dGet (fsHandle fs) (blockIndexToAddress (fsHeader fs) idx) (blockSize (fsHeader fs))
readBlockSection :: Device m h
=> Filesystem m h
-> BlockIndex
-> Word64
-> Word64
-> m ByteString
readBlockSection fs idx ofs len
= dGet (fsHandle fs) (blockIndexToAddress (fsHeader fs) idx + ofs') len'
where ofs' = ofs `mod` blockSize (fsHeader fs)
len' | ofs' + len > blockSize (fsHeader fs) = blockSize (fsHeader fs) ofs'
| otherwise = len
writeBlock :: Device m h
=> Filesystem m h
-> BlockIndex
-> ByteString
-> m ()
writeBlock fs idx str = dPut (fsHandle fs) (blockIndexToAddress (fsHeader fs) idx) padstr
where padstr | fromIntegral (B.length str) > blockSize (fsHeader fs)
= B.take (fromIntegral . blockSize $ fsHeader fs) str
| fromIntegral (B.length str) < blockSize (fsHeader fs)
= B.append str . flip B.replicate 0 $ fromIntegral (blockSize $ fsHeader fs) B.length str
| otherwise
= str