Sophie

Sophie

distrib > Mandriva > 2009.1 > x86_64 > by-pkgid > 8bc63a65c40388299760395af6f684f7 > files > 1

libarchive-2.6.2-1mdv2009.1.src.rpm

--- libarchive-2.6.0/configure.ac.xz~	2008-12-28 21:09:16.000000000 +0100
+++ libarchive-2.6.0/configure.ac	2009-01-21 22:11:51.000000000 +0100
@@ -186,14 +186,29 @@ if test "x$with_bz2lib" != "xno"; then
   AC_CHECK_LIB(bz2,BZ2_bzDecompressInit)
 fi
 
+AC_ARG_WITH([liblzma],
+  AS_HELP_STRING([--without-liblzma], [Don't build support for lzma/xz through liblzma]))
+
+# This is a bit clumsy, room for improval..
+# The issue is that liblzmadec & liblzma cannot both be used at once,
+# so in case of liblzma being found we disable libzlmadec.
+WITH_LIBLZMA=false
+if test "x$with_liblzma" != "xno"; then
+  AC_CHECK_HEADERS([lzma.h])
+  AC_CHECK_LIB(lzma,lzma_auto_decoder, [AC_DEFINE(HAVE_LIBLZMA, 1, [Define to 1 if you have the liblzma library.])
+					WITH_LIBLZMA=true
+					LIBS="$LIBS -llzma"])
+fi
+
 AC_ARG_WITH([lzmadec],
   AS_HELP_STRING([--without-lzmadec], [Don't build support for lzma through lzmadec]))
 
-if test "x$with_lzmadec" != "xno"; then
+if test "x$with_lzmadec" != "xno" && test "x$WITH_LIBLZMA" != "xtrue"; then
   AC_CHECK_HEADERS([lzmadec.h])
   AC_CHECK_LIB(lzmadec,lzmadec_decode)
 fi
 
+
 # TODO: Give the user the option of using a pre-existing system
 # libarchive.  This will define HAVE_LIBARCHIVE which will cause
 # bsdtar_platform.h to use #include <...> for the libarchive headers.
--- libarchive-2.6.0/libarchive/archive.h.xz~	2008-12-28 21:09:16.000000000 +0100
+++ libarchive-2.6.0/libarchive/archive.h	2009-01-21 22:11:51.000000000 +0100
@@ -226,6 +226,8 @@ typedef int	archive_close_callback(struc
 #define	ARCHIVE_COMPRESSION_COMPRESS	3
 #define	ARCHIVE_COMPRESSION_PROGRAM	4
 #define	ARCHIVE_COMPRESSION_LZMA	5
+#define	ARCHIVE_COMPRESSION_XZ		6
+
 
 /*
  * Codes returned by archive_format.
--- libarchive-2.6.0/libarchive/archive_read_support_compression_all.c.xz~	2008-12-28 21:08:32.000000000 +0100
+++ libarchive-2.6.0/libarchive/archive_read_support_compression_all.c	2009-01-21 22:11:51.000000000 +0100
@@ -39,11 +39,14 @@ archive_read_support_compression_all(str
 #if HAVE_ZLIB_H
 	archive_read_support_compression_gzip(a);
 #endif
-#if HAVE_LZMADEC_H
+#if HAVE_LZMADEC_H || HAVE_LZMA_H
 	/* LZMA bidding is subject to false positives because
 	 * the LZMA file format has a very weak signature.  It
 	 * may not be feasible to include LZMA detection here. */
 	/* archive_read_support_compression_lzma(a); */
 #endif
+#if HAVE_LZMA_H
+	archive_read_support_compression_xz(a);
+#endif	
 	return (ARCHIVE_OK);
 }
--- libarchive-2.6.0/libarchive/archive_read_support_compression_lzma.c.xz~	2008-12-28 21:08:32.000000000 +0100
+++ libarchive-2.6.0/libarchive/archive_read_support_compression_lzma.c	2009-01-21 22:11:51.000000000 +0100
@@ -74,6 +74,7 @@ static struct archive_read_source *lzma_
     const void *, size_t);
 static int	lzma_reader_free(struct archive_reader *);
 
+#ifndef HAVE_LZMA_H
 int
 archive_read_support_compression_lzma(struct archive *_a)
 {
@@ -89,6 +90,7 @@ archive_read_support_compression_lzma(st
 	reader->free = lzma_reader_free;
 	return (ARCHIVE_OK);
 }
+#endif
 
 static int
 lzma_reader_free(struct archive_reader *self){
--- libarchive-2.6.0/libarchive/archive_read_support_compression_xz.c.xz~	2009-01-21 22:11:51.000000000 +0100
+++ libarchive-2.6.0/libarchive/archive_read_support_compression_xz.c	2009-01-21 22:11:51.000000000 +0100
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna
+ * Copyright (c) 2009 Per Øyvind Karlsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#if HAVE_LZMA_H
+struct private_data {
+	lzma_stream	 stream;
+	unsigned char	*out_block;
+	size_t		 out_block_size;
+	int64_t		 total_out;
+	char		 eof; /* True = found end of compressed data. */
+};
+
+/* Lzma source */
+static ssize_t	xz_source_read(struct archive_read_source *, const void **);
+static int	xz_source_close(struct archive_read_source *);
+#endif
+
+/*
+ * Note that we can detect lzma archives even if we can't decompress
+ * them.  (In fact, we like detecting them because we can give better
+ * error messages.)  So the bid framework here gets compiled even
+ * if liblzma is unavailable.
+ */
+static int	lzma_reader_bid(struct archive_reader *, const void *, size_t);
+static int	xz_reader_bid(struct archive_reader *, const void *, size_t);
+static struct archive_read_source *lzma_reader_init(struct archive_read *,
+    struct archive_reader *, struct archive_read_source *,
+    const void *, size_t);
+static struct archive_read_source *xz_reader_init(struct archive_read *,
+    struct archive_reader *, struct archive_read_source *,
+    const void *, size_t);
+static struct archive_read_source *liblzma_reader_init(struct archive_read *,
+    struct archive_reader *, struct archive_read_source *,
+    const void *, size_t);
+static int	xz_reader_free(struct archive_reader *);
+
+#ifndef HAVE_LZMADEC_H
+int
+archive_read_support_compression_lzma(struct archive *_a)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	struct archive_reader *reader = __archive_read_get_reader(a);
+
+	if (reader == NULL)
+		return (ARCHIVE_FATAL);
+
+	reader->data = NULL;
+	reader->bid = lzma_reader_bid;
+	reader->init = lzma_reader_init;
+	reader->free = xz_reader_free;
+	return (ARCHIVE_OK);
+}
+#endif
+
+int
+archive_read_support_compression_xz(struct archive *_a)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	struct archive_reader *reader = __archive_read_get_reader(a);
+
+	if (reader == NULL)
+		return (ARCHIVE_FATAL);
+
+	reader->data = NULL;
+	reader->bid = xz_reader_bid;
+	reader->init = xz_reader_init;
+	reader->free = xz_reader_free;
+	return (ARCHIVE_OK);
+}
+
+static int
+xz_reader_free(__attribute__((unused)) struct archive_reader *self){
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails.  It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ *
+ * <sigh> LZMA has a rather poor file signature.  Zeros do not
+ * make good signature bytes as a rule, and the only non-zero byte
+ * here is an ASCII character.  For example, an uncompressed tar
+ * archive whose first file is ']' would satisfy this check.  It may
+ * be necessary to exclude LZMA from compression_all() because of
+ * this.  Clients of libarchive would then have to explicitly enable
+ * LZMA checking instead of (or in addition to) compression_all() when
+ * they have other evidence (file name, command-line option) to go on.
+ */
+static int
+lzma_reader_bid(__attribute__((unused)) struct archive_reader *self,
+		const void *buff, size_t len)
+{
+	const unsigned char *buffer;
+	int bits_checked;
+
+	buffer = (const unsigned char *)buff;
+
+
+	/* First byte of raw LZMA stream is always 0x5d. */
+	if (len < 1)
+		return (0);
+	bits_checked = 0;
+	if (buffer[0] != 0x5d)
+		return (0);
+	bits_checked += 8;
+
+	/* Second through fifth bytes are dictionary code, stored in
+	 * little-endian order.  The two least-significant bytes are
+	 * always zero. */
+	if (len < 2)
+		return (bits_checked);
+	if (buffer[1] != 0)
+		return (0);
+	bits_checked += 8;
+
+	if (len < 3)
+		return (bits_checked);
+	if (buffer[2] != 0)
+		return (0);
+	bits_checked += 8;
+
+	/* peroyvind: the LZMA_Alone format doesn't really have any signature at all,
+	 * the header data is affected by lzma compression options, thus arbitrary.
+	 * The first byte doesn't even have to be 0x5d, ie. with the new liblzma
+	 * library when using extreme mode this won't be true..
+	 */
+	/* NSIS format check uses this, but I've seen tar.lzma
+	 * archives where this byte is 0xff, not 0. */
+#if 0
+	if (len < 6)
+		return (bits_checked);
+	if (buffer[5] != 0)
+		return (0);
+	bits_checked += 8;
+#endif
+
+	/* TODO: The above test is still very weak.  It would be
+	 * good to do better. */
+
+	return (bits_checked);
+}
+
+static int
+xz_reader_bid(__attribute__((unused)) struct archive_reader *self,
+		const void *buff, size_t len)
+{
+	const unsigned char *buffer;
+	int bits_checked;
+
+	if (len < 1)
+		return (0);
+
+	buffer = (const unsigned char *)buff;
+	bits_checked = 0;
+	if (buffer[0] != 0xFD)	/* Verify first ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 2)
+		return (bits_checked);
+
+	if (buffer[1] != '7')	/* Verify second ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 3)
+		return (bits_checked);
+
+	if (buffer[2] != 'z')	/* Verify third ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 4)
+		return (bits_checked);
+
+	if (buffer[3] != 'X')	/* Verify fourth ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 5)
+		return (bits_checked);
+
+	if (buffer[4] != 'Z')	/* Verify fifth ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 6)
+		return (bits_checked);
+	
+	if (buffer[5] != 0x00)	/* Verify sixth ID byte. */
+		return (0);
+	bits_checked += 8;
+	if (len < 7)
+		return (bits_checked);
+
+	/*
+	 * TODO: Verify more; xz has more data in both the header and footer that
+	 * would be nice to verify (ie. CRC).
+	 * See section 2.1 of the xz format description.
+	 */
+
+	return (bits_checked);
+}
+
+#ifndef HAVE_LZMA_H
+
+/*
+ * If we don't have the library on this system, we can't actually do the
+ * decompression.  We can, however, still detect compressed archives
+ * and emit a useful message.
+ */
+static struct archive_read_source *
+lzma_reader_init(struct archive_read *a,
+		__attribute__((unused)) struct archive_reader *reader,
+	    __attribute__((unused)) struct archive_read_source *upstream,
+	    __attribute__((unused)) const void *buff,
+	   __attribute__((unused)) size_t n)
+{
+	archive_set_error(&a->archive, -1,
+	    "This version of libarchive was compiled without lzma support");
+	return (NULL);
+}
+
+static struct archive_read_source *
+xz_reader_init(struct archive_read *a,
+		__attribute__((unused)) struct archive_reader *reader,
+	    __attribute__((unused)) struct archive_read_source *upstream,
+	    __attribute__((unused)) const void *buff,
+	   __attribute__((unused)) size_t n)
+{
+	archive_set_error(&a->archive, -1,
+	    "This version of libarchive was compiled without xz support");
+	return (NULL);
+}
+
+#else
+
+/*
+ * Setup the callbacks.
+ */
+static struct archive_read_source *
+lzma_reader_init(struct archive_read *a, struct archive_reader *reader,
+    struct archive_read_source *upstream, const void *buff, size_t n)
+{
+	a->archive.compression_code = ARCHIVE_COMPRESSION_LZMA;
+	a->archive.compression_name = "lzma";
+	return liblzma_reader_init(a, reader, upstream, buff, n);
+}
+
+static struct archive_read_source *
+xz_reader_init(struct archive_read *a, struct archive_reader *reader,
+    struct archive_read_source *upstream, const void *buff, size_t n)
+{
+	a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
+	a->archive.compression_name = "xz";
+	return liblzma_reader_init(a, reader, upstream, buff, n);
+}
+
+static struct archive_read_source *
+liblzma_reader_init(struct archive_read *a, __attribute__((unused)) struct archive_reader *reader,
+    struct archive_read_source *upstream, const void *buff, size_t n)
+{
+	static const size_t out_block_size = 64 * 1024;
+	void *out_block;
+	struct archive_read_source *self;
+	struct private_data *state;
+	lzma_ret ret;
+
+	self = calloc(sizeof(*self), 1);
+	state = (struct private_data *)calloc(sizeof(*state), 1);
+	out_block = (unsigned char *)malloc(out_block_size);
+	if (self == NULL || state == NULL || out_block == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate data for %s decompression",
+		    a->archive.compression_name);
+		free(out_block);
+		free(state);
+		free(self);
+		return (NULL);
+	}
+
+
+	self->archive = a;
+	self->data = state;
+	state->out_block_size = out_block_size;
+	state->out_block = out_block;
+	self->upstream = upstream;
+	self->read = xz_source_read;
+	self->skip = NULL; /* not supported */
+	self->close = xz_source_close;
+
+	state->stream.next_in = buff;
+	state->stream.avail_in = n;
+
+	state->stream.next_out = state->out_block;
+	state->stream.avail_out = state->out_block_size;
+
+	/* Initialize compression library. */
+	ret = lzma_auto_decoder(&(state->stream), -1, 0);
+
+	if (ret == LZMA_OK)
+		return (self);
+
+	/* Library setup failed: Clean up. */
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+	    "Internal error initializing %s library",
+	    a->archive.compression_name);
+
+	/* Override the error message if we know what really went wrong. */
+	switch (ret) {
+	case LZMA_DATA_ERROR:
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Internal error initializing compression library: "
+		    "invalid data");
+		break;
+	case LZMA_MEM_ERROR:
+		archive_set_error(&a->archive, ENOMEM,
+		    "Internal error initializing compression library: "
+		    "out of memory");
+		break;
+	}
+
+	free(state->out_block);
+	free(state);
+	free(self);
+	return (NULL);
+}
+
+/*
+ * Return the next block of decompressed data.
+ */
+static ssize_t
+xz_source_read(struct archive_read_source *self, const void **p)
+{
+	struct private_data *state;
+	size_t read_avail, decompressed;
+	const void *read_buf;
+	lzma_ret ret;
+
+	state = (struct private_data *)self->data;
+	read_avail = 0;
+
+	/* Empty our output buffer. */
+	state->stream.next_out = state->out_block;
+	state->stream.avail_out = state->out_block_size;
+
+	/* Try to fill the output buffer. */
+	for (;;) {
+		/* If the last upstream block is done, get another one. */
+		if (state->stream.avail_in == 0) {
+			ret = (self->upstream->read)(self->upstream,
+			    &read_buf);
+			/* stream.next_in is really const, but lzmadec
+			 * doesn't declare it so. <sigh> */
+			state->stream.next_in
+			    = (unsigned char *)(uintptr_t)read_buf;
+			if (ret < 0)
+				return (ARCHIVE_FATAL);
+			/* There is no more data, return whatever we have. */
+			if (ret == 0) {
+				*p = state->out_block;
+				decompressed = state->stream.next_out
+				    - state->out_block;
+				state->total_out += decompressed;
+				return (decompressed);
+			}
+			state->stream.avail_in = ret;
+		}
+
+		/* Decompress as much as we can in one pass. */
+		ret = lzma_code(&(state->stream), LZMA_RUN);
+		switch (ret) {
+		case LZMA_STREAM_END: /* Found end of stream. */
+			/* TODO: Peek ahead to see if there's another
+			 * stream so we can mimic the behavior of gunzip
+			 * on concatenated streams. */
+			state->eof = 1;
+		case LZMA_OK: /* Decompressor made some progress. */
+			/* If we filled our buffer, update stats and return. */
+			if (state->eof || state->stream.avail_out == 0) {
+				*p = state->out_block;
+				decompressed = state->stream.next_out
+				    - state->out_block;
+				state->total_out += decompressed;
+				return (decompressed);
+			}
+			break;
+		default:
+			/* Return an error. */
+			archive_set_error(&self->archive->archive,
+			    ARCHIVE_ERRNO_MISC,
+			    "%s decompression failed",
+			    self->archive->archive.compression_name);
+			return (ARCHIVE_FATAL);
+		}
+	}
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+xz_source_close(struct archive_read_source *self)
+{
+	struct private_data *state;
+	int ret;
+
+	state = (struct private_data *)self->data;
+	ret = ARCHIVE_OK;
+	lzma_end(&(state->stream));
+
+	free(state->out_block);
+	free(state);
+	free(self);
+	return (ret);
+}
+
+#endif /* HAVE_LZMA_H */
--- libarchive-2.6.0/libarchive/archive_write_set_compression_xz.c.xz~	2009-01-21 22:11:51.000000000 +0100
+++ libarchive-2.6.0/libarchive/archive_write_set_compression_xz.c	2009-01-21 22:11:51.000000000 +0100
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2009 Per Øyvind Karlsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+/* Don't compile this if we don't have bzlib. */
+#if HAVE_LZMA_H
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+struct private_data {
+	lzma_stream	 stream;
+	int64_t		 total_in;
+	char		*compressed;
+	size_t		 compressed_buffer_size;
+};
+
+
+static int	archive_compressor_xz_finish(struct archive_write *);
+static int	archive_compressor_xz_init(struct archive_write *);
+static int	archive_compressor_xz_write(struct archive_write *,
+		    const void *, size_t);
+static int	drive_compressor(struct archive_write *, struct private_data *,
+		    int finishing);
+
+/*
+ * Allocate, initialize and return an archive object.
+ */
+int
+archive_write_set_compression_xz(struct archive *_a)
+{
+	struct archive_write *a = (struct archive_write *)_a;
+	__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_set_compression_xz");
+	a->compressor.init = &archive_compressor_xz_init;
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_xz_init(struct archive_write *a)
+{
+	int ret;
+	struct private_data *state;
+
+	a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
+	a->archive.compression_name = "xz";
+
+	if (a->client_opener != NULL) {
+		ret = (a->client_opener)(&a->archive, a->client_data);
+		if (ret != 0)
+			return (ret);
+	}
+
+	state = (struct private_data *)malloc(sizeof(*state));
+	if (state == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate data for compression");
+		return (ARCHIVE_FATAL);
+	}
+	memset(state, 0, sizeof(*state));
+
+	state->compressed_buffer_size = a->bytes_per_block;
+	state->compressed = (char *)malloc(state->compressed_buffer_size);
+
+	if (state->compressed == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate data for compression buffer");
+		free(state);
+		return (ARCHIVE_FATAL);
+	}
+
+	state->stream.next_out = state->compressed;
+	state->stream.avail_out = state->compressed_buffer_size;
+	a->compressor.write = archive_compressor_xz_write;
+	a->compressor.finish = archive_compressor_xz_finish;
+
+	/* Initialize compression library */
+	ret = lzma_easy_encoder(&(state->stream), LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
+	if (ret == LZMA_OK) {
+		a->compressor.data = state;
+		return (ARCHIVE_OK);
+	}
+
+	/* Library setup failed: clean up. */
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+	    "Internal error initializing compression library");
+	free(state->compressed);
+	free(state);
+
+	/* Override the error message if we know what really went wrong. */
+	switch (ret) {
+	case LZMA_PROG_ERROR:
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Internal error initializing compression library: "
+		    "invalid setup parameter");
+		break;
+	case LZMA_MEM_ERROR:
+		archive_set_error(&a->archive, ENOMEM,
+		    "Internal error initializing compression library: "
+		    "out of memory");
+		break;
+	}
+
+	return (ARCHIVE_FATAL);
+
+}
+
+/*
+ * Write data to the compressed stream.
+ *
+ * Returns ARCHIVE_OK if all data written, error otherwise.
+ */
+static int
+archive_compressor_xz_write(struct archive_write *a, const void *buff,
+    size_t length)
+{
+	struct private_data *state;
+
+	state = (struct private_data *)a->compressor.data;
+	if (a->client_writer == NULL) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+		    "No write callback is registered?  "
+		    "This is probably an internal programming error.");
+		return (ARCHIVE_FATAL);
+	}
+
+	/* Update statistics */
+	state->total_in += length;
+
+	/* Compress input data to output buffer */
+	state->stream.next_in = buff;
+	state->stream.avail_in = length;
+	if (drive_compressor(a, state, 0))
+		return (ARCHIVE_FATAL);
+	a->archive.file_position += length;
+	return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_compressor_xz_finish(struct archive_write *a)
+{
+	ssize_t block_length;
+	int ret;
+	struct private_data *state;
+	ssize_t target_block_length;
+	ssize_t bytes_written;
+	unsigned tocopy;
+
+	state = (struct private_data *)a->compressor.data;
+	ret = ARCHIVE_OK;
+	if (a->client_writer == NULL) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+		    "No write callback is registered?\n"
+		    "This is probably an internal programming error.");
+		ret = ARCHIVE_FATAL;
+		goto cleanup;
+	}
+
+	/* By default, always pad the uncompressed data. */
+	if (a->pad_uncompressed) {
+		tocopy = a->bytes_per_block -
+		    (state->total_in % a->bytes_per_block);
+		while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+			state->stream.next_in, a->nulls;
+			state->stream.avail_in = tocopy < a->null_length ?
+			    tocopy : a->null_length;
+			state->total_in += state->stream.avail_in;
+			tocopy -= state->stream.avail_in;
+			ret = drive_compressor(a, state, 0);
+			if (ret != ARCHIVE_OK)
+				goto cleanup;
+		}
+	}
+
+	/* Finish compression cycle. */
+	if ((ret = drive_compressor(a, state, 1)))
+		goto cleanup;
+
+	/* Optionally, pad the final compressed block. */
+	block_length = (char *)state->stream.next_out - state->compressed;
+
+
+	/* Tricky calculation to determine size of last block. */
+	target_block_length = block_length;
+	if (a->bytes_in_last_block <= 0)
+		/* Default or Zero: pad to full block */
+		target_block_length = a->bytes_per_block;
+	else
+		/* Round length to next multiple of bytes_in_last_block. */
+		target_block_length = a->bytes_in_last_block *
+		    ( (block_length + a->bytes_in_last_block - 1) /
+			a->bytes_in_last_block);
+	if (target_block_length > a->bytes_per_block)
+		target_block_length = a->bytes_per_block;
+	if (block_length < target_block_length) {
+		memset(state->stream.next_out, 0,
+		    target_block_length - block_length);
+		block_length = target_block_length;
+	}
+
+	/* Write the last block */
+	bytes_written = (a->client_writer)(&a->archive, a->client_data,
+	    state->compressed, block_length);
+
+	/* TODO: Handle short write of final block. */
+	if (bytes_written <= 0)
+		ret = ARCHIVE_FATAL;
+	else {
+		a->archive.raw_position += ret;
+		ret = ARCHIVE_OK;
+	}
+
+	/* Cleanup: shut down compressor, release memory, etc. */
+cleanup:
+	lzma_end(&(state->stream));
+
+	free(state->compressed);
+	free(state);
+	return (ret);
+}
+
+/*
+ * Utility function to push input data through compressor, writing
+ * full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
+{
+	ssize_t	bytes_written;
+	int ret;
+
+	for (;;) {
+		if (state->stream.avail_out == 0) {
+			bytes_written = (a->client_writer)(&a->archive,
+			    a->client_data, state->compressed,
+			    state->compressed_buffer_size);
+			if (bytes_written <= 0) {
+				/* TODO: Handle this write failure */
+				return (ARCHIVE_FATAL);
+			} else if ((size_t)bytes_written < state->compressed_buffer_size) {
+				/* Short write: Move remainder to
+				 * front and keep filling */
+				memmove(state->compressed,
+				    state->compressed + bytes_written,
+				    state->compressed_buffer_size - bytes_written);
+			}
+
+			a->archive.raw_position += bytes_written;
+			state->stream.next_out = state->compressed +
+			    state->compressed_buffer_size - bytes_written;
+			state->stream.avail_out = bytes_written;
+		}
+
+		/* If there's nothing to do, we're done. */
+		if (!finishing && state->stream.avail_in == 0)
+			return (ARCHIVE_OK);
+
+		ret = lzma_code(&(state->stream),
+		    finishing ? LZMA_FINISH : LZMA_RUN);
+
+		switch (ret) {
+		case LZMA_RUN:
+			/* In non-finishing case, did compressor
+			 * consume everything? */
+			if (!finishing && state->stream.avail_in == 0)
+				return (ARCHIVE_OK);
+			break;
+		case LZMA_FINISH:  /* Finishing: There's more work to do */
+			break;
+		case LZMA_STREAM_END: /* Finishing: all done */
+			/* Only occurs in finishing case */
+			return (ARCHIVE_OK);
+		default:
+			/* Any other return value indicates an error */
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_PROGRAMMER,
+			    "XZ compression failed;"
+			    " lzma_code() returned %d",
+			    ret);
+			return (ARCHIVE_FATAL);
+		}
+	}
+}
+
+#endif /* HAVE_LZMA_H */
--- libarchive-2.6.0/libarchive/test/test_compat_xz_1.tar.xz.uu.xz~	2009-01-21 22:27:43.000000000 +0100
+++ libarchive-2.6.0/libarchive/test/test_compat_xz_1.tar.xz.uu	2009-01-21 22:25:41.000000000 +0100
@@ -0,0 +1,9 @@
+begin 644 test_compat_xz_1.tar.xz
+M_3=Z6%H```3FUK1&`@`A`18```!T+^6CX!O_`*%=`#,,/!NGC#0&C6L"2_R2
+M/O9*^(7KX=WM^(=KA(RH"\09$$)!Q_+JUHQ*`]R;ITL_F3/I6:^Q0550A&)B
+MHS@=K]7@K1-9FOIP#PU!I<PUHW+W#<F(6FSL/<?5:4*>?E5&IHH&Q=N>_C&G
+M-$G]+L[\,B<7%8&$NO5K31*Y>"D^+<YY3.*21VQ'3VXK3<KW>P,ES086$*..
+MC?A%?!$<8ZD8]A--`````/,<.:MU#&'6``&]`8`X``#5_T"?L<1G^P(`````
+#!%E:
+`
+end
--- libarchive-2.6.0/libarchive/test/test_compat_xz_2.tar.xz.uu.xz~	2009-01-21 22:27:41.000000000 +0100
+++ libarchive-2.6.0/libarchive/test/test_compat_xz_2.tar.xz.uu	2009-01-21 22:27:21.000000000 +0100
@@ -0,0 +1,9 @@
+begin 644 test_compat_xz_2.tar.xz
+M_3=Z6%H```3FUK1&`@`A`18```!T+^6CX!O_`*%=`#,,/!NGC#0&C6L"2_R2
+M/O9*^(7KX=WM^(=KA(RH"\09$$)!Q_+JUHQ*`]R;ITL_F3/I6:^Q0550A&)B
+MHS@=K]7@K1-9FOIP#PU!I<PUHW+W#<F(6FSL/<?5:4*>?E5&IHH&Q=N>_C&G
+M-$G]+L[\,B<7%8&$NO5K31*Y>"D^+<YY3.*21VQ'3VXK3<KW>P,ES086$*..
+MC?A%?!$<8ZD8]A--`````/,<.:MU#&'6``&]`8`X``#5_T"?L<1G^P(`````
+#!%E:
+`
+end
--- libarchive-2.6.0/libarchive/test/test_compat_xz.c.xz~	2009-01-21 22:20:18.000000000 +0100
+++ libarchive-2.6.0/libarchive/test/test_compat_xz.c	2009-01-21 22:21:39.000000000 +0100
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle
+ * Copyright (c) 2009 Per Øyvind Karlsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Verify our ability to read sample files compatibly with unxz.
+ *
+ * In particular:
+ *  * unxz will read multiple xz streams, concatenating the output
+ *  * unxz will stop at the end of a stream if the following data
+ *    doesn't start with a xz signature.
+ */
+
+/*
+ * All of the sample files have the same contents; they're just
+ * compressed in different ways.
+ */
+static void
+compat_xz(const char *name)
+{
+	const char *n[7] = { "f1", "f2", "f3", "d1/f1", "d1/f2", "d1/f3", NULL };
+	struct archive_entry *ae;
+	struct archive *a;
+	int i,r;
+
+	assert((a = archive_read_new()) != NULL);
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+	extract_reference_file(name);
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 200));
+
+	/* Read entries, match up names with list above. */
+	for (i = 0; i < 6; ++i) {
+		r = archive_read_next_header(a, &ae);
+		failure("Could not read file %d (%s) from %s", i, n[i], name);
+		assertEqualIntA(a, ARCHIVE_OK, r);
+		if (r != ARCHIVE_OK) {
+			archive_read_finish(a);
+			return;
+		}
+		assertEqualString(n[i], archive_entry_pathname(ae));
+	}
+
+	/* Verify the end-of-archive. */
+	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+	/* Verify that the format detection worked. */
+	assertEqualInt(archive_compression(a), ARCHIVE_COMPRESSION_XZ);
+	assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
+
+	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+#if ARCHIVE_VERSION_NUMBER < 2000000
+	archive_read_finish(a);
+#else
+	assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+#endif
+}
+
+
+DEFINE_TEST(test_compat_xz)
+{
+	compat_xz("test_compat_xz_1.tar.xz");
+	compat_xz("test_compat_xz_2.tar.xz");
+}
+
+
--- libarchive-2.6.0/libarchive/test/test_read_format_gtar_xz.c.xz~	2009-01-21 22:11:51.000000000 +0100
+++ libarchive-2.6.0/libarchive/test/test_read_format_gtar_xz.c	2009-01-21 22:11:51.000000000 +0100
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2008 Miklos Vajna
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x04, 0xe6, 0xd6, 0xb4, 0x46, 0x02,
+0x00, 0x21, 0x01, 0x16, 0x00, 0x00, 0x00, 0x74, 0x2f, 0xe5, 0xa3, 0xe0, 0x27,
+0xff, 0x00, 0x62, 0x5d, 0x00, 0x17, 0x0b, 0xbc, 0x1c, 0x7d, 0x01, 0x95, 0xc0,
+0x1d, 0x4a, 0x46, 0x9c, 0x1c, 0xc5, 0x08, 0x83, 0x9b, 0x8a, 0x01, 0xc4, 0x5a,
+0x08, 0xe8, 0xf1, 0xac, 0xc0, 0x24, 0x8a, 0xfd, 0x60, 0xc9, 0xcd, 0xdc, 0xaa,
+0x1b, 0xab, 0x28, 0x63, 0xfe, 0xda, 0x71, 0x9a, 0x84, 0x94, 0xa2, 0x85, 0x96,
+0x59, 0x26, 0x48, 0x4d, 0x6f, 0x70, 0x24, 0x8d, 0x4a, 0x75, 0x07, 0x67, 0xcc,
+0xad, 0x7a, 0x6d, 0xd3, 0xb2, 0xb2, 0x8e, 0x61, 0xaa, 0xc2, 0xc3, 0xbe, 0xc8,
+0x9e, 0x75, 0x9d, 0xbb, 0x8a, 0x1f, 0x5c, 0xdd, 0xcf, 0xe2, 0x21, 0xb2, 0x13,
+0xe5, 0x1e, 0xd4, 0x49, 0xbc, 0x55, 0x90, 0x88, 0x3a, 0xc4, 0x05, 0x00, 0x00,
+0x00, 0x00, 0x3a, 0x18, 0xfa, 0xd5, 0x35, 0x88, 0x18, 0x90, 0x00, 0x01, 0x7e,
+0x80, 0x50, 0x00, 0x00, 0x00, 0x5c, 0x07, 0x96, 0x88, 0xb1, 0xc4, 0x67, 0xfb,
+0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5a};
+
+DEFINE_TEST(test_read_format_gtar_xz)
+{
+	int r;
+
+	struct archive_entry *ae;
+	struct archive *a;
+	assert((a = archive_read_new()) != NULL);
+	assertEqualIntA(a, ARCHIVE_OK,
+	    archive_read_support_compression_all(a));
+	assertEqualIntA(a, ARCHIVE_OK,
+	    archive_read_support_compression_xz(a));
+	assertEqualIntA(a, ARCHIVE_OK,
+	    archive_read_support_format_all(a));
+	r = archive_read_open_memory(a, archive, sizeof(archive));
+	if (r != ARCHIVE_OK) {
+		skipping("Skipping LZMA compression check: %s",
+		    archive_error_string(a));
+		goto finish;
+	}
+	assertEqualIntA(a, ARCHIVE_OK,
+	    archive_read_next_header(a, &ae));
+	assertEqualInt(archive_compression(a), ARCHIVE_COMPRESSION_XZ);
+	assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+finish:
+#if ARCHIVE_VERSION_NUMBER < 2000000
+	archive_read_finish(a);
+#else
+	assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+#endif
+}
+
+
--- libarchive-2.6.0/Makefile.am.xz~	2008-12-28 21:08:32.000000000 +0100
+++ libarchive-2.6.0/Makefile.am	2009-01-21 22:28:17.000000000 +0100
@@ -99,6 +99,7 @@ libarchive_la_SOURCES=						\
 	libarchive/archive_read_support_compression_none.c	\
 	libarchive/archive_read_support_compression_program.c	\
 	libarchive/archive_read_support_compression_lzma.c	\
+	libarchive/archive_read_support_compression_xz.c	\
 	libarchive/archive_read_support_format_all.c		\
 	libarchive/archive_read_support_format_ar.c		\
 	libarchive/archive_read_support_format_cpio.c		\
@@ -126,6 +127,7 @@ libarchive_la_SOURCES=						\
 	libarchive/archive_write_set_compression_gzip.c		\
 	libarchive/archive_write_set_compression_none.c		\
 	libarchive/archive_write_set_compression_program.c	\
+	libarchive/archive_write_set_compression_xz.c	\
 	libarchive/archive_write_set_format.c			\
 	libarchive/archive_write_set_format_ar.c		\
 	libarchive/archive_write_set_format_by_name.c		\
@@ -185,6 +187,7 @@ libarchive_test_SOURCES=					\
 	libarchive/test/test_compat_gtar.c			\
 	libarchive/test/test_compat_gzip.c			\
 	libarchive/test/test_compat_tar_hardlink.c		\
+	libarchive/test/test_compat_xz.c			\
 	libarchive/test/test_compat_zip.c			\
 	libarchive/test/test_empty_write.c			\
 	libarchive/test/test_entry.c				\
@@ -207,6 +210,7 @@ libarchive_test_SOURCES=					\
 	libarchive/test/test_read_format_gtar_gz.c		\
 	libarchive/test/test_read_format_gtar_lzma.c		\
 	libarchive/test/test_read_format_gtar_sparse.c		\
+	libarchive/test/test_read_format_gtar_xz.c		\
 	libarchive/test/test_read_format_iso_gz.c		\
 	libarchive/test/test_read_format_isorr_bz2.c		\
 	libarchive/test/test_read_format_mtree.c		\
@@ -260,6 +264,8 @@ libarchive_test_EXTRA_DIST=\
 	libarchive/test/test_compat_gzip_1.tgz.uu			\
 	libarchive/test/test_compat_gzip_2.tgz.uu			\
 	libarchive/test/test_compat_tar_hardlink_1.tar.uu		\
+	libarchive/test/test_compat_xz_1.tar.xz.uu			\
+	libarchive/test/test_compat_xz_2.tar.xz.uu			\
 	libarchive/test/test_compat_zip_1.zip.uu			\
 	libarchive/test/test_fuzz_1.iso.uu				\
 	libarchive/test/test_pax_filename_encoding.tar.gz.uu		\
--- libarchive-2.6.0/tar/bsdtar.1.xz~	2008-12-28 21:08:12.000000000 +0100
+++ libarchive-2.6.0/tar/bsdtar.1	2009-01-21 22:11:51.000000000 +0100
@@ -434,6 +434,15 @@ Note that, unlike other
 .Nm tar
 implementations, this implementation recognizes bzip2 compression
 automatically when reading archives.
+.It Fl Y
+(c mode only)
+Compress the resulting archive with
+.Xr xz 1 .
+In extract or list modes, this option is ignored.
+Note that, unlike other
+.Nm tar
+implementations, this implementation recognizes xz compression
+automatically when reading archives.
 .It Fl z
 (c mode only)
 Compress the resulting archive with
@@ -694,7 +703,8 @@ components, or symlinks to other directo
 .Xr shar 1 ,
 .Xr libarchive 3 ,
 .Xr libarchive-formats 5 ,
-.Xr tar 5
+.Xr tar 5 ,
+.Xr xz 1
 .Sh STANDARDS
 There is no current POSIX standard for the tar command; it appeared
 in
--- libarchive-2.6.0/tar/bsdtar.c.xz~	2008-12-28 21:08:12.000000000 +0100
+++ libarchive-2.6.0/tar/bsdtar.c	2009-01-21 22:11:51.000000000 +0100
@@ -417,6 +417,19 @@ main(int argc, char **argv)
 		case 'x': /* SUSv2 */
 			set_mode(bsdtar, opt);
 			break;
+		case 'Y':
+#if HAVE_LIBLZMA
+			if (bsdtar->create_compression != '\0')
+				bsdtar_errc(bsdtar, 1, 0,
+				    "Can't specify both -%c and -%c", opt,
+				    bsdtar->create_compression);
+			bsdtar->create_compression = opt;
+#else
+			bsdtar_warnc(bsdtar, 0,
+			    "xz compression not supported by this version of bsdtar");
+			usage(bsdtar);
+#endif
+			break;
 		case 'y': /* FreeBSD version of GNU tar */
 #if HAVE_LIBBZ2
 			if (bsdtar->create_compression != '\0')
--- libarchive-2.6.0/tar/cmdline.c.xz~	2008-12-28 21:08:12.000000000 +0100
+++ libarchive-2.6.0/tar/cmdline.c	2009-01-21 22:11:51.000000000 +0100
@@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$");
  * Short options for tar.  Please keep this sorted.
  */
 static const char *short_options
-	= "Bb:C:cf:HhI:jkLlmnOoPpqrSs:T:tUuvW:wX:xyZz";
+	= "Bb:C:cf:HhI:jkLlmnOoPpqrSs:T:tUuvW:wX:xYyZz";
 
 /*
  * Long options for tar.  Please keep this list sorted.
@@ -117,10 +117,12 @@ static struct option {
 	{ "uncompress",           0, 'Z' },
 	{ "unlink",		  0, 'U' },
 	{ "unlink-first",	  0, 'U' },
+	{ "unxz",                 0, 'Y' },
 	{ "update",               0, 'u' },
 	{ "use-compress-program", 1, OPTION_USE_COMPRESS_PROGRAM },
 	{ "verbose",              0, 'v' },
 	{ "version",              0, OPTION_VERSION },
+	{ "xz",                   0, 'Y' },
 	{ NULL, 0, 0 }
 };
 
--- libarchive-2.6.0/tar/write.c.xz~	2008-12-28 21:08:12.000000000 +0100
+++ libarchive-2.6.0/tar/write.c	2009-01-21 22:11:51.000000000 +0100
@@ -197,6 +197,11 @@ tar_mode_c(struct bsdtar *bsdtar)
 			archive_write_set_compression_bzip2(a);
 			break;
 #endif
+#ifdef HAVE_LIBLZMA
+		case 'Y':
+			archive_write_set_compression_xz(a);
+			break;
+#endif
 #ifdef HAVE_LIBZ
 		case 'z':
 			archive_write_set_compression_gzip(a);