halfs-2.0: Halfs/SuperBlock.hs
module Halfs.SuperBlock(
SuperBlock(..)
, superBlockSize
)
where
import Control.Exception
import Control.Monad
import Data.ByteString(ByteString)
import qualified Data.ByteString as BS
import Data.Char
import Data.Serialize
import Data.Word
import Halfs.Types
data SuperBlock = SuperBlock {
version :: !Word64 -- ^ Version of this superblock
, devBlockSize :: !Word64 -- ^ Block size of underlying blkdev
, devBlockCount :: !Word64 -- ^ Number of blocks on underlying blkdev
, unmountClean :: !Bool -- ^ Was this filesystem unmounted cleanly?
, freeBlocks :: !Word64 -- ^ Number of free blocks
, usedBlocks :: !Word64 -- ^ Number of blocks in use
, fileCount :: !Word64 -- ^ Number of files present in the FS;
-- does not count directories
, rootDir :: !InodeRef -- ^ IR to root directory
, blockMapStart :: !InodeRef -- ^ IR to first block map addr
}
deriving (Show, Eq, Ord)
instance Serialize SuperBlock where
put sb = do putByteString magic1
putWord64be $ version sb
putWord64be $ devBlockSize sb
putWord64be $ devBlockCount sb
putByteString magic2
putWord64be $ if unmountClean sb then cleanMark else 0
putWord64be $ freeBlocks sb
putWord64be $ usedBlocks sb
putByteString magic3
putWord64be $ fileCount sb
put $ rootDir sb
put $ blockMapStart sb
putByteString magic4
get = do checkMagic magic1
v <- getWord64be
unless (v == 1) $ fail "Unsupported HALFS version found."
bs <- getWord64be
bc <- getWord64be
checkMagic magic2
uc <- wasUnmountedCleanly `fmap` getWord64be
fb <- getWord64be
ub <- getWord64be
checkMagic magic3
fc <- getWord64be
rd <- get
bm <- get
checkMagic magic4
return $ SuperBlock v bs bc uc fb ub fc rd bm
where
checkMagic x = do magic <- getBytes 8
unless (magic == x) $ fail "Invalid superblock."
superBlockSize :: Word64
superBlockSize = fromIntegral $ BS.length $ encode blank
where blank = SuperBlock 0 0 0 False 0 0 0 0 0
-- ----------------------------------------------------------------------------
cleanMark :: Word64
cleanMark = 0x2357111317192329
wasUnmountedCleanly :: Word64 -> Bool
wasUnmountedCleanly x = x == cleanMark
magicStr :: String
magicStr = "The Haskell File System, Halfs!!"
magicBytes :: [Word8]
magicBytes = assert (length magicStr == 32) $
map (fromIntegral . ord) magicStr
magic1, magic2, magic3, magic4 :: ByteString
magic1 = BS.pack $ take 8 $ drop 0 magicBytes
magic2 = BS.pack $ take 8 $ drop 8 magicBytes
magic3 = BS.pack $ take 8 $ drop 16 magicBytes
magic4 = BS.pack $ take 8 $ drop 24 magicBytes