{-# LANGUAGE CPP #-}
module System.IO.HVFS.Combinators (
HVFSReadOnly(..),
HVFSChroot, newHVFSChroot)
where
import System.IO ( IOMode(ReadMode) )
import System.IO.Error
( doesNotExistErrorType, permissionErrorType )
import System.IO.HVFS
( HVFSOpenable(vOpen),
HVFS(vRemoveFile, vCreateLink, vCreateSymbolicLink, vRenameFile,
vRenameDirectory, vRemoveDirectory, vCreateDirectory,
vGetCurrentDirectory, vGetDirectoryContents, vDoesFileExist,
vGetFileStatus, vGetSymbolicLinkStatus, vGetModificationTime,
vReadSymbolicLink, vRaiseError, vDoesDirectoryExist,
vSetCurrentDirectory) )
import System.IO.HVFS.InstanceHelpers (getFullPath)
import System.FilePath (isPathSeparator, pathSeparator,
(</>))
import System.Path (secureAbsNormPath)
import System.Path.NameManip (normalise_path)
data HVFS a => HVFSReadOnly a = HVFSReadOnly a
deriving (HVFSReadOnly a -> HVFSReadOnly a -> Bool
forall a.
(HVFS a, Eq a) =>
HVFSReadOnly a -> HVFSReadOnly a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HVFSReadOnly a -> HVFSReadOnly a -> Bool
$c/= :: forall a.
(HVFS a, Eq a) =>
HVFSReadOnly a -> HVFSReadOnly a -> Bool
== :: HVFSReadOnly a -> HVFSReadOnly a -> Bool
$c== :: forall a.
(HVFS a, Eq a) =>
HVFSReadOnly a -> HVFSReadOnly a -> Bool
Eq, Int -> HVFSReadOnly a -> ShowS
forall a. HVFS a => Int -> HVFSReadOnly a -> ShowS
forall a. HVFS a => [HVFSReadOnly a] -> ShowS
forall a. HVFS a => HVFSReadOnly a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HVFSReadOnly a] -> ShowS
$cshowList :: forall a. HVFS a => [HVFSReadOnly a] -> ShowS
show :: HVFSReadOnly a -> String
$cshow :: forall a. HVFS a => HVFSReadOnly a -> String
showsPrec :: Int -> HVFSReadOnly a -> ShowS
$cshowsPrec :: forall a. HVFS a => Int -> HVFSReadOnly a -> ShowS
Show)
withro :: HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro :: forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro a -> b
f (HVFSReadOnly a
x) = a -> b
f a
x
roerror :: (HVFS a) => HVFSReadOnly a -> IO c
roerror :: forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h =
let err :: a -> IO c
err a
x = forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError a
x IOErrorType
permissionErrorType String
"Read-only virtual filesystem"
forall a. Maybe a
Nothing
in forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall {a} {c}. HVFS a => a -> IO c
err HVFSReadOnly a
h
instance HVFS a => HVFS (HVFSReadOnly a) where
vGetCurrentDirectory :: HVFSReadOnly a -> IO String
vGetCurrentDirectory = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> IO String
vGetCurrentDirectory
vSetCurrentDirectory :: HVFSReadOnly a -> String -> IO ()
vSetCurrentDirectory = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO ()
vSetCurrentDirectory
vGetDirectoryContents :: HVFSReadOnly a -> String -> IO [String]
vGetDirectoryContents = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO [String]
vGetDirectoryContents
vDoesFileExist :: HVFSReadOnly a -> String -> IO Bool
vDoesFileExist = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO Bool
vDoesFileExist
vDoesDirectoryExist :: HVFSReadOnly a -> String -> IO Bool
vDoesDirectoryExist = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO Bool
vDoesDirectoryExist
vCreateDirectory :: HVFSReadOnly a -> String -> IO ()
vCreateDirectory HVFSReadOnly a
h String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
vRemoveDirectory :: HVFSReadOnly a -> String -> IO ()
vRemoveDirectory HVFSReadOnly a
h String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
vRenameDirectory :: HVFSReadOnly a -> String -> String -> IO ()
vRenameDirectory HVFSReadOnly a
h String
_ String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
vRenameFile :: HVFSReadOnly a -> String -> String -> IO ()
vRenameFile HVFSReadOnly a
h String
_ String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
vGetFileStatus :: HVFSReadOnly a -> String -> IO HVFSStatEncap
vGetFileStatus = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO HVFSStatEncap
vGetFileStatus
vGetSymbolicLinkStatus :: HVFSReadOnly a -> String -> IO HVFSStatEncap
vGetSymbolicLinkStatus = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO HVFSStatEncap
vGetSymbolicLinkStatus
vGetModificationTime :: HVFSReadOnly a -> String -> IO ClockTime
vGetModificationTime = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO ClockTime
vGetModificationTime
vRaiseError :: forall c.
HVFSReadOnly a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError
vCreateSymbolicLink :: HVFSReadOnly a -> String -> String -> IO ()
vCreateSymbolicLink HVFSReadOnly a
h String
_ String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
vReadSymbolicLink :: HVFSReadOnly a -> String -> IO String
vReadSymbolicLink = forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro forall a. HVFS a => a -> String -> IO String
vReadSymbolicLink
vCreateLink :: HVFSReadOnly a -> String -> String -> IO ()
vCreateLink HVFSReadOnly a
h String
_ String
_ = forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
h
instance HVFSOpenable a => HVFSOpenable (HVFSReadOnly a) where
vOpen :: HVFSReadOnly a -> String -> IOMode -> IO HVFSOpenEncap
vOpen HVFSReadOnly a
fh String
fp IOMode
mode =
case IOMode
mode of IOMode
ReadMode -> forall a b. HVFS a => (a -> b) -> HVFSReadOnly a -> b
withro (\a
h -> forall a.
HVFSOpenable a =>
a -> String -> IOMode -> IO HVFSOpenEncap
vOpen a
h String
fp IOMode
mode) HVFSReadOnly a
fh
IOMode
_ -> forall a c. HVFS a => HVFSReadOnly a -> IO c
roerror HVFSReadOnly a
fh
data HVFS a => HVFSChroot a = HVFSChroot String a
deriving (HVFSChroot a -> HVFSChroot a -> Bool
forall a. (HVFS a, Eq a) => HVFSChroot a -> HVFSChroot a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HVFSChroot a -> HVFSChroot a -> Bool
$c/= :: forall a. (HVFS a, Eq a) => HVFSChroot a -> HVFSChroot a -> Bool
== :: HVFSChroot a -> HVFSChroot a -> Bool
$c== :: forall a. (HVFS a, Eq a) => HVFSChroot a -> HVFSChroot a -> Bool
Eq, Int -> HVFSChroot a -> ShowS
forall a. HVFS a => Int -> HVFSChroot a -> ShowS
forall a. HVFS a => [HVFSChroot a] -> ShowS
forall a. HVFS a => HVFSChroot a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HVFSChroot a] -> ShowS
$cshowList :: forall a. HVFS a => [HVFSChroot a] -> ShowS
show :: HVFSChroot a -> String
$cshow :: forall a. HVFS a => HVFSChroot a -> String
showsPrec :: Int -> HVFSChroot a -> ShowS
$cshowsPrec :: forall a. HVFS a => Int -> HVFSChroot a -> ShowS
Show)
newHVFSChroot :: HVFS a => a
-> FilePath
-> IO (HVFSChroot a)
newHVFSChroot :: forall a. HVFS a => a -> String -> IO (HVFSChroot a)
newHVFSChroot a
fh String
fp =
do String
full <- forall a. HVFS a => a -> String -> IO String
getFullPath a
fh String
fp
Bool
isdir <- forall a. HVFS a => a -> String -> IO Bool
vDoesDirectoryExist a
fh String
full
if Bool
isdir
then do let newobj :: HVFSChroot a
newobj = (forall a. String -> a -> HVFSChroot a
HVFSChroot String
full a
fh)
forall a. HVFS a => a -> String -> IO ()
vSetCurrentDirectory HVFSChroot a
newobj [Char
pathSeparator]
forall (m :: * -> *) a. Monad m => a -> m a
return HVFSChroot a
newobj
else forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError a
fh IOErrorType
doesNotExistErrorType
(String
"Attempt to instantiate HVFSChroot over non-directory " forall a. [a] -> [a] -> [a]
++ String
full)
(forall a. a -> Maybe a
Just String
full)
dch :: (HVFS t) => HVFSChroot t -> t
dch :: forall t. HVFS t => HVFSChroot t -> t
dch (HVFSChroot String
_ t
a) = t
a
dch2fp, fp2dch :: (HVFS t) => HVFSChroot t -> String -> IO String
dch2fp :: forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp mainh :: HVFSChroot t
mainh@(HVFSChroot String
fp t
h) String
locfp =
do String
full <- (String
fp forall a. [a] -> [a] -> [a]
++) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` if Char -> Bool
isPathSeparator (forall a. [a] -> a
head String
locfp)
then forall (m :: * -> *) a. Monad m => a -> m a
return String
locfp
else forall a. HVFS a => a -> String -> IO String
getFullPath HVFSChroot t
mainh String
locfp
case String -> String -> Maybe String
secureAbsNormPath String
fp String
full of
Maybe String
Nothing -> forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError t
h IOErrorType
doesNotExistErrorType
(String
"Trouble normalizing path in chroot")
(forall a. a -> Maybe a
Just (String
fp forall a. [a] -> [a] -> [a]
++ String
"," forall a. [a] -> [a] -> [a]
++ String
full))
Just String
x -> forall (m :: * -> *) a. Monad m => a -> m a
return String
x
fp2dch :: forall t. HVFS t => HVFSChroot t -> String -> IO String
fp2dch (HVFSChroot String
fp t
h) String
locfp =
do String
newpath <- case String -> String -> Maybe String
secureAbsNormPath String
fp String
locfp of
Maybe String
Nothing -> forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError t
h IOErrorType
doesNotExistErrorType
(String
"Unable to securely normalize path")
(forall a. a -> Maybe a
Just (String
fp String -> ShowS
</> String
locfp))
Just String
x -> forall (m :: * -> *) a. Monad m => a -> m a
return String
x
if (forall a. Int -> [a] -> [a]
take (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
fp) String
newpath forall a. Eq a => a -> a -> Bool
/= String
fp)
then forall a c.
HVFS a =>
a -> IOErrorType -> String -> Maybe String -> IO c
vRaiseError t
h IOErrorType
doesNotExistErrorType
(String
"Local path is not subdirectory of parent path")
(forall a. a -> Maybe a
Just String
newpath)
else let newpath2 :: String
newpath2 = forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
fp) String
newpath
in forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ShowS
normalise_path ([Char
pathSeparator] forall a. [a] -> [a] -> [a]
++ String
newpath2)
dch2fph :: (HVFS t) => (t -> String -> IO t1) -> HVFSChroot t -> [Char] -> IO t1
dch2fph :: forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph t -> String -> IO t1
func fh :: HVFSChroot t
fh@(HVFSChroot String
_ t
h) String
locfp =
do String
newfp <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot t
fh String
locfp
t -> String -> IO t1
func t
h String
newfp
instance HVFS a => HVFS (HVFSChroot a) where
vGetCurrentDirectory :: HVFSChroot a -> IO String
vGetCurrentDirectory HVFSChroot a
x = do String
fp <- forall a. HVFS a => a -> IO String
vGetCurrentDirectory (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
x)
forall t. HVFS t => HVFSChroot t -> String -> IO String
fp2dch HVFSChroot a
x String
fp
vSetCurrentDirectory :: HVFSChroot a -> String -> IO ()
vSetCurrentDirectory = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO ()
vSetCurrentDirectory
vGetDirectoryContents :: HVFSChroot a -> String -> IO [String]
vGetDirectoryContents = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO [String]
vGetDirectoryContents
vDoesFileExist :: HVFSChroot a -> String -> IO Bool
vDoesFileExist = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO Bool
vDoesFileExist
vDoesDirectoryExist :: HVFSChroot a -> String -> IO Bool
vDoesDirectoryExist = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO Bool
vDoesDirectoryExist
vCreateDirectory :: HVFSChroot a -> String -> IO ()
vCreateDirectory = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO ()
vCreateDirectory
vRemoveDirectory :: HVFSChroot a -> String -> IO ()
vRemoveDirectory = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO ()
vRemoveDirectory
vRenameDirectory :: HVFSChroot a -> String -> String -> IO ()
vRenameDirectory HVFSChroot a
fh String
old String
new = do String
old' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
old
String
new' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
new
forall a. HVFS a => a -> String -> String -> IO ()
vRenameDirectory (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
fh) String
old' String
new'
vRemoveFile :: HVFSChroot a -> String -> IO ()
vRemoveFile = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO ()
vRemoveFile
vRenameFile :: HVFSChroot a -> String -> String -> IO ()
vRenameFile HVFSChroot a
fh String
old String
new = do String
old' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
old
String
new' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
new
forall a. HVFS a => a -> String -> String -> IO ()
vRenameFile (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
fh) String
old' String
new'
vGetFileStatus :: HVFSChroot a -> String -> IO HVFSStatEncap
vGetFileStatus = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO HVFSStatEncap
vGetFileStatus
vGetSymbolicLinkStatus :: HVFSChroot a -> String -> IO HVFSStatEncap
vGetSymbolicLinkStatus = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO HVFSStatEncap
vGetSymbolicLinkStatus
vGetModificationTime :: HVFSChroot a -> String -> IO ClockTime
vGetModificationTime = forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO ClockTime
vGetModificationTime
vCreateSymbolicLink :: HVFSChroot a -> String -> String -> IO ()
vCreateSymbolicLink HVFSChroot a
fh String
old String
new = do String
old' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
old
String
new' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
new
forall a. HVFS a => a -> String -> String -> IO ()
vCreateSymbolicLink (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
fh) String
old' String
new'
vReadSymbolicLink :: HVFSChroot a -> String -> IO String
vReadSymbolicLink HVFSChroot a
fh String
fp = do String
result <- forall t t1.
HVFS t =>
(t -> String -> IO t1) -> HVFSChroot t -> String -> IO t1
dch2fph forall a. HVFS a => a -> String -> IO String
vReadSymbolicLink HVFSChroot a
fh String
fp
forall t. HVFS t => HVFSChroot t -> String -> IO String
fp2dch HVFSChroot a
fh String
result
vCreateLink :: HVFSChroot a -> String -> String -> IO ()
vCreateLink HVFSChroot a
fh String
old String
new = do String
old' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
old
String
new' <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
new
forall a. HVFS a => a -> String -> String -> IO ()
vCreateLink (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
fh) String
old' String
new'
instance HVFSOpenable a => HVFSOpenable (HVFSChroot a) where
vOpen :: HVFSChroot a -> String -> IOMode -> IO HVFSOpenEncap
vOpen HVFSChroot a
fh String
fp IOMode
mode = do String
newfile <- forall t. HVFS t => HVFSChroot t -> String -> IO String
dch2fp HVFSChroot a
fh String
fp
forall a.
HVFSOpenable a =>
a -> String -> IOMode -> IO HVFSOpenEncap
vOpen (forall t. HVFS t => HVFSChroot t -> t
dch HVFSChroot a
fh) String
newfile IOMode
mode