    {-# 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