-- 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.3.0 module Codec.Archive.Tar.Index.Utils -- | Construct a `UArray Word32 Word32` from a ByteString of 32bit big -- endian words. -- -- Note: If using unsafePerformIO, be sure to force the result of -- running the IO action right away... (e.g. see calls to beToLe in -- StringTable) beToLe :: (Integral i, Num i) => i -> ByteString -> IO (UArray i Word32) readInt32BE :: ByteString -> Int -> Int32 readWord32OffPtrBE :: Ptr Word32 -> Int -> IO Word32 readWord32BE :: ByteString -> Int -> Word32 -- | 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 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: -- -- -- -- 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. -- -- 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. -- -- 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. -- -- 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. -- -- 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: -- -- 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: -- -- -- -- 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: -- -- -- -- 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: -- -- 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. -- -- read :: ByteString -> Entries FormatError -- | Create the external representation of a tar archive by serialising a -- list of tar entries. -- -- 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. -- -- 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