{-# OPTIONS_GHC -optc-DFUSE_USE_VERSION=26 #-}
{-# LINE 1 "System/Fuse.hsc" #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Fuse
-- Copyright   :  (c) Jérémy Bobbio, Taru Karttunen
-- License     :  BSD-style
-- 
-- Maintainer  :  Montez Fitzpatrick
-- Stability   :  experimental
-- Portability :  GHC 6.4-7.8.2
--
-- A binding for the FUSE (Filesystem in USErspace) library
-- (<http://fuse.sourceforge.net/>), which allows filesystems to be implemented
-- as userspace processes.
--
-- The binding tries to follow as much as possible current Haskell POSIX
-- interface in "System.Posix.Files" and "System.Posix.Directory".
--
-- FUSE uses POSIX threads, so any Haskell application using this library must
-- be linked against a threaded runtime system (eg. using the @threaded@ GHC
-- option).
--
-----------------------------------------------------------------------------
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE CPP #-}
module System.Fuse
    ( -- * Using FUSE

      -- $intro

      module Foreign.C.Error
    , FuseOperations(..)
    , defaultFuseOps
    , fuseMain -- :: FuseOperations fh -> (Exception -> IO Errno) -> IO ()
    , fuseRun -- :: String -> [String] -> FuseOperations fh -> (Exception -> IO Errno) -> IO ()

    , fuseMainInline -- :: FuseOperations fh -> (Exception -> IO Errno) -> IO ()
    , fuseRunInline -- :: String -> [String] -> FuseOperations fh -> (Exception -> IO Errno) -> IO ()
    , defaultExceptionHandler -- :: Exception -> IO Errno
      -- * Operations datatypes
    , FileStat(..)
    , EntryType(..)
    , FileSystemStats(..)
    , SyncType(..)
      -- * FUSE Context
    , getFuseContext -- :: IO FuseContext
    , FuseContext(fuseCtxUserID, fuseCtxGroupID, fuseCtxProcessID)
      -- * File modes
    , entryTypeToFileMode -- :: EntryType -> FileMode
    , fileModeToEntryType -- :: FileMode -> EntryType
    , OpenMode(..)
    , OpenFileFlags(..)
    , intersectFileModes -- :: FileMode
    , unionFileModes -- :: FileMode
    ) where

import Prelude hiding ( Read )

import Control.Concurrent (forkIO, threadDelay)
import Control.Monad
import Control.Exception as E (Exception, handle, finally, SomeException, bracket_, bracket)
import Data.Maybe
import qualified Data.ByteString.Char8    as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Unsafe   as B
import Foreign
import Foreign.C
import Foreign.C.Error
import Foreign.Marshal
import System.Environment ( getProgName, getArgs )
import System.IO ( hPutStrLn, stderr, withFile, stdin, stdout, IOMode(..) )
import System.Posix.Types
import System.Posix.Files ( accessModes, intersectFileModes, unionFileModes )
import System.Posix.Directory(changeWorkingDirectory)
import System.Posix.Process(forkProcess,createSession,exitImmediately)
import System.Posix.IO ( OpenMode(..), OpenFileFlags(..) )
import qualified System.Posix.Signals as Signals
import GHC.IO.Handle(hDuplicateTo)
import System.Exit

{-# LINE 81 "System/Fuse.hsc" #-}
import System.IO.Error (catchIOError,ioeGetErrorString)

{-# LINE 85 "System/Fuse.hsc" #-}

-- TODO: FileMode -> Permissions
-- TODO: Arguments !
-- TODO: implement binding to fuse_invalidate
-- TODO: bind fuse_*xattr




{-# LINE 96 "System/Fuse.hsc" #-}


{-# LINE 98 "System/Fuse.hsc" #-}





{- $intro
'FuseOperations' contains a field for each filesystem operations that can be called
by FUSE. Think like if you were implementing a file system inside the Linux kernel.

Each actions must return a POSIX error code, also called 'Errno' reflecting
operation result. For actions not using 'Either', you should return 'eOK' in case
of success.

Read and writes are done with Haskell 'ByteString' type.

-}

{-  All operations should return the negated error value (-errno) on
      error.
-}

{- | Used by 'fuseGetFileStat'.  Corresponds to @struct stat@ from @stat.h@;
     @st_dev@, @st_ino@ and @st_blksize@ are omitted, since (from the libfuse
     documentation): \"the @st_dev@ and @st_blksize@ fields are ignored.  The
     @st_ino@ field is ignored except if the use_ino mount option is given.\"

     /TODO: at some point the inode field will probably be needed./
-}
data FileStat = FileStat { statEntryType :: EntryType
                         , statFileMode :: FileMode
                         , statLinkCount :: LinkCount
                         , statFileOwner :: UserID
                         , statFileGroup :: GroupID
                         , statSpecialDeviceID :: DeviceID
                         , statFileSize :: FileOffset
                         , statBlocks :: Integer
                         , statAccessTime :: EpochTime
                         , statModificationTime :: EpochTime
                         , statStatusChangeTime :: EpochTime
                         }
    deriving Show

{- FIXME: I don't know how to determine the alignment of struct stat without
 - making unportable assumptions about the order of elements within it.  Hence,
 - FileStat is not an instance of Storable.  But it should be, rather than this
 - next function existing!
 -}

fileStatToCStat :: FileStat -> Ptr CStat -> IO ()
fileStatToCStat stat pStat = do
    let mode = (entryTypeToFileMode (statEntryType stat)
             `unionFileModes`
               (statFileMode stat `intersectFileModes` accessModes))
    let block_count = (fromIntegral (statBlocks stat) :: (Int64))
{-# LINE 152 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 24))   pStat mode
{-# LINE 153 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  pStat (statLinkCount  stat)
{-# LINE 154 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 28))    pStat (statFileOwner  stat)
{-# LINE 155 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 32))    pStat (statFileGroup  stat)
{-# LINE 156 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 40))   pStat (statSpecialDeviceID stat)
{-# LINE 157 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 48))   pStat (statFileSize   stat)
{-# LINE 158 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 64)) pStat block_count
{-# LINE 159 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 72))  pStat (statAccessTime stat)
{-# LINE 160 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 88))  pStat (statModificationTime stat)
{-# LINE 161 "System/Fuse.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 104))  pStat (statStatusChangeTime stat)
{-# LINE 162 "System/Fuse.hsc" #-}


-- | The Unix type of a node in the filesystem.
data EntryType
    = Unknown            -- ^ Unknown entry type
    | NamedPipe
    | CharacterSpecial
    | Directory
    | BlockSpecial
    | RegularFile
    | SymbolicLink
    | Socket
      deriving(Show)

entryTypeToDT :: EntryType -> Int
entryTypeToDT Unknown          = (0)
{-# LINE 178 "System/Fuse.hsc" #-}
entryTypeToDT NamedPipe        = (1)
{-# LINE 179 "System/Fuse.hsc" #-}
entryTypeToDT CharacterSpecial = (2)
{-# LINE 180 "System/Fuse.hsc" #-}
entryTypeToDT Directory        = (4)
{-# LINE 181 "System/Fuse.hsc" #-}
entryTypeToDT BlockSpecial     = (6)
{-# LINE 182 "System/Fuse.hsc" #-}
entryTypeToDT RegularFile      = (8)
{-# LINE 183 "System/Fuse.hsc" #-}
entryTypeToDT SymbolicLink     = (10)
{-# LINE 184 "System/Fuse.hsc" #-}
entryTypeToDT Socket           = (12)
{-# LINE 185 "System/Fuse.hsc" #-}

fileTypeModes :: FileMode
fileTypeModes = (61440)
{-# LINE 188 "System/Fuse.hsc" #-}

blockSpecialMode :: FileMode
blockSpecialMode = (24576)
{-# LINE 191 "System/Fuse.hsc" #-}

characterSpecialMode :: FileMode
characterSpecialMode = (8192)
{-# LINE 194 "System/Fuse.hsc" #-}

namedPipeMode :: FileMode
namedPipeMode = (4096)
{-# LINE 197 "System/Fuse.hsc" #-}

regularFileMode :: FileMode
regularFileMode = (32768)
{-# LINE 200 "System/Fuse.hsc" #-}

directoryMode :: FileMode
directoryMode = (16384)
{-# LINE 203 "System/Fuse.hsc" #-}

symbolicLinkMode :: FileMode
symbolicLinkMode = (40960)
{-# LINE 206 "System/Fuse.hsc" #-}

socketMode :: FileMode
socketMode = (49152)
{-# LINE 209 "System/Fuse.hsc" #-}

-- | Converts an 'EntryType' into the corresponding POSIX 'FileMode'.
entryTypeToFileMode :: EntryType -> FileMode
entryTypeToFileMode Unknown          = 0
entryTypeToFileMode NamedPipe        = namedPipeMode
entryTypeToFileMode CharacterSpecial = characterSpecialMode
entryTypeToFileMode Directory        = directoryMode
entryTypeToFileMode BlockSpecial     = blockSpecialMode
entryTypeToFileMode RegularFile      = regularFileMode
entryTypeToFileMode SymbolicLink     = symbolicLinkMode
entryTypeToFileMode Socket           = socketMode

fileModeToEntryType :: FileMode -> EntryType
fileModeToEntryType mode
    | fileType == namedPipeMode        = NamedPipe
    | fileType == characterSpecialMode = CharacterSpecial
    | fileType == directoryMode        = Directory
    | fileType == blockSpecialMode     = BlockSpecial
    | fileType == regularFileMode      = RegularFile
    | fileType == symbolicLinkMode     = SymbolicLink
    | fileType == socketMode           = Socket
    where fileType = mode .&. (61440)
{-# LINE 231 "System/Fuse.hsc" #-}

{-
    There is no create() operation, mknod() will be called for
    creation of all non directory, non symlink nodes.
-}

-- | Type used by the 'fuseGetFileSystemStats'.
data FileSystemStats = FileSystemStats
    { fsStatBlockSize :: Integer
      -- ^ Optimal transfer block size. FUSE default is 512.
    , fsStatBlockCount :: Integer
      -- ^ Total data blocks in file system.
    , fsStatBlocksFree :: Integer
      -- ^ Free blocks in file system.
    , fsStatBlocksAvailable :: Integer
      -- ^ Free blocks available to non-superusers.
    , fsStatFileCount :: Integer
      -- ^ Total file nodes in file system.
    , fsStatFilesFree :: Integer
      -- ^ Free file nodes in file system.
    , fsStatMaxNameLength :: Integer
      -- ^ Maximum length of filenames. FUSE default is 255.
    }


-- | Used by 'fuseSynchronizeFile' and 'fuseSynchronizeDirectory'.
data SyncType
    = FullSync
    -- ^ Synchronize all in-core parts of a file to disk: file content and
    -- metadata.
    | DataSync
    -- ^ Synchronize only the file content.
    deriving (Eq, Enum)


-- | Returned by 'getFuseContext'.
data FuseContext = FuseContext
    { fuseCtxUserID :: UserID
    , fuseCtxGroupID :: GroupID
    , fuseCtxProcessID :: ProcessID
    }

-- | Returns the context of the program doing the current FUSE call.
getFuseContext :: IO FuseContext
getFuseContext =
    do pCtx <- fuse_get_context
       userID <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) pCtx
{-# LINE 278 "System/Fuse.hsc" #-}
       groupID <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) pCtx
{-# LINE 279 "System/Fuse.hsc" #-}
       processID <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) pCtx
{-# LINE 280 "System/Fuse.hsc" #-}
       return $ FuseContext { fuseCtxUserID = userID
                            , fuseCtxGroupID = groupID
                            , fuseCtxProcessID = processID
                            }

-- | This record, given to 'fuseMain', binds each required file system
--   operations.
--
--   Each field is named against 'System.Posix' names. Matching Linux system
--   calls are also given as a reference.
--
--   @fh@ is the file handle type returned by 'fuseOpen' and subsequently passed
--   to all other file operations.
data FuseOperations fh = FuseOperations
      { -- | Implements 'System.Posix.Files.getSymbolicLinkStatus' operation
        --   (POSIX @lstat(2)@).
        fuseGetFileStat :: FilePath -> IO (Either Errno FileStat),

        -- | Implements 'System.Posix.Files.readSymbolicLink' operation (POSIX
        --   @readlink(2)@).  The returned 'FilePath' might be truncated
        --   depending on caller buffer size.
        fuseReadSymbolicLink :: FilePath -> IO (Either Errno FilePath),

        -- | Implements 'System.Posix.Files.createDevice' (POSIX @mknod(2)@).
        --   This function will also be called for regular file creation.
        fuseCreateDevice :: FilePath -> EntryType -> FileMode
                         -> DeviceID -> IO Errno,

        -- | Implements 'System.Posix.Directory.createDirectory' (POSIX
        --   @mkdir(2)@).
        fuseCreateDirectory :: FilePath -> FileMode -> IO Errno,

        -- | Implements 'System.Posix.Files.removeLink' (POSIX @unlink(2)@).
        fuseRemoveLink :: FilePath -> IO Errno,

        -- | Implements 'System.Posix.Directory.removeDirectory' (POSIX
        --   @rmdir(2)@).
        fuseRemoveDirectory :: FilePath -> IO Errno,

        -- | Implements 'System.Posix.Files.createSymbolicLink' (POSIX
        --   @symlink(2)@).
        fuseCreateSymbolicLink :: FilePath -> FilePath -> IO Errno,

        -- | Implements 'System.Posix.Files.rename' (POSIX @rename(2)@).
        fuseRename :: FilePath -> FilePath -> IO Errno,

        -- | Implements 'System.Posix.Files.createLink' (POSIX @link(2)@).
        fuseCreateLink :: FilePath -> FilePath -> IO Errno,

        -- | Implements 'System.Posix.Files.setFileMode' (POSIX @chmod(2)@).
        fuseSetFileMode :: FilePath -> FileMode -> IO Errno,

        -- | Implements 'System.Posix.Files.setOwnerAndGroup' (POSIX
        --   @chown(2)@).
        fuseSetOwnerAndGroup :: FilePath -> UserID -> GroupID -> IO Errno,

        -- | Implements 'System.Posix.Files.setFileSize' (POSIX @truncate(2)@).
        fuseSetFileSize :: FilePath -> FileOffset -> IO Errno,

        -- | Implements 'System.Posix.Files.setFileTimes'
        --   (POSIX @utime(2)@).
        fuseSetFileTimes :: FilePath -> EpochTime -> EpochTime -> IO Errno,

        -- | Implements 'System.Posix.Files.openFd' (POSIX @open(2)@).  On
        --   success, returns 'Right' of a filehandle-like value that will be
        --   passed to future file operations; on failure, returns 'Left' of the
        --   appropriate 'Errno'.
        --
        --   No creation, exclusive access or truncating flags will be passed.
        --   This should check that the operation is permitted for the given
        --   flags.
        fuseOpen :: FilePath -> OpenMode -> OpenFileFlags -> IO (Either Errno fh),

        -- | Implements Unix98 @pread(2)@. It differs from
        --   'System.Posix.Files.fdRead' by the explicit 'FileOffset' argument.
        --   The @fuse.h@ documentation stipulates that this \"should return
        --   exactly the number of bytes requested except on EOF or error,
        --   otherwise the rest of the data will be substituted with zeroes.\"
        fuseRead :: FilePath -> fh -> ByteCount -> FileOffset
                 -> IO (Either Errno B.ByteString),

        -- | Implements Unix98 @pwrite(2)@. It differs
        --   from 'System.Posix.Files.fdWrite' by the explicit 'FileOffset' argument.
        fuseWrite :: FilePath -> fh -> B.ByteString -> FileOffset
                  -> IO (Either Errno ByteCount),

        -- | Implements @statfs(2)@.
        fuseGetFileSystemStats :: String -> IO (Either Errno FileSystemStats),

        -- | Called when @close(2)@ has been called on an open file.
        --   Note: this does not mean that the file is released.  This function may be
        --   called more than once for each @open(2)@.  The return value is passed on
        --   to the @close(2)@ system call.
        fuseFlush :: FilePath -> fh -> IO Errno,

        -- | Called when an open file has all file descriptors closed and all
        -- memory mappings unmapped.  For every @open@ call there will be
        -- exactly one @release@ call with the same flags.  It is possible to
        -- have a file opened more than once, in which case only the last
        -- release will mean that no more reads or writes will happen on the
        -- file.
        fuseRelease :: FilePath -> fh -> IO (),

        -- | Implements @fsync(2)@.
        fuseSynchronizeFile :: FilePath -> SyncType -> IO Errno,

        -- | Implements @opendir(3)@.  This method should check if the open
        --   operation is permitted for this directory.
        fuseOpenDirectory :: FilePath -> IO Errno,

        -- | Implements @readdir(3)@.  The entire contents of the directory
        --   should be returned as a list of tuples (corresponding to the first
        --   mode of operation documented in @fuse.h@).
        fuseReadDirectory :: FilePath -> IO (Either Errno [(FilePath, FileStat)]),

        -- | Implements @closedir(3)@.
        fuseReleaseDirectory :: FilePath -> IO Errno,

        -- | Synchronize the directory's contents; analogous to
        --   'fuseSynchronizeFile'.
        fuseSynchronizeDirectory :: FilePath -> SyncType -> IO Errno,

        -- | Check file access permissions; this will be called for the
        --   access() system call.  If the @default_permissions@ mount option
        --   is given, this method is not called.  This method is also not
        --   called under Linux kernel versions 2.4.x
        fuseAccess :: FilePath -> Int -> IO Errno, -- FIXME present a nicer type to Haskell

        -- | Initializes the filesystem.  This is called before all other
        --   operations.
        fuseInit :: IO (),

        -- | Called on filesystem exit to allow cleanup.
        fuseDestroy :: IO ()
      }

-- | Empty \/ default versions of the FUSE operations.
defaultFuseOps :: FuseOperations fh
defaultFuseOps =
    FuseOperations { fuseGetFileStat = \_ -> return (Left eNOSYS)
                   , fuseReadSymbolicLink = \_ -> return (Left eNOSYS)
                   , fuseCreateDevice = \_ _ _ _ ->  return eNOSYS
                   , fuseCreateDirectory = \_ _ -> return eNOSYS
                   , fuseRemoveLink = \_ -> return eNOSYS
                   , fuseRemoveDirectory = \_ -> return eNOSYS
                   , fuseCreateSymbolicLink = \_ _ -> return eNOSYS
                   , fuseRename = \_ _ -> return eNOSYS
                   , fuseCreateLink = \_ _ -> return eNOSYS
                   , fuseSetFileMode = \_ _ -> return eNOSYS
                   , fuseSetOwnerAndGroup = \_ _ _ -> return eNOSYS
                   , fuseSetFileSize = \_ _ -> return eNOSYS
                   , fuseSetFileTimes = \_ _ _ -> return eNOSYS
                   , fuseOpen =   \_ _ _   -> return (Left eNOSYS)
                   , fuseRead =   \_ _ _ _ -> return (Left eNOSYS)
                   , fuseWrite =  \_ _ _ _ -> return (Left eNOSYS)
                   , fuseGetFileSystemStats = \_ -> return (Left eNOSYS)
                   , fuseFlush = \_ _ -> return eOK
                   , fuseRelease = \_ _ -> return ()
                   , fuseSynchronizeFile = \_ _ -> return eNOSYS
                   , fuseOpenDirectory = \_ -> return eNOSYS
                   , fuseReadDirectory = \_ -> return (Left eNOSYS)
                   , fuseReleaseDirectory = \_ -> return eNOSYS
                   , fuseSynchronizeDirectory = \_ _ -> return eNOSYS
                   , fuseAccess = \_ _ -> return eNOSYS
                   , fuseInit = return ()
                   , fuseDestroy = return ()
                   }

-- Allocates a fuse_args struct to hold the commandline arguments.
withFuseArgs :: String -> [String] -> (Ptr CFuseArgs -> IO b) -> IO b
withFuseArgs prog args f =
    do let allArgs = (prog:args)
           argc = length allArgs
       withMany withCString allArgs (\ cArgs ->
           withArray cArgs $ (\ pArgv ->
               allocaBytes ((24)) (\ fuseArgs ->
{-# LINE 456 "System/Fuse.hsc" #-}
                    do ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) fuseArgs argc
{-# LINE 457 "System/Fuse.hsc" #-}
                       ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) fuseArgs pArgv
{-# LINE 458 "System/Fuse.hsc" #-}
                       ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) fuseArgs (0::CInt)
{-# LINE 459 "System/Fuse.hsc" #-}
                       finally (f fuseArgs)
                               (fuse_opt_free_args fuseArgs))))

withStructFuse :: forall e fh b. Exception e => Ptr CFuseChan -> Ptr CFuseArgs -> FuseOperations fh -> (e -> IO Errno) -> (Ptr CStructFuse -> IO b) -> IO b
withStructFuse pFuseChan pArgs ops handler f =
    allocaBytes ((360)) $ \ pOps -> do
{-# LINE 465 "System/Fuse.hsc" #-}
      bzero pOps ((360))
{-# LINE 466 "System/Fuse.hsc" #-}
      mkGetAttr    wrapGetAttr    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 0))    pOps
{-# LINE 467 "System/Fuse.hsc" #-}
      mkReadLink   wrapReadLink   >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 8))   pOps 
{-# LINE 468 "System/Fuse.hsc" #-}
      -- getdir is deprecated and thus unsupported
      ((\hsc_ptr -> pokeByteOff hsc_ptr 16))    pOps nullPtr
{-# LINE 470 "System/Fuse.hsc" #-}
      mkMkNod      wrapMkNod      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 24))      pOps 
{-# LINE 471 "System/Fuse.hsc" #-}
      mkMkDir      wrapMkDir      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 32))      pOps 
{-# LINE 472 "System/Fuse.hsc" #-}
      mkUnlink     wrapUnlink     >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 40))     pOps 
{-# LINE 473 "System/Fuse.hsc" #-}
      mkRmDir      wrapRmDir      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 48))      pOps 
{-# LINE 474 "System/Fuse.hsc" #-}
      mkSymLink    wrapSymLink    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 56))    pOps 
{-# LINE 475 "System/Fuse.hsc" #-}
      mkRename     wrapRename     >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 64))     pOps 
{-# LINE 476 "System/Fuse.hsc" #-}
      mkLink       wrapLink       >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 72))       pOps 
{-# LINE 477 "System/Fuse.hsc" #-}
      mkChMod      wrapChMod      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 80))      pOps 
{-# LINE 478 "System/Fuse.hsc" #-}
      mkChOwn      wrapChOwn      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 88))      pOps 
{-# LINE 479 "System/Fuse.hsc" #-}
      mkTruncate   wrapTruncate   >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 96))   pOps 
{-# LINE 480 "System/Fuse.hsc" #-}
      -- TODO: Deprecated, use utimens() instead.
      mkUTime      wrapUTime      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 104))      pOps 
{-# LINE 482 "System/Fuse.hsc" #-}
      mkOpen       wrapOpen       >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 112))       pOps 
{-# LINE 483 "System/Fuse.hsc" #-}
      mkRead       wrapRead       >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 120))       pOps 
{-# LINE 484 "System/Fuse.hsc" #-}
      mkWrite      wrapWrite      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 128))      pOps 
{-# LINE 485 "System/Fuse.hsc" #-}
      mkStatFS     wrapStatFS     >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 136))     pOps
{-# LINE 486 "System/Fuse.hsc" #-}
      mkFlush      wrapFlush      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 144))      pOps
{-# LINE 487 "System/Fuse.hsc" #-}
      mkRelease    wrapRelease    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 152))    pOps 
{-# LINE 488 "System/Fuse.hsc" #-}
      mkFSync      wrapFSync      >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 160))      pOps
{-# LINE 489 "System/Fuse.hsc" #-}
      -- TODO: Implement these
      ((\hsc_ptr -> pokeByteOff hsc_ptr 168))    pOps nullPtr
{-# LINE 491 "System/Fuse.hsc" #-}
      ((\hsc_ptr -> pokeByteOff hsc_ptr 176))    pOps nullPtr
{-# LINE 492 "System/Fuse.hsc" #-}
      ((\hsc_ptr -> pokeByteOff hsc_ptr 184))   pOps nullPtr
{-# LINE 493 "System/Fuse.hsc" #-}
      ((\hsc_ptr -> pokeByteOff hsc_ptr 192)) pOps nullPtr
{-# LINE 494 "System/Fuse.hsc" #-}
      mkOpenDir    wrapOpenDir    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 200))    pOps
{-# LINE 495 "System/Fuse.hsc" #-}
      mkReadDir    wrapReadDir    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 208))    pOps
{-# LINE 496 "System/Fuse.hsc" #-}
      mkReleaseDir wrapReleaseDir >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 216)) pOps
{-# LINE 497 "System/Fuse.hsc" #-}
      mkFSyncDir   wrapFSyncDir   >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 224))   pOps
{-# LINE 498 "System/Fuse.hsc" #-}

{-# LINE 499 "System/Fuse.hsc" #-}
      mkAccess     wrapAccess     >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 248))     pOps
{-# LINE 500 "System/Fuse.hsc" #-}

{-# LINE 501 "System/Fuse.hsc" #-}
      mkInit       wrapInit       >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 232))       pOps
{-# LINE 502 "System/Fuse.hsc" #-}
      mkDestroy    wrapDestroy    >>= ((\hsc_ptr -> pokeByteOff hsc_ptr 240))    pOps
{-# LINE 503 "System/Fuse.hsc" #-}
      structFuse <- fuse_new pFuseChan pArgs pOps ((360)) nullPtr 
{-# LINE 504 "System/Fuse.hsc" #-}
      if structFuse == nullPtr
        then fail ""
        else E.finally (f structFuse)
                       (fuse_destroy structFuse)
    where fuseHandler :: e -> IO CInt
          fuseHandler e = handler e >>= return . negate . unErrno
          wrapGetAttr :: CGetAttr
          wrapGetAttr pFilePath pStat = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 eitherFileStat <- (fuseGetFileStat ops) filePath
                 case eitherFileStat of
                   Left (Errno errno) -> return (- errno)
                   Right stat         -> do fileStatToCStat stat pStat
                                            return okErrno

          wrapReadLink :: CReadLink
          wrapReadLink pFilePath pBuf bufSize = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 return (- unErrno eNOSYS)
                 eitherTarget <- (fuseReadSymbolicLink ops) filePath
                 case eitherTarget of
                   Left (Errno errno) -> return (- errno)
                   Right target ->
                   -- This will truncate target if it's longer than the buffer
                   -- can hold, which is correct according to fuse.h
                     do pokeCStringLen0 (pBuf, (fromIntegral bufSize)) target
                        return okErrno

          wrapMkNod :: CMkNod
          wrapMkNod pFilePath mode dev = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseCreateDevice ops) filePath
                                      (fileModeToEntryType mode) mode dev
                 return (- errno)
          wrapMkDir :: CMkDir
          wrapMkDir pFilePath mode = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseCreateDirectory ops) filePath mode
                 return (- errno)
          wrapUnlink :: CUnlink
          wrapUnlink pFilePath = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseRemoveLink ops) filePath
                 return (- errno)
          wrapRmDir :: CRmDir
          wrapRmDir pFilePath = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseRemoveDirectory ops) filePath
                 return (- errno)
          wrapSymLink :: CSymLink
          wrapSymLink pSource pDestination = handle fuseHandler $
              do source <- peekCString pSource
                 destination <- peekCString pDestination
                 (Errno errno) <- (fuseCreateSymbolicLink ops) source destination
                 return (- errno)
          wrapRename :: CRename
          wrapRename pOld pNew = handle fuseHandler $
              do old <- peekCString pOld
                 new <- peekCString pNew
                 (Errno errno) <- (fuseRename ops) old new
                 return (- errno)
          wrapLink :: CLink
          wrapLink pSource pDestination = handle fuseHandler $
              do source <- peekCString pSource
                 destination <- peekCString pDestination
                 (Errno errno) <- (fuseCreateLink ops) source destination
                 return (- errno)
          wrapChMod :: CChMod
          wrapChMod pFilePath mode = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseSetFileMode ops) filePath mode
                 return (- errno)
          wrapChOwn :: CChOwn
          wrapChOwn pFilePath uid gid = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseSetOwnerAndGroup ops) filePath uid gid
                 return (- errno)
          wrapTruncate :: CTruncate
          wrapTruncate pFilePath off = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseSetFileSize ops) filePath off
                 return (- errno)
          wrapUTime :: CUTime
          wrapUTime pFilePath pUTimBuf = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 accessTime <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) pUTimBuf
{-# LINE 590 "System/Fuse.hsc" #-}
                 modificationTime <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) pUTimBuf
{-# LINE 591 "System/Fuse.hsc" #-}
                 (Errno errno) <- (fuseSetFileTimes ops) filePath
                                      accessTime modificationTime
                 return (- errno)
          wrapOpen :: COpen
          wrapOpen pFilePath pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (flags :: CInt) <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) pFuseFileInfo
{-# LINE 598 "System/Fuse.hsc" #-}
                 let append    = (1024)   .&. flags == (1024)
{-# LINE 599 "System/Fuse.hsc" #-}
                     noctty    = (256)   .&. flags == (256)
{-# LINE 600 "System/Fuse.hsc" #-}
                     nonBlock  = (2048) .&. flags == (2048)
{-# LINE 601 "System/Fuse.hsc" #-}
                     how | (2) .&. flags == (2) = ReadWrite
{-# LINE 602 "System/Fuse.hsc" #-}
                         | (1) .&. flags == (1) = WriteOnly
{-# LINE 603 "System/Fuse.hsc" #-}
                         | otherwise = ReadOnly
                     openFileFlags = OpenFileFlags { append = append
                                                   , exclusive = False
                                                   , noctty = noctty
                                                   , nonBlock = nonBlock
                                                   , trunc = False
                                                   }
                 result <- (fuseOpen ops) filePath how openFileFlags
                 case result of
                    Left (Errno errno) -> return (- errno)
                    Right cval         -> do
                        sptr <- newStablePtr cval
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) pFuseFileInfo $ castStablePtrToPtr sptr
{-# LINE 616 "System/Fuse.hsc" #-}
                        return okErrno

          wrapRead :: CRead
          wrapRead pFilePath pBuf bufSiz off pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 cVal <- getFH pFuseFileInfo
                 eitherRead <- (fuseRead ops) filePath cVal bufSiz off
                 case eitherRead of
                   Left (Errno errno) -> return (- errno)
                   Right bytes  -> 
                     do let len = fromIntegral bufSiz `min` B.length bytes
                        bsToBuf pBuf bytes len
                        return (fromIntegral len)
          wrapWrite :: CWrite
          wrapWrite pFilePath pBuf bufSiz off pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 cVal <- getFH pFuseFileInfo
                 buf  <- B.packCStringLen (pBuf, fromIntegral bufSiz)
                 eitherBytes <- (fuseWrite ops) filePath cVal buf off
                 case eitherBytes of
                   Left  (Errno errno) -> return (- errno)
                   Right bytes         -> return (fromIntegral bytes)
          wrapStatFS :: CStatFS
          wrapStatFS pStr pStatVFS = handle fuseHandler $
            do str <- peekCString pStr
               eitherStatVFS <- (fuseGetFileSystemStats ops) str
               case eitherStatVFS of
                 Left (Errno errno) -> return (- errno)
                 Right stat         ->
                   do ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) pStatVFS
{-# LINE 646 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatBlockSize stat) :: (Int64))
{-# LINE 647 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 16)) pStatVFS
{-# LINE 648 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatBlockCount stat) :: (Word64))
{-# LINE 649 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) pStatVFS
{-# LINE 650 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatBlocksFree stat) :: (Word64))
{-# LINE 651 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) pStatVFS
{-# LINE 652 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatBlocksAvailable stat) :: (Word64))
{-# LINE 653 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) pStatVFS
{-# LINE 654 "System/Fuse.hsc" #-}
                           (fromIntegral (fsStatFileCount stat) :: (Word64))
{-# LINE 655 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 48)) pStatVFS
{-# LINE 656 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatFilesFree stat) :: (Word64))
{-# LINE 657 "System/Fuse.hsc" #-}
                      ((\hsc_ptr -> pokeByteOff hsc_ptr 80)) pStatVFS
{-# LINE 658 "System/Fuse.hsc" #-}
                          (fromIntegral (fsStatMaxNameLength stat) :: (Int64))
{-# LINE 659 "System/Fuse.hsc" #-}
                      return 0
          wrapFlush :: CFlush
          wrapFlush pFilePath pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 cVal     <- getFH pFuseFileInfo
                 (Errno errno) <- (fuseFlush ops) filePath cVal
                 return (- errno)
          wrapRelease :: CRelease
          wrapRelease pFilePath pFuseFileInfo = E.finally (handle fuseHandler $
              do filePath <- peekCString pFilePath
                 cVal     <- getFH pFuseFileInfo
                 -- TODO: deal with these flags?
--                 flags <- (#peek struct fuse_file_info, flags) pFuseFileInfo
                 (fuseRelease ops) filePath cVal
                 return 0) (delFH pFuseFileInfo)
          wrapFSync :: CFSync
          wrapFSync pFilePath isFullSync pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseSynchronizeFile ops)
                                      filePath (toEnum isFullSync)
                 return (- errno)
          wrapOpenDir :: COpenDir
          wrapOpenDir pFilePath pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 -- XXX: Should we pass flags from pFuseFileInfo?
                 (Errno errno) <- (fuseOpenDirectory ops) filePath
                 return (- errno)

          wrapReadDir :: CReadDir
          wrapReadDir pFilePath pBuf pFillDir off pFuseFileInfo =
            handle fuseHandler $ do
              filePath <- peekCString pFilePath
              let fillDir = mkFillDir pFillDir
              let filler :: (FilePath, FileStat) -> IO ()
                  filler (fileName, fileStat) =
                    withCString fileName $ \ pFileName ->
                      allocaBytes ((144)) $ \ pFileStat ->
{-# LINE 696 "System/Fuse.hsc" #-}
                        do fileStatToCStat fileStat pFileStat
                           fillDir pBuf pFileName pFileStat 0
                           -- Ignoring return value of pFillDir, namely 1 if
                           -- pBuff is full.
                           return ()
              eitherContents <- (fuseReadDirectory ops) filePath -- XXX fileinfo
              case eitherContents of
                Left (Errno errno) -> return (- errno)
                Right contents     -> mapM filler contents >> return okErrno

          wrapReleaseDir :: CReleaseDir
          wrapReleaseDir pFilePath pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseReleaseDirectory ops) filePath
                 return (- errno)
          wrapFSyncDir :: CFSyncDir
          wrapFSyncDir pFilePath isFullSync pFuseFileInfo = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseSynchronizeDirectory ops)
                                      filePath (toEnum isFullSync)
                 return (- errno)
          wrapAccess :: CAccess
          wrapAccess pFilePath at = handle fuseHandler $
              do filePath <- peekCString pFilePath
                 (Errno errno) <- (fuseAccess ops) filePath (fromIntegral at)
                 return (- errno)
          wrapInit :: CInit
          wrapInit pFuseConnInfo =
            handle (\e -> defaultExceptionHandler e >> return nullPtr) $
              do fuseInit ops
                 return nullPtr
          wrapDestroy :: CDestroy
          wrapDestroy _ = handle (\e -> defaultExceptionHandler e >> return ()) $
              do fuseDestroy ops

-- | Default exception handler.
-- Print the exception on error output and returns 'eFAULT'.
defaultExceptionHandler :: (SomeException -> IO Errno)
defaultExceptionHandler e = hPutStrLn stderr (show e) >> return eFAULT

-- Calls fuse_parse_cmdline to parses the part of the commandline arguments that
-- we care about. fuse_parse_cmdline will modify the CFuseArgs struct passed in
-- to remove those arguments; the CFuseArgs struct containing remaining arguments
-- must be passed to fuse_mount/fuse_new.
--
-- The multithreaded runtime will be used regardless of the threading flag!
-- See the comment in fuse_session_exit for why.
fuseParseCommandLine :: Ptr CFuseArgs -> IO (Maybe (Maybe String, Bool, Bool))
fuseParseCommandLine pArgs = 
    alloca (\pMountPt -> 
        alloca (\pMultiThreaded ->
            alloca (\pFG ->
                do poke pMultiThreaded 0
                   poke pFG 0
                   retval <- fuse_parse_cmdline pArgs pMountPt pMultiThreaded pFG
                   if retval == 0
                     then do cMountPt <- peek pMountPt
                             mountPt <- if cMountPt /= nullPtr
                                          then do a <- peekCString cMountPt
                                                  free cMountPt
                                                  return $ Just a
                                          else return $ Nothing
                             multiThreaded <- peek pMultiThreaded
                             foreground <- peek pFG
                             return $ Just (mountPt, multiThreaded == 1, foreground == 1)
                     else return Nothing)))

-- haskell version of daemon(2)
-- Mimic's daemon()s use of _exit() instead of exit(); we depend on this in fuseMainReal,
-- because otherwise we'll unmount the filesystem when the foreground process exits.
daemon :: IO a -> IO a
-- exitImmediately never returns. This `error` is only here to please the
-- typechecker. 
-- It's a dirty hack, but I think the problem is in the posix package, not
-- making this IO a instead of IO ()
daemon f = forkProcess d >> exitImmediately ExitSuccess >> error "This is unreachable code"
  where d = catch (do createSession
                      changeWorkingDirectory "/"
                      -- need to open /dev/null twice because hDuplicateTo can't dup a
                      -- ReadWriteMode to a ReadMode handle
                      withFile "/dev/null" WriteMode (\devNullOut ->
                         do hDuplicateTo devNullOut stdout
                            hDuplicateTo devNullOut stderr)
                      withFile "/dev/null" ReadMode (\devNullIn -> hDuplicateTo devNullIn stdin)
                      f
                      exitWith ExitSuccess)
                  (const exitFailure)

-- Installs signal handlers for the duration of the main loop.
withSignalHandlers :: IO () -> IO a -> IO a
withSignalHandlers exitHandler = bracket_ setHandlers resetHandlers
    where   setHandlers = do
                let sigHandler = Signals.CatchOnce exitHandler
                Signals.installHandler Signals.keyboardSignal sigHandler Nothing
                Signals.installHandler Signals.lostConnection sigHandler Nothing
                Signals.installHandler Signals.softwareTermination sigHandler Nothing
                Signals.installHandler Signals.openEndedPipe Signals.Ignore Nothing
            resetHandlers = do
                Signals.installHandler Signals.keyboardSignal Signals.Default Nothing
                Signals.installHandler Signals.lostConnection Signals.Default Nothing
                Signals.installHandler Signals.softwareTermination Signals.Default Nothing
                Signals.installHandler Signals.openEndedPipe Signals.Default Nothing

handleOnce :: Ptr CFuseSession -> Ptr CFuseBuf -> Ptr CFuseChan -> IO ()
handleOnce session buf chan = do
    size <- fuse_chan_bufsize chan
    allocaBytes (fromIntegral size) $ \ptr -> do
        (\hsc_ptr -> pokeByteOff hsc_ptr 16) buf ptr
{-# LINE 804 "System/Fuse.hsc" #-}
        (\hsc_ptr -> pokeByteOff hsc_ptr 0) buf size
{-# LINE 805 "System/Fuse.hsc" #-}
        with chan $ \chanP -> do
            fuse_session_receive_buf session buf chanP
            fuse_session_process_buf session buf =<< peek chanP

-- fuse_session_next_chan :: Ptr CFuseSession -> Ptr CFuseChan -> IO (Ptr CFuseChan)
forAllChans
    :: Ptr CFuseSession
    -> (Ptr CFuseChan -> IO a -> IO a)
    -> IO a
    -> IO a
forAllChans session fun cont = forAllChans' session fun nullPtr
    where   forAllChans' session fun cur = do
                new <- fuse_session_next_chan session cur
                if new == nullPtr
                    then cont
                    else fun new (forAllChans' session fun new)

-- TODO: Add an unregister function to run as well
runInline
    :: (Fd -> IO () -> IO b)
    -> (b -> IO ())
    -> (Either String () -> IO a)
    -> Ptr CStructFuse
    -> IO a
runInline register unregister act pFuse = bracket (callocBytes (40)) free $ \buf -> do
{-# LINE 830 "System/Fuse.hsc" #-}
    session <- fuse_get_session pFuse
    let registerChan chan cont = do
            fd <- fuse_chan_fd chan
            bracket
                (register fd (handleOnce session buf chan))
                unregister
                (const cont)
    ret <- forAllChans session registerChan $ withSignalHandlers (fuse_session_exit session) (act $ Right ())
    fuse_session_exit session
    pure ret


-- Mounts the filesystem, forks, and then starts fuse
fuseMainReal
    :: Exception e
    => Maybe (Fd -> IO () -> IO b, b -> IO (), Either String () -> IO a)
    -> Bool
    -> FuseOperations fh
    -> (e -> IO Errno)
    -> Ptr CFuseArgs
    -> String
    -> IO a
fuseMainReal inline foreground ops handler pArgs mountPt =
    let strategy = case inline of
            Just (register, unregister, act) -> runInline register unregister act
            Nothing -> if foreground
                then (>>) (changeWorkingDirectory "/") . procMain
                else daemon . procMain
     in withCString mountPt $ \cMountPt -> bracket
        (fuse_mount cMountPt pArgs)
        (const $ fuse_unmount cMountPt nullPtr) $ \pFuseChan -> do
            if pFuseChan == nullPtr
                then case inline of
                    Nothing -> exitFailure
                    -- TODO: Add some way to notify the called application
                    -- whether fuse is up, or not
                    Just (_, _, act) -> act $ Left "Failed to create fuse handle"
                else withStructFuse pFuseChan pArgs ops handler strategy
    -- here, we're finally inside the daemon process, we can run the main loop
    where procMain pFuse = do
            session <- fuse_get_session pFuse
            -- calling fuse_session_exit to exit the main loop only
            -- appears to work with the multithreaded fuse loop.
            -- In the single-threaded case, FUSE depends on their
            -- recv() call to finish with EINTR when signals arrive.
            -- This doesn't happen with GHC's signal handling in place.
            withSignalHandlers (fuse_session_exit session) $ do
                retVal <- fuse_loop_mt pFuse
                if retVal == 1
                    then exitWith ExitSuccess
                    else exitFailure

-- | Main function of FUSE.
-- This is all that has to be called from the @main@ function. On top of
-- the 'FuseOperations' record with filesystem implementation, you must give
-- an exception handler converting Haskell exceptions to 'Errno'.
-- 
-- This function does the following:
--
--   * parses command line options (@-d@, @-s@ and @-h@) ;
--
--   * passes all options after @--@ to the fusermount program ;
--
--   * mounts the filesystem by calling @fusermount@ ;
--
--   * installs signal handlers for 'System.Posix.Signals.keyboardSignal',
--     'System.Posix.Signals.lostConnection',
--     'System.Posix.Signals.softwareTermination' and
--     'System.Posix.Signals.openEndedPipe' ;
--
--   * registers an exit handler to unmount the filesystem on program exit ;
--
--   * registers the operations ;
--
--   * calls FUSE event loop.
fuseMain :: Exception e => FuseOperations fh -> (e -> IO Errno) -> IO ()
fuseMain ops handler = do
    -- this used to be implemented using libfuse's fuse_main. Doing this will fork()
    -- from C behind the GHC runtime's back, which deadlocks in GHC 6.8.
    -- Instead, we reimplement fuse_main in Haskell using the forkProcess and the
    -- lower-level fuse_new/fuse_loop_mt API.
    prog <- getProgName
    args <- getArgs
    fuseRun prog args ops handler

fuseRun :: String -> [String] -> Exception e => FuseOperations fh -> (e -> IO Errno) -> IO ()
fuseRun prog args ops handler =
    catch
       (withFuseArgs prog args (\pArgs ->
         do cmd <- fuseParseCommandLine pArgs
            case cmd of
              Nothing -> fail ""
              Just (Nothing, _, _) -> fail "Usage error: mount point required"
              Just (Just mountPt, _, foreground) -> fuseMainReal Nothing foreground ops handler pArgs mountPt))
       ((\errStr -> when (not $ null errStr) (putStrLn errStr) >> exitFailure) . ioeGetErrorString)

-- | Inline version of 'fuseMain'. This prevents exiting and keeps the fuse
-- file system in the same process (and therefore memory space)
fuseMainInline :: Exception e => (Fd -> IO () -> IO b) -> (b -> IO ()) -> (Either String () -> IO a) -> FuseOperations fh -> (e -> IO Errno) -> IO a
fuseMainInline register unregister act ops handler = do
    -- this used to be implemented using libfuse's fuse_main. Doing this will fork()
    -- from C behind the GHC runtime's back, which deadlocks in GHC 6.8.
    -- Instead, we reimplement fuse_main in Haskell using the forkProcess and the
    -- lower-level fuse_new/fuse_loop_mt API.
    prog <- getProgName
    args <- getArgs
    fuseRunInline register unregister act prog args ops handler

fuseRunInline :: Exception e => (Fd -> IO () -> IO b) -> (b -> IO ()) -> (Either String () -> IO a) -> String -> [String] -> FuseOperations fh -> (e -> IO Errno) -> IO a
fuseRunInline register unregister act prog args ops handler =
    catch (withFuseArgs prog args $ \pArgs -> do
        cmd <-fuseParseCommandLine pArgs
        case cmd of
            Nothing -> act $ Left ""
            Just (Nothing, _, _) -> act $ Left "Usage error: mount point required"
            Just (Just mountPt, _, foreground) -> fuseMainReal (Just (register, unregister, act)) foreground ops handler pArgs mountPt)
       (act . Left . ioeGetErrorString)
-----------------------------------------------------------------------------
-- Miscellaneous utilities

unErrno :: Errno -> CInt
unErrno (Errno errno) = errno

okErrno :: CInt
okErrno = unErrno eOK

pokeCStringLen :: CStringLen -> String -> IO ()
pokeCStringLen (pBuf, bufSize) src =
    pokeArray pBuf $ take bufSize $ map castCharToCChar src

pokeCStringLen0 :: CStringLen -> String -> IO ()
pokeCStringLen0 (pBuf, bufSize) src =
    pokeArray0 0 pBuf $ take (bufSize - 1) $ map castCharToCChar src


{-# LINE 965 "System/Fuse.hsc" #-}
catch = catchIOError

{-# LINE 968 "System/Fuse.hsc" #-}

-----------------------------------------------------------------------------
-- C land

---
-- exported C called from Haskell
---  

data CFuseArgs -- struct fuse_args

data CFuseChan -- struct fuse_chan
foreign import ccall safe "fuse.h fuse_mount"
    fuse_mount :: CString -> Ptr CFuseArgs -> IO (Ptr CFuseChan)

foreign import ccall safe "fuse.h fuse_unmount"
    fuse_unmount :: CString -> Ptr CFuseChan -> IO ()

foreign import ccall unsafe "fuse_lowlevel.h fuse_chan_bufsize"
    fuse_chan_bufsize :: Ptr CFuseChan -> IO Word

foreign import ccall unsafe "fuse_lowlevel.h fuse_chan_fd"
    fuse_chan_fd :: Ptr CFuseChan -> IO Fd

data CFuseSession -- struct fuse_session
foreign import ccall safe "fuse.h fuse_get_session"
    fuse_get_session :: Ptr CStructFuse -> IO (Ptr CFuseSession)

foreign import ccall safe "fuse.h fuse_session_exit"
    fuse_session_exit :: Ptr CFuseSession -> IO ()

foreign import ccall safe "fuse.h fuse_set_signal_handlers"
    fuse_set_signal_handlers :: Ptr CFuseSession -> IO Int

foreign import ccall safe "fuse.h fuse_remove_signal_handlers"
    fuse_remove_signal_handlers :: Ptr CFuseSession -> IO ()

foreign import ccall safe "fuse.h fuse_parse_cmdline"
    fuse_parse_cmdline :: Ptr CFuseArgs -> Ptr CString -> Ptr Int -> Ptr Int -> IO Int

foreign import ccall unsafe "fuse_lowlevel.h fuse_session_next_chan"
    fuse_session_next_chan :: Ptr CFuseSession -> Ptr CFuseChan -> IO (Ptr CFuseChan)

data CStructFuse -- struct fuse
data CFuseOperations -- struct fuse_operations
foreign import ccall safe "fuse.h fuse_new"
    fuse_new :: Ptr CFuseChan -> Ptr CFuseArgs -> Ptr CFuseOperations -> Int -> Ptr () -> IO (Ptr CStructFuse)

foreign import ccall safe "fuse.h fuse_destroy"
    fuse_destroy :: Ptr CStructFuse -> IO ()

foreign import ccall safe "fuse.h fuse_opt_free_args"
    fuse_opt_free_args :: Ptr CFuseArgs -> IO ()

foreign import ccall safe "fuse.h fuse_loop_mt"
    fuse_loop_mt :: Ptr CStructFuse -> IO Int

foreign import ccall safe "fuse.h fuse_loop"
    fuse_loop :: Ptr CStructFuse -> IO Int

data CFuseContext
foreign import ccall safe "fuse.h fuse_get_context"
    fuse_get_context :: IO (Ptr CFuseContext)

data CFuseBuf
foreign import ccall unsafe "fuse_lowlevel.h fuse_session_receive_buf"
    fuse_session_receive_buf :: Ptr CFuseSession -> Ptr CFuseBuf -> Ptr (Ptr CFuseChan) -> IO ()

foreign import ccall safe "fuse_lowlevel.h fuse_session_process_buf"
    fuse_session_process_buf :: Ptr CFuseSession -> Ptr CFuseBuf -> Ptr CFuseChan -> IO ()

---
-- dynamic Haskell called from C
---

data CFuseFileInfo -- struct fuse_file_info
data CFuseConnInfo -- struct fuse_conn_info

data CStat -- struct stat
type CGetAttr = CString -> Ptr CStat -> IO CInt
foreign import ccall safe "wrapper"
    mkGetAttr :: CGetAttr -> IO (FunPtr CGetAttr)

type CReadLink = CString -> CString -> CSize -> IO CInt
foreign import ccall safe "wrapper"
    mkReadLink :: CReadLink -> IO (FunPtr CReadLink)

type CMkNod = CString -> CMode -> CDev -> IO CInt
foreign import ccall safe "wrapper"
    mkMkNod :: CMkNod -> IO (FunPtr CMkNod)

type CMkDir = CString -> CMode -> IO CInt
foreign import ccall safe "wrapper"
    mkMkDir :: CMkDir -> IO (FunPtr CMkDir)

type CUnlink = CString -> IO CInt
foreign import ccall safe "wrapper"
    mkUnlink :: CUnlink -> IO (FunPtr CUnlink)

type CRmDir = CString -> IO CInt
foreign import ccall safe "wrapper"
    mkRmDir :: CRmDir -> IO (FunPtr CRmDir)

type CSymLink = CString -> CString -> IO CInt
foreign import ccall safe "wrapper"
    mkSymLink :: CSymLink -> IO (FunPtr CSymLink)

type CRename = CString -> CString -> IO CInt
foreign import ccall safe "wrapper"
    mkRename :: CRename -> IO (FunPtr CRename)

type CLink = CString -> CString -> IO CInt
foreign import ccall safe "wrapper"
    mkLink :: CLink -> IO (FunPtr CLink)

type CChMod = CString -> CMode -> IO CInt
foreign import ccall safe "wrapper"
    mkChMod :: CChMod -> IO (FunPtr CChMod)

type CChOwn = CString -> CUid -> CGid -> IO CInt
foreign import ccall safe "wrapper"
    mkChOwn :: CChOwn -> IO (FunPtr CChOwn)

type CTruncate = CString -> COff -> IO CInt
foreign import ccall safe "wrapper"
    mkTruncate :: CTruncate -> IO (FunPtr CTruncate)

data CUTimBuf -- struct utimbuf
type CUTime = CString -> Ptr CUTimBuf -> IO CInt
foreign import ccall safe "wrapper"
    mkUTime :: CUTime -> IO (FunPtr CUTime)

type COpen = CString -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkOpen :: COpen -> IO (FunPtr COpen)

type CRead = CString -> CString -> CSize -> COff -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkRead :: CRead -> IO (FunPtr CRead)

type CWrite = CString -> CString -> CSize -> COff -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkWrite :: CWrite -> IO (FunPtr CWrite)

data CStructStatVFS -- struct fuse_stat_fs
type CStatFS = CString -> Ptr CStructStatVFS -> IO CInt
foreign import ccall safe "wrapper"
    mkStatFS :: CStatFS -> IO (FunPtr CStatFS)

type CFlush = CString -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkFlush :: CFlush -> IO (FunPtr CFlush)

type CRelease = CString -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkRelease :: CRelease -> IO (FunPtr CRelease)

type CFSync = CString -> Int -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkFSync :: CFSync -> IO (FunPtr CFSync) 

-- XXX add *xattr bindings

type COpenDir = CString -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkOpenDir :: COpenDir -> IO (FunPtr COpenDir)

type CReadDir = CString -> Ptr CFillDirBuf -> FunPtr CFillDir -> COff
             -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkReadDir :: CReadDir -> IO (FunPtr CReadDir)

type CReleaseDir = CString -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkReleaseDir :: CReleaseDir -> IO (FunPtr CReleaseDir)

type CFSyncDir = CString -> Int -> Ptr CFuseFileInfo -> IO CInt
foreign import ccall safe "wrapper"
    mkFSyncDir :: CFSyncDir -> IO (FunPtr CFSyncDir)

type CAccess = CString -> CInt -> IO CInt
foreign import ccall safe "wrapper"
    mkAccess :: CAccess -> IO (FunPtr CAccess)

-- CInt because anything would be fine as we don't use them
type CInit = Ptr CFuseConnInfo -> IO (Ptr CInt)
foreign import ccall safe "wrapper"
    mkInit :: CInit -> IO (FunPtr CInit)

type CDestroy = Ptr CInt -> IO ()
foreign import ccall safe "wrapper"
    mkDestroy :: CDestroy -> IO (FunPtr CDestroy)

----

bsToBuf :: Ptr a -> B.ByteString -> Int -> IO ()
bsToBuf dst bs len = do
  let l = fromIntegral $ min len $ B.length bs
  B.unsafeUseAsCString bs $ \src -> B.memcpy (castPtr dst) (castPtr src) l
  return ()

-- Get filehandle
getFH pFuseFileInfo = do
  sptr <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) pFuseFileInfo
{-# LINE 1171 "System/Fuse.hsc" #-}
  cVal <- deRefStablePtr $ castPtrToStablePtr sptr
  return cVal

delFH pFuseFileInfo = do
  sptr <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) pFuseFileInfo
{-# LINE 1176 "System/Fuse.hsc" #-}
  freeStablePtr $ castPtrToStablePtr sptr


---
-- dynamic C called from Haskell
---

data CDirHandle -- fuse_dirh_t
type CDirFil = Ptr CDirHandle -> CString -> Int -> IO CInt -- fuse_dirfil_t
foreign import ccall safe "dynamic"
    mkDirFil :: FunPtr CDirFil -> CDirFil

data CFillDirBuf -- void
type CFillDir = Ptr CFillDirBuf -> CString -> Ptr CStat -> COff -> IO CInt

foreign import ccall safe "dynamic"
    mkFillDir :: FunPtr CFillDir -> CFillDir

foreign import ccall safe "bzero"
    bzero :: Ptr a -> Int -> IO ()