{-# LANGUAGE CPP #-}
module Darcs.Util.Path
( encodeWhite
, decodeWhite
, encodeWhiteName
, decodeWhiteName
, AbsolutePath
, makeAbsolute
, ioAbsolute
, AbsolutePathOrStd
, makeAbsoluteOrStd
, ioAbsoluteOrStd
, useAbsoluteOrStd
, stdOut
, AbsoluteOrRemotePath
, ioAbsoluteOrRemote
, isRemote
, SubPath
, makeSubPathOf
, simpleSubPath
, floatSubPath
, FilePathOrURL(..)
, FilePathLike(toFilePath)
, getCurrentDirectory
, setCurrentDirectory
, getUniquePathName
, doesPathExist
, isMaliciousSubPath
, filterPaths
, Name
, name2fp
, makeName
, rawMakeName
, eqAnycase
, AnchoredPath(..)
, anchoredRoot
, appendPath
, anchorPath
, isPrefix
, breakOnDir
, movedirfilename
, parent
, parents
, replaceParent
, catPaths
, flatten
, inDarcsdir
, displayPath
, realPath
, isRoot
, darcsdirName
, floatPath
) where
import Darcs.Prelude
import Data.List
( isPrefixOf
, isSuffixOf
, stripPrefix
, intersect
, inits
)
import Data.Char ( isSpace, chr, ord, toLower )
import Data.Typeable ( Typeable )
import Control.Exception ( tryJust, bracket_, throw, Exception )
import Control.Monad ( when )
import System.IO.Error ( isDoesNotExistError )
import qualified Darcs.Util.Workaround as Workaround ( getCurrentDirectory )
import qualified System.Directory ( setCurrentDirectory )
import System.Directory ( doesDirectoryExist, doesFileExist )
import qualified System.FilePath.Posix as FilePath ( (</>), normalise, isRelative )
import qualified System.FilePath as NativeFilePath ( takeFileName, takeDirectory )
import System.FilePath( splitDirectories, normalise, dropTrailingPathSeparator )
import System.Posix.Files ( isDirectory, getSymbolicLinkStatus )
import Darcs.Util.ByteString ( encodeLocale, decodeLocale )
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString as B
import Data.Binary
import Darcs.Util.Global ( darcsdir )
import Darcs.Util.URL ( isAbsolute, isRelative, isSshNopath )
displayPath :: AnchoredPath -> FilePath
displayPath :: AnchoredPath -> FilePath
displayPath AnchoredPath
p
| AnchoredPath -> Bool
isRoot AnchoredPath
p = FilePath
"."
| Bool
otherwise = FilePath -> AnchoredPath -> FilePath
anchorPath FilePath
"." AnchoredPath
p
realPath :: AnchoredPath -> FilePath
realPath :: AnchoredPath -> FilePath
realPath = FilePath -> AnchoredPath -> FilePath
anchorPath FilePath
""
encodeWhite :: FilePath -> String
encodeWhite :: FilePath -> FilePath
encodeWhite (Char
c:FilePath
cs) | Char -> Bool
isSpace Char
c Bool -> Bool -> Bool
|| Char
c forall a. Eq a => a -> a -> Bool
== Char
'\\' =
Char
'\\' forall a. a -> [a] -> [a]
: forall a. Show a => a -> FilePath
show (Char -> Int
ord Char
c) forall a. [a] -> [a] -> [a]
++ FilePath
"\\" forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
encodeWhite FilePath
cs
encodeWhite (Char
c:FilePath
cs) = Char
c forall a. a -> [a] -> [a]
: FilePath -> FilePath
encodeWhite FilePath
cs
encodeWhite [] = []
decodeWhite :: String -> FilePath
decodeWhite :: FilePath -> FilePath
decodeWhite FilePath
cs_ = FilePath -> FilePath -> Bool -> FilePath
go FilePath
cs_ [] Bool
False
where go :: FilePath -> FilePath -> Bool -> FilePath
go FilePath
"" FilePath
acc Bool
True = forall a. [a] -> [a]
reverse FilePath
acc
go FilePath
"" FilePath
_ Bool
False = FilePath
cs_
go (Char
'\\':FilePath
cs) FilePath
acc Bool
_ =
case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
'\\') FilePath
cs of
(FilePath
theord, Char
'\\':FilePath
rest) ->
FilePath -> FilePath -> Bool -> FilePath
go FilePath
rest (Int -> Char
chr (forall a. Read a => FilePath -> a
read FilePath
theord) forall a. a -> [a] -> [a]
:FilePath
acc) Bool
True
(FilePath, FilePath)
_ -> forall a. HasCallStack => FilePath -> a
error FilePath
"malformed filename"
go (Char
c:FilePath
cs) FilePath
acc Bool
modified = FilePath -> FilePath -> Bool -> FilePath
go FilePath
cs (Char
cforall a. a -> [a] -> [a]
:FilePath
acc) Bool
modified
class FilePathOrURL a where
toPath :: a -> String
class FilePathOrURL a => FilePathLike a where
toFilePath :: a -> FilePath
newtype SubPath = SubPath FilePath deriving (SubPath -> SubPath -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SubPath -> SubPath -> Bool
$c/= :: SubPath -> SubPath -> Bool
== :: SubPath -> SubPath -> Bool
$c== :: SubPath -> SubPath -> Bool
Eq, Eq SubPath
SubPath -> SubPath -> Bool
SubPath -> SubPath -> Ordering
SubPath -> SubPath -> SubPath
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SubPath -> SubPath -> SubPath
$cmin :: SubPath -> SubPath -> SubPath
max :: SubPath -> SubPath -> SubPath
$cmax :: SubPath -> SubPath -> SubPath
>= :: SubPath -> SubPath -> Bool
$c>= :: SubPath -> SubPath -> Bool
> :: SubPath -> SubPath -> Bool
$c> :: SubPath -> SubPath -> Bool
<= :: SubPath -> SubPath -> Bool
$c<= :: SubPath -> SubPath -> Bool
< :: SubPath -> SubPath -> Bool
$c< :: SubPath -> SubPath -> Bool
compare :: SubPath -> SubPath -> Ordering
$ccompare :: SubPath -> SubPath -> Ordering
Ord)
newtype AbsolutePath = AbsolutePath FilePath deriving (AbsolutePath -> AbsolutePath -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AbsolutePath -> AbsolutePath -> Bool
$c/= :: AbsolutePath -> AbsolutePath -> Bool
== :: AbsolutePath -> AbsolutePath -> Bool
$c== :: AbsolutePath -> AbsolutePath -> Bool
Eq, Eq AbsolutePath
AbsolutePath -> AbsolutePath -> Bool
AbsolutePath -> AbsolutePath -> Ordering
AbsolutePath -> AbsolutePath -> AbsolutePath
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AbsolutePath -> AbsolutePath -> AbsolutePath
$cmin :: AbsolutePath -> AbsolutePath -> AbsolutePath
max :: AbsolutePath -> AbsolutePath -> AbsolutePath
$cmax :: AbsolutePath -> AbsolutePath -> AbsolutePath
>= :: AbsolutePath -> AbsolutePath -> Bool
$c>= :: AbsolutePath -> AbsolutePath -> Bool
> :: AbsolutePath -> AbsolutePath -> Bool
$c> :: AbsolutePath -> AbsolutePath -> Bool
<= :: AbsolutePath -> AbsolutePath -> Bool
$c<= :: AbsolutePath -> AbsolutePath -> Bool
< :: AbsolutePath -> AbsolutePath -> Bool
$c< :: AbsolutePath -> AbsolutePath -> Bool
compare :: AbsolutePath -> AbsolutePath -> Ordering
$ccompare :: AbsolutePath -> AbsolutePath -> Ordering
Ord)
data AbsolutePathOrStd = AP AbsolutePath | APStd deriving (AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c/= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
== :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c== :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
Eq, Eq AbsolutePathOrStd
AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
AbsolutePathOrStd -> AbsolutePathOrStd -> Ordering
AbsolutePathOrStd -> AbsolutePathOrStd -> AbsolutePathOrStd
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AbsolutePathOrStd -> AbsolutePathOrStd -> AbsolutePathOrStd
$cmin :: AbsolutePathOrStd -> AbsolutePathOrStd -> AbsolutePathOrStd
max :: AbsolutePathOrStd -> AbsolutePathOrStd -> AbsolutePathOrStd
$cmax :: AbsolutePathOrStd -> AbsolutePathOrStd -> AbsolutePathOrStd
>= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c>= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
> :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c> :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
<= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c<= :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
< :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
$c< :: AbsolutePathOrStd -> AbsolutePathOrStd -> Bool
compare :: AbsolutePathOrStd -> AbsolutePathOrStd -> Ordering
$ccompare :: AbsolutePathOrStd -> AbsolutePathOrStd -> Ordering
Ord)
data AbsoluteOrRemotePath = AbsP AbsolutePath | RmtP String deriving (AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c/= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
== :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c== :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
Eq, Eq AbsoluteOrRemotePath
AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Ordering
AbsoluteOrRemotePath
-> AbsoluteOrRemotePath -> AbsoluteOrRemotePath
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AbsoluteOrRemotePath
-> AbsoluteOrRemotePath -> AbsoluteOrRemotePath
$cmin :: AbsoluteOrRemotePath
-> AbsoluteOrRemotePath -> AbsoluteOrRemotePath
max :: AbsoluteOrRemotePath
-> AbsoluteOrRemotePath -> AbsoluteOrRemotePath
$cmax :: AbsoluteOrRemotePath
-> AbsoluteOrRemotePath -> AbsoluteOrRemotePath
>= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c>= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
> :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c> :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
<= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c<= :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
< :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
$c< :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Bool
compare :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Ordering
$ccompare :: AbsoluteOrRemotePath -> AbsoluteOrRemotePath -> Ordering
Ord)
instance FilePathOrURL AbsolutePath where
toPath :: AbsolutePath -> FilePath
toPath (AbsolutePath FilePath
x) = FilePath
x
instance FilePathOrURL SubPath where
toPath :: SubPath -> FilePath
toPath (SubPath FilePath
x) = FilePath
x
instance CharLike c => FilePathOrURL [c] where
toPath :: [c] -> FilePath
toPath = forall a. FilePathLike a => a -> FilePath
toFilePath
instance FilePathOrURL AbsoluteOrRemotePath where
toPath :: AbsoluteOrRemotePath -> FilePath
toPath (AbsP AbsolutePath
a) = forall a. FilePathOrURL a => a -> FilePath
toPath AbsolutePath
a
toPath (RmtP FilePath
r) = FilePath
r
instance FilePathLike AbsolutePath where
toFilePath :: AbsolutePath -> FilePath
toFilePath (AbsolutePath FilePath
x) = FilePath
x
instance FilePathLike SubPath where
toFilePath :: SubPath -> FilePath
toFilePath (SubPath FilePath
x) = FilePath
x
class CharLike c where
toChar :: c -> Char
instance CharLike Char where
toChar :: Char -> Char
toChar = forall a. a -> a
id
instance CharLike c => FilePathLike [c] where
toFilePath :: [c] -> FilePath
toFilePath = forall a b. (a -> b) -> [a] -> [b]
map forall c. CharLike c => c -> Char
toChar
makeSubPathOf :: AbsolutePath -> AbsolutePath -> Maybe SubPath
makeSubPathOf :: AbsolutePath -> AbsolutePath -> Maybe SubPath
makeSubPathOf (AbsolutePath FilePath
p1) (AbsolutePath FilePath
p2) =
if FilePath
p1 forall a. Eq a => a -> a -> Bool
== FilePath
p2 Bool -> Bool -> Bool
|| (FilePath
p1 forall a. [a] -> [a] -> [a]
++ FilePath
"/") forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath
p2
then forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ FilePath -> SubPath
SubPath forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
p1 forall a. Num a => a -> a -> a
+ Int
1) FilePath
p2
else forall a. Maybe a
Nothing
simpleSubPath :: FilePath -> Maybe SubPath
simpleSubPath :: FilePath -> Maybe SubPath
simpleSubPath FilePath
x | forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
x = forall a. HasCallStack => FilePath -> a
error FilePath
"simpleSubPath called with empty path"
| FilePath -> Bool
isRelative FilePath
x = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ FilePath -> SubPath
SubPath forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
FilePath.normalise forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
pathToPosix FilePath
x
| Bool
otherwise = forall a. Maybe a
Nothing
doesDirectoryReallyExist :: FilePath -> IO Bool
doesDirectoryReallyExist :: FilePath -> IO Bool
doesDirectoryReallyExist FilePath
f = do
Either () Bool
x <- forall e b a.
Exception e =>
(e -> Maybe b) -> IO a -> IO (Either b a)
tryJust (\IOError
x -> if IOError -> Bool
isDoesNotExistError IOError
x then forall a. a -> Maybe a
Just () else forall a. Maybe a
Nothing) forall a b. (a -> b) -> a -> b
$
FileStatus -> Bool
isDirectory forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO FileStatus
getSymbolicLinkStatus FilePath
f
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ case Either () Bool
x of
Left () -> Bool
False
Right Bool
y -> Bool
y
doesPathExist :: FilePath -> IO Bool
doesPathExist :: FilePath -> IO Bool
doesPathExist FilePath
p = do
Bool
dir_exists <- FilePath -> IO Bool
doesDirectoryExist FilePath
p
Bool
file_exists <- FilePath -> IO Bool
doesFileExist FilePath
p
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Bool
dir_exists Bool -> Bool -> Bool
|| Bool
file_exists
ioAbsolute :: FilePath -> IO AbsolutePath
ioAbsolute :: FilePath -> IO AbsolutePath
ioAbsolute FilePath
dir =
do Bool
isdir <- FilePath -> IO Bool
doesDirectoryReallyExist FilePath
dir
AbsolutePath
here <- IO AbsolutePath
getCurrentDirectory
if Bool
isdir
then forall a b c. IO a -> IO b -> IO c -> IO c
bracket_ (forall p. FilePathLike p => p -> IO ()
setCurrentDirectory FilePath
dir)
(forall p. FilePathLike p => p -> IO ()
setCurrentDirectory forall a b. (a -> b) -> a -> b
$ forall a. FilePathLike a => a -> FilePath
toFilePath AbsolutePath
here)
IO AbsolutePath
getCurrentDirectory
else let super_dir :: FilePath
super_dir = case FilePath -> FilePath
NativeFilePath.takeDirectory FilePath
dir of
FilePath
"" -> FilePath
"."
FilePath
d -> FilePath
d
file :: FilePath
file = FilePath -> FilePath
NativeFilePath.takeFileName FilePath
dir
in do AbsolutePath
abs_dir <- if FilePath
dir forall a. Eq a => a -> a -> Bool
== FilePath
super_dir
then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ FilePath -> AbsolutePath
AbsolutePath FilePath
dir
else FilePath -> IO AbsolutePath
ioAbsolute FilePath
super_dir
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ AbsolutePath -> FilePath -> AbsolutePath
makeAbsolute AbsolutePath
abs_dir FilePath
file
makeAbsolute :: AbsolutePath -> FilePath -> AbsolutePath
makeAbsolute :: AbsolutePath -> FilePath -> AbsolutePath
makeAbsolute AbsolutePath
a FilePath
dir = if Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
dir) Bool -> Bool -> Bool
&& FilePath -> Bool
isAbsolute FilePath
dir
then FilePath -> AbsolutePath
AbsolutePath (FilePath -> FilePath
normSlashes FilePath
dir')
else AbsolutePath -> FilePath -> AbsolutePath
ma AbsolutePath
a FilePath
dir'
where
dir' :: FilePath
dir' = FilePath -> FilePath
FilePath.normalise forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
pathToPosix FilePath
dir
ma :: AbsolutePath -> FilePath -> AbsolutePath
ma AbsolutePath
here (Char
'.':Char
'.':Char
'/':FilePath
r) = AbsolutePath -> FilePath -> AbsolutePath
ma (AbsolutePath -> AbsolutePath
takeDirectory AbsolutePath
here) FilePath
r
ma AbsolutePath
here FilePath
".." = AbsolutePath -> AbsolutePath
takeDirectory AbsolutePath
here
ma AbsolutePath
here FilePath
"." = AbsolutePath
here
ma AbsolutePath
here FilePath
"" = AbsolutePath
here
ma AbsolutePath
here FilePath
r = AbsolutePath
here AbsolutePath -> FilePath -> AbsolutePath
/- (Char
'/'forall a. a -> [a] -> [a]
:FilePath
r)
(/-) :: AbsolutePath -> String -> AbsolutePath
AbsolutePath
x /- :: AbsolutePath -> FilePath -> AbsolutePath
/- (Char
'/':FilePath
r) = AbsolutePath
x AbsolutePath -> FilePath -> AbsolutePath
/- FilePath
r
(AbsolutePath FilePath
"/") /- FilePath
r = FilePath -> AbsolutePath
AbsolutePath (Char
'/'forall a. a -> [a] -> [a]
:FilePath -> FilePath
simpleClean FilePath
r)
(AbsolutePath FilePath
x) /- FilePath
r = FilePath -> AbsolutePath
AbsolutePath (FilePath
xforall a. [a] -> [a] -> [a]
++Char
'/'forall a. a -> [a] -> [a]
:FilePath -> FilePath
simpleClean FilePath
r)
simpleClean :: String -> String
simpleClean :: FilePath -> FilePath
simpleClean = FilePath -> FilePath
normSlashes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
==Char
'/') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
pathToPosix
makeAbsoluteOrStd :: AbsolutePath -> String -> AbsolutePathOrStd
makeAbsoluteOrStd :: AbsolutePath -> FilePath -> AbsolutePathOrStd
makeAbsoluteOrStd AbsolutePath
_ FilePath
"-" = AbsolutePathOrStd
APStd
makeAbsoluteOrStd AbsolutePath
a FilePath
p = AbsolutePath -> AbsolutePathOrStd
AP forall a b. (a -> b) -> a -> b
$ AbsolutePath -> FilePath -> AbsolutePath
makeAbsolute AbsolutePath
a FilePath
p
stdOut :: AbsolutePathOrStd
stdOut :: AbsolutePathOrStd
stdOut = AbsolutePathOrStd
APStd
ioAbsoluteOrStd :: String -> IO AbsolutePathOrStd
ioAbsoluteOrStd :: FilePath -> IO AbsolutePathOrStd
ioAbsoluteOrStd FilePath
"-" = forall (m :: * -> *) a. Monad m => a -> m a
return AbsolutePathOrStd
APStd
ioAbsoluteOrStd FilePath
p = AbsolutePath -> AbsolutePathOrStd
AP forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` FilePath -> IO AbsolutePath
ioAbsolute FilePath
p
useAbsoluteOrStd :: (AbsolutePath -> a) -> a -> AbsolutePathOrStd -> a
useAbsoluteOrStd :: forall a. (AbsolutePath -> a) -> a -> AbsolutePathOrStd -> a
useAbsoluteOrStd AbsolutePath -> a
_ a
f AbsolutePathOrStd
APStd = a
f
useAbsoluteOrStd AbsolutePath -> a
f a
_ (AP AbsolutePath
x) = AbsolutePath -> a
f AbsolutePath
x
ioAbsoluteOrRemote :: String -> IO AbsoluteOrRemotePath
ioAbsoluteOrRemote :: FilePath -> IO AbsoluteOrRemotePath
ioAbsoluteOrRemote FilePath
p = do
Bool
isdir <- FilePath -> IO Bool
doesDirectoryExist FilePath
p
if Bool -> Bool
not Bool
isdir
then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ FilePath -> AbsoluteOrRemotePath
RmtP forall a b. (a -> b) -> a -> b
$
case () of ()
_ | FilePath -> Bool
isSshNopath FilePath
p -> FilePath
pforall a. [a] -> [a] -> [a]
++FilePath
"."
| FilePath
"/" forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` FilePath
p -> forall a. [a] -> [a]
init FilePath
p
| Bool
otherwise -> FilePath
p
else AbsolutePath -> AbsoluteOrRemotePath
AbsP forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` FilePath -> IO AbsolutePath
ioAbsolute FilePath
p
isRemote :: AbsoluteOrRemotePath -> Bool
isRemote :: AbsoluteOrRemotePath -> Bool
isRemote (RmtP FilePath
_) = Bool
True
isRemote AbsoluteOrRemotePath
_ = Bool
False
takeDirectory :: AbsolutePath -> AbsolutePath
takeDirectory :: AbsolutePath -> AbsolutePath
takeDirectory (AbsolutePath FilePath
x) =
case forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
drop Int
1 forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
/=Char
'/') forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse FilePath
x of
FilePath
"" -> FilePath -> AbsolutePath
AbsolutePath FilePath
"/"
FilePath
x' -> FilePath -> AbsolutePath
AbsolutePath FilePath
x'
instance Show AbsolutePath where
show :: AbsolutePath -> FilePath
show = forall a. Show a => a -> FilePath
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FilePathLike a => a -> FilePath
toFilePath
instance Show SubPath where
show :: SubPath -> FilePath
show = forall a. Show a => a -> FilePath
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FilePathLike a => a -> FilePath
toFilePath
instance Show AbsolutePathOrStd where
show :: AbsolutePathOrStd -> FilePath
show (AP AbsolutePath
a) = forall a. Show a => a -> FilePath
show AbsolutePath
a
show AbsolutePathOrStd
APStd = FilePath
"standard input/output"
instance Show AbsoluteOrRemotePath where
show :: AbsoluteOrRemotePath -> FilePath
show (AbsP AbsolutePath
a) = forall a. Show a => a -> FilePath
show AbsolutePath
a
show (RmtP FilePath
r) = forall a. Show a => a -> FilePath
show FilePath
r
pathToPosix :: FilePath -> FilePath
pathToPosix :: FilePath -> FilePath
pathToPosix = forall a b. (a -> b) -> [a] -> [b]
map forall a. a -> a
convert where
#ifdef WIN32
convert '\\' = '/'
#endif
convert :: p -> p
convert p
c = p
c
normSlashes :: FilePath -> FilePath
#ifndef WIN32
normSlashes :: FilePath -> FilePath
normSlashes (Char
'/':FilePath
p) = Char
'/' forall a. a -> [a] -> [a]
: forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
== Char
'/') FilePath
p
#endif
normSlashes FilePath
p = FilePath
p
getCurrentDirectory :: IO AbsolutePath
getCurrentDirectory :: IO AbsolutePath
getCurrentDirectory = FilePath -> AbsolutePath
AbsolutePath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO FilePath
Workaround.getCurrentDirectory
setCurrentDirectory :: FilePathLike p => p -> IO ()
setCurrentDirectory :: forall p. FilePathLike p => p -> IO ()
setCurrentDirectory = FilePath -> IO ()
System.Directory.setCurrentDirectory forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FilePathLike a => a -> FilePath
toFilePath
isMaliciousSubPath :: String -> Bool
isMaliciousSubPath :: FilePath -> Bool
isMaliciousSubPath FilePath
fp =
Bool -> Bool
not (FilePath -> Bool
FilePath.isRelative FilePath
fp) Bool -> Bool -> Bool
|| FilePath -> Bool
isGenerallyMalicious FilePath
fp
isGenerallyMalicious :: String -> Bool
isGenerallyMalicious :: FilePath -> Bool
isGenerallyMalicious FilePath
fp =
FilePath -> [FilePath]
splitDirectories FilePath
fp forall a. Eq a => [a] -> [a] -> Bool
`contains_any` [ FilePath
"..", FilePath
darcsdir ]
where
contains_any :: [a] -> [a] -> Bool
contains_any [a]
a [a]
b = Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ forall a. Eq a => [a] -> [a] -> [a]
intersect [a]
a [a]
b
getUniquePathName :: Bool -> (FilePath -> String) -> (Int -> FilePath) -> IO FilePath
getUniquePathName :: Bool -> (FilePath -> FilePath) -> (Int -> FilePath) -> IO FilePath
getUniquePathName Bool
talkative FilePath -> FilePath
buildMsg Int -> FilePath
buildName = Int -> IO FilePath
go (-Int
1)
where
go :: Int -> IO FilePath
go :: Int -> IO FilePath
go Int
i = do
Bool
exists <- FilePath -> IO Bool
doesPathExist FilePath
thename
if Bool -> Bool
not Bool
exists
then do forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
i forall a. Eq a => a -> a -> Bool
/= -Int
1 Bool -> Bool -> Bool
&& Bool
talkative) forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
buildMsg FilePath
thename
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
thename
else Int -> IO FilePath
go forall a b. (a -> b) -> a -> b
$ Int
iforall a. Num a => a -> a -> a
+Int
1
where thename :: FilePath
thename = Int -> FilePath
buildName Int
i
newtype Name = Name { Name -> ByteString
unName :: B.ByteString } deriving (Get Name
[Name] -> Put
Name -> Put
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
putList :: [Name] -> Put
$cputList :: [Name] -> Put
get :: Get Name
$cget :: Get Name
put :: Name -> Put
$cput :: Name -> Put
Binary, Name -> Name -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Name -> Name -> Bool
$c/= :: Name -> Name -> Bool
== :: Name -> Name -> Bool
$c== :: Name -> Name -> Bool
Eq, Int -> Name -> FilePath -> FilePath
[Name] -> FilePath -> FilePath
Name -> FilePath
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [Name] -> FilePath -> FilePath
$cshowList :: [Name] -> FilePath -> FilePath
show :: Name -> FilePath
$cshow :: Name -> FilePath
showsPrec :: Int -> Name -> FilePath -> FilePath
$cshowsPrec :: Int -> Name -> FilePath -> FilePath
Show, Eq Name
Name -> Name -> Bool
Name -> Name -> Ordering
Name -> Name -> Name
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Name -> Name -> Name
$cmin :: Name -> Name -> Name
max :: Name -> Name -> Name
$cmax :: Name -> Name -> Name
>= :: Name -> Name -> Bool
$c>= :: Name -> Name -> Bool
> :: Name -> Name -> Bool
$c> :: Name -> Name -> Bool
<= :: Name -> Name -> Bool
$c<= :: Name -> Name -> Bool
< :: Name -> Name -> Bool
$c< :: Name -> Name -> Bool
compare :: Name -> Name -> Ordering
$ccompare :: Name -> Name -> Ordering
Ord)
newtype AnchoredPath = AnchoredPath [Name] deriving (Get AnchoredPath
[AnchoredPath] -> Put
AnchoredPath -> Put
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
putList :: [AnchoredPath] -> Put
$cputList :: [AnchoredPath] -> Put
get :: Get AnchoredPath
$cget :: Get AnchoredPath
put :: AnchoredPath -> Put
$cput :: AnchoredPath -> Put
Binary, AnchoredPath -> AnchoredPath -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AnchoredPath -> AnchoredPath -> Bool
$c/= :: AnchoredPath -> AnchoredPath -> Bool
== :: AnchoredPath -> AnchoredPath -> Bool
$c== :: AnchoredPath -> AnchoredPath -> Bool
Eq, Int -> AnchoredPath -> FilePath -> FilePath
[AnchoredPath] -> FilePath -> FilePath
AnchoredPath -> FilePath
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [AnchoredPath] -> FilePath -> FilePath
$cshowList :: [AnchoredPath] -> FilePath -> FilePath
show :: AnchoredPath -> FilePath
$cshow :: AnchoredPath -> FilePath
showsPrec :: Int -> AnchoredPath -> FilePath -> FilePath
$cshowsPrec :: Int -> AnchoredPath -> FilePath -> FilePath
Show, Eq AnchoredPath
AnchoredPath -> AnchoredPath -> Bool
AnchoredPath -> AnchoredPath -> Ordering
AnchoredPath -> AnchoredPath -> AnchoredPath
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AnchoredPath -> AnchoredPath -> AnchoredPath
$cmin :: AnchoredPath -> AnchoredPath -> AnchoredPath
max :: AnchoredPath -> AnchoredPath -> AnchoredPath
$cmax :: AnchoredPath -> AnchoredPath -> AnchoredPath
>= :: AnchoredPath -> AnchoredPath -> Bool
$c>= :: AnchoredPath -> AnchoredPath -> Bool
> :: AnchoredPath -> AnchoredPath -> Bool
$c> :: AnchoredPath -> AnchoredPath -> Bool
<= :: AnchoredPath -> AnchoredPath -> Bool
$c<= :: AnchoredPath -> AnchoredPath -> Bool
< :: AnchoredPath -> AnchoredPath -> Bool
$c< :: AnchoredPath -> AnchoredPath -> Bool
compare :: AnchoredPath -> AnchoredPath -> Ordering
$ccompare :: AnchoredPath -> AnchoredPath -> Ordering
Ord)
isPrefix :: AnchoredPath -> AnchoredPath -> Bool
(AnchoredPath [Name]
a) isPrefix :: AnchoredPath -> AnchoredPath -> Bool
`isPrefix` (AnchoredPath [Name]
b) = [Name]
a forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` [Name]
b
appendPath :: AnchoredPath -> Name -> AnchoredPath
appendPath :: AnchoredPath -> Name -> AnchoredPath
appendPath (AnchoredPath [Name]
p) Name
n = [Name] -> AnchoredPath
AnchoredPath forall a b. (a -> b) -> a -> b
$ [Name]
p forall a. [a] -> [a] -> [a]
++ [Name
n]
catPaths :: AnchoredPath -> AnchoredPath -> AnchoredPath
catPaths :: AnchoredPath -> AnchoredPath -> AnchoredPath
catPaths (AnchoredPath [Name]
p) (AnchoredPath [Name]
n) = [Name] -> AnchoredPath
AnchoredPath ([Name]
p forall a. [a] -> [a] -> [a]
++ [Name]
n)
parent :: AnchoredPath -> Maybe AnchoredPath
parent :: AnchoredPath -> Maybe AnchoredPath
parent (AnchoredPath []) = forall a. Maybe a
Nothing
parent (AnchoredPath [Name]
x) = forall a. a -> Maybe a
Just ([Name] -> AnchoredPath
AnchoredPath (forall a. [a] -> [a]
init [Name]
x))
parents :: AnchoredPath -> [AnchoredPath]
parents :: AnchoredPath -> [AnchoredPath]
parents (AnchoredPath []) = []
parents (AnchoredPath [Name]
xs) = forall a b. (a -> b) -> [a] -> [b]
map [Name] -> AnchoredPath
AnchoredPath forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [[a]]
inits forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
init [Name]
xs
breakOnDir :: AnchoredPath -> Either Name (Name, AnchoredPath)
breakOnDir :: AnchoredPath -> Either Name (Name, AnchoredPath)
breakOnDir (AnchoredPath []) = forall a. HasCallStack => FilePath -> a
error FilePath
"breakOnDir called on root"
breakOnDir (AnchoredPath (Name
n:[])) = forall a b. a -> Either a b
Left Name
n
breakOnDir (AnchoredPath (Name
n:[Name]
ns)) = forall a b. b -> Either a b
Right (Name
n, [Name] -> AnchoredPath
AnchoredPath [Name]
ns)
anchorPath :: FilePath -> AnchoredPath -> FilePath
anchorPath :: FilePath -> AnchoredPath -> FilePath
anchorPath FilePath
dir AnchoredPath
p = FilePath
dir FilePath -> FilePath -> FilePath
FilePath.</> ByteString -> FilePath
decodeLocale (AnchoredPath -> ByteString
flatten AnchoredPath
p)
{-# INLINE anchorPath #-}
name2fp :: Name -> FilePath
name2fp :: Name -> FilePath
name2fp (Name ByteString
ps) = ByteString -> FilePath
decodeLocale ByteString
ps
flatten :: AnchoredPath -> BC.ByteString
flatten :: AnchoredPath -> ByteString
flatten (AnchoredPath []) = Char -> ByteString
BC.singleton Char
'.'
flatten (AnchoredPath [Name]
p) = ByteString -> [ByteString] -> ByteString
BC.intercalate (Char -> ByteString
BC.singleton Char
'/') [ByteString
n | (Name ByteString
n) <- [Name]
p]
makeName :: String -> Either String Name
makeName :: FilePath -> Either FilePath Name
makeName = ByteString -> Either FilePath Name
rawMakeName forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString
encodeLocale
internalMakeName :: String -> Name
internalMakeName :: FilePath -> Name
internalMakeName = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. HasCallStack => FilePath -> a
error forall a. a -> a
id forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either FilePath Name
rawMakeName forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString
encodeLocale
floatPath :: FilePath -> AnchoredPath
floatPath :: FilePath -> AnchoredPath
floatPath =
[Name] -> AnchoredPath
AnchoredPath forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Name
internalMakeName forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
sensible forall b c a. (b -> c) -> (a -> b) -> a -> c
.
FilePath -> [FilePath]
splitDirectories forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
normalise forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
dropTrailingPathSeparator
where
sensible :: FilePath -> Bool
sensible FilePath
s = FilePath
s forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [FilePath
"", FilePath
"."]
anchoredRoot :: AnchoredPath
anchoredRoot :: AnchoredPath
anchoredRoot = [Name] -> AnchoredPath
AnchoredPath []
parentChild :: AnchoredPath -> Maybe (AnchoredPath, Name)
parentChild :: AnchoredPath -> Maybe (AnchoredPath, Name)
parentChild (AnchoredPath []) = forall a. Maybe a
Nothing
parentChild (AnchoredPath [Name]
xs) = forall a. a -> Maybe a
Just ([Name] -> AnchoredPath
AnchoredPath (forall a. [a] -> [a]
init [Name]
xs), forall a. [a] -> a
last [Name]
xs)
replaceParent :: AnchoredPath -> AnchoredPath -> Maybe AnchoredPath
replaceParent :: AnchoredPath -> AnchoredPath -> Maybe AnchoredPath
replaceParent (AnchoredPath [Name]
xs) AnchoredPath
p =
case AnchoredPath -> Maybe (AnchoredPath, Name)
parentChild AnchoredPath
p of
Maybe (AnchoredPath, Name)
Nothing -> forall a. Maybe a
Nothing
Just (AnchoredPath
_,Name
x) -> forall a. a -> Maybe a
Just ([Name] -> AnchoredPath
AnchoredPath ([Name]
xs forall a. [a] -> [a] -> [a]
++ [Name
x]))
rawMakeName :: B.ByteString -> Either String Name
rawMakeName :: ByteString -> Either FilePath Name
rawMakeName ByteString
s
| ByteString -> Bool
isBadName ByteString
s =
forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ FilePath
"'"forall a. [a] -> [a] -> [a]
++ByteString -> FilePath
decodeLocale ByteString
sforall a. [a] -> [a] -> [a]
++FilePath
"' is not a valid AnchoredPath component name"
| Bool
otherwise = forall a b. b -> Either a b
Right (ByteString -> Name
Name ByteString
s)
isBadName :: B.ByteString -> Bool
isBadName :: ByteString -> Bool
isBadName ByteString
n = ByteString -> Bool
hasPathSeparator ByteString
n Bool -> Bool -> Bool
|| ByteString
n forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ByteString]
forbiddenNames
forbiddenNames :: [B.ByteString]
forbiddenNames :: [ByteString]
forbiddenNames = [ByteString
BC.empty, FilePath -> ByteString
BC.pack FilePath
".", FilePath -> ByteString
BC.pack FilePath
".."]
hasPathSeparator :: B.ByteString -> Bool
hasPathSeparator :: ByteString -> Bool
hasPathSeparator = Char -> ByteString -> Bool
BC.elem Char
'/'
eqAnycase :: Name -> Name -> Bool
eqAnycase :: Name -> Name -> Bool
eqAnycase (Name ByteString
a) (Name ByteString
b) = (Char -> Char) -> ByteString -> ByteString
BC.map Char -> Char
toLower ByteString
a forall a. Eq a => a -> a -> Bool
== (Char -> Char) -> ByteString -> ByteString
BC.map Char -> Char
toLower ByteString
b
encodeWhiteName :: Name -> B.ByteString
encodeWhiteName :: Name -> ByteString
encodeWhiteName = FilePath -> ByteString
encodeLocale forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
encodeWhite forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> FilePath
decodeLocale forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> ByteString
unName
data CorruptPatch = CorruptPatch String deriving (CorruptPatch -> CorruptPatch -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CorruptPatch -> CorruptPatch -> Bool
$c/= :: CorruptPatch -> CorruptPatch -> Bool
== :: CorruptPatch -> CorruptPatch -> Bool
$c== :: CorruptPatch -> CorruptPatch -> Bool
Eq, Typeable)
instance Exception CorruptPatch
instance Show CorruptPatch where show :: CorruptPatch -> FilePath
show (CorruptPatch FilePath
s) = FilePath
s
decodeWhiteName :: B.ByteString -> Name
decodeWhiteName :: ByteString -> Name
decodeWhiteName =
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a e. Exception e => e -> a
throw forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> CorruptPatch
CorruptPatch) forall a. a -> a
id forall b c a. (b -> c) -> (a -> b) -> a -> c
.
ByteString -> Either FilePath Name
rawMakeName forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString
encodeLocale forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
decodeWhite forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> FilePath
decodeLocale
movedirfilename :: AnchoredPath -> AnchoredPath -> AnchoredPath -> AnchoredPath
movedirfilename :: AnchoredPath -> AnchoredPath -> AnchoredPath -> AnchoredPath
movedirfilename (AnchoredPath [Name]
old) newp :: AnchoredPath
newp@(AnchoredPath [Name]
new) orig :: AnchoredPath
orig@(AnchoredPath [Name]
path) =
case forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix [Name]
old [Name]
path of
Just [] -> AnchoredPath
newp
Just [Name]
rest -> [Name] -> AnchoredPath
AnchoredPath ([Name]
new forall a. [a] -> [a] -> [a]
++ [Name]
rest)
Maybe [Name]
Nothing -> AnchoredPath
orig
filterPaths :: [AnchoredPath] -> AnchoredPath -> t -> Bool
filterPaths :: forall t. [AnchoredPath] -> AnchoredPath -> t -> Bool
filterPaths [AnchoredPath]
files AnchoredPath
p t
_ = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\AnchoredPath
x -> AnchoredPath
x AnchoredPath -> AnchoredPath -> Bool
`isPrefix` AnchoredPath
p Bool -> Bool -> Bool
|| AnchoredPath
p AnchoredPath -> AnchoredPath -> Bool
`isPrefix` AnchoredPath
x) [AnchoredPath]
files
floatSubPath :: SubPath -> AnchoredPath
floatSubPath :: SubPath -> AnchoredPath
floatSubPath = FilePath -> AnchoredPath
floatPath forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FilePathLike a => a -> FilePath
toFilePath
inDarcsdir :: AnchoredPath -> Bool
inDarcsdir :: AnchoredPath -> Bool
inDarcsdir (AnchoredPath (Name
x:[Name]
_)) | Name
x forall a. Eq a => a -> a -> Bool
== Name
darcsdirName = Bool
True
inDarcsdir AnchoredPath
_ = Bool
False
darcsdirName :: Name
darcsdirName :: Name
darcsdirName = FilePath -> Name
internalMakeName FilePath
darcsdir
isRoot :: AnchoredPath -> Bool
isRoot :: AnchoredPath -> Bool
isRoot (AnchoredPath [Name]
xs) = forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Name]
xs