module Codec.Archive.Tar.Extract where
import Codec.Archive.Tar.Types
import Codec.Archive.Tar.Util
import System.PosixCompat.Extensions
import System.PosixCompat.Files
import Control.Monad
import qualified Data.ByteString.Lazy as BS
import System.Directory
import System.PosixCompat.Types
extractTarArchive :: TarArchive -> IO ()
extractTarArchive = mapM_ extractTarEntry . archiveEntries
extractTarEntry :: TarEntry -> IO ()
extractTarEntry (TarEntry hdr cnt) =
do
path <- forceRelativePath $ tarFileName hdr
let dir = dirName path
mode = tarFileMode hdr
when (not (null dir)) $ createDirectoryIfMissing True dir
case tarFileType hdr of
TarHardLink ->
createLink (tarLinkTarget hdr) path
TarSymbolicLink ->
createSymbolicLink (tarLinkTarget hdr) path
TarCharacterDevice ->
createCharacterDevice path mode (tarDeviceID hdr)
TarBlockDevice ->
createBlockDevice path mode (tarDeviceID hdr)
TarDirectory -> createDirectoryIfMissing False path
TarFIFO -> createNamedPipe path mode
_ -> BS.writeFile path cnt
warnIOError $ setFileMode path mode
setFileTimes path (tarModTime hdr) (tarModTime hdr)
createCharacterDevice :: FilePath -> FileMode -> DeviceID -> IO ()
createCharacterDevice path mode dev = createDevice path m dev
where m = mode `unionFileModes` characterSpecialMode
createBlockDevice :: FilePath -> FileMode -> DeviceID -> IO ()
createBlockDevice path mode dev = createDevice path m dev
where m = mode `unionFileModes` blockSpecialMode
characterSpecialMode :: FileMode
characterSpecialMode = 0o0020000
blockSpecialMode :: FileMode
blockSpecialMode = 0o0060000
tarDeviceID :: TarHeader -> DeviceID
tarDeviceID hdr = makeDeviceID (tarDeviceMajor hdr) (tarDeviceMajor hdr)