packages feed

tar-bytestring 0.6.2.0 → 0.6.3.0

raw patch · 6 files changed

+117/−41 lines, 6 filesdep +thesePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: these

API changes (from Hackage documentation)

- Codec.Archive.Tar.Entry: packDirectoryEntry :: RawFilePath -> TarPath -> IO Entry
+ Codec.Archive.Tar.Entry: packDirectoryEntry :: RawFilePath -> These SplitError TarPath -> IO [Entry]
- Codec.Archive.Tar.Entry: packFileEntry :: RawFilePath -> TarPath -> IO Entry
+ Codec.Archive.Tar.Entry: packFileEntry :: RawFilePath -> These SplitError TarPath -> IO [Entry]
- Codec.Archive.Tar.Entry: toTarPath :: Bool -> RawFilePath -> Either String TarPath
+ Codec.Archive.Tar.Entry: toTarPath :: Bool -> RawFilePath -> These SplitError TarPath

Files

Codec/Archive/Tar/Index.hs view
@@ -124,6 +124,7 @@ #endif  #ifdef TESTS+import Data.These import qualified Prelude import Test.QuickCheck import Test.QuickCheck.Property (ioProperty)@@ -710,7 +711,7 @@ testEntry :: RawFilePath -> Int64 -> Entry testEntry name size = simpleEntry path (NormalFile mempty size)   where-    Right path = toTarPath False name+    That path = toTarPath False name  -- | Simple tar archive containing regular files only data SimpleTarArchive = SimpleTarArchive {@@ -775,7 +776,7 @@       mkList []            = []       mkList ((fp, bs):es) = entry : mkList es         where-          Right path = toTarPath False fp+          That path = toTarPath False fp           entry   = simpleEntry path content           content = NormalFile bs (LBS.length bs) 
Codec/Archive/Tar/Pack.hs view
@@ -21,8 +21,10 @@  import Codec.Archive.Tar.Types import Control.Applicative+import Control.Monad (join) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as L+import Data.These import qualified System.Posix.IO.ByteString as SPI import System.Posix.FD import System.Posix.ByteString.FilePath (RawFilePath)@@ -73,8 +75,8 @@  packPaths :: RawFilePath -> [RawFilePath] -> IO [Entry] packPaths baseDir paths =-  interleave-    [ do tarpath <- either fail return (toTarPath isDir relpath)+  join <$> interleave+    [ do let tarpath = toTarPath isDir relpath          if isDir then packDirectoryEntry filepath tarpath                   else packFileEntry      filepath tarpath     | relpath <- paths@@ -99,33 +101,51 @@ -- * The file contents is read lazily. -- packFileEntry :: RawFilePath -- ^ Full path to find the file on the local disk-              -> TarPath  -- ^ Path to use for the tar Entry in the archive-              -> IO Entry+              -> These SplitError TarPath  -- ^ Path to use for the tar Entry in the archive+              -> IO [Entry] packFileEntry filepath tarpath = do   mtime   <- getModTime filepath   executable   <- isExecutable filepath   file    <- openFd filepath SPI.ReadOnly [] Nothing >>= SPI.fdToHandle   size    <- hFileSize file   content <- L.hGetContents file-  return (simpleEntry tarpath (NormalFile content (fromIntegral size))) {-    entryPermissions = if executable then executableFilePermissions-                                     else ordinaryFilePermissions,-    entryTime = mtime-  } +  let entry tp = (simpleEntry tp (NormalFile content (fromIntegral size))) {+         entryPermissions = if executable then executableFilePermissions+                                          else ordinaryFilePermissions,+         entryTime = mtime+         }++  case tarpath of+       This e     -> fail $ show e+       That tp    -> return [entry tp]+       These _ tp -> do+         let lEntry = longLinkEntry filepath+         return [lEntry, entry tp]++ -- | 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 :: RawFilePath -- ^ Full path to find the file on the local disk-                   -> TarPath  -- ^ Path to use for the tar Entry in the archive-                   -> IO Entry+                   -> These SplitError TarPath  -- ^ Path to use for the tar Entry in the archive+                   -> IO [Entry] packDirectoryEntry filepath tarpath = do   mtime   <- getModTime filepath-  return (directoryEntry tarpath) {++  let dEntry tp = (directoryEntry tp) {     entryTime = mtime   }++  case tarpath of+       This e     -> fail $ show e+       That tp    -> return [dEntry tp]+       These _ tp -> do+         let lEntry = longLinkEntry filepath+         return [lEntry, dEntry tp]+  -- | This is a utility function, much like 'getDirectoryContents'. The -- difference is that it includes the contents of subdirectories.
Codec/Archive/Tar/Types.hs view
@@ -29,6 +29,7 @@   RawFilePath,    simpleEntry,+  longLinkEntry,   fileEntry,   directoryEntry, @@ -37,6 +38,7 @@   directoryPermissions,    TarPath(..),+  SplitError(..),   toTarPath,   fromTarPath,   fromTarPathToPosixPath,@@ -64,6 +66,7 @@ import Data.Int      (Int64) import Data.Monoid   (Monoid(..)) import Data.Semigroup as Sem+import Data.These import qualified Data.ByteString       as BS import qualified Data.ByteString.Char8 as BS.Char8 import qualified Data.ByteString.Lazy  as LBS@@ -246,6 +249,22 @@     entryFormat      = UstarFormat   } ++-- | Gnu entry for when a filepath is too long to be in entryTarPath.+-- Gnu tar uses OtherEntryType 'L' then as the first Entry and puts path+-- in the entryContent. The Next entry will then be the "original"+-- entry with the entryTarPath truncated.+longLinkEntry :: RawFilePath -> Entry+longLinkEntry tarpath = Entry {+    entryTarPath     = TarPath (BS.Char8.pack "././@LongLink") BS.empty,+    entryContent     = OtherEntryType 'L' (LBS.fromStrict tarpath) (fromIntegral $ BS.length tarpath),+    entryPermissions = ordinaryFilePermissions,+    entryOwnership   = Ownership "" "" 0 0,+    entryTime        = 0,+    entryFormat      = GnuFormat+  }++ -- | A tar 'Entry' for a file. -- -- Entry  fields such as file permissions and ownership have default values.@@ -349,7 +368,7 @@ -- toTarPath :: Bool -- ^ Is the path for a directory? This is needed because for                   -- directories a 'TarPath' must always use a trailing @\/@.-          -> RawFilePath -> Either String TarPath+          -> RawFilePath -> These SplitError TarPath toTarPath isDir = splitLongPath                 . addTrailingSep                 . FilePath.Posix.joinPath@@ -358,6 +377,11 @@     addTrailingSep | isDir     = FilePath.Posix.addTrailingPathSeparator                    | otherwise = id ++data SplitError = FileNameEmpty+                | FileNameTooLong+                deriving Show+ -- | Take a sanitised path, split on directory separators and try to pack it -- into the 155 + 100 tar file name format. --@@ -365,15 +389,17 @@ -- and try to fit as many components into the 100 long name area as possible. -- If all the remaining components fit in the 155 name area then we win. ---splitLongPath :: RawFilePath -> Either String TarPath+splitLongPath :: RawFilePath -> These SplitError TarPath splitLongPath path =   case packName nameMax (reverse (FilePath.Posix.splitPath path)) of-    Left err                 -> Left err-    Right (name, [])         -> Right $! TarPath name BS.empty+    Left FileNameTooLong     -> These FileNameTooLong $ TarPath (BS.take 100 path) BS.empty+    Left e                   -> This e+    Right (name, [])         -> That $! TarPath name BS.empty     Right (name, first:rest) -> case packName prefixMax remainder of-      Left err               -> Left err-      Right (_     , (_:_))  -> Left "File name too long (cannot split)"-      Right (prefix, [])     -> Right $! TarPath name prefix+      Left FileNameTooLong   -> These FileNameTooLong $ TarPath (BS.take 100 path) BS.empty+      Left e                 -> This e+      Right (_     , (_:_))  -> These FileNameTooLong $ TarPath (BS.take 100 path) BS.empty+      Right (prefix, [])     -> That $! TarPath name prefix       where         -- drop the '/' between the name and prefix:         remainder = BS.init first : rest@@ -383,9 +409,9 @@     nameMax   = 100     prefixMax = 155 -    packName _      []     = Left "File name empty"+    packName _      []     = Left FileNameEmpty     packName maxLen (c:cs)-      | n > maxLen         = Left "File name too long"+      | n > maxLen         = Left FileNameTooLong       | otherwise          = Right (packName' maxLen n [c] cs)       where n = BS.length c @@ -558,14 +584,14 @@       | perms' <- shrinkIntegral perms ]  instance Arbitrary TarPath where-  arbitrary = either error id+  arbitrary = these (error . show) id (flip const)             . toTarPath False             . FilePath.Posix.joinPath             . fmap BS.Char8.pack           <$> listOf1ToN (255 `div` 5)                          (elements (map (replicate 4) "abcd")) -  shrink = map (either error id . toTarPath False)+  shrink = map (these (error . show) id (flip const) . toTarPath False)          . map FilePath.Posix.joinPath          . filter (not . null)          . shrinkList shrinkNothing
Codec/Archive/Tar/Unpack.hs view
@@ -18,6 +18,7 @@ import Codec.Archive.Tar.Types import Codec.Archive.Tar.Check +import Data.List (partition) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as L import System.Posix.FilePath@@ -65,8 +66,12 @@ -- use 'checkSecurity' before 'checkTarbomb' or other checks. -- unpack :: Exception e => RawFilePath -> Entries e -> IO ()-unpack baseDir entries = unpackEntries [] (checkSecurity entries)-                     >>= emulateLinks+unpack baseDir entries = do+  uEntries <- unpackEntries [] (checkSecurity entries)+  let (hardlinks, symlinks) = partition (\(_, _, x) -> x) uEntries+  -- emulate hardlinks first, in case a symlink points to it+  emulateLinks hardlinks+  emulateLinks symlinks    where     -- We're relying here on 'checkSecurity' to make sure we're not scribbling@@ -75,23 +80,37 @@     unpackEntries _     (Fail err)      = either throwIO throwIO err     unpackEntries links Done            = return links     unpackEntries links (Next entry es) = case entryContent entry of-      NormalFile file _ -> extractFile entry path file mtime+      NormalFile file _ -> extractFile fPerms path file mtime                         >> unpackEntries links es       Directory         -> extractDir path mtime                         >> unpackEntries links es-      HardLink     link -> (unpackEntries $! saveLink path link links) es-      SymbolicLink link -> (unpackEntries $! saveLink path link links) es-      _                 -> unpackEntries links es --ignore other file types+      HardLink     link -> (unpackEntries $! saveLink True path link links) es+      SymbolicLink link -> (unpackEntries $! saveLink False path link links) es+      OtherEntryType 'L' fn _ ->+        case es of+             (Next entry' es') -> case entryContent entry' of+               NormalFile file _ -> extractFile fPerms (L.toStrict fn) file mtime+                                 >> unpackEntries links es'+               Directory         -> extractDir (L.toStrict fn) mtime+                                 >> unpackEntries links es'+               HardLink     link -> (unpackEntries $! saveLink True path link links) es'+               SymbolicLink link -> (unpackEntries $! saveLink False path link links) es'+               OtherEntryType 'L' _ _ -> throwIO $ userError "Two subsequent OtherEntryType 'L'"+               _ -> unpackEntries links es'+             (Fail err)      -> either throwIO throwIO err+             Done            -> throwIO $ userError "././@LongLink without a subsequent entry"+      _ -> unpackEntries links es --ignore other file types       where         path  = entryPath entry         mtime = entryTime entry+        fPerms = entryPermissions entry -    extractFile entry path content mtime = do+    extractFile fPerms path content mtime = do       -- Note that tar archives do not make sure each directory is created       -- before files they contain, indeed we may have to create several       -- levels of directory.       createDirRecursive dirPerms (normalise absDir)-      writeFileL absPath (Just $ entryPermissions entry) content+      writeFileL absPath (Just fPerms) content       setModTime absPath mtime       where         absDir  = baseDir </> FilePath.Native.takeDirectory path@@ -103,15 +122,18 @@       where         absPath = baseDir </> path -    saveLink path link links = seq (BS.length path)-                             $ seq (BS.length link')-                             $ (path, link'):links+    saveLink isHardLink path link links = seq (BS.length path)+                                        $ seq (BS.length link')+                                        $ (path, link', isHardLink):links       where link' = fromLinkTarget link -    emulateLinks = mapM_ $ \(relPath, relLinkTarget) -> do-      let absPath = baseDir </> relPath-          absTarget = FilePath.Native.takeDirectory absPath </> relLinkTarget-      copyFile absTarget absPath Overwrite+    emulateLinks = mapM_ $ \(relPath, relLinkTarget, isHardLink) ->+      let absPath   = baseDir </> relPath+          -- hard links link targets are always "absolute" paths in+          -- the context of the tar root+          absTarget = if isHardLink then baseDir </> relLinkTarget else FilePath.Native.takeDirectory absPath </> relLinkTarget+      in copyFile absTarget absPath Overwrite+  setModTime :: RawFilePath -> EpochTime -> IO () setModTime p t = setModificationTime p (fromIntegral t)
changelog.md view
@@ -1,5 +1,9 @@ See also http://pvp.haskell.org/faq +0.6.3.0++  * Fix unpacking of hard links+ 0.6.2.0    * fix executable bit: https://github.com/haskell/tar/issues/25
tar-bytestring.cabal view
@@ -1,5 +1,5 @@ name:            tar-bytestring-version:         0.6.2.0+version:         0.6.3.0 license:         BSD3 license-file:    LICENSE author:          Duncan Coutts <duncan@community.haskell.org>@@ -48,6 +48,7 @@                  hpath-filepath   >= 0.10.4 && < 0.11,                  hpath-posix      >= 0.13.1 && < 0.14,                  safe-exceptions  >= 0.1,+                 these            >= 1.0.1,                  unix,                  word8 @@ -98,6 +99,7 @@                  hpath-filepath   >= 0.10.4 && < 0.11,                  hpath-posix      >= 0.13.1 && < 0.14,                  safe-exceptions  >= 0.1,+                 these            >= 1.0.1,                  unix,                  word8 @@ -151,6 +153,7 @@                  hpath-filepath   >= 0.10.4 && < 0.11,                  hpath-posix      >= 0.13.1 && < 0.14,                  safe-exceptions  >= 0.1,+                 these            >= 1.0.1,                  unix,                  word8