module Halfs.Inode (Inode(..), InodeBlock, InodeMetadata(..)
,newFSRootInode, newFSBlockMapInode, newFSRootDirInode
,newFSInodeMapInode, dupInode
,rootInodeDiskAddr, firstFreeInodeDiskAddr
,getPointerAt, updatePointers, isRootDirInode
,goodInodeMagic, inodeBumpSize, newInode, inodeAddLink)
where
import Binary(Binary(..), Bin(..),tellBin,seekBin)
import Halfs.Utils hiding (bytesPerBlock)
import qualified Halfs.Utils (bytesPerBlock)
import Data.Integral
import Data.Array(listArray, (!), (//), elems)
import Control.Exception(assert)
bytesPerBlock :: INLong
bytesPerBlock = intToINLong Halfs.Utils.bytesPerBlock
data Inode
= Inode
{
metaData :: InodeMetadata
,blockPtrs :: INPointers
} deriving (Show, Eq)
type InodeBlock = [Inode]
updatePointers :: Inode -> [(Int, INInt)] -> Inode
updatePointers inode@Inode{blockPtrs=ptrs} updatedPtrs
= inode{blockPtrs=ptrs // (assert ((length (filter (\(x,_) ->
x >= blockPointersPerInode)
updatedPtrs))
== 0)
updatedPtrs)}
dupInode :: Inode
-> Inode
-> Inode
dupInode fromI@Inode{metaData=fromMD} _toI@Inode{metaData=toMD}
= fromI{metaData=fromMD{magic1 =magic1 toMD
,inode_num=inode_num toMD
}
}
newFSRootInode :: Inode
newFSRootInode = let tempInode1 = newInode rootInodeNum File
tempInode = tempInode1{metaData=(metaData tempInode1)
{magic1=rootInodeMagicNum}}
in
inodeBumpSize (updatePointers tempInode [(0, rootInodeDiskAddr),
(1, rootInodeDiskAddr + 1)])
(bytesPerBlock * 2)
newFSBlockMapInode :: Inode
newFSBlockMapInode = inodeBumpSize (updatePointers (newInode blockMapInodeNum File)
[(0,blockMapInodeDiskAddr)])
bytesPerBlock
newFSInodeMapInode :: Inode
newFSInodeMapInode = inodeBumpSize (updatePointers (newInode inodeMapInodeNum File)
[(0, inodeMapInodeDiskAddr)])
bytesPerBlock
newFSRootDirInode :: Inode
newFSRootDirInode = inodeBumpSize (updatePointers (newInode rootDirInodeNum Dir)
[(0, rootDirInodeDiskAddr)])
bytesPerBlock
goodInodeMagic :: Inode -> Bool
goodInodeMagic Inode{metaData=InodeMetadata{magic1=magicNum
,inode_num=num}}
= if num == rootInodeNum
then magicNum == rootInodeMagicNum
else magicNum == otherInodeMagicNum
isRootDirInode :: Inode -> Bool
isRootDirInode Inode{metaData=InodeMetadata{inode_num=inodeNum}}
= inodeNum == rootDirInodeNum
newInode :: INInt -> FileType -> Inode
newInode num filetype
= let inodeMD = InodeMetadata otherInodeMagicNum 0 0 0
filetype
num
0 0 0 0
1
in Inode inodeMD (listArray (0, blockPointersPerInode 1)
(replicate blockPointersPerInode 0))
inodeBumpSize :: Inode
-> INLong
-> Inode
inodeBumpSize inode@(Inode md _) newSize =
inode{metaData=md{num_bytes=max (num_bytes md) newSize}}
inodeAddLink :: Inode -> Inode
inodeAddLink i@Inode{metaData=md@InodeMetadata{hard_links=hl}}
= i{metaData=md{hard_links=hl+1}}
getPointerAt :: Inode -> BlockNumber -> INInt
getPointerAt inode blockNumber =
(blockPtrs inode) !
(assert (blockNumber < intToINInt blockPointersPerInode
&& blockNumber >= 0)
(inIntToInt blockNumber))
rootInodeDiskAddr :: INInt
rootInodeDiskAddr = 0
firstFreeInodeDiskAddr :: INInt
firstFreeInodeDiskAddr = rootDirInodeDiskAddr + 1
blockMapInodeDiskAddr :: INInt
blockMapInodeDiskAddr = 2
inodeMapInodeDiskAddr :: INInt
inodeMapInodeDiskAddr = 3
rootDirInodeDiskAddr :: INInt
rootDirInodeDiskAddr = 4
data InodeMetadata
= InodeMetadata
{
magic1 :: INInt
,num_bytes :: INLong
,uid :: INInt
,gid :: INInt
,mode :: FileType
,inode_num :: INInt
,flags :: INInt
,hard_links :: INInt
,create_time :: INLong
,last_modified_time :: INLong
,level :: INInt
} deriving Eq
instance Show InodeMetadata where
show i
= "\n-----\n"
++ printField x "magic1" magic1
++ printField s' "num_bytes" num_bytes
++ printField s "uid" uid
++ printField s "gid" gid
++ printField show "mode" mode
++ printField s "inode_num" inode_num
++ printField s "flags" flags
++ printField s "hard_links" hard_links
++ printField s' "create_time" create_time
++ printField s' "last_modified_time" last_modified_time
++ printField s "level" level
++ "-----\n"
where
x = myShowHex
s = show
s' = show
printField :: (Show a) => (a -> String)
-> String
-> (InodeMetadata -> a)
-> String
printField shower lab f
= lab ++ ": " ++ (shower $ f i) ++ "\n"
instance Binary Inode where
put_ h inode = do
(BinPtr start) <- tellBin h
put_ h (metaData inode)
sequence_ [ put_ h ptr | ptr <- elems $ blockPtrs inode]
seekBin h (BinPtr (start + bytesPerInode))
return ()
get h = do
(BinPtr start) <- tellBin h
meta <- get h
ptrs <- sequence [ get h | _ <- take 16 [1..blockPointersPerInode] ]
seekBin h (BinPtr (start + bytesPerInode))
return $ Inode { metaData = meta
, blockPtrs = listArray (0, blockPointersPerInode 1) $ ptrs
}
instance Binary InodeMetadata where
put_ h a = do
put_ h (magic1 a)
put_ h (num_bytes a)
put_ h (uid a)
put_ h (gid a)
put_ h (mode a)
put_ h (inode_num a)
put_ h (flags a)
put_ h (hard_links a)
put_ h (create_time a)
put_ h (last_modified_time a)
put_ h (level a)
return ()
get h = do magic1' <- get h
num_bytes' <- get h
uid' <- get h
gid' <- get h
mode' <- get h
inode_num' <- get h
flags' <- get h
hard_links' <- get h
create_time' <- get h
last_modified' <- get h
level' <- get h
return $ InodeMetadata magic1' num_bytes' uid'
gid' mode' inode_num' flags'
hard_links' create_time' last_modified' level'