From fe3cf0e14f5d3626c61231a9bc8e9ca6ba3e4812 Mon Sep 17 00:00:00 2001 From: kientzle Date: Sun, 31 Aug 2008 07:21:46 +0000 Subject: New mtree writer, thanks to Joerg Sonnenberger. Obtained from: Joerg Sonnenberger --- lib/libarchive/Makefile | 1 + lib/libarchive/archive.h | 1 + lib/libarchive/archive_write_set_format.c | 1 + lib/libarchive/archive_write_set_format_by_name.c | 1 + lib/libarchive/archive_write_set_format_mtree.c | 259 ++++++++++++++++++++++ 5 files changed, 263 insertions(+) create mode 100644 lib/libarchive/archive_write_set_format_mtree.c (limited to 'lib') diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile index 0d10500..d41e456 100644 --- a/lib/libarchive/Makefile +++ b/lib/libarchive/Makefile @@ -65,6 +65,7 @@ SRCS= archive_check_magic.c \ archive_write_set_format_by_name.c \ archive_write_set_format_cpio.c \ archive_write_set_format_cpio_newc.c \ + archive_write_set_format_mtree.c \ archive_write_set_format_pax.c \ archive_write_set_format_shar.c \ archive_write_set_format_ustar.c \ diff --git a/lib/libarchive/archive.h b/lib/libarchive/archive.h index 791da1d..d383ab5 100644 --- a/lib/libarchive/archive.h +++ b/lib/libarchive/archive.h @@ -465,6 +465,7 @@ __LA_DECL int archive_write_set_format_ar_bsd(struct archive *); __LA_DECL int archive_write_set_format_ar_svr4(struct archive *); __LA_DECL int archive_write_set_format_cpio(struct archive *); __LA_DECL int archive_write_set_format_cpio_newc(struct archive *); +__LA_DECL int archive_write_set_format_mtree(struct archive *); /* TODO: int archive_write_set_format_old_tar(struct archive *); */ __LA_DECL int archive_write_set_format_pax(struct archive *); __LA_DECL int archive_write_set_format_pax_restricted(struct archive *); diff --git a/lib/libarchive/archive_write_set_format.c b/lib/libarchive/archive_write_set_format.c index 5b879bd..369f2c9 100644 --- a/lib/libarchive/archive_write_set_format.c +++ b/lib/libarchive/archive_write_set_format.c @@ -44,6 +44,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] = { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio }, { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc }, { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio }, + { ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree }, { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar }, { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar }, { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump }, diff --git a/lib/libarchive/archive_write_set_format_by_name.c b/lib/libarchive/archive_write_set_format_by_name.c index 00f7242..6daa51c 100644 --- a/lib/libarchive/archive_write_set_format_by_name.c +++ b/lib/libarchive/archive_write_set_format_by_name.c @@ -49,6 +49,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] = { "argnu", archive_write_set_format_ar_svr4 }, { "arsvr4", archive_write_set_format_ar_svr4 }, { "cpio", archive_write_set_format_cpio }, + { "mtree", archive_write_set_format_mtree }, { "newc", archive_write_set_format_cpio_newc }, { "odc", archive_write_set_format_cpio }, { "pax", archive_write_set_format_pax }, diff --git a/lib/libarchive/archive_write_set_format_mtree.c b/lib/libarchive/archive_write_set_format_mtree.c new file mode 100644 index 0000000..ff01aa1 --- /dev/null +++ b/lib/libarchive/archive_write_set_format_mtree.c @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 2008 Joerg Sonnenberger + * 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$"); + +#include +#include +#include + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_write_private.h" + +struct mtree_writer { + struct archive_entry *entry; + struct archive_string buf; + int first; +}; + +static int +mtree_safe_char(char c) +{ + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return 1; + if (c >= '0' && c <= '9') + return 1; + if (c == 35 || c == 61 || c == 92) + return 0; /* #, = and \ are always quoted */ + + if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */ + return 1; + if (c >= 58 && c <= 64) /* :;<>?@ */ + return 1; + if (c >= 91 && c <= 96) /* []^_` */ + return 1; + if (c >= 123 && c <= 126) /* {|}~ */ + return 1; + return 0; +} + +static void +mtree_quote(struct mtree_writer *mtree, const char *str) +{ + const char *start; + char buf[4]; + unsigned char c; + + for (start = str; *str != '\0'; ++str) { + if (mtree_safe_char(*str)) + continue; + if (start != str) + archive_strncat(&mtree->buf, start, str - start); + c = (unsigned char)*str; + buf[0] = '\\'; + buf[1] = (c / 64) + '0'; + buf[2] = (c / 8 % 8) + '0'; + buf[3] = (c % 8) + '0'; + archive_strncat(&mtree->buf, buf, 4); + start = str + 1; + } + + if (start != str) + archive_strncat(&mtree->buf, start, str - start); +} + +static int +archive_write_mtree_header(struct archive_write *a, + struct archive_entry *entry) +{ + struct mtree_writer *mtree= a->format_data; + const char *path; + + mtree->entry = archive_entry_clone(entry); + path = archive_entry_pathname(mtree->entry); + + if (mtree->first) { + mtree->first = 0; + archive_strcat(&mtree->buf, "#mtree\n"); + } + + mtree_quote(mtree, path); + + return (ARCHIVE_OK); +} + +static int +archive_write_mtree_finish_entry(struct archive_write *a) +{ + struct mtree_writer *mtree = a->format_data; + struct archive_entry *entry; + const char *name; + int ret; + + entry = mtree->entry; + if (entry == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Finished entry without being open first."); + return (ARCHIVE_FATAL); + } + mtree->entry = NULL; + + if (archive_entry_nlink(entry) != 1 && + archive_entry_filetype(entry) != AE_IFDIR) + archive_string_sprintf(&mtree->buf, + " nlink=%u", archive_entry_nlink(entry)); + + if ((name = archive_entry_gname(entry)) != NULL) { + archive_strcat(&mtree->buf, " gname="); + mtree_quote(mtree, name); + } + if ((name = archive_entry_uname(entry)) != NULL) { + archive_strcat(&mtree->buf, " uname="); + mtree_quote(mtree, name); + } + if ((name = archive_entry_fflags_text(entry)) != NULL) { + archive_strcat(&mtree->buf, " flags="); + mtree_quote(mtree, name); + } + + archive_string_sprintf(&mtree->buf, + " time=%jd mode=%o gid=%jd uid=%jd", + (intmax_t)archive_entry_mtime(entry), + archive_entry_mode(entry) & 07777, + (intmax_t)archive_entry_gid(entry), + (intmax_t)archive_entry_uid(entry)); + + switch (archive_entry_filetype(entry)) { + case AE_IFLNK: + archive_strcat(&mtree->buf, " type=link link="); + mtree_quote(mtree, archive_entry_symlink(entry)); + archive_strcat(&mtree->buf, "\n"); + break; + case AE_IFSOCK: + archive_strcat(&mtree->buf, " type=socket\n"); + break; + case AE_IFCHR: + archive_string_sprintf(&mtree->buf, + " type=char device=native,%d,%d\n", + archive_entry_rdevmajor(entry), + archive_entry_rdevminor(entry)); + break; + case AE_IFBLK: + archive_string_sprintf(&mtree->buf, + " type=block device=native,%d,%d\n", + archive_entry_rdevmajor(entry), + archive_entry_rdevminor(entry)); + break; + case AE_IFDIR: + archive_strcat(&mtree->buf, " type=dir\n"); + break; + case AE_IFIFO: + archive_strcat(&mtree->buf, " type=fifo\n"); + break; + case AE_IFREG: + default: /* Handle unknown file types as regular files. */ + archive_string_sprintf(&mtree->buf, " type=file size=%jd\n", + (intmax_t)archive_entry_size(entry)); + break; + } + + archive_entry_free(entry); + + if (mtree->buf.length > 32768) { + ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length); + archive_string_empty(&mtree->buf); + } else + ret = ARCHIVE_OK; + + return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL); +} + +static int +archive_write_mtree_finish(struct archive_write *a) +{ + struct mtree_writer *mtree= a->format_data; + + archive_write_set_bytes_in_last_block(&a->archive, 1); + + return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length); +} + +static ssize_t +archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) +{ + (void)a; /* UNUSED */ + (void)buff; /* UNUSED */ + return n; +} + +static int +archive_write_mtree_destroy(struct archive_write *a) +{ + struct mtree_writer *mtree= a->format_data; + + if (mtree == NULL) + return (ARCHIVE_OK); + + archive_entry_free(mtree->entry); + archive_string_free(&mtree->buf); + free(mtree); + a->format_data = NULL; + return (ARCHIVE_OK); +} + +int +archive_write_set_format_mtree(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct mtree_writer *mtree; + + if (a->format_destroy != NULL) + (a->format_destroy)(a); + + if ((mtree = malloc(sizeof(*mtree))) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate mtree data"); + return (ARCHIVE_FATAL); + } + + mtree->entry = NULL; + mtree->first = 1; + archive_string_init(&mtree->buf); + a->format_data = mtree; + a->format_destroy = archive_write_mtree_destroy; + + a->pad_uncompressed = 0; + a->format_write_header = archive_write_mtree_header; + a->format_finish = archive_write_mtree_finish; + a->format_write_data = archive_write_mtree_data; + a->format_finish_entry = archive_write_mtree_finish_entry; + a->archive.archive_format = ARCHIVE_FORMAT_MTREE; + a->archive.archive_format_name = "mtree"; + + return (ARCHIVE_OK); +} -- cgit v1.1