makeDirectory :: HalfsCapable b t r l m =>
                 InodeRef                 -- ^ inr to parent directory
              -> String                   -- ^ directory name
              -> UserID                   -- ^ user id for created directory
              -> GroupID                  -- ^ group id for created directory
              -> FileMode                 -- ^ initial perms for new directory
              -> HalfsM b r l m InodeRef  -- ^ on success, the inode ref to the
                                          --   created directory
makeDirectory parentIR dname user group perms =
  withDirectory parentIR $ \pdh -> do
    withDHLock pdh $ do
      -- Begin critical section over parent's DirHandle
      contents <- readRef (dhContents pdh)
      if M.member dname contents
       then throwError $ HE_ObjectExists dname
       else do
         bm  <- hasks hsBlockMap
         mir <- fmap blockAddrToInodeRef `fmap` alloc1 bm
         case mir of
           Nothing     -> throwError HE_AllocFailed
           Just thisIR -> do
             -- Build the directory inode and persist it
             dev  <- hasks hsBlockDev
             bstr <- lift $ buildEmptyInodeEnc
                              dev
                              Directory
                              perms
                              thisIR
                              parentIR
                              user
                              group
             assert (BS.length bstr == fromIntegral (bdBlockSize dev)) $ do
               lift $ bdWriteBlock dev (inodeRefToBlockAddr thisIR) bstr

               -- Add 'dname' to parent directory's contents
               addDirEnt_lckd pdh dname thisIR user group perms Directory
               return thisIR
      -- End critical section over parent's DirHandle

-- | Given a parent directory's inode ref, remove the directory with the given name.
makeDirectory :: HalfsCapable b t r l m =>
                 InodeRef                 -- ^ inr to parent directory
              -> String                   -- ^ directory name
              -> UserID                   -- ^ user id for created directory
              -> GroupID                  -- ^ group id for created directory
              -> FileMode                 -- ^ initial perms for new directory
              -> HalfsM b r l m InodeRef
makeDirectory parentIR dname user group perms =
  withDirectory parentIR $ \pdh -> do
    withDHLock pdh $ do
      -- Begin critical section over parent's DirHandle
      contents <- readRef (dhContents pdh)
      if M.member dname contents
       then throwError $ HE_ObjectExists dname
       else do
         bm  <- hasks hsBlockMap
         mir <- fmap blockAddrToInodeRef `fmap` alloc1 bm
         case mir of
           Nothing     -> throwError HE_AllocFailed
           Just thisIR -> do
             -- Build the directory inode and persist it
             dev  <- hasks hsBlockDev
             bstr <- lift $ buildEmptyInodeEnc
                              dev
                              Directory
                              perms
                              thisIR
                              parentIR
                              user
                              group
             assert (BS.length bstr == fromIntegral (bdBlockSize dev)) $ do
               lift $ bdWriteBlock dev (inodeRefToBlockAddr thisIR) bstr

               -- Add 'dname' to parent directory's contents
               addDirEnt_lckd pdh dname thisIR user group perms Directory
               return thisIR
      -- End critical section over parent's DirHandle

-- | Given a parent directory's inode ref, remove the directory with the given name.
makeDirectory parentIR dname user group perms =
  withDirectory parentIR $ \pdh -> do
    withDHLock pdh $ do
      -- Begin critical section over parent's DirHandle
      contents <- readRef (dhContents pdh)
      if M.member dname contents
       then throwError $ HE_ObjectExists dname
       else do
         bm  <- hasks hsBlockMap
         mir <- fmap blockAddrToInodeRef `fmap` alloc1 bm
         case mir of
           Nothing     -> throwError HE_AllocFailed
           Just thisIR -> do
             -- Build the directory inode and persist it
             dev  <- hasks hsBlockDev
             bstr <- lift $ buildEmptyInodeEnc
                              dev
                              Directory
                              perms
                              thisIR
                              parentIR
                              user
                              group
             assert (BS.length bstr == fromIntegral (bdBlockSize dev)) $ do
               lift $ bdWriteBlock dev (inodeRefToBlockAddr thisIR) bstr

               -- Add 'dname' to parent directory's contents
               addDirEnt_lckd pdh dname thisIR user group perms Directory
               return thisIR
      -- End critical section over parent's DirHandle

-- | Given a parent directory's inode ref, remove the directory with the given name.