-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Reading, writing and manipulating ".tar" archive files.
--
-- This library is for working with ".tar" archive files. It can
-- read and write a range of common variations of archive format
-- including V7, POSIX USTAR and GNU formats.
--
-- It provides support for packing and unpacking portable archives. This
-- makes it suitable for distribution but not backup because details like
-- file ownership and exact permissions are not preserved.
--
-- It also provides features for random access to archive content using
-- an index.
@package tar
@version 0.6.0.0
module Codec.Archive.Tar.Index.IntTrie
-- | A compact mapping from sequences of nats to nats.
--
-- NOTE: The tries in this module have values only at the leaves
-- (which correspond to files), they do not have values at the branch
-- points (which correspond to directories).
newtype IntTrie
IntTrie :: UArray Word32 Word32 -> IntTrie
-- | Build an IntTrie from a bunch of (key, value) pairs, where the
-- keys are sequences.
construct :: [([Key], Value)] -> IntTrie
-- | Convert the trie to a list
--
-- This is the left inverse to construct (modulo ordering).
toList :: IntTrie -> [([Key], Value)]
newtype IntTrieBuilder
IntTrieBuilder :: IntMap TrieNode -> IntTrieBuilder
empty :: IntTrieBuilder
insert :: [Key] -> Value -> IntTrieBuilder -> IntTrieBuilder
finalise :: IntTrieBuilder -> IntTrie
unfinalise :: IntTrie -> IntTrieBuilder
lookup :: IntTrie -> [Key] -> Maybe TrieLookup
data TrieLookup
Entry :: !Value -> TrieLookup
Completions :: Completions -> TrieLookup
serialise :: IntTrie -> Builder
serialiseSize :: IntTrie -> Int
deserialise :: ByteString -> Maybe (IntTrie, ByteString)
data TrieNode
TrieLeaf :: {-# UNPACK #-} !Word32 -> TrieNode
TrieNode :: !IntTrieBuilder -> TrieNode
type Completions = [(Key, TrieLookup)]
inserts :: [([Key], Value)] -> IntTrieBuilder -> IntTrieBuilder
completionsFrom :: IntTrie -> Word32 -> Completions
flattenTrie :: IntTrieBuilder -> [Word32]
tagLeaf :: Word32 -> Word32
tagNode :: Word32 -> Word32
-- | The most significant bit is used for tagging, see tagLeaf /
-- tagNode below, so morally it's Word31 only.
newtype Key
Key :: Word32 -> Key
[unKey] :: Key -> Word32
newtype Value
Value :: Word32 -> Value
[unValue] :: Value -> Word32
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.IntTrie
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.IntTrie
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.Key
instance GHC.Classes.Ord Codec.Archive.Tar.Index.IntTrie.Key
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.Key
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.Value
instance GHC.Classes.Ord Codec.Archive.Tar.Index.IntTrie.Value
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.Value
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.TrieLookup
instance GHC.Classes.Ord Codec.Archive.Tar.Index.IntTrie.TrieLookup
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.TrieLookup
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.IntTrieBuilder
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.IntTrieBuilder
instance GHC.Classes.Eq Codec.Archive.Tar.Index.IntTrie.TrieNode
instance GHC.Show.Show Codec.Archive.Tar.Index.IntTrie.TrieNode
module Codec.Archive.Tar.Index.StringTable
-- | An efficient mapping from strings to a dense set of integers.
data StringTable id
StringTable :: {-# UNPACK #-} !ByteString -> {-# UNPACK #-} !UArray Int32 Word32 -> {-# UNPACK #-} !UArray Int32 Int32 -> {-# UNPACK #-} !UArray Int32 Int32 -> StringTable id
-- | Look up a string in the token table. If the string is present, return
-- its corresponding index.
lookup :: Enum id => StringTable id -> ByteString -> Maybe id
-- | Given the index of a string in the table, return the string.
index :: Enum id => StringTable id -> id -> ByteString
-- | Given a list of strings, construct a StringTable mapping those
-- strings to a dense set of integers. Also return the ids for all the
-- strings used in the construction.
construct :: Enum id => [ByteString] -> StringTable id
data StringTableBuilder id
empty :: StringTableBuilder id
insert :: Enum id => ByteString -> StringTableBuilder id -> (StringTableBuilder id, id)
inserts :: Enum id => [ByteString] -> StringTableBuilder id -> (StringTableBuilder id, [id])
finalise :: Enum id => StringTableBuilder id -> StringTable id
unfinalise :: Enum id => StringTable id -> StringTableBuilder id
serialise :: StringTable id -> Builder
serialiseSize :: StringTable id -> Int
deserialiseV1 :: ByteString -> Maybe (StringTable id, ByteString)
deserialiseV2 :: ByteString -> Maybe (StringTable id, ByteString)
index' :: ByteString -> UArray Int32 Word32 -> Int32 -> ByteString
instance GHC.Show.Show (Codec.Archive.Tar.Index.StringTable.StringTable id)
instance GHC.Show.Show id => GHC.Show.Show (Codec.Archive.Tar.Index.StringTable.StringTableBuilder id)
instance GHC.Classes.Eq id => GHC.Classes.Eq (Codec.Archive.Tar.Index.StringTable.StringTableBuilder id)
instance (GHC.Classes.Eq id, GHC.Enum.Enum id) => GHC.Classes.Eq (Codec.Archive.Tar.Index.StringTable.StringTable id)
module Codec.Archive.Tar.PackAscii
-- | We should really migrate to OsPath from filepath
-- package, but for now let's not corrupt data silently.
packAscii :: HasCallStack => FilePath -> ByteString
-- | Types to represent the content of .tar archives.
module Codec.Archive.Tar.Types
-- | Polymorphic tar archive entry. High-level interfaces commonly work
-- with GenEntry FilePath FilePath, while low level
-- uses GenEntry TarPath LinkTarget.
data GenEntry tarPath linkTarget
Entry :: !tarPath -> !GenEntryContent linkTarget -> {-# UNPACK #-} !Permissions -> {-# UNPACK #-} !Ownership -> {-# UNPACK #-} !EpochTime -> !Format -> GenEntry tarPath linkTarget
-- | The path of the file or directory within the archive.
[entryTarPath] :: GenEntry tarPath linkTarget -> !tarPath
-- | The real content of the entry. For NormalFile this includes the
-- file data. An entry usually contains a NormalFile or a
-- Directory.
[entryContent] :: GenEntry tarPath linkTarget -> !GenEntryContent linkTarget
-- | File permissions (Unix style file mode).
[entryPermissions] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !Permissions
-- | The user and group to which this file belongs.
[entryOwnership] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !Ownership
-- | The time the file was last modified.
[entryTime] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !EpochTime
-- | The tar format the archive is using.
[entryFormat] :: GenEntry tarPath linkTarget -> !Format
-- | Monomorphic tar archive entry, ready for serialization /
-- deserialization.
type Entry = GenEntry TarPath LinkTarget
-- | Native FilePath of the file or directory within the archive.
entryPath :: GenEntry TarPath linkTarget -> FilePath
-- | Polymorphic content of a tar archive entry. High-level interfaces
-- commonly work with GenEntryContent FilePath, while low
-- level uses GenEntryContent LinkTarget.
--
-- Portable archives should contain only NormalFile and
-- Directory.
data GenEntryContent linkTarget
NormalFile :: ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
Directory :: GenEntryContent linkTarget
SymbolicLink :: !linkTarget -> GenEntryContent linkTarget
HardLink :: !linkTarget -> GenEntryContent linkTarget
CharacterDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
BlockDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
NamedPipe :: GenEntryContent linkTarget
OtherEntryType :: {-# UNPACK #-} !TypeCode -> ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
-- | Monomorphic content of a tar archive entry, ready for serialization /
-- deserialization.
type EntryContent = GenEntryContent LinkTarget
type FileSize = Int64
type Permissions = FileMode
data Ownership
Ownership :: String -> String -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Ownership
-- | The owner user name. Should be set to "" if unknown.
[ownerName] :: Ownership -> String
-- | The owner group name. Should be set to "" if unknown.
[groupName] :: Ownership -> String
-- | Numeric owner user id. Should be set to 0 if unknown.
[ownerId] :: Ownership -> {-# UNPACK #-} !Int
-- | Numeric owner group id. Should be set to 0 if unknown.
[groupId] :: Ownership -> {-# UNPACK #-} !Int
-- | The number of seconds since the UNIX epoch
type EpochTime = Int64
type TypeCode = Char
type DevMajor = Int
type DevMinor = Int
-- | There have been a number of extensions to the tar file format over the
-- years. They all share the basic entry fields and put more meta-data in
-- different extended headers.
data Format
-- | This is the classic Unix V7 tar format. It does not support owner and
-- group names, just numeric Ids. It also does not support device
-- numbers.
V7Format :: Format
-- | The "USTAR" format is an extension of the classic V7 format. It was
-- later standardised by POSIX. It has some restrictions but is the most
-- portable format.
UstarFormat :: Format
-- | The GNU tar implementation also extends the classic V7 format, though
-- in a slightly different way from the USTAR format. This is the only
-- format supporting long file names.
GnuFormat :: Format
-- | An GenEntry with all default values except for the file name
-- and type. It uses the portable USTAR/POSIX format (see
-- UstarFormat).
--
-- You can use this as a basis and override specific fields, eg:
--
--
-- (emptyEntry name HardLink) { linkTarget = target }
--
simpleEntry :: tarPath -> GenEntryContent linkTarget -> GenEntry tarPath linkTarget
-- | GNU extension to store a filepath too long to fit into
-- entryTarPath as OtherEntryType 'L' with the
-- full filepath as entryContent. The next entry must contain the
-- actual data with truncated entryTarPath.
--
-- See What exactly is the GNU tar ..@LongLink "trick"?
longLinkEntry :: FilePath -> GenEntry TarPath linkTarget
-- | GNU extension to store a link target too long to fit into
-- entryTarPath as OtherEntryType 'K' with the
-- full filepath as entryContent. The next entry must contain the
-- actual data with truncated entryTarPath.
longSymLinkEntry :: FilePath -> GenEntry TarPath linkTarget
-- | A tar GenEntry for a file.
--
-- Entry fields such as file permissions and ownership have default
-- values.
--
-- You can use this as a basis and override specific fields. For example
-- if you need an executable file you could use:
--
--
-- (fileEntry name content) { fileMode = executableFileMode }
--
fileEntry :: tarPath -> ByteString -> GenEntry tarPath linkTarget
-- | A tar GenEntry for a symbolic link.
symlinkEntry :: tarPath -> linkTarget -> GenEntry tarPath linkTarget
-- | A tar GenEntry for a directory.
--
-- Entry fields such as file permissions and ownership have default
-- values.
directoryEntry :: tarPath -> GenEntry tarPath linkTarget
-- | rw-r--r-- for normal files
ordinaryFilePermissions :: Permissions
-- | rw-r--r-- for normal files
symbolicLinkPermission :: Permissions
-- | rwxr-xr-x for executable files
executableFilePermissions :: Permissions
-- | rwxr-xr-x for directories
directoryPermissions :: Permissions
-- | The classic tar format allowed just 100 characters for the file name.
-- The USTAR format extended this with an extra 155 characters, however
-- it uses a complex method of splitting the name between the two
-- sections.
--
-- Instead of just putting any overflow into the extended area, it uses
-- the extended area as a prefix. The aggravating insane bit however is
-- that the prefix (if any) must only contain a directory prefix. That is
-- the split between the two areas must be on a directory separator
-- boundary. So there is no simple calculation to work out if a file name
-- is too long. Instead we have to try to find a valid split that makes
-- the name fit in the two areas.
--
-- The rationale presumably was to make it a bit more compatible with old
-- tar programs that only understand the classic format. A classic tar
-- would be able to extract the file name and possibly some dir prefix,
-- but not the full dir prefix. So the files would end up in the wrong
-- place, but that's probably better than ending up with the wrong names
-- too.
--
-- So it's understandable but rather annoying.
--
--
-- - Tar paths use Posix format (ie '/' directory separators),
-- irrespective of the local path conventions.
-- - The directory separator between the prefix and name is not
-- stored.
--
data TarPath
TarPath :: {-# UNPACK #-} !ByteString -> {-# UNPACK #-} !ByteString -> TarPath
-- | Convert a native FilePath to a TarPath.
--
-- The conversion may fail if the FilePath is empty or too long.
-- Use toTarPath' for a structured output.
toTarPath :: Bool -> FilePath -> Either String TarPath
-- | Convert a native FilePath to a TarPath. Directory paths
-- must always have a trailing /, this is not checked.
toTarPath' :: FilePath -> ToTarPathResult
-- | Return type of toTarPath'.
data ToTarPathResult
-- | FilePath was empty, but TarPath must be non-empty.
FileNameEmpty :: ToTarPathResult
-- | All good, this is just a normal TarPath.
FileNameOK :: TarPath -> ToTarPathResult
-- | FilePath was longer than 255 characters, TarPath
-- contains a truncated part only. An actual entry must be preceded by
-- longLinkEntry.
FileNameTooLong :: TarPath -> ToTarPathResult
-- | Convert a TarPath to a native FilePath.
--
-- The native FilePath will use the native directory separator but
-- it is not otherwise checked for validity or sanity. In particular:
--
--
-- - The tar path may be invalid as a native path, eg the file name
-- "nul" is not valid on Windows.
-- - The tar path may be an absolute path or may contain ".."
-- components. For security reasons this should not usually be allowed,
-- but it is your responsibility to check for these conditions (e.g.,
-- using checkEntrySecurity).
--
fromTarPath :: TarPath -> FilePath
-- | Convert a TarPath to a Unix/Posix FilePath.
--
-- The difference compared to fromTarPath is that it always
-- returns a Unix style path irrespective of the current operating
-- system.
--
-- This is useful to check how a TarPath would be interpreted on a
-- specific operating system, eg to perform portability checks.
fromTarPathToPosixPath :: TarPath -> FilePath
-- | Convert a TarPath to a Windows FilePath.
--
-- The only difference compared to fromTarPath is that it always
-- returns a Windows style path irrespective of the current operating
-- system.
--
-- This is useful to check how a TarPath would be interpreted on a
-- specific operating system, eg to perform portability checks.
fromTarPathToWindowsPath :: TarPath -> FilePath
-- | Convert a unix FilePath to a native FilePath.
fromFilePathToNative :: FilePath -> FilePath
-- | The tar format allows just 100 ASCII characters for the
-- SymbolicLink and HardLink entry types.
newtype LinkTarget
LinkTarget :: ByteString -> LinkTarget
-- | Convert a native FilePath to a tar LinkTarget. string is
-- longer than 100 characters or if it contains non-portable characters.
toLinkTarget :: FilePath -> Maybe LinkTarget
-- | Convert a tar LinkTarget to a native FilePath.
fromLinkTarget :: LinkTarget -> FilePath
-- | Convert a tar LinkTarget to a Unix/POSIX FilePath
-- ('/' path separators).
fromLinkTargetToPosixPath :: LinkTarget -> FilePath
-- | Convert a tar LinkTarget to a Windows FilePath
-- ('\\' path separators).
fromLinkTargetToWindowsPath :: LinkTarget -> FilePath
-- | Convert a unix FilePath to a Windows FilePath.
fromFilePathToWindowsPath :: FilePath -> FilePath
-- | Polymorphic sequence of archive entries. High-level interfaces
-- commonly work with GenEntries FilePath FilePath,
-- while low level uses GenEntries TarPath
-- LinkTarget.
--
-- The point of this type as opposed to just using a list is that it
-- makes the failure case explicit. We need this because the sequence of
-- entries we get from reading a tarball can include errors.
--
-- Converting from a list can be done with just foldr Next Done.
-- Converting back into a list can be done with foldEntries
-- however in that case you must be prepared to handle the Fail
-- case inherent in the Entries type.
--
-- The Monoid instance lets you concatenate archives or append
-- entries to an archive.
data GenEntries tarPath linkTarget e
Next :: GenEntry tarPath linkTarget -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget e
Done :: GenEntries tarPath linkTarget e
Fail :: e -> GenEntries tarPath linkTarget e
infixr 5 `Next`
-- | Monomorphic sequence of archive entries, ready for serialization /
-- deserialization.
type Entries e = GenEntries TarPath LinkTarget e
-- | This is like the standard map function on lists, but for
-- Entries. It includes failure as a extra possible outcome of the
-- mapping function.
--
-- If your mapping function cannot fail it may be more convenient to use
-- mapEntriesNoFail
mapEntries :: (GenEntry tarPath linkTarget -> Either e' (GenEntry tarPath linkTarget)) -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget (Either e e')
-- | Like mapEntries but the mapping function itself cannot fail.
mapEntriesNoFail :: (GenEntry tarPath linkTarget -> GenEntry tarPath linkTarget) -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget e
-- | This is like the standard foldr function on lists, but for
-- Entries. Compared to foldr it takes an extra function to
-- account for the possibility of failure.
--
-- This is used to consume a sequence of entries. For example it could be
-- used to scan a tarball for problems or to collect an index of the
-- contents.
foldEntries :: (GenEntry tarPath linkTarget -> a -> a) -> a -> (e -> a) -> GenEntries tarPath linkTarget e -> a
-- | A foldl-like function on Entries. It either returns the final
-- accumulator result, or the failure along with the intermediate
-- accumulator value.
foldlEntries :: (a -> GenEntry tarPath linkTarget -> a) -> a -> GenEntries tarPath linkTarget e -> Either (e, a) a
-- | This is like the standard unfoldr function on lists, but for
-- Entries. It includes failure as an extra possibility that the
-- stepper function may return.
--
-- It can be used to generate Entries from some other type. For
-- example it is used internally to lazily unfold entries from a
-- ByteString.
unfoldEntries :: (a -> Either e (Maybe (GenEntry tarPath linkTarget, a))) -> a -> GenEntries tarPath linkTarget e
instance GHC.Show.Show linkTarget => GHC.Show.Show (Codec.Archive.Tar.Types.GenEntryContent linkTarget)
instance GHC.Classes.Ord linkTarget => GHC.Classes.Ord (Codec.Archive.Tar.Types.GenEntryContent linkTarget)
instance GHC.Classes.Eq linkTarget => GHC.Classes.Eq (Codec.Archive.Tar.Types.GenEntryContent linkTarget)
instance GHC.Show.Show Codec.Archive.Tar.Types.Ownership
instance GHC.Classes.Ord Codec.Archive.Tar.Types.Ownership
instance GHC.Classes.Eq Codec.Archive.Tar.Types.Ownership
instance GHC.Show.Show Codec.Archive.Tar.Types.Format
instance GHC.Classes.Ord Codec.Archive.Tar.Types.Format
instance GHC.Classes.Eq Codec.Archive.Tar.Types.Format
instance (GHC.Show.Show tarPath, GHC.Show.Show linkTarget) => GHC.Show.Show (Codec.Archive.Tar.Types.GenEntry tarPath linkTarget)
instance (GHC.Classes.Eq tarPath, GHC.Classes.Eq linkTarget) => GHC.Classes.Eq (Codec.Archive.Tar.Types.GenEntry tarPath linkTarget)
instance GHC.Classes.Ord Codec.Archive.Tar.Types.TarPath
instance GHC.Classes.Eq Codec.Archive.Tar.Types.TarPath
instance GHC.Show.Show Codec.Archive.Tar.Types.LinkTarget
instance GHC.Classes.Ord Codec.Archive.Tar.Types.LinkTarget
instance GHC.Classes.Eq Codec.Archive.Tar.Types.LinkTarget
instance GHC.Show.Show Codec.Archive.Tar.Types.LinkTargetException
instance Data.Traversable.Traversable (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget)
instance Data.Foldable.Foldable (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget)
instance GHC.Base.Functor (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget)
instance (GHC.Show.Show tarPath, GHC.Show.Show linkTarget, GHC.Show.Show e) => GHC.Show.Show (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget e)
instance (GHC.Classes.Eq tarPath, GHC.Classes.Eq linkTarget, GHC.Classes.Eq e) => GHC.Classes.Eq (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget e)
instance GHC.Base.Semigroup (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget e)
instance GHC.Base.Monoid (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget e)
instance (Control.DeepSeq.NFData tarPath, Control.DeepSeq.NFData linkTarget, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Codec.Archive.Tar.Types.GenEntries tarPath linkTarget e)
instance GHC.Exception.Type.Exception Codec.Archive.Tar.Types.LinkTargetException
instance Control.DeepSeq.NFData Codec.Archive.Tar.Types.LinkTarget
instance Control.DeepSeq.NFData Codec.Archive.Tar.Types.TarPath
instance GHC.Show.Show Codec.Archive.Tar.Types.TarPath
instance (Control.DeepSeq.NFData tarPath, Control.DeepSeq.NFData linkTarget) => Control.DeepSeq.NFData (Codec.Archive.Tar.Types.GenEntry tarPath linkTarget)
instance Control.DeepSeq.NFData Codec.Archive.Tar.Types.Ownership
instance Control.DeepSeq.NFData linkTarget => Control.DeepSeq.NFData (Codec.Archive.Tar.Types.GenEntryContent linkTarget)
module Codec.Archive.Tar.Read
-- | Convert a data stream in the tar file format into an internal data
-- structure. Decoding errors are reported by the Fail constructor
-- of the Entries type.
--
--
-- - The conversion is done lazily.
--
read :: ByteString -> Entries FormatError
-- | Errors that can be encountered when parsing a Tar archive.
data FormatError
TruncatedArchive :: FormatError
ShortTrailer :: FormatError
BadTrailer :: FormatError
TrailingJunk :: FormatError
ChecksumIncorrect :: FormatError
NotTarFormat :: FormatError
UnrecognisedTarFormat :: FormatError
HeaderBadNumericEncoding :: FormatError
instance GHC.Show.Show Codec.Archive.Tar.Read.FormatError
instance GHC.Classes.Eq Codec.Archive.Tar.Read.FormatError
instance GHC.Exception.Type.Exception Codec.Archive.Tar.Read.FormatError
instance Control.DeepSeq.NFData Codec.Archive.Tar.Read.FormatError
module Codec.Archive.Tar.LongNames
-- | Translate high-level entries with POSIX FilePaths for files and
-- symlinks into entries suitable for serialization by emitting
-- additional OtherEntryType 'K' and
-- OtherEntryType 'L' nodes.
--
-- Input FilePaths must be POSIX file names, not native ones.
encodeLongNames :: GenEntry FilePath FilePath -> [Entry]
-- | Translate low-level entries (usually freshly deserialized) into
-- high-level entries with POSIX FilePaths for files and symlinks
-- by parsing and eliminating OtherEntryType 'K' and
-- OtherEntryType 'L' nodes.
--
-- Resolved FilePaths are still POSIX file names, not native ones.
decodeLongNames :: Entries e -> GenEntries FilePath FilePath (Either e DecodeLongNamesError)
-- | Errors raised by decodeLongNames.
data DecodeLongNamesError
-- | Two adjacent OtherEntryType 'K' nodes.
TwoTypeKEntries :: DecodeLongNamesError
-- | Two adjacent OtherEntryType 'L' nodes.
TwoTypeLEntries :: DecodeLongNamesError
-- | OtherEntryType 'K' node is not followed by a
-- SymbolicLink / HardLink.
NoLinkEntryAfterTypeKEntry :: DecodeLongNamesError
instance GHC.Show.Show Codec.Archive.Tar.LongNames.DecodeLongNamesError
instance GHC.Classes.Ord Codec.Archive.Tar.LongNames.DecodeLongNamesError
instance GHC.Classes.Eq Codec.Archive.Tar.LongNames.DecodeLongNamesError
instance GHC.Exception.Type.Exception Codec.Archive.Tar.LongNames.DecodeLongNamesError
module Codec.Archive.Tar.Index.Internal
-- | An index of the entries in a tar file.
--
-- This index type is designed to be quite compact and suitable to store
-- either on disk or in memory.
data TarIndex
TarIndex :: {-# UNPACK #-} !StringTable PathComponentId -> {-# UNPACK #-} !IntTrie -> {-# UNPACK #-} !TarEntryOffset -> TarIndex
-- | Look up a given filepath in the TarIndex. It may return a
-- TarFileEntry containing the TarEntryOffset of the file
-- within the tar file, or if the filepath identifies a directory then it
-- returns a TarDir containing the list of files within that
-- directory.
--
-- Given the TarEntryOffset you can then use one of the I/O
-- operations:
--
--
lookup :: TarIndex -> FilePath -> Maybe TarIndexEntry
-- | The result of lookup in a TarIndex. It can either be a
-- file directly, or a directory entry containing further entries (and
-- all subdirectories recursively). Note that the subtrees are
-- constructed lazily, so it's cheaper if you don't look at them.
data TarIndexEntry
TarFileEntry :: {-# UNPACK #-} !TarEntryOffset -> TarIndexEntry
TarDir :: [(FilePath, TarIndexEntry)] -> TarIndexEntry
-- | All the files in the index with their corresponding
-- TarEntryOffsets.
--
-- Note that the files are in no special order. If you intend to read all
-- or most files then is is recommended to sort by the
-- TarEntryOffset.
toList :: TarIndex -> [(FilePath, TarEntryOffset)]
newtype PathComponentId
PathComponentId :: Int -> PathComponentId
-- | An offset within a tar file. Use hReadEntry,
-- hReadEntryHeader or hSeekEntryOffset.
--
-- This is actually a tar "record" number, not a byte offset.
type TarEntryOffset = Word32
-- | Reads an entire GenEntry at the given TarEntryOffset in
-- the tar file. The Handle must be open for reading and be
-- seekable.
--
-- This reads the whole entry into memory strictly, not incrementally.
-- For more control, use hReadEntryHeader and then read the entry
-- content manually.
hReadEntry :: Handle -> TarEntryOffset -> IO Entry
-- | Read the header for a GenEntry at the given
-- TarEntryOffset in the tar file. The entryContent will
-- contain the correct metadata but an empty file content. The
-- Handle must be open for reading and be seekable.
--
-- The Handle position is advanced to the beginning of the entry
-- content (if any). You must check the entryContent to see if the
-- entry is of type NormalFile. If it is, the NormalFile
-- gives the content length and you are free to read this much data from
-- the Handle.
--
--
-- entry <- Tar.hReadEntryHeader hnd
-- case Tar.entryContent entry of
-- Tar.NormalFile _ size -> do content <- BS.hGet hnd size
-- ...
--
--
-- Of course you don't have to read it all in one go (as
-- hReadEntry does), you can use any appropriate method to read it
-- incrementally.
--
-- In addition to I/O errors, this can throw a FormatError if the
-- offset is wrong, or if the file is not valid tar format.
--
-- There is also the lower level operation hSeekEntryOffset.
hReadEntryHeader :: Handle -> TarEntryOffset -> IO Entry
-- | Build a TarIndex from a sequence of tar Entries. The
-- Entries are assumed to start at offset 0 within a
-- file.
build :: Entries e -> Either e TarIndex
-- | The intermediate type used for incremental construction of a
-- TarIndex.
data IndexBuilder
-- | The initial empty IndexBuilder.
empty :: IndexBuilder
-- | Add the next GenEntry into the IndexBuilder.
addNextEntry :: Entry -> IndexBuilder -> IndexBuilder
-- | Use this function if you want to skip some entries and not add them to
-- the final TarIndex.
skipNextEntry :: Entry -> IndexBuilder -> IndexBuilder
-- | Finish accumulating GenEntry information and build the compact
-- TarIndex lookup structure.
finalise :: IndexBuilder -> TarIndex
-- | Resume building an existing index
--
-- A TarIndex is optimized for a highly compact and efficient
-- in-memory representation. This, however, makes it read-only. If you
-- have an existing TarIndex for a large file, and want to add to
-- it, you can translate the TarIndex back to an
-- IndexBuilder. Be aware that this is a relatively costly
-- operation (linear in the size of the TarIndex), though still
-- faster than starting again from scratch.
--
-- This is the left inverse to finalise (modulo ordering).
unfinalise :: TarIndex -> IndexBuilder
-- | The TarIndex is compact in memory, and it has a similarly
-- compact external representation.
serialise :: TarIndex -> ByteString
-- | Read the external representation back into a TarIndex.
deserialise :: ByteString -> Maybe (TarIndex, ByteString)
-- | This is a low level variant on hReadEntryHeader, that can be
-- used to iterate through a tar file, entry by entry.
--
-- It has a few differences compared to hReadEntryHeader:
--
--
-- - It returns an indication when the end of the tar file is
-- reached.
-- - It does not move the Handle position to the
-- beginning of the entry content.
-- - It returns the TarEntryOffset of the next entry.
--
--
-- After this action, the Handle position is not in any useful
-- place. If you want to skip to the next entry, take the
-- TarEntryOffset returned and use hReadEntryHeaderOrEof
-- again. Or if having inspected the GenEntry header you want to
-- read the entry content (if it has one) then use
-- hSeekEntryContentOffset on the original input
-- TarEntryOffset.
hReadEntryHeaderOrEof :: Handle -> TarEntryOffset -> IO (Maybe (Entry, TarEntryOffset))
-- | Set the Handle position to the position corresponding to the
-- given TarEntryOffset.
--
-- This position is where the entry metadata can be read. If you already
-- know the entry has a body (and perhaps know it's length), you may wish
-- to seek to the body content directly using
-- hSeekEntryContentOffset.
hSeekEntryOffset :: Handle -> TarEntryOffset -> IO ()
-- | Set the Handle position to the entry content position
-- corresponding to the given TarEntryOffset.
--
-- This position is where the entry content can be read using ordinary
-- I/O operations (though you have to know in advance how big the entry
-- content is). This is only valid if you already know the
-- entry has a body (i.e. is a normal file).
hSeekEntryContentOffset :: Handle -> TarEntryOffset -> IO ()
-- | Seek to the end of a tar file, to the position where new entries can
-- be appended, and return that TarEntryOffset.
--
-- If you have a valid TarIndex for this tar file then you should
-- supply it because it allows seeking directly to the correct location.
--
-- If you do not have an index, then this becomes an expensive linear
-- operation because we have to read each tar entry header from the
-- beginning to find the location immediately after the last entry (this
-- is because tar files have a variable length trailer and we cannot
-- reliably find that by starting at the end). In this mode, it will fail
-- with an exception if the file is not in fact in the tar format.
hSeekEndEntryOffset :: Handle -> Maybe TarIndex -> IO TarEntryOffset
-- | Calculate the TarEntryOffset of the next entry, given the size
-- and offset of the current entry.
--
-- This is much like using skipNextEntry and
-- indexNextEntryOffset, but without using an IndexBuilder.
nextEntryOffset :: Entry -> TarEntryOffset -> TarEntryOffset
-- | This is the offset immediately following the last entry in the tar
-- file. This can be useful to append further entries into the tar file.
-- Use with hSeekEntryOffset, or just use
-- hSeekEndEntryOffset directly.
indexEndEntryOffset :: TarIndex -> TarEntryOffset
-- | This is the offset immediately following the entry most recently added
-- to the IndexBuilder. You might use this if you need to know the
-- offsets but don't want to use the TarIndex lookup structure.
-- Use with hSeekEntryOffset. See also nextEntryOffset.
indexNextEntryOffset :: IndexBuilder -> TarEntryOffset
toComponentIds :: StringTable PathComponentId -> FilePath -> Maybe [PathComponentId]
serialiseLBS :: TarIndex -> ByteString
serialiseSize :: TarIndex -> Int
instance GHC.Show.Show Codec.Archive.Tar.Index.Internal.PathComponentId
instance GHC.Enum.Enum Codec.Archive.Tar.Index.Internal.PathComponentId
instance GHC.Classes.Ord Codec.Archive.Tar.Index.Internal.PathComponentId
instance GHC.Classes.Eq Codec.Archive.Tar.Index.Internal.PathComponentId
instance GHC.Show.Show Codec.Archive.Tar.Index.Internal.TarIndexEntry
instance GHC.Show.Show Codec.Archive.Tar.Index.Internal.TarIndex
instance GHC.Classes.Eq Codec.Archive.Tar.Index.Internal.TarIndex
instance GHC.Show.Show Codec.Archive.Tar.Index.Internal.IndexBuilder
instance GHC.Classes.Eq Codec.Archive.Tar.Index.Internal.IndexBuilder
instance Control.DeepSeq.NFData Codec.Archive.Tar.Index.Internal.IndexBuilder
instance Control.DeepSeq.NFData Codec.Archive.Tar.Index.Internal.TarIndex
-- | Random access to the content of a .tar archive.
--
-- This module uses common names and so is designed to be imported
-- qualified:
--
--
-- import qualified Codec.Archive.Tar.Index as TarIndex
--
module Codec.Archive.Tar.Index
-- | An index of the entries in a tar file.
--
-- This index type is designed to be quite compact and suitable to store
-- either on disk or in memory.
data TarIndex
-- | Look up a given filepath in the TarIndex. It may return a
-- TarFileEntry containing the TarEntryOffset of the file
-- within the tar file, or if the filepath identifies a directory then it
-- returns a TarDir containing the list of files within that
-- directory.
--
-- Given the TarEntryOffset you can then use one of the I/O
-- operations:
--
--
lookup :: TarIndex -> FilePath -> Maybe TarIndexEntry
-- | The result of lookup in a TarIndex. It can either be a
-- file directly, or a directory entry containing further entries (and
-- all subdirectories recursively). Note that the subtrees are
-- constructed lazily, so it's cheaper if you don't look at them.
data TarIndexEntry
TarFileEntry :: {-# UNPACK #-} !TarEntryOffset -> TarIndexEntry
TarDir :: [(FilePath, TarIndexEntry)] -> TarIndexEntry
-- | All the files in the index with their corresponding
-- TarEntryOffsets.
--
-- Note that the files are in no special order. If you intend to read all
-- or most files then is is recommended to sort by the
-- TarEntryOffset.
toList :: TarIndex -> [(FilePath, TarEntryOffset)]
-- | An offset within a tar file. Use hReadEntry,
-- hReadEntryHeader or hSeekEntryOffset.
--
-- This is actually a tar "record" number, not a byte offset.
type TarEntryOffset = Word32
-- | Reads an entire GenEntry at the given TarEntryOffset in
-- the tar file. The Handle must be open for reading and be
-- seekable.
--
-- This reads the whole entry into memory strictly, not incrementally.
-- For more control, use hReadEntryHeader and then read the entry
-- content manually.
hReadEntry :: Handle -> TarEntryOffset -> IO Entry
-- | Read the header for a GenEntry at the given
-- TarEntryOffset in the tar file. The entryContent will
-- contain the correct metadata but an empty file content. The
-- Handle must be open for reading and be seekable.
--
-- The Handle position is advanced to the beginning of the entry
-- content (if any). You must check the entryContent to see if the
-- entry is of type NormalFile. If it is, the NormalFile
-- gives the content length and you are free to read this much data from
-- the Handle.
--
--
-- entry <- Tar.hReadEntryHeader hnd
-- case Tar.entryContent entry of
-- Tar.NormalFile _ size -> do content <- BS.hGet hnd size
-- ...
--
--
-- Of course you don't have to read it all in one go (as
-- hReadEntry does), you can use any appropriate method to read it
-- incrementally.
--
-- In addition to I/O errors, this can throw a FormatError if the
-- offset is wrong, or if the file is not valid tar format.
--
-- There is also the lower level operation hSeekEntryOffset.
hReadEntryHeader :: Handle -> TarEntryOffset -> IO Entry
-- | Build a TarIndex from a sequence of tar Entries. The
-- Entries are assumed to start at offset 0 within a
-- file.
build :: Entries e -> Either e TarIndex
-- | The intermediate type used for incremental construction of a
-- TarIndex.
data IndexBuilder
-- | The initial empty IndexBuilder.
empty :: IndexBuilder
-- | Add the next GenEntry into the IndexBuilder.
addNextEntry :: Entry -> IndexBuilder -> IndexBuilder
-- | Use this function if you want to skip some entries and not add them to
-- the final TarIndex.
skipNextEntry :: Entry -> IndexBuilder -> IndexBuilder
-- | Finish accumulating GenEntry information and build the compact
-- TarIndex lookup structure.
finalise :: IndexBuilder -> TarIndex
-- | Resume building an existing index
--
-- A TarIndex is optimized for a highly compact and efficient
-- in-memory representation. This, however, makes it read-only. If you
-- have an existing TarIndex for a large file, and want to add to
-- it, you can translate the TarIndex back to an
-- IndexBuilder. Be aware that this is a relatively costly
-- operation (linear in the size of the TarIndex), though still
-- faster than starting again from scratch.
--
-- This is the left inverse to finalise (modulo ordering).
unfinalise :: TarIndex -> IndexBuilder
-- | The TarIndex is compact in memory, and it has a similarly
-- compact external representation.
serialise :: TarIndex -> ByteString
-- | Read the external representation back into a TarIndex.
deserialise :: ByteString -> Maybe (TarIndex, ByteString)
-- | This is a low level variant on hReadEntryHeader, that can be
-- used to iterate through a tar file, entry by entry.
--
-- It has a few differences compared to hReadEntryHeader:
--
--
-- - It returns an indication when the end of the tar file is
-- reached.
-- - It does not move the Handle position to the
-- beginning of the entry content.
-- - It returns the TarEntryOffset of the next entry.
--
--
-- After this action, the Handle position is not in any useful
-- place. If you want to skip to the next entry, take the
-- TarEntryOffset returned and use hReadEntryHeaderOrEof
-- again. Or if having inspected the GenEntry header you want to
-- read the entry content (if it has one) then use
-- hSeekEntryContentOffset on the original input
-- TarEntryOffset.
hReadEntryHeaderOrEof :: Handle -> TarEntryOffset -> IO (Maybe (Entry, TarEntryOffset))
-- | Set the Handle position to the position corresponding to the
-- given TarEntryOffset.
--
-- This position is where the entry metadata can be read. If you already
-- know the entry has a body (and perhaps know it's length), you may wish
-- to seek to the body content directly using
-- hSeekEntryContentOffset.
hSeekEntryOffset :: Handle -> TarEntryOffset -> IO ()
-- | Set the Handle position to the entry content position
-- corresponding to the given TarEntryOffset.
--
-- This position is where the entry content can be read using ordinary
-- I/O operations (though you have to know in advance how big the entry
-- content is). This is only valid if you already know the
-- entry has a body (i.e. is a normal file).
hSeekEntryContentOffset :: Handle -> TarEntryOffset -> IO ()
-- | Seek to the end of a tar file, to the position where new entries can
-- be appended, and return that TarEntryOffset.
--
-- If you have a valid TarIndex for this tar file then you should
-- supply it because it allows seeking directly to the correct location.
--
-- If you do not have an index, then this becomes an expensive linear
-- operation because we have to read each tar entry header from the
-- beginning to find the location immediately after the last entry (this
-- is because tar files have a variable length trailer and we cannot
-- reliably find that by starting at the end). In this mode, it will fail
-- with an exception if the file is not in fact in the tar format.
hSeekEndEntryOffset :: Handle -> Maybe TarIndex -> IO TarEntryOffset
-- | Calculate the TarEntryOffset of the next entry, given the size
-- and offset of the current entry.
--
-- This is much like using skipNextEntry and
-- indexNextEntryOffset, but without using an IndexBuilder.
nextEntryOffset :: Entry -> TarEntryOffset -> TarEntryOffset
-- | This is the offset immediately following the last entry in the tar
-- file. This can be useful to append further entries into the tar file.
-- Use with hSeekEntryOffset, or just use
-- hSeekEndEntryOffset directly.
indexEndEntryOffset :: TarIndex -> TarEntryOffset
-- | This is the offset immediately following the entry most recently added
-- to the IndexBuilder. You might use this if you need to know the
-- offsets but don't want to use the TarIndex lookup structure.
-- Use with hSeekEntryOffset. See also nextEntryOffset.
indexNextEntryOffset :: IndexBuilder -> TarEntryOffset
-- | Perform various checks on tar file entries.
module Codec.Archive.Tar.Check.Internal
-- | This function checks a sequence of tar entries for file name security
-- problems. It checks that:
--
--
-- - file paths are not absolute
-- - file paths do not refer outside of the archive
-- - file names are valid
--
--
-- These checks are from the perspective of the current OS. That means we
-- check for "C:blah" files on Windows and "/blah" files on
-- Unix. For archive entry types HardLink and SymbolicLink
-- the same checks are done for the link target. A failure in any entry
-- terminates the sequence of entries with an error.
checkSecurity :: Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) FileNameError)
-- | Worker of checkSecurity.
checkEntrySecurity :: GenEntry FilePath FilePath -> Maybe FileNameError
-- | Errors arising from tar file names being in some way invalid or
-- dangerous
data FileNameError
InvalidFileName :: FilePath -> FileNameError
AbsoluteFileName :: FilePath -> FileNameError
UnsafeLinkTarget :: FilePath -> FileNameError
-- | This function checks a sequence of tar entries for being a "tar bomb".
-- This means that the tar file does not follow the standard convention
-- that all entries are within a single subdirectory, e.g. a file
-- "foo.tar" would usually have all entries within the "foo/"
-- subdirectory.
--
-- Given the expected subdirectory, this function checks all entries are
-- within that subdirectroy.
--
-- Note: This check must be used in conjunction with checkSecurity
-- (or checkPortability).
checkTarbomb :: FilePath -> Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) TarBombError)
-- | Worker of checkTarbomb.
checkEntryTarbomb :: FilePath -> GenEntry FilePath linkTarget -> Maybe TarBombError
-- | An error that occurs if a tar file is a "tar bomb" that would extract
-- files outside of the intended directory.
data TarBombError
TarBombError :: FilePath -> FilePath -> TarBombError
-- | This function checks a sequence of tar entries for a number of
-- portability issues. It will complain if:
--
--
-- - The old "Unix V7" or "gnu" formats are used. For maximum
-- portability only the POSIX standard "ustar" format should be
-- used.
-- - A non-portable entry type is used. Only ordinary files, hard
-- links, symlinks and directories are portable. Device files, pipes and
-- others are not portable between all common operating systems.
-- - Non-ASCII characters are used in file names. There is no agreed
-- portable convention for Unicode or other extended character sets in
-- file names in tar archives.
-- - File names that would not be portable to both Unix and Windows.
-- This check includes characters that are valid in both systems and the
-- '/' vs '\' directory separator conventions.
--
checkPortability :: Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) PortabilityError)
-- | Worker of checkPortability.
checkEntryPortability :: GenEntry FilePath linkTarget -> Maybe PortabilityError
-- | Portability problems in a tar archive
data PortabilityError
NonPortableFormat :: Format -> PortabilityError
NonPortableFileType :: PortabilityError
NonPortableEntryNameChar :: FilePath -> PortabilityError
NonPortableFileName :: PortabilityPlatform -> FileNameError -> PortabilityError
-- | The name of a platform that portability issues arise from
type PortabilityPlatform = String
instance GHC.Exception.Type.Exception Codec.Archive.Tar.Check.Internal.PortabilityError
instance GHC.Show.Show Codec.Archive.Tar.Check.Internal.PortabilityError
instance GHC.Exception.Type.Exception Codec.Archive.Tar.Check.Internal.TarBombError
instance GHC.Show.Show Codec.Archive.Tar.Check.Internal.TarBombError
instance GHC.Show.Show Codec.Archive.Tar.Check.Internal.FileNameError
instance GHC.Exception.Type.Exception Codec.Archive.Tar.Check.Internal.FileNameError
module Codec.Archive.Tar.Pack
-- | Creates a tar archive from a list of directory or files. Any
-- directories specified will have their contents included recursively.
-- Paths in the archive will be relative to the given base directory.
--
-- This is a portable implementation of packing suitable for portable
-- archives. In particular it only constructs NormalFile,
-- Directory and SymbolicLink entries. Hard links are
-- treated like ordinary files. Special files like FIFOs (named pipes),
-- sockets or device files will cause problems.
--
-- An exception will be thrown for any file names that are too long to
-- represent as a TarPath.
--
--
-- - This function returns results lazily. Subdirectories are scanned
-- and files are read one by one as the list of entries is consumed.
--
pack :: FilePath -> [FilePath] -> IO [Entry]
-- | Like pack, but allows to specify additional sanity/security
-- checks on the input filenames. This is useful if you know which check
-- will be used on client side in unpack / unpackAndCheck.
packAndCheck :: (GenEntry FilePath FilePath -> Maybe SomeException) -> FilePath -> [FilePath] -> IO [Entry]
-- | Construct a tar GenEntry based on a local file.
--
-- This sets the entry size, the data contained in the file and the
-- file's modification time. If the file is executable then that
-- information is also preserved. File ownership and detailed permissions
-- are not preserved.
--
--
-- - The file contents is read lazily.
--
packFileEntry :: FilePath -> tarPath -> IO (GenEntry tarPath linkTarget)
-- | Construct a tar GenEntry based on a local directory (but not
-- its contents).
--
-- The only attribute of the directory that is used is its modification
-- time. Directory ownership and detailed permissions are not preserved.
packDirectoryEntry :: FilePath -> tarPath -> IO (GenEntry tarPath linkTarget)
-- | Construct a tar GenEntry based on a local symlink.
--
-- This automatically checks symlink safety via
-- checkEntrySecurity.
packSymlinkEntry :: FilePath -> tarPath -> IO (GenEntry tarPath FilePath)
-- | GNU extension to store a filepath too long to fit into
-- entryTarPath as OtherEntryType 'L' with the
-- full filepath as entryContent. The next entry must contain the
-- actual data with truncated entryTarPath.
--
-- See What exactly is the GNU tar ..@LongLink "trick"?
longLinkEntry :: FilePath -> GenEntry TarPath linkTarget
-- | This is a utility function, much like listDirectory. The
-- difference is that it includes the contents of subdirectories.
--
-- The paths returned are all relative to the top directory. Directory
-- paths are distinguishable by having a trailing path separator (see
-- hasTrailingPathSeparator).
--
-- All directories are listed before the files that they contain. Amongst
-- the contents of a directory, subdirectories are listed after normal
-- files. The overall result is that files within a directory will be
-- together in a single contiguous group. This tends to improve file
-- layout and IO performance when creating or extracting tar archives.
--
--
-- - This function returns results lazily. Subdirectories are not
-- scanned until the files entries in the parent directory have been
-- consumed. If the source directory structure changes before the result
-- is used, the behaviour is undefined.
--
getDirectoryContentsRecursive :: FilePath -> IO [FilePath]
-- | Types and functions to manipulate tar entries.
--
-- While the Codec.Archive.Tar module provides only the simple
-- high level API, this module provides full access to the details of tar
-- entries. This lets you inspect all the meta-data, construct entries
-- and handle error cases more precisely.
--
-- This module uses common names and so is designed to be imported
-- qualified:
--
--
-- import qualified Codec.Archive.Tar as Tar
-- import qualified Codec.Archive.Tar.Entry as Tar
--
module Codec.Archive.Tar.Entry
-- | Polymorphic tar archive entry. High-level interfaces commonly work
-- with GenEntry FilePath FilePath, while low level
-- uses GenEntry TarPath LinkTarget.
data GenEntry tarPath linkTarget
Entry :: !tarPath -> !GenEntryContent linkTarget -> {-# UNPACK #-} !Permissions -> {-# UNPACK #-} !Ownership -> {-# UNPACK #-} !EpochTime -> !Format -> GenEntry tarPath linkTarget
-- | The path of the file or directory within the archive.
[entryTarPath] :: GenEntry tarPath linkTarget -> !tarPath
-- | The real content of the entry. For NormalFile this includes the
-- file data. An entry usually contains a NormalFile or a
-- Directory.
[entryContent] :: GenEntry tarPath linkTarget -> !GenEntryContent linkTarget
-- | File permissions (Unix style file mode).
[entryPermissions] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !Permissions
-- | The user and group to which this file belongs.
[entryOwnership] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !Ownership
-- | The time the file was last modified.
[entryTime] :: GenEntry tarPath linkTarget -> {-# UNPACK #-} !EpochTime
-- | The tar format the archive is using.
[entryFormat] :: GenEntry tarPath linkTarget -> !Format
-- | Monomorphic tar archive entry, ready for serialization /
-- deserialization.
type Entry = GenEntry TarPath LinkTarget
-- | Native FilePath of the file or directory within the archive.
entryPath :: GenEntry TarPath linkTarget -> FilePath
-- | Polymorphic content of a tar archive entry. High-level interfaces
-- commonly work with GenEntryContent FilePath, while low
-- level uses GenEntryContent LinkTarget.
--
-- Portable archives should contain only NormalFile and
-- Directory.
data GenEntryContent linkTarget
NormalFile :: ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
Directory :: GenEntryContent linkTarget
SymbolicLink :: !linkTarget -> GenEntryContent linkTarget
HardLink :: !linkTarget -> GenEntryContent linkTarget
CharacterDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
BlockDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
NamedPipe :: GenEntryContent linkTarget
OtherEntryType :: {-# UNPACK #-} !TypeCode -> ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
-- | Monomorphic content of a tar archive entry, ready for serialization /
-- deserialization.
type EntryContent = GenEntryContent LinkTarget
data Ownership
Ownership :: String -> String -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Ownership
-- | The owner user name. Should be set to "" if unknown.
[ownerName] :: Ownership -> String
-- | The owner group name. Should be set to "" if unknown.
[groupName] :: Ownership -> String
-- | Numeric owner user id. Should be set to 0 if unknown.
[ownerId] :: Ownership -> {-# UNPACK #-} !Int
-- | Numeric owner group id. Should be set to 0 if unknown.
[groupId] :: Ownership -> {-# UNPACK #-} !Int
type FileSize = Int64
type Permissions = FileMode
-- | The number of seconds since the UNIX epoch
type EpochTime = Int64
type DevMajor = Int
type DevMinor = Int
type TypeCode = Char
-- | There have been a number of extensions to the tar file format over the
-- years. They all share the basic entry fields and put more meta-data in
-- different extended headers.
data Format
-- | This is the classic Unix V7 tar format. It does not support owner and
-- group names, just numeric Ids. It also does not support device
-- numbers.
V7Format :: Format
-- | The "USTAR" format is an extension of the classic V7 format. It was
-- later standardised by POSIX. It has some restrictions but is the most
-- portable format.
UstarFormat :: Format
-- | The GNU tar implementation also extends the classic V7 format, though
-- in a slightly different way from the USTAR format. This is the only
-- format supporting long file names.
GnuFormat :: Format
-- | An GenEntry with all default values except for the file name
-- and type. It uses the portable USTAR/POSIX format (see
-- UstarFormat).
--
-- You can use this as a basis and override specific fields, eg:
--
--
-- (emptyEntry name HardLink) { linkTarget = target }
--
simpleEntry :: tarPath -> GenEntryContent linkTarget -> GenEntry tarPath linkTarget
-- | A tar GenEntry for a file.
--
-- Entry fields such as file permissions and ownership have default
-- values.
--
-- You can use this as a basis and override specific fields. For example
-- if you need an executable file you could use:
--
--
-- (fileEntry name content) { fileMode = executableFileMode }
--
fileEntry :: tarPath -> ByteString -> GenEntry tarPath linkTarget
-- | A tar GenEntry for a directory.
--
-- Entry fields such as file permissions and ownership have default
-- values.
directoryEntry :: tarPath -> GenEntry tarPath linkTarget
-- | GNU extension to store a filepath too long to fit into
-- entryTarPath as OtherEntryType 'L' with the
-- full filepath as entryContent. The next entry must contain the
-- actual data with truncated entryTarPath.
--
-- See What exactly is the GNU tar ..@LongLink "trick"?
longLinkEntry :: FilePath -> GenEntry TarPath linkTarget
-- | GNU extension to store a link target too long to fit into
-- entryTarPath as OtherEntryType 'K' with the
-- full filepath as entryContent. The next entry must contain the
-- actual data with truncated entryTarPath.
longSymLinkEntry :: FilePath -> GenEntry TarPath linkTarget
-- | rw-r--r-- for normal files
ordinaryFilePermissions :: Permissions
-- | rwxr-xr-x for executable files
executableFilePermissions :: Permissions
-- | rwxr-xr-x for directories
directoryPermissions :: Permissions
-- | Construct a tar GenEntry based on a local file.
--
-- This sets the entry size, the data contained in the file and the
-- file's modification time. If the file is executable then that
-- information is also preserved. File ownership and detailed permissions
-- are not preserved.
--
--
-- - The file contents is read lazily.
--
packFileEntry :: FilePath -> tarPath -> IO (GenEntry tarPath linkTarget)
-- | Construct a tar GenEntry based on a local directory (but not
-- its contents).
--
-- The only attribute of the directory that is used is its modification
-- time. Directory ownership and detailed permissions are not preserved.
packDirectoryEntry :: FilePath -> tarPath -> IO (GenEntry tarPath linkTarget)
-- | Construct a tar GenEntry based on a local symlink.
--
-- This automatically checks symlink safety via
-- checkEntrySecurity.
packSymlinkEntry :: FilePath -> tarPath -> IO (GenEntry tarPath FilePath)
-- | This is a utility function, much like listDirectory. The
-- difference is that it includes the contents of subdirectories.
--
-- The paths returned are all relative to the top directory. Directory
-- paths are distinguishable by having a trailing path separator (see
-- hasTrailingPathSeparator).
--
-- All directories are listed before the files that they contain. Amongst
-- the contents of a directory, subdirectories are listed after normal
-- files. The overall result is that files within a directory will be
-- together in a single contiguous group. This tends to improve file
-- layout and IO performance when creating or extracting tar archives.
--
--
-- - This function returns results lazily. Subdirectories are not
-- scanned until the files entries in the parent directory have been
-- consumed. If the source directory structure changes before the result
-- is used, the behaviour is undefined.
--
getDirectoryContentsRecursive :: FilePath -> IO [FilePath]
-- | The classic tar format allowed just 100 characters for the file name.
-- The USTAR format extended this with an extra 155 characters, however
-- it uses a complex method of splitting the name between the two
-- sections.
--
-- Instead of just putting any overflow into the extended area, it uses
-- the extended area as a prefix. The aggravating insane bit however is
-- that the prefix (if any) must only contain a directory prefix. That is
-- the split between the two areas must be on a directory separator
-- boundary. So there is no simple calculation to work out if a file name
-- is too long. Instead we have to try to find a valid split that makes
-- the name fit in the two areas.
--
-- The rationale presumably was to make it a bit more compatible with old
-- tar programs that only understand the classic format. A classic tar
-- would be able to extract the file name and possibly some dir prefix,
-- but not the full dir prefix. So the files would end up in the wrong
-- place, but that's probably better than ending up with the wrong names
-- too.
--
-- So it's understandable but rather annoying.
--
--
-- - Tar paths use Posix format (ie '/' directory separators),
-- irrespective of the local path conventions.
-- - The directory separator between the prefix and name is not
-- stored.
--
data TarPath
-- | Convert a native FilePath to a TarPath.
--
-- The conversion may fail if the FilePath is empty or too long.
-- Use toTarPath' for a structured output.
toTarPath :: Bool -> FilePath -> Either String TarPath
-- | Convert a TarPath to a native FilePath.
--
-- The native FilePath will use the native directory separator but
-- it is not otherwise checked for validity or sanity. In particular:
--
--
-- - The tar path may be invalid as a native path, eg the file name
-- "nul" is not valid on Windows.
-- - The tar path may be an absolute path or may contain ".."
-- components. For security reasons this should not usually be allowed,
-- but it is your responsibility to check for these conditions (e.g.,
-- using checkEntrySecurity).
--
fromTarPath :: TarPath -> FilePath
-- | Convert a TarPath to a Unix/Posix FilePath.
--
-- The difference compared to fromTarPath is that it always
-- returns a Unix style path irrespective of the current operating
-- system.
--
-- This is useful to check how a TarPath would be interpreted on a
-- specific operating system, eg to perform portability checks.
fromTarPathToPosixPath :: TarPath -> FilePath
-- | Convert a TarPath to a Windows FilePath.
--
-- The only difference compared to fromTarPath is that it always
-- returns a Windows style path irrespective of the current operating
-- system.
--
-- This is useful to check how a TarPath would be interpreted on a
-- specific operating system, eg to perform portability checks.
fromTarPathToWindowsPath :: TarPath -> FilePath
-- | The tar format allows just 100 ASCII characters for the
-- SymbolicLink and HardLink entry types.
data LinkTarget
-- | Convert a native FilePath to a tar LinkTarget. string is
-- longer than 100 characters or if it contains non-portable characters.
toLinkTarget :: FilePath -> Maybe LinkTarget
-- | Convert a tar LinkTarget to a native FilePath.
fromLinkTarget :: LinkTarget -> FilePath
-- | Convert a tar LinkTarget to a Unix/POSIX FilePath
-- ('/' path separators).
fromLinkTargetToPosixPath :: LinkTarget -> FilePath
-- | Convert a tar LinkTarget to a Windows FilePath
-- ('\\' path separators).
fromLinkTargetToWindowsPath :: LinkTarget -> FilePath
-- | Perform various checks on tar file entries.
module Codec.Archive.Tar.Check
-- | This function checks a sequence of tar entries for file name security
-- problems. It checks that:
--
--
-- - file paths are not absolute
-- - file paths do not refer outside of the archive
-- - file names are valid
--
--
-- These checks are from the perspective of the current OS. That means we
-- check for "C:blah" files on Windows and "/blah" files on
-- Unix. For archive entry types HardLink and SymbolicLink
-- the same checks are done for the link target. A failure in any entry
-- terminates the sequence of entries with an error.
checkSecurity :: Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) FileNameError)
-- | Worker of checkSecurity.
checkEntrySecurity :: GenEntry FilePath FilePath -> Maybe FileNameError
-- | Errors arising from tar file names being in some way invalid or
-- dangerous
data FileNameError
InvalidFileName :: FilePath -> FileNameError
AbsoluteFileName :: FilePath -> FileNameError
UnsafeLinkTarget :: FilePath -> FileNameError
-- | This function checks a sequence of tar entries for being a "tar bomb".
-- This means that the tar file does not follow the standard convention
-- that all entries are within a single subdirectory, e.g. a file
-- "foo.tar" would usually have all entries within the "foo/"
-- subdirectory.
--
-- Given the expected subdirectory, this function checks all entries are
-- within that subdirectroy.
--
-- Note: This check must be used in conjunction with checkSecurity
-- (or checkPortability).
checkTarbomb :: FilePath -> Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) TarBombError)
-- | Worker of checkTarbomb.
checkEntryTarbomb :: FilePath -> GenEntry FilePath linkTarget -> Maybe TarBombError
-- | An error that occurs if a tar file is a "tar bomb" that would extract
-- files outside of the intended directory.
data TarBombError
TarBombError :: FilePath -> FilePath -> TarBombError
-- | This function checks a sequence of tar entries for a number of
-- portability issues. It will complain if:
--
--
-- - The old "Unix V7" or "gnu" formats are used. For maximum
-- portability only the POSIX standard "ustar" format should be
-- used.
-- - A non-portable entry type is used. Only ordinary files, hard
-- links, symlinks and directories are portable. Device files, pipes and
-- others are not portable between all common operating systems.
-- - Non-ASCII characters are used in file names. There is no agreed
-- portable convention for Unicode or other extended character sets in
-- file names in tar archives.
-- - File names that would not be portable to both Unix and Windows.
-- This check includes characters that are valid in both systems and the
-- '/' vs '\' directory separator conventions.
--
checkPortability :: Entries e -> GenEntries FilePath FilePath (Either (Either e DecodeLongNamesError) PortabilityError)
-- | Worker of checkPortability.
checkEntryPortability :: GenEntry FilePath linkTarget -> Maybe PortabilityError
-- | Portability problems in a tar archive
data PortabilityError
NonPortableFormat :: Format -> PortabilityError
NonPortableFileType :: PortabilityError
NonPortableEntryNameChar :: FilePath -> PortabilityError
NonPortableFileName :: PortabilityPlatform -> FileNameError -> PortabilityError
-- | The name of a platform that portability issues arise from
type PortabilityPlatform = String
module Codec.Archive.Tar.Unpack
-- | Create local files and directories based on the entries of a tar
-- archive.
--
-- This is a portable implementation of unpacking suitable for portable
-- archives. It handles NormalFile and Directory entries
-- and has simulated support for SymbolicLink and HardLink
-- entries. Links are implemented by copying the target file. This
-- therefore works on Windows as well as Unix. All other entry types are
-- ignored, that is they are not unpacked and no exception is raised.
--
-- If the Entries ends in an error then it is raised an an
-- exception. Any files or directories that have been unpacked before the
-- error was encountered will not be deleted. For this reason you may
-- want to unpack into an empty directory so that you can easily clean up
-- if unpacking fails part-way.
--
-- On its own, this function only checks for security (using
-- checkEntrySecurity). Use unpackAndCheck if you need more
-- checks.
unpack :: Exception e => FilePath -> Entries e -> IO ()
-- | Like unpack, but run custom sanity/security checks instead of
-- checkEntrySecurity. For example,
--
--
-- unpackAndCheck (\x -> SomeException <$> checkEntryPortability x
-- <|> SomeException <$> checkEntrySecurity x) dir entries
--
unpackAndCheck :: Exception e => (GenEntry FilePath FilePath -> Maybe SomeException) -> FilePath -> Entries e -> IO ()
module Codec.Archive.Tar.Write
-- | Create the external representation of a tar archive by serialising a
-- list of tar entries.
--
--
-- - The conversion is done lazily.
--
write :: [Entry] -> ByteString
-- | Reading, writing and manipulating ".tar" archive files.
--
-- This module uses common names and so is designed to be imported
-- qualified:
--
--
-- import qualified Codec.Archive.Tar as Tar
--
module Codec.Archive.Tar
-- | Create a new ".tar" file from a directory of files.
--
-- It is equivalent to calling the standard tar program like so:
--
--
-- $ tar -f tarball.tar -C base -c dir
--
--
-- This assumes a directory ./base/dir with files inside, eg
-- ./base/dir/foo.txt. The file names inside the resulting tar
-- file will be relative to dir, eg dir/foo.txt.
--
-- This is a high level "all in one" operation. Since you may need
-- variations on this function it is instructive to see how it is
-- written. It is just:
--
--
-- BS.writeFile tar . Tar.write =<< Tar.pack base paths
--
--
-- Notes:
--
-- The files and directories must not change during this operation or the
-- result is not well defined.
--
-- The intention of this function is to create tarballs that are portable
-- between systems. It is not suitable for doing file system
-- backups because file ownership and permissions are not fully
-- preserved. File ownership is not preserved at all. File permissions
-- are set to simple portable values:
--
--
-- - rw-r--r-- for normal files
-- - rwxr-xr-x for executable files
-- - rwxr-xr-x for directories
--
create :: FilePath -> FilePath -> [FilePath] -> IO ()
-- | Extract all the files contained in a ".tar" file.
--
-- It is equivalent to calling the standard tar program like so:
--
--
-- $ tar -x -f tarball.tar -C dir
--
--
-- So for example if the tarball.tar file contains
-- foo/bar.txt then this will extract it to
-- dir/foo/bar.txt.
--
-- This is a high level "all in one" operation. Since you may need
-- variations on this function it is instructive to see how it is
-- written. It is just:
--
--
-- Tar.unpack dir . Tar.read =<< BS.readFile tar
--
--
-- Notes:
--
-- Extracting can fail for a number of reasons. The tarball may be
-- incorrectly formatted. There may be IO or permission errors. In such
-- cases an exception will be thrown and extraction will not continue.
--
-- Since the extraction may fail part way through it is not atomic. For
-- this reason you may want to extract into an empty directory and, if
-- the extraction fails, recursively delete the directory.
--
-- Security: only files inside the target directory will be written.
-- Tarballs containing entries that point outside of the tarball (either
-- absolute paths or relative paths) will be caught and an exception will
-- be thrown.
extract :: FilePath -> FilePath -> IO ()
-- | Append new entries to a ".tar" file from a directory of
-- files.
--
-- This is much like create, except that all the entries are added
-- to the end of an existing tar file. Or if the file does not already
-- exists then it behaves the same as create.
append :: FilePath -> FilePath -> [FilePath] -> IO ()
-- | Convert a data stream in the tar file format into an internal data
-- structure. Decoding errors are reported by the Fail constructor
-- of the Entries type.
--
--
-- - The conversion is done lazily.
--
read :: ByteString -> Entries FormatError
-- | Create the external representation of a tar archive by serialising a
-- list of tar entries.
--
--
-- - The conversion is done lazily.
--
write :: [Entry] -> ByteString
-- | Creates a tar archive from a list of directory or files. Any
-- directories specified will have their contents included recursively.
-- Paths in the archive will be relative to the given base directory.
--
-- This is a portable implementation of packing suitable for portable
-- archives. In particular it only constructs NormalFile,
-- Directory and SymbolicLink entries. Hard links are
-- treated like ordinary files. Special files like FIFOs (named pipes),
-- sockets or device files will cause problems.
--
-- An exception will be thrown for any file names that are too long to
-- represent as a TarPath.
--
--
-- - This function returns results lazily. Subdirectories are scanned
-- and files are read one by one as the list of entries is consumed.
--
pack :: FilePath -> [FilePath] -> IO [Entry]
-- | Like pack, but allows to specify additional sanity/security
-- checks on the input filenames. This is useful if you know which check
-- will be used on client side in unpack / unpackAndCheck.
packAndCheck :: (GenEntry FilePath FilePath -> Maybe SomeException) -> FilePath -> [FilePath] -> IO [Entry]
-- | Create local files and directories based on the entries of a tar
-- archive.
--
-- This is a portable implementation of unpacking suitable for portable
-- archives. It handles NormalFile and Directory entries
-- and has simulated support for SymbolicLink and HardLink
-- entries. Links are implemented by copying the target file. This
-- therefore works on Windows as well as Unix. All other entry types are
-- ignored, that is they are not unpacked and no exception is raised.
--
-- If the Entries ends in an error then it is raised an an
-- exception. Any files or directories that have been unpacked before the
-- error was encountered will not be deleted. For this reason you may
-- want to unpack into an empty directory so that you can easily clean up
-- if unpacking fails part-way.
--
-- On its own, this function only checks for security (using
-- checkEntrySecurity). Use unpackAndCheck if you need more
-- checks.
unpack :: Exception e => FilePath -> Entries e -> IO ()
-- | Like unpack, but run custom sanity/security checks instead of
-- checkEntrySecurity. For example,
--
--
-- unpackAndCheck (\x -> SomeException <$> checkEntryPortability x
-- <|> SomeException <$> checkEntrySecurity x) dir entries
--
unpackAndCheck :: Exception e => (GenEntry FilePath FilePath -> Maybe SomeException) -> FilePath -> Entries e -> IO ()
-- | Polymorphic tar archive entry. High-level interfaces commonly work
-- with GenEntry FilePath FilePath, while low level
-- uses GenEntry TarPath LinkTarget.
data GenEntry tarPath linkTarget
-- | Monomorphic tar archive entry, ready for serialization /
-- deserialization.
type Entry = GenEntry TarPath LinkTarget
-- | Native FilePath of the file or directory within the archive.
entryPath :: GenEntry TarPath linkTarget -> FilePath
-- | The real content of the entry. For NormalFile this includes the
-- file data. An entry usually contains a NormalFile or a
-- Directory.
entryContent :: GenEntry tarPath linkTarget -> GenEntryContent linkTarget
-- | Polymorphic content of a tar archive entry. High-level interfaces
-- commonly work with GenEntryContent FilePath, while low
-- level uses GenEntryContent LinkTarget.
--
-- Portable archives should contain only NormalFile and
-- Directory.
data GenEntryContent linkTarget
NormalFile :: ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
Directory :: GenEntryContent linkTarget
SymbolicLink :: !linkTarget -> GenEntryContent linkTarget
HardLink :: !linkTarget -> GenEntryContent linkTarget
CharacterDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
BlockDevice :: {-# UNPACK #-} !DevMajor -> {-# UNPACK #-} !DevMinor -> GenEntryContent linkTarget
NamedPipe :: GenEntryContent linkTarget
OtherEntryType :: {-# UNPACK #-} !TypeCode -> ByteString -> {-# UNPACK #-} !FileSize -> GenEntryContent linkTarget
-- | Monomorphic content of a tar archive entry, ready for serialization /
-- deserialization.
type EntryContent = GenEntryContent LinkTarget
-- | Polymorphic sequence of archive entries. High-level interfaces
-- commonly work with GenEntries FilePath FilePath,
-- while low level uses GenEntries TarPath
-- LinkTarget.
--
-- The point of this type as opposed to just using a list is that it
-- makes the failure case explicit. We need this because the sequence of
-- entries we get from reading a tarball can include errors.
--
-- Converting from a list can be done with just foldr Next Done.
-- Converting back into a list can be done with foldEntries
-- however in that case you must be prepared to handle the Fail
-- case inherent in the Entries type.
--
-- The Monoid instance lets you concatenate archives or append
-- entries to an archive.
data GenEntries tarPath linkTarget e
Next :: GenEntry tarPath linkTarget -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget e
Done :: GenEntries tarPath linkTarget e
Fail :: e -> GenEntries tarPath linkTarget e
infixr 5 `Next`
-- | Monomorphic sequence of archive entries, ready for serialization /
-- deserialization.
type Entries e = GenEntries TarPath LinkTarget e
-- | This is like the standard map function on lists, but for
-- Entries. It includes failure as a extra possible outcome of the
-- mapping function.
--
-- If your mapping function cannot fail it may be more convenient to use
-- mapEntriesNoFail
mapEntries :: (GenEntry tarPath linkTarget -> Either e' (GenEntry tarPath linkTarget)) -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget (Either e e')
-- | Like mapEntries but the mapping function itself cannot fail.
mapEntriesNoFail :: (GenEntry tarPath linkTarget -> GenEntry tarPath linkTarget) -> GenEntries tarPath linkTarget e -> GenEntries tarPath linkTarget e
-- | This is like the standard foldr function on lists, but for
-- Entries. Compared to foldr it takes an extra function to
-- account for the possibility of failure.
--
-- This is used to consume a sequence of entries. For example it could be
-- used to scan a tarball for problems or to collect an index of the
-- contents.
foldEntries :: (GenEntry tarPath linkTarget -> a -> a) -> a -> (e -> a) -> GenEntries tarPath linkTarget e -> a
-- | A foldl-like function on Entries. It either returns the final
-- accumulator result, or the failure along with the intermediate
-- accumulator value.
foldlEntries :: (a -> GenEntry tarPath linkTarget -> a) -> a -> GenEntries tarPath linkTarget e -> Either (e, a) a
-- | This is like the standard unfoldr function on lists, but for
-- Entries. It includes failure as an extra possibility that the
-- stepper function may return.
--
-- It can be used to generate Entries from some other type. For
-- example it is used internally to lazily unfold entries from a
-- ByteString.
unfoldEntries :: (a -> Either e (Maybe (GenEntry tarPath linkTarget, a))) -> a -> GenEntries tarPath linkTarget e
-- | Translate high-level entries with POSIX FilePaths for files and
-- symlinks into entries suitable for serialization by emitting
-- additional OtherEntryType 'K' and
-- OtherEntryType 'L' nodes.
--
-- Input FilePaths must be POSIX file names, not native ones.
encodeLongNames :: GenEntry FilePath FilePath -> [Entry]
-- | Translate low-level entries (usually freshly deserialized) into
-- high-level entries with POSIX FilePaths for files and symlinks
-- by parsing and eliminating OtherEntryType 'K' and
-- OtherEntryType 'L' nodes.
--
-- Resolved FilePaths are still POSIX file names, not native ones.
decodeLongNames :: Entries e -> GenEntries FilePath FilePath (Either e DecodeLongNamesError)
-- | Errors raised by decodeLongNames.
data DecodeLongNamesError
-- | Two adjacent OtherEntryType 'K' nodes.
TwoTypeKEntries :: DecodeLongNamesError
-- | Two adjacent OtherEntryType 'L' nodes.
TwoTypeLEntries :: DecodeLongNamesError
-- | OtherEntryType 'K' node is not followed by a
-- SymbolicLink / HardLink.
NoLinkEntryAfterTypeKEntry :: DecodeLongNamesError
-- | Errors that can be encountered when parsing a Tar archive.
data FormatError
TruncatedArchive :: FormatError
ShortTrailer :: FormatError
BadTrailer :: FormatError
TrailingJunk :: FormatError
ChecksumIncorrect :: FormatError
NotTarFormat :: FormatError
UnrecognisedTarFormat :: FormatError
HeaderBadNumericEncoding :: FormatError