diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # libarchive
 
+## 2.2.4.0
+
+  * Add convenience functions for `.xar` archives
+
 ## 2.2.3.0
 
   * Add convenience functions for working with `.cpio` archives
diff --git a/libarchive.cabal b/libarchive.cabal
--- a/libarchive.cabal
+++ b/libarchive.cabal
@@ -1,6 +1,6 @@
 cabal-version:   1.18
 name:            libarchive
-version:         2.2.3.0
+version:         2.2.4.0
 license:         BSD3
 license-file:    LICENSE
 copyright:       Copyright: (c) 2018-2020 Vanessa McHale
diff --git a/src/Codec/Archive.hs b/src/Codec/Archive.hs
--- a/src/Codec/Archive.hs
+++ b/src/Codec/Archive.hs
@@ -10,6 +10,7 @@
     , entriesToFileZip
     , entriesToFile7Zip
     , entriesToFileCpio
+    , entriesToFileXar
     , entriesToBS
     , entriesToBS7zip
     , entriesToBSzip
@@ -17,6 +18,7 @@
     , entriesToBSLzip
     , entriesToBSL7zip
     , entriesToBSLCpio
+    , entriesToBSLXar
     , readArchiveFile
     , readArchiveBS
     , readArchiveBSL
@@ -24,10 +26,12 @@
     , packFilesZip
     , packFiles7zip
     , packFilesCpio
+    , packFilesXar
     , packToFile
     , packToFileZip
     , packToFile7Zip
     , packToFileCpio
+    , packToFileXar
     -- * Concrete (Haskell) types
     , ArchiveResult (..)
     , Entry (..)
diff --git a/src/Codec/Archive/Pack.hs b/src/Codec/Archive/Pack.hs
--- a/src/Codec/Archive/Pack.hs
+++ b/src/Codec/Archive/Pack.hs
@@ -2,6 +2,7 @@
                           , entriesToFileZip
                           , entriesToFile7Zip
                           , entriesToFileCpio
+                          , entriesToFileXar
                           , entriesToBS
                           , entriesToBSzip
                           , entriesToBS7zip
@@ -11,6 +12,7 @@
                           , packToFileZip
                           , packToFile7Zip
                           , packToFileCpio
+                          , packToFileXar
                           ) where
 
 import           Codec.Archive.Foreign
@@ -132,7 +134,7 @@
           bufSize = entriesSz hsEntries'
 
 filePacker :: (Traversable t) => (FilePath -> t Entry -> ArchiveM ()) -> FilePath -> t FilePath -> ArchiveM ()
-filePacker f tar fps = f tar =<< liftIO (traverse mkEntry fps) -- TODO: undsafeInterleaveIO? lol.
+filePacker f tar fps = f tar =<< liftIO (traverse mkEntry fps)
 
 -- | @since 2.0.0.0
 packToFile :: Traversable t
@@ -162,6 +164,13 @@
                -> ArchiveM ()
 packToFileCpio = filePacker entriesToFileCpio
 
+-- | @since 2.2.4.0
+packToFileXar :: Traversable t
+              => FilePath
+              -> t FilePath
+              -> ArchiveM ()
+packToFileXar = filePacker entriesToFileXar
+
 -- | Write some entries to a file, creating a tar archive. This is more
 -- efficient than
 --
@@ -192,6 +201,12 @@
 entriesToFileCpio :: Foldable t => FilePath -> t Entry -> ArchiveM ()
 entriesToFileCpio = entriesToFileGeneral archiveWriteSetFormatCpio
 
+-- | Write some entries to a file, creating a @.xar@ archive.
+--
+-- @since 2.2.4.0
+entriesToFileXar :: Foldable t => FilePath -> t Entry -> ArchiveM ()
+entriesToFileXar = entriesToFileGeneral archiveWriteSetFormatXar
+
 entriesToFileGeneral :: Foldable t => (Ptr Archive -> IO ArchiveResult) -> FilePath -> t Entry -> ArchiveM ()
 entriesToFileGeneral modifier fp hsEntries' =
     bracketM
@@ -204,11 +219,10 @@
             packEntries a hsEntries')
 
 withArchiveEntry :: (Ptr ArchiveEntry -> ArchiveM a) -> ArchiveM a
-withArchiveEntry fact =
+withArchiveEntry =
     bracketM
         archiveEntryNew
         archiveEntryFree
-        fact
 
 archiveEntryAdd :: Ptr Archive -> Entry -> ArchiveM ()
 archiveEntryAdd a (Entry fp contents perms owner mtime) =
diff --git a/src/Codec/Archive/Pack/Lazy.hs b/src/Codec/Archive/Pack/Lazy.hs
--- a/src/Codec/Archive/Pack/Lazy.hs
+++ b/src/Codec/Archive/Pack/Lazy.hs
@@ -2,10 +2,12 @@
                                , entriesToBSL7zip
                                , entriesToBSLzip
                                , entriesToBSLCpio
+                               , entriesToBSLXar
                                , packFiles
                                , packFilesZip
                                , packFiles7zip
                                , packFilesCpio
+                               , packFilesXar
                                ) where
 
 import           Codec.Archive.Foreign
@@ -48,6 +50,10 @@
 packFilesCpio :: Traversable t => t FilePath -> IO BSL.ByteString
 packFilesCpio = packer entriesToBSLCpio
 
+-- | @since 2.2.4.0
+packFilesXar :: Traversable t => t FilePath -> IO BSL.ByteString
+packFilesXar = packer entriesToBSLXar
+
 -- | @since 1.0.5.0
 entriesToBSLzip :: Foldable t => t Entry -> BSL.ByteString
 entriesToBSLzip = unsafeDupablePerformIO . noFail . entriesToBSLGeneral archiveWriteSetFormatZip
@@ -62,6 +68,11 @@
 entriesToBSLCpio :: Foldable t => t Entry -> BSL.ByteString
 entriesToBSLCpio = unsafeDupablePerformIO . noFail . entriesToBSLGeneral archiveWriteSetFormatCpio
 {-# NOINLINE entriesToBSLCpio #-}
+
+-- | @since 2.2.4.0
+entriesToBSLXar :: Foldable t => t Entry -> BSL.ByteString
+entriesToBSLXar = unsafeDupablePerformIO . noFail . entriesToBSLGeneral archiveWriteSetFormatXar
+{-# NOINLINE entriesToBSLXar #-}
 
 -- | In general, this will be more efficient than 'entriesToBS'
 --
