{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PackageImports #-}
{-# OPTIONS_HADDOCK hide #-}

module Codec.Archive.Tar.LongNames
  ( encodeLongNames
  , decodeLongNames
  , DecodeLongNamesError(..)
  ) where

import Codec.Archive.Tar.PackAscii
import Codec.Archive.Tar.Types
import Control.Exception
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as BL
import "os-string" System.OsString.Posix (PosixString, PosixChar)
import qualified "os-string" System.OsString.Posix as PS

-- | Errors raised by 'decodeLongNames'.
--
-- @since 0.6.0.0
data DecodeLongNamesError
  = TwoTypeKEntries
  -- ^ Two adjacent 'OtherEntryType' @\'K\'@ nodes.
  | TwoTypeLEntries
  -- ^ Two adjacent 'OtherEntryType' @\'L\'@ nodes.
  | NoLinkEntryAfterTypeKEntry
  -- ^ 'OtherEntryType' @\'K\'@ node is not followed by a 'SymbolicLink' / 'HardLink'.
  deriving (DecodeLongNamesError -> DecodeLongNamesError -> Bool
(DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> (DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> Eq DecodeLongNamesError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
== :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
$c/= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
/= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
Eq, Eq DecodeLongNamesError
Eq DecodeLongNamesError =>
(DecodeLongNamesError -> DecodeLongNamesError -> Ordering)
-> (DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> (DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> (DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> (DecodeLongNamesError -> DecodeLongNamesError -> Bool)
-> (DecodeLongNamesError
    -> DecodeLongNamesError -> DecodeLongNamesError)
-> (DecodeLongNamesError
    -> DecodeLongNamesError -> DecodeLongNamesError)
-> Ord DecodeLongNamesError
DecodeLongNamesError -> DecodeLongNamesError -> Bool
DecodeLongNamesError -> DecodeLongNamesError -> Ordering
DecodeLongNamesError
-> DecodeLongNamesError -> DecodeLongNamesError
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
$ccompare :: DecodeLongNamesError -> DecodeLongNamesError -> Ordering
compare :: DecodeLongNamesError -> DecodeLongNamesError -> Ordering
$c< :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
< :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
$c<= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
<= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
$c> :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
> :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
$c>= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
>= :: DecodeLongNamesError -> DecodeLongNamesError -> Bool
$cmax :: DecodeLongNamesError
-> DecodeLongNamesError -> DecodeLongNamesError
max :: DecodeLongNamesError
-> DecodeLongNamesError -> DecodeLongNamesError
$cmin :: DecodeLongNamesError
-> DecodeLongNamesError -> DecodeLongNamesError
min :: DecodeLongNamesError
-> DecodeLongNamesError -> DecodeLongNamesError
Ord, Int -> DecodeLongNamesError -> ShowS
[DecodeLongNamesError] -> ShowS
DecodeLongNamesError -> String
(Int -> DecodeLongNamesError -> ShowS)
-> (DecodeLongNamesError -> String)
-> ([DecodeLongNamesError] -> ShowS)
-> Show DecodeLongNamesError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecodeLongNamesError -> ShowS
showsPrec :: Int -> DecodeLongNamesError -> ShowS
$cshow :: DecodeLongNamesError -> String
show :: DecodeLongNamesError -> String
$cshowList :: [DecodeLongNamesError] -> ShowS
showList :: [DecodeLongNamesError] -> ShowS
Show)

instance Exception DecodeLongNamesError

-- | Translate high-level entries with POSIX 'FilePath's for files and symlinks
-- into entries suitable for serialization by emitting additional
-- 'OtherEntryType' @\'K\'@ and 'OtherEntryType' @\'L\'@ nodes.
--
-- Input 'FilePath's must be POSIX file names, not native ones.
--
-- @since 0.6.0.0
encodeLongNames
  :: GenEntry FilePath FilePath
  -> [Entry]
encodeLongNames :: GenEntry String String -> [Entry]
encodeLongNames GenEntry String String
e = ([Entry] -> [Entry])
-> (Entry -> [Entry] -> [Entry])
-> Maybe Entry
-> [Entry]
-> [Entry]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Entry] -> [Entry]
forall a. a -> a
id (:) Maybe Entry
mEntry ([Entry] -> [Entry]) -> [Entry] -> [Entry]
forall a b. (a -> b) -> a -> b
$ ([Entry] -> [Entry])
-> (Entry -> [Entry] -> [Entry])
-> Maybe Entry
-> [Entry]
-> [Entry]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Entry] -> [Entry]
forall a. a -> a
id (:) Maybe Entry
forall {whatever}. Maybe (GenEntry TarPath whatever)
mEntry' [Entry
e'']
  where
    (Maybe Entry
mEntry, GenEntry String LinkTarget
e') = GenEntry String String -> (Maybe Entry, GenEntry String LinkTarget)
forall tarPath.
GenEntry tarPath String
-> (Maybe Entry, GenEntry tarPath LinkTarget)
encodeLinkTarget GenEntry String String
e
    (Maybe (GenEntry TarPath whatever)
mEntry', Entry
e'') = GenEntry String LinkTarget
-> (Maybe (GenEntry TarPath whatever), Entry)
forall linkTarget whatever.
GenEntry String linkTarget
-> (Maybe (GenEntry TarPath whatever), GenEntry TarPath linkTarget)
encodeTarPath GenEntry String LinkTarget
e'

encodeTarPath
  :: GenEntry FilePath linkTarget
  -> (Maybe (GenEntry TarPath whatever), GenEntry TarPath linkTarget)
  -- ^ (LongLink entry, actual entry)
encodeTarPath :: forall linkTarget whatever.
GenEntry String linkTarget
-> (Maybe (GenEntry TarPath whatever), GenEntry TarPath linkTarget)
encodeTarPath GenEntry String linkTarget
e = case String -> ToTarPathResult
toTarPath' (GenEntry String linkTarget -> String
forall tarPath linkTarget. GenEntry tarPath linkTarget -> tarPath
entryTarPath GenEntry String linkTarget
e) of
  ToTarPathResult
FileNameEmpty -> (Maybe (GenEntry TarPath whatever)
forall a. Maybe a
Nothing, GenEntry String linkTarget
e { entryTarPath = TarPath mempty mempty })
  FileNameOK TarPath
tarPath -> (Maybe (GenEntry TarPath whatever)
forall a. Maybe a
Nothing, GenEntry String linkTarget
e { entryTarPath = tarPath })
  FileNameTooLong TarPath
tarPath -> (GenEntry TarPath whatever -> Maybe (GenEntry TarPath whatever)
forall a. a -> Maybe a
Just (GenEntry TarPath whatever -> Maybe (GenEntry TarPath whatever))
-> GenEntry TarPath whatever -> Maybe (GenEntry TarPath whatever)
forall a b. (a -> b) -> a -> b
$ String -> GenEntry TarPath whatever
forall linkTarget. String -> GenEntry TarPath linkTarget
longLinkEntry (String -> GenEntry TarPath whatever)
-> String -> GenEntry TarPath whatever
forall a b. (a -> b) -> a -> b
$ GenEntry String linkTarget -> String
forall tarPath linkTarget. GenEntry tarPath linkTarget -> tarPath
entryTarPath GenEntry String linkTarget
e, GenEntry String linkTarget
e { entryTarPath = tarPath })

encodeLinkTarget
  :: GenEntry tarPath FilePath
  -> (Maybe (GenEntry TarPath LinkTarget), GenEntry tarPath LinkTarget)
  -- ^ (LongLink symlink entry, actual entry)
encodeLinkTarget :: forall tarPath.
GenEntry tarPath String
-> (Maybe Entry, GenEntry tarPath LinkTarget)
encodeLinkTarget GenEntry tarPath String
e = case GenEntry tarPath String -> GenEntryContent String
forall tarPath linkTarget.
GenEntry tarPath linkTarget -> GenEntryContent linkTarget
entryContent GenEntry tarPath String
e of
  NormalFile ByteString
x FileSize
y -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = NormalFile x y })
  GenEntryContent String
Directory -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = Directory })
  SymbolicLink String
lnk -> let (Maybe Entry
mEntry, LinkTarget
lnk') = String -> (Maybe Entry, LinkTarget)
encodeLinkPath String
lnk in
    (Maybe Entry
mEntry, GenEntry tarPath String
e { entryContent = SymbolicLink lnk' })
  HardLink String
lnk -> let (Maybe Entry
mEntry, LinkTarget
lnk') = String -> (Maybe Entry, LinkTarget)
encodeLinkPath String
lnk in
    (Maybe Entry
mEntry, GenEntry tarPath String
e { entryContent = HardLink lnk' })
  CharacterDevice Int
x Int
y -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = CharacterDevice x y })
  BlockDevice Int
x Int
y -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = BlockDevice x y })
  GenEntryContent String
NamedPipe -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = NamedPipe })
  OtherEntryType Char
x ByteString
y FileSize
z -> (Maybe Entry
forall a. Maybe a
Nothing, GenEntry tarPath String
e { entryContent = OtherEntryType x y z })

encodeLinkPath
  :: FilePath
  -> (Maybe (GenEntry TarPath LinkTarget), LinkTarget)
encodeLinkPath :: String -> (Maybe Entry, LinkTarget)
encodeLinkPath String
lnk = case String -> ToTarPathResult
toTarPath' String
lnk of
  ToTarPathResult
FileNameEmpty -> (Maybe Entry
forall a. Maybe a
Nothing, PosixString -> LinkTarget
LinkTarget PosixString
forall a. Monoid a => a
mempty)
  FileNameOK (TarPath PosixString
name PosixString
prefix)
    | PosixString -> Bool
PS.null PosixString
prefix -> (Maybe Entry
forall a. Maybe a
Nothing, PosixString -> LinkTarget
LinkTarget PosixString
name)
    | Bool
otherwise -> (Entry -> Maybe Entry
forall a. a -> Maybe a
Just (Entry -> Maybe Entry) -> Entry -> Maybe Entry
forall a b. (a -> b) -> a -> b
$ String -> Entry
forall linkTarget. String -> GenEntry TarPath linkTarget
longSymLinkEntry String
lnk, PosixString -> LinkTarget
LinkTarget PosixString
name)
  FileNameTooLong (TarPath PosixString
name PosixString
_) ->
    (Entry -> Maybe Entry
forall a. a -> Maybe a
Just (Entry -> Maybe Entry) -> Entry -> Maybe Entry
forall a b. (a -> b) -> a -> b
$ String -> Entry
forall linkTarget. String -> GenEntry TarPath linkTarget
longSymLinkEntry String
lnk, PosixString -> LinkTarget
LinkTarget PosixString
name)

-- | Translate low-level entries (usually freshly deserialized) into
-- high-level entries with POSIX 'FilePath's for files and symlinks
-- by parsing and eliminating
-- 'OtherEntryType' @\'K\'@ and 'OtherEntryType' @\'L\'@ nodes.
--
-- Resolved 'FilePath's are still POSIX file names, not native ones.
--
-- @since 0.6.0.0
decodeLongNames
  :: Entries e
  -> GenEntries FilePath FilePath (Either e DecodeLongNamesError)
decodeLongNames :: forall e.
Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
decodeLongNames = Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing
  where
    go :: Maybe FilePath -> Maybe FilePath -> Entries e -> GenEntries FilePath FilePath (Either e DecodeLongNamesError)
    go :: forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
_ Maybe String
_ (Fail e
err) = Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (e -> Either e DecodeLongNamesError
forall a b. a -> Either a b
Left e
err)
    go Maybe String
_ Maybe String
_ GenEntries TarPath LinkTarget e
Done = GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. GenEntries tarPath linkTarget e
Done

    go Maybe String
Nothing Maybe String
Nothing (Next Entry
e GenEntries TarPath LinkTarget e
rest) = case Entry -> GenEntryContent LinkTarget
forall tarPath linkTarget.
GenEntry tarPath linkTarget -> GenEntryContent linkTarget
entryContent Entry
e of
      OtherEntryType Char
'K' ByteString
fn FileSize
_ ->
        Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go (String -> Maybe String
forall a. a -> Maybe a
Just (ByteString -> String
otherEntryPayloadToFilePath ByteString
fn)) Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest
      OtherEntryType Char
'L' ByteString
fn FileSize
_ ->
        Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing (String -> Maybe String
forall a. a -> Maybe a
Just (ByteString -> String
otherEntryPayloadToFilePath ByteString
fn)) GenEntries TarPath LinkTarget e
rest
      GenEntryContent LinkTarget
_ ->
        GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next (Entry -> GenEntry String String
castEntry Entry
e) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)

    go Maybe String
Nothing (Just String
path) (Next Entry
e GenEntries TarPath LinkTarget e
rest) = case Entry -> GenEntryContent LinkTarget
forall tarPath linkTarget.
GenEntry tarPath linkTarget -> GenEntryContent linkTarget
entryContent Entry
e of
      OtherEntryType Char
'K' ByteString
fn FileSize
_ ->
        Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go (String -> Maybe String
forall a. a -> Maybe a
Just (ByteString -> String
otherEntryPayloadToFilePath ByteString
fn)) (String -> Maybe String
forall a. a -> Maybe a
Just String
path) GenEntries TarPath LinkTarget e
rest
      OtherEntryType Char
'L' ByteString
_ FileSize
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
TwoTypeLEntries
      GenEntryContent LinkTarget
_ -> GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next ((Entry -> GenEntry String String
castEntry Entry
e) { entryTarPath = path }) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)

    go (Just String
link) Maybe String
Nothing (Next Entry
e GenEntries TarPath LinkTarget e
rest) = case Entry -> GenEntryContent LinkTarget
forall tarPath linkTarget.
GenEntry tarPath linkTarget -> GenEntryContent linkTarget
entryContent Entry
e of
      OtherEntryType Char
'K' ByteString
_ FileSize
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
TwoTypeKEntries
      OtherEntryType Char
'L' ByteString
fn FileSize
_ ->
        Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go (String -> Maybe String
forall a. a -> Maybe a
Just String
link) (String -> Maybe String
forall a. a -> Maybe a
Just (ByteString -> String
otherEntryPayloadToFilePath ByteString
fn)) GenEntries TarPath LinkTarget e
rest
      SymbolicLink{} ->
        GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next ((Entry -> GenEntry String String
castEntry Entry
e) { entryContent = SymbolicLink link }) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)
      HardLink{} ->
        GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next ((Entry -> GenEntry String String
castEntry Entry
e) { entryContent = HardLink link }) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)
      GenEntryContent LinkTarget
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
NoLinkEntryAfterTypeKEntry

    go (Just String
link) (Just String
path) (Next Entry
e GenEntries TarPath LinkTarget e
rest) = case Entry -> GenEntryContent LinkTarget
forall tarPath linkTarget.
GenEntry tarPath linkTarget -> GenEntryContent linkTarget
entryContent Entry
e of
      OtherEntryType Char
'K' ByteString
_ FileSize
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
TwoTypeKEntries
      OtherEntryType Char
'L' ByteString
_ FileSize
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
TwoTypeLEntries
      SymbolicLink{} ->
        GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next ((Entry -> GenEntry String String
castEntry Entry
e) { entryTarPath = path, entryContent = SymbolicLink link }) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)
      HardLink{} ->
        GenEntry String String
-> GenEntries String String (Either e DecodeLongNamesError)
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e.
GenEntry tarPath linkTarget
-> GenEntries tarPath linkTarget e
-> GenEntries tarPath linkTarget e
Next ((Entry -> GenEntry String String
castEntry Entry
e) { entryTarPath = path, entryContent = HardLink link }) (Maybe String
-> Maybe String
-> GenEntries TarPath LinkTarget e
-> GenEntries String String (Either e DecodeLongNamesError)
forall e.
Maybe String
-> Maybe String
-> Entries e
-> GenEntries String String (Either e DecodeLongNamesError)
go Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing GenEntries TarPath LinkTarget e
rest)
      GenEntryContent LinkTarget
_ ->
        Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall tarPath linkTarget e. e -> GenEntries tarPath linkTarget e
Fail (Either e DecodeLongNamesError
 -> GenEntries String String (Either e DecodeLongNamesError))
-> Either e DecodeLongNamesError
-> GenEntries String String (Either e DecodeLongNamesError)
forall a b. (a -> b) -> a -> b
$ DecodeLongNamesError -> Either e DecodeLongNamesError
forall a b. b -> Either a b
Right DecodeLongNamesError
NoLinkEntryAfterTypeKEntry

otherEntryPayloadToFilePath :: BL.ByteString -> FilePath
otherEntryPayloadToFilePath :: ByteString -> String
otherEntryPayloadToFilePath =
  PosixString -> String
fromPosixString (PosixString -> String)
-> (ByteString -> PosixString) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> PosixString
byteToPosixString (ByteString -> PosixString)
-> (ByteString -> ByteString) -> ByteString -> PosixString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> ByteString
B.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\0') (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict

castEntry :: Entry -> GenEntry FilePath FilePath
castEntry :: Entry -> GenEntry String String
castEntry Entry
e = Entry
e
  { entryTarPath = fromTarPathToPosixPath (entryTarPath e)
  , entryContent = castEntryContent (entryContent e)
  }

castEntryContent :: EntryContent -> GenEntryContent FilePath
castEntryContent :: GenEntryContent LinkTarget -> GenEntryContent String
castEntryContent = \case
  NormalFile ByteString
x FileSize
y -> ByteString -> FileSize -> GenEntryContent String
forall linkTarget.
ByteString -> FileSize -> GenEntryContent linkTarget
NormalFile ByteString
x FileSize
y
  GenEntryContent LinkTarget
Directory -> GenEntryContent String
forall linkTarget. GenEntryContent linkTarget
Directory
  SymbolicLink LinkTarget
linkTarget -> String -> GenEntryContent String
forall linkTarget. linkTarget -> GenEntryContent linkTarget
SymbolicLink (String -> GenEntryContent String)
-> String -> GenEntryContent String
forall a b. (a -> b) -> a -> b
$ LinkTarget -> String
fromLinkTargetToPosixPath LinkTarget
linkTarget
  HardLink LinkTarget
linkTarget -> String -> GenEntryContent String
forall linkTarget. linkTarget -> GenEntryContent linkTarget
HardLink (String -> GenEntryContent String)
-> String -> GenEntryContent String
forall a b. (a -> b) -> a -> b
$ LinkTarget -> String
fromLinkTargetToPosixPath LinkTarget
linkTarget
  CharacterDevice Int
x Int
y -> Int -> Int -> GenEntryContent String
forall linkTarget. Int -> Int -> GenEntryContent linkTarget
CharacterDevice Int
x Int
y
  BlockDevice Int
x Int
y -> Int -> Int -> GenEntryContent String
forall linkTarget. Int -> Int -> GenEntryContent linkTarget
BlockDevice Int
x Int
y
  GenEntryContent LinkTarget
NamedPipe -> GenEntryContent String
forall linkTarget. GenEntryContent linkTarget
NamedPipe
  OtherEntryType Char
x ByteString
y FileSize
z -> Char -> ByteString -> FileSize -> GenEntryContent String
forall linkTarget.
Char -> ByteString -> FileSize -> GenEntryContent linkTarget
OtherEntryType Char
x ByteString
y FileSize
z