-- 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.4.0

-- | 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:
--   
--   
--   
- hReadEntry to read the whole entry;
--   
- hReadEntryHeader to read just the file metadata (e.g. its
--   length);
--   
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 Entry 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 Entry 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 Entry 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 Entry 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 Entry 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

-- | 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
--   ones use 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

-- | Low-level function to get a native FilePath of the file or
--   directory within the archive, not accounting for long names. It's
--   likely that you want to apply decodeLongNames and use
--   entryTarPath afterwards instead of entryPath.
entryPath :: GenEntry TarPath linkTarget -> FilePath

-- | Polymorphic content of a tar archive entry. High-level interfaces
--   commonly work with GenEntryContent FilePath, while
--   low-level ones use 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

-- | Ownership information for GenEntry.
data Ownership
Ownership :: String -> String -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Ownership

-- | The owner user name. Should be set to "" if unknown. Must not
--   contain non-ASCII characters.
[ownerName] :: Ownership -> String

-- | The owner group name. Should be set to "" if unknown. Must
--   not contain non-ASCII characters.
[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

-- | File size in bytes.
type FileSize = Int64

-- | Permissions information for GenEntry.
type Permissions = FileMode

-- | The number of seconds since the UNIX epoch.
type EpochTime = Int64

-- | Major device number.
type DevMajor = Int

-- | Minor device number.
type DevMinor = Int

-- | User-defined tar format expansion.
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 entry 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 entry 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 entry 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 entry 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 entry 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 entry based on a local symlink.
packSymlinkEntry :: FilePath -> tarPath -> IO (GenEntry tarPath FilePath)

-- | Recursively list all the files and directories in a directory and all
--   subdirectories.
--   
--   The directory structure is traversed depth-first.
--   
--   The result is generated lazily so is not well defined if the source
--   directory structure changes before the list is fully consumed.
--   
--   Symlinks within directory structure may cause result to be infinitely
--   long.
getDirectoryContentsRecursive :: OsPath -> IO [(OsPath, FileType)]

-- | 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.
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.
--   
--   Whenever possible, consider fusing checkSecurity with packing /
--   unpacking by using packAndCheck / unpackAndCheck with
--   checkEntrySecurity. Not only it is faster, but also alleviates
--   issues with lazy I/O such as exhaustion of file handlers.
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).
--   
--   Whenever possible, consider fusing checkTarbomb with packing /
--   unpacking by using packAndCheck / unpackAndCheck with
--   checkEntryTarbomb. Not only it is faster, but also alleviates
--   issues with lazy I/O such as exhaustion of file handlers.
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.
--   
--   
--   Whenever possible, consider fusing checkPortability with
--   packing / unpacking by using packAndCheck /
--   unpackAndCheck with checkEntryPortability. Not only it
--   is faster, but also alleviates issues with lazy I/O such as exhaustion
--   of file handlers.
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

-- | 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:
--   
--   
--   import qualified Data.ByteString.Lazy as BL
--   
--   BL.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:
--   
--   
--   import qualified Data.ByteString.Lazy as BL
--   
--   Tar.unpack dir . Tar.read =<< BL.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.
--   
--   
--   
- This function returns results lazily. Subdirectories are scanned
--   and files are read one by one as the list of entries is consumed. Do
--   not change their contents before the output of pack was
--   consumed in full.
--   
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,
--   
--   
--   import Control.Exception (SomeException(..))
--   import Control.Applicative ((<|>))
--   
--   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
--   ones use GenEntry TarPath LinkTarget.
data GenEntry tarPath linkTarget

-- | Monomorphic tar archive entry, ready for serialization /
--   deserialization.
type Entry = GenEntry TarPath LinkTarget

-- | Low-level function to get a native FilePath of the file or
--   directory within the archive, not accounting for long names. It's
--   likely that you want to apply decodeLongNames and use
--   entryTarPath afterwards instead of entryPath.
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 ones use 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 ones use 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
