{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}

module Network.NineP.Internal.Msg
	( Config(..)
	, rversion
	, rattach
	, rwalk
	, rstat
	, rwstat
	, rclunk
	, rauth
	, ropen
	, rcreate
	, rread
	, rwrite
	, rremove
	, rflush
	) where

import Control.Concurrent.MState hiding (put)
import Control.Exception
import Control.Monad.EmbedIO
import Control.Monad.Reader
import Data.Binary.Put
import Data.Bits
import qualified Data.ByteString.Lazy as B
import Data.NineP
import Data.Map (Map)
import Data.Maybe
import Data.Word
import Prelude hiding (lookup, read)

import Network.NineP.Error
import Network.NineP.Internal.File
import Network.NineP.Internal.State

checkPerms :: (Monad m, EmbedIO m) => Word16 -> NineFile m -> Word8 -> Nine m ()
checkPerms :: Word16 -> NineFile m -> Word8 -> Nine m ()
checkPerms Word16
tag NineFile m
f Word8
want = do
	Stat
s <- Word16 -> NineFile m -> Nine m Stat
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Stat
getStat Word16
tag NineFile m
f
	Word32 -> Word8 -> Nine m ()
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word32 -> Word8 -> Nine m ()
checkPerms' (Stat -> Word32
st_mode Stat
s) Word8
want

checkPerms' :: (Monad m, EmbedIO m) => Word32 -> Word8 -> Nine m ()
checkPerms' :: Word32 -> Word8 -> Nine m ()
checkPerms' Word32
have Word8
want = do
	-- TODO stop presuming we are owners
	let checkRead :: Nine m ()
checkRead = Bool -> Nine m () -> Nine m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
have Int
2) (Nine m () -> Nine m ()) -> Nine m () -> Nine m ()
forall a b. (a -> b) -> a -> b
$ NineError -> Nine m ()
forall a e. Exception e => e -> a
throw NineError
EPermissionDenied
	let checkWrite :: Nine m ()
checkWrite = Bool -> Nine m () -> Nine m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
have Int
1) (Nine m () -> Nine m ()) -> Nine m () -> Nine m ()
forall a b. (a -> b) -> a -> b
$ NineError -> Nine m ()
forall a e. Exception e => e -> a
throw NineError
EPermissionDenied
	let checkExec :: Nine m ()
checkExec = Bool -> Nine m () -> Nine m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
have Int
0) (Nine m () -> Nine m ()) -> Nine m () -> Nine m ()
forall a b. (a -> b) -> a -> b
$ NineError -> Nine m ()
forall a e. Exception e => e -> a
throw NineError
EPermissionDenied
	Bool -> Nine m () -> Nine m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word8 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word8
want Int
4) (Nine m () -> Nine m ()) -> Nine m () -> Nine m ()
forall a b. (a -> b) -> a -> b
$ do
		Nine m ()
checkWrite
		NineError -> Nine m ()
forall a e. Exception e => e -> a
throw (NineError -> Nine m ()) -> NineError -> Nine m ()
forall a b. (a -> b) -> a -> b
$ String -> NineError
ENotImplemented String
"OTRUNC"
	Bool -> Nine m () -> Nine m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word8 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word8
want Int
6) (Nine m () -> Nine m ()) -> Nine m () -> Nine m ()
forall a b. (a -> b) -> a -> b
$ do
		NineError -> Nine m ()
forall a e. Exception e => e -> a
throw (NineError -> Nine m ()) -> NineError -> Nine m ()
forall a b. (a -> b) -> a -> b
$ String -> NineError
ENotImplemented String
"ORCLOSE"
	case Word8
want of
		Word8
0 -> Nine m ()
checkRead
		Word8
1 -> Nine m ()
checkWrite
		Word8
2 -> Nine m ()
checkRead Nine m () -> Nine m () -> Nine m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Nine m ()
checkWrite
		Word8
3 -> Nine m ()
checkExec

getQidTyp :: Stat -> Word8
getQidTyp :: Stat -> Word8
getQidTyp Stat
s = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word8) -> Word32 -> Word8
forall a b. (a -> b) -> a -> b
$ Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shift (Stat -> Word32
st_mode Stat
s) Int
24

makeQid :: (Monad m, EmbedIO m) => Word16 -> NineFile m -> Nine m Qid
makeQid :: Word16 -> NineFile m -> Nine m Qid
makeQid Word16
t NineFile m
x = do
	Stat
s <- Word16 -> NineFile m -> Nine m Stat
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Stat
getStat Word16
t NineFile m
x
	Qid -> Nine m Qid
forall (m :: * -> *) a. Monad m => a -> m a
return (Qid -> Nine m Qid) -> Qid -> Nine m Qid
forall a b. (a -> b) -> a -> b
$ Word8 -> Word32 -> Word64 -> Qid
Qid (Stat -> Word8
getQidTyp Stat
s) Word32
0 Word64
42

rversion :: Msg -> Nine m [Msg]
rversion :: Msg -> Nine m [Msg]
rversion (Msg Tag
_ Word16
t (Tversion Word32
s String
v)) = do
	let ver :: NineVersion
ver = String -> NineVersion
readVersion String
v
	(NineState m -> NineState m)
-> MState (NineState m) (ReaderT (Config m) IO) ()
forall (m :: * -> *) t. MonadIO m => (t -> t) -> MState t m ()
modifyM_ (\NineState m
st -> NineState m
st { msize :: Word32
msize = Word32
s, protoVersion :: NineVersion
protoVersion = NineVersion
ver })
	-- FIXME clunk everything and abort all outstanding I/O
	[Msg] -> Nine m [Msg]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Msg] -> Nine m [Msg]) -> [Msg] -> Nine m [Msg]
forall a b. (a -> b) -> a -> b
$ Msg -> [Msg]
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> [Msg]) -> Msg -> [Msg]
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRversion Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ Word32 -> String -> VarMsg
Rversion Word32
s (String -> VarMsg) -> String -> VarMsg
forall a b. (a -> b) -> a -> b
$ NineVersion -> String
forall a. Show a => a -> String
show NineVersion
ver

rattach :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rattach (Msg Tag
_ Word16
t (Tattach Word32
fid Word32
_ String
_ String
_)) = do
	NineFile m
root <- (Config m -> NineFile m)
-> MState (NineState m) (ReaderT (Config m) IO) (NineFile m)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Config m -> NineFile m
forall (m :: * -> *). Config m -> NineFile m
root
	Word32 -> NineFile m -> Nine m ()
forall (m :: * -> *). Word32 -> NineFile m -> Nine m ()
insert Word32
fid NineFile m
root
	Qid
q <- Word16 -> NineFile m -> Nine m Qid
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Qid
makeQid Word16
t NineFile m
root
	m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRattach Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ Qid -> VarMsg
Rattach Qid
q 

desc :: (Monad m, EmbedIO m) => NineFile m -> String -> m (NineFile m)
desc :: NineFile m -> String -> m (NineFile m)
desc NineFile m
f String
".." = do
	Maybe (NineFile m)
mp <- NineFile m -> m (Maybe (NineFile m))
forall (m :: * -> *). NineFile m -> m (Maybe (NineFile m))
parent NineFile m
f
	NineFile m -> m (NineFile m)
forall (m :: * -> *) a. Monad m => a -> m a
return (NineFile m -> m (NineFile m)) -> NineFile m -> m (NineFile m)
forall a b. (a -> b) -> a -> b
$ case Maybe (NineFile m)
mp of
		Just NineFile m
p -> NineFile m
p
		Maybe (NineFile m)
Nothing -> NineFile m
f
desc NineFile m
f String
s = NineFile m -> String -> m (NineFile m)
forall (m :: * -> *). NineFile m -> String -> m (NineFile m)
descend NineFile m
f String
s

walk :: (Monad m, EmbedIO m) => [Qid] -> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk :: [Qid]
-> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk [Qid]
qs Word16
t [] NineFile m
f = (NineFile m, [Qid]) -> Nine m (NineFile m, [Qid])
forall (m :: * -> *) a. Monad m => a -> m a
return (NineFile m
f, [Qid]
qs)
walk [Qid]
qs Word16
t (String
x:[String]
xs) (RegularFile {}) = NineError -> Nine m (NineFile m, [Qid])
forall a e. Exception e => e -> a
throw NineError
ENotADir
walk [Qid]
qs Word16
t (String
x:[String]
xs) d :: NineFile m
d@(Directory {}) = do
	NineFile m
f <- Word16
-> m (NineFile m)
-> MState (NineState m) (ReaderT (Config m) IO) (NineFile m)
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m (NineFile m)
 -> MState (NineState m) (ReaderT (Config m) IO) (NineFile m))
-> m (NineFile m)
-> MState (NineState m) (ReaderT (Config m) IO) (NineFile m)
forall a b. (a -> b) -> a -> b
$ NineFile m -> String -> m (NineFile m)
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
NineFile m -> String -> m (NineFile m)
desc NineFile m
d String
x
	Qid
q <- Word16 -> NineFile m -> Nine m Qid
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Qid
makeQid Word16
t NineFile m
f
	[Qid]
-> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
[Qid]
-> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk (Qid
qQid -> [Qid] -> [Qid]
forall a. a -> [a] -> [a]
:[Qid]
qs) Word16
t [String]
xs NineFile m
f

walk' :: (Monad m, EmbedIO m) => Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk' :: Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk' = [Qid]
-> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
[Qid]
-> Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk []

rwalk :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rwalk (Msg Tag
_ Word16
t (Twalk Word32
fid Word32
newfid [String]
path)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	(NineFile m
nf, [Qid]
qs) <- Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> [String] -> NineFile m -> Nine m (NineFile m, [Qid])
walk' Word16
t [String]
path NineFile m
f
	Word32 -> NineFile m -> Nine m ()
forall (m :: * -> *). Word32 -> NineFile m -> Nine m ()
insert Word32
newfid NineFile m
nf
	m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRwalk Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ [Qid] -> VarMsg
Rwalk ([Qid] -> VarMsg) -> [Qid] -> VarMsg
forall a b. (a -> b) -> a -> b
$ [Qid]
qs

getStat :: (Monad m, EmbedIO m) => Word16 -> NineFile m -> Nine m Stat
getStat :: Word16 -> NineFile m -> Nine m Stat
getStat Word16
t NineFile m
f = do
	let fixDirBit :: Word32 -> Word32
fixDirBit = (case NineFile m
f of
				(RegularFile {}) -> (Word32 -> Int -> Word32) -> Int -> Word32 -> Word32
forall a b c. (a -> b -> c) -> b -> a -> c
flip Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
clearBit Int
31
				(Directory {}) -> (Word32 -> Int -> Word32) -> Int -> Word32 -> Word32
forall a b c. (a -> b -> c) -> b -> a -> c
flip Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
setBit Int
31
			)
	Stat
s <- Word16 -> m Stat -> Nine m Stat
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m Stat -> Nine m Stat) -> m Stat -> Nine m Stat
forall a b. (a -> b) -> a -> b
$ NineFile m -> m Stat
forall (m :: * -> *). NineFile m -> m Stat
stat NineFile m
f
	Stat -> Nine m Stat
forall (m :: * -> *) a. Monad m => a -> m a
return Stat
s { st_mode :: Word32
st_mode = Word32 -> Word32
fixDirBit (Word32 -> Word32) -> Word32 -> Word32
forall a b. (a -> b) -> a -> b
$ Stat -> Word32
st_mode Stat
s,
		st_qid :: Qid
st_qid = (Stat -> Qid
st_qid Stat
s) { qid_typ :: Word8
qid_typ = Stat -> Word8
getQidTyp Stat
s } }
	
rstat :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rstat (Msg Tag
_ Word16
t (Tstat Word32
fid)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	case NineFile m
f of
		RegularFile {} -> do
			Stat
s <- Word16 -> NineFile m -> Nine m Stat
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Stat
getStat Word16
t NineFile m
f
			m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRstat Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ [Stat] -> VarMsg
Rstat ([Stat] -> VarMsg) -> [Stat] -> VarMsg
forall a b. (a -> b) -> a -> b
$ [Stat
s]
		Directory {} -> do
			Stat
mys <- Word16 -> NineFile m -> Nine m Stat
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Stat
getStat Word16
t NineFile m
f
			m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRstat Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ [Stat] -> VarMsg
Rstat ([Stat] -> VarMsg) -> [Stat] -> VarMsg
forall a b. (a -> b) -> a -> b
$ Stat -> [Stat]
forall (m :: * -> *) a. Monad m => a -> m a
return (Stat -> [Stat]) -> Stat -> [Stat]
forall a b. (a -> b) -> a -> b
$ Stat
mys

rclunk :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rclunk (Msg Tag
_ Word16
t (Tclunk Word32
fid)) = do
	Word32 -> Nine m ()
forall (m :: * -> *). Word32 -> Nine m ()
delete Word32
fid
	m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRclunk Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ VarMsg
Rclunk

rauth :: Msg -> a
rauth (Msg {}) = do
	NineError -> a
forall a e. Exception e => e -> a
throw NineError
ENoAuthRequired

open :: (Monad m, EmbedIO m) => Word16 -> NineFile m -> Nine m Qid
open :: Word16 -> NineFile m -> Nine m Qid
open Word16
t NineFile m
f = do
	Word16 -> NineFile m -> Nine m Qid
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Qid
makeQid Word16
t NineFile m
f

ropen :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
ropen (Msg Tag
_ Word16
t (Topen Word32
fid Word8
mode)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	Word16 -> NineFile m -> Word8 -> Nine m ()
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Word8 -> Nine m ()
checkPerms Word16
t NineFile m
f Word8
mode
	Qid
qid <- Word16 -> NineFile m -> Nine m Qid
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Qid
open Word16
t NineFile m
f
	Word32
iou <- Nine m Word32
forall (m :: * -> *). Nine m Word32
iounit
	m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRopen Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ Qid -> Word32 -> VarMsg
Ropen Qid
qid Word32
iou

rcreate :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rcreate (Msg Tag
_ Word16
t (Tcreate Word32
fid String
name Word32
perm Word8
mode)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	-- TODO check permissions to create
	case NineFile m
f of
		RegularFile {} -> NineError -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a e. Exception e => e -> a
throw NineError
ENotADir
		Directory {} -> do
			NineFile m
nf <- Word16 -> m (NineFile m) -> Nine m (NineFile m)
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m (NineFile m) -> Nine m (NineFile m))
-> m (NineFile m) -> Nine m (NineFile m)
forall a b. (a -> b) -> a -> b
$ (NineFile m -> String -> Word32 -> m (NineFile m)
forall (m :: * -> *).
NineFile m -> String -> Word32 -> m (NineFile m)
create NineFile m
f) String
name Word32
perm
			Word32 -> NineFile m -> Nine m ()
forall (m :: * -> *). Word32 -> NineFile m -> Nine m ()
insert Word32
fid NineFile m
nf
			Qid
qid <- Word16 -> NineFile m -> Nine m Qid
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Qid
open Word16
t NineFile m
f
			Word32
iou <- Nine m Word32
forall (m :: * -> *). Nine m Word32
iounit
			m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRcreate Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ Qid -> Word32 -> VarMsg
Rcreate Qid
qid Word32
iou

rread :: (Monad m, EmbedIO m) => Msg -> Nine m [Msg]
rread :: Msg -> Nine m [Msg]
rread (Msg Tag
_ Word16
t (Tread Word32
fid Word64
offset Word32
count)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	Word32
u <- Nine m Word32
forall (m :: * -> *). Nine m Word32
iounit
	Word16 -> NineFile m -> Word8 -> Nine m ()
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Word8 -> Nine m ()
checkPerms Word16
t NineFile m
f Word8
0
	let	splitMsg :: ByteString -> Int64 -> [ByteString]
splitMsg ByteString
d Int64
s = let r :: [ByteString]
r = ByteString -> Int64 -> [ByteString]
splitMsg' ByteString
d Int64
s in if [ByteString] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
r then [ByteString
B.empty] else [ByteString]
r
		splitMsg' :: ByteString -> Int64 -> [ByteString]
splitMsg' ByteString
d Int64
s = if ByteString -> Bool
B.null ByteString
d then [] else
			let (ByteString
a, ByteString
b) = Int64 -> ByteString -> (ByteString, ByteString)
B.splitAt Int64
s ByteString
d in ByteString
a ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: ByteString -> Int64 -> [ByteString]
splitMsg' ByteString
b Int64
s
	case NineFile m
f of
		RegularFile {} -> do
			ByteString
d <- Word16
-> m ByteString
-> MState (NineState m) (ReaderT (Config m) IO) ByteString
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m ByteString
 -> MState (NineState m) (ReaderT (Config m) IO) ByteString)
-> m ByteString
-> MState (NineState m) (ReaderT (Config m) IO) ByteString
forall a b. (a -> b) -> a -> b
$ (NineFile m -> Word64 -> Word32 -> m ByteString
forall (m :: * -> *).
NineFile m -> Word64 -> Word32 -> m ByteString
read NineFile m
f) Word64
offset Word32
count
			(ByteString -> MState (NineState m) (ReaderT (Config m) IO) Msg)
-> [ByteString] -> Nine m [Msg]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Msg -> MState (NineState m) (ReaderT (Config m) IO) Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> MState (NineState m) (ReaderT (Config m) IO) Msg)
-> (ByteString -> Msg)
-> ByteString
-> MState (NineState m) (ReaderT (Config m) IO) Msg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRread Word16
t (VarMsg -> Msg) -> (ByteString -> VarMsg) -> ByteString -> Msg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> VarMsg
Rread) ([ByteString] -> Nine m [Msg]) -> [ByteString] -> Nine m [Msg]
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64 -> [ByteString]
splitMsg ByteString
d (Int64 -> [ByteString]) -> Int64 -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
u
		Directory {} -> do
			[NineFile m]
contents <- Word16
-> m [NineFile m]
-> MState (NineState m) (ReaderT (Config m) IO) [NineFile m]
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m [NineFile m]
 -> MState (NineState m) (ReaderT (Config m) IO) [NineFile m])
-> m [NineFile m]
-> MState (NineState m) (ReaderT (Config m) IO) [NineFile m]
forall a b. (a -> b) -> a -> b
$ NineFile m -> m [NineFile m]
forall (m :: * -> *). NineFile m -> m [NineFile m]
getFiles NineFile m
f
			[Stat]
s <- (NineFile m -> MState (NineState m) (ReaderT (Config m) IO) Stat)
-> [NineFile m]
-> MState (NineState m) (ReaderT (Config m) IO) [Stat]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Word16
-> NineFile m -> MState (NineState m) (ReaderT (Config m) IO) Stat
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Nine m Stat
getStat Word16
t) ([NineFile m]
 -> MState (NineState m) (ReaderT (Config m) IO) [Stat])
-> [NineFile m]
-> MState (NineState m) (ReaderT (Config m) IO) [Stat]
forall a b. (a -> b) -> a -> b
$ [NineFile m]
contents
			let d :: ByteString
d = Put -> ByteString
runPut (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ (Stat -> Put) -> [Stat] -> Put
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Stat -> Put
forall a. Bin a => a -> Put
put [Stat]
s
			(ByteString -> MState (NineState m) (ReaderT (Config m) IO) Msg)
-> [ByteString] -> Nine m [Msg]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Msg -> MState (NineState m) (ReaderT (Config m) IO) Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> MState (NineState m) (ReaderT (Config m) IO) Msg)
-> (ByteString -> Msg)
-> ByteString
-> MState (NineState m) (ReaderT (Config m) IO) Msg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRread Word16
t (VarMsg -> Msg) -> (ByteString -> VarMsg) -> ByteString -> Msg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> VarMsg
Rread) ([ByteString] -> Nine m [Msg]) -> [ByteString] -> Nine m [Msg]
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64 -> [ByteString]
splitMsg (Int64 -> ByteString -> ByteString
B.drop (Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
offset) ByteString
d) (Int64 -> [ByteString]) -> Int64 -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
u
		
--rwrite :: Msg -> Nine m [Msg]
rwrite :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rwrite (Msg Tag
_ Word16
t (Twrite Word32
fid Word64
offset ByteString
d)) = do
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	Word16 -> NineFile m -> Word8 -> Nine m ()
forall (m :: * -> *).
(Monad m, EmbedIO m) =>
Word16 -> NineFile m -> Word8 -> Nine m ()
checkPerms Word16
t NineFile m
f Word8
1
	case NineFile m
f of
		Directory {} -> NineError -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a e. Exception e => e -> a
throw NineError
EDir
		RegularFile {} -> do
			Word32
c <- Word16
-> m Word32 -> MState (NineState m) (ReaderT (Config m) IO) Word32
forall (m :: * -> *) a.
EmbedIO m =>
Word16 -> m a -> MState (NineState m) (ReaderT (Config m) IO) a
call Word16
t (m Word32 -> MState (NineState m) (ReaderT (Config m) IO) Word32)
-> m Word32 -> MState (NineState m) (ReaderT (Config m) IO) Word32
forall a b. (a -> b) -> a -> b
$ (NineFile m -> Word64 -> ByteString -> m Word32
forall (m :: * -> *).
NineFile m -> Word64 -> ByteString -> m Word32
write NineFile m
f) Word64
offset ByteString
d
			m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRwrite Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ Word32 -> VarMsg
Rwrite Word32
c

rwstat :: Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
rwstat (Msg Tag
_ Word16
t (Twstat Word32
fid [Stat]
stat)) = do
	-- TODO check perms
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	-- TODO implement
	m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg))
-> m Msg -> MState (NineState m) (ReaderT (Config m) IO) (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRwstat Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ VarMsg
Rwstat

rremove :: Msg -> MState (NineState m) (ReaderT (Config m) IO) b
rremove (Msg Tag
_ Word16
t (Tremove Word32
fid)) = do
	-- TODO check perms
	NineFile m
f <- Word32 -> Nine m (NineFile m)
forall (m :: * -> *). Word32 -> Nine m (NineFile m)
lookup Word32
fid
	NineError -> MState (NineState m) (ReaderT (Config m) IO) b
forall a e. Exception e => e -> a
throw (NineError -> MState (NineState m) (ReaderT (Config m) IO) b)
-> NineError -> MState (NineState m) (ReaderT (Config m) IO) b
forall a b. (a -> b) -> a -> b
$ String -> NineError
ENotImplemented String
"remove"

-- TODO meaningful flush behaviour instead of pretending it works
rflush :: Msg -> m (m Msg)
rflush (Msg Tag
_ Word16
t VarMsg
_) = m Msg -> m (m Msg)
forall (m :: * -> *) a. Monad m => a -> m a
return (m Msg -> m (m Msg)) -> m Msg -> m (m Msg)
forall a b. (a -> b) -> a -> b
$ Msg -> m Msg
forall (m :: * -> *) a. Monad m => a -> m a
return (Msg -> m Msg) -> Msg -> m Msg
forall a b. (a -> b) -> a -> b
$ Tag -> Word16 -> VarMsg -> Msg
Msg Tag
TRflush Word16
t (VarMsg -> Msg) -> VarMsg -> Msg
forall a b. (a -> b) -> a -> b
$ VarMsg
Rflush