freebsd-src/lib/libarchive/archive_entry.c
Tim Kientzle 2710e4d1ef Initial import of libarchive.
What it is:
   A library for reading and writing various streaming archive
   formats, especially tar and cpio.  Being a library, it should
   be easy to incorporate into pkg_* tools, sysinstall, and any
   other place that needs to read or write such archives.

Features:
  * Full automatic detection of both compression and archive format.
  * Extensible internal architecture to make it easy to add new formats.
  * Support for "pax interchange format," a new POSIX-standard tar format
    that eliminates essentially all of the restrictions of historic formats.
  * BSD license

Thanks to: jkh for pushing me to start this work, gordon for
  encouraging me to commit it, bde for answering endless style
  questions, and many others for feedback and encouragement.

Status: Pretty good overall, though there are still a few rough edges and
  the library could always use more testing.  Feedback eagerly solicited.
2004-02-09 23:22:54 +00:00

408 lines
8.9 KiB
C

/*-
* Copyright (c) 2003-2004 Tim Kientzle
* 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
* in this position and unchanged.
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/types.h>
#ifdef DMALLOC
#include <dmalloc.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "archive_entry.h"
/*
* Description of an archive entry.
*
* Basically, this is a "struct stat" with a few text fields added in.
*
* TODO: Add "comment", "charset", "acl", and possibly other entries
* that are supported by "pax interchange" format. However, GNU, ustar,
* cpio, and other variants don't support these features, so they're not an
* excruciatingly high priority right now.
*
* TODO: "pax interchange" format allows essentially arbitrary
* key/value attributes to be attached to any entry. Supporting
* such extensions may make this library useful for special
* applications (e.g., a package manager could attach special
* package-management attributes to each entry). There are tricky
* API issues involved, so this is not going to happen until
* there's a real demand for it.
*
* TODO: Design a good API for handling sparse files.
*/
struct archive_entry {
/*
* Note that ae_stat.st_mode & S_IFMT can be 0!
* This occurs when the actual file type of the underlying object is
* not in the archive. For example, 'tar' archives store hardlinks
* without marking the type of the underlying object.
*/
struct stat ae_stat;
/* I'm not happy with having this format-particular data here. */
int ae_tartype;
/*
* Note: If you add any more string fields, update
* archive_entry_clone accordingly.
*/
const char *ae_acl; /* ACL text */
const char *ae_acl_default; /* default ACL */
const char *ae_fflags; /* Text fflags per fflagstostr(3) */
const char *ae_gname; /* Name of owning group */
const char *ae_hardlink; /* Name of target for hardlink */
const char *ae_pathname; /* Name of entry */
const char *ae_symlink; /* symlink contents */
const char *ae_uname; /* Name of owner */
char buff[1]; /* MUST BE AT END OF STRUCT!!! */
};
struct archive_entry *
archive_entry_clear(struct archive_entry *entry)
{
memset(entry, 0, sizeof(*entry));
entry->ae_tartype = -1;
return entry;
}
struct archive_entry *
archive_entry_clone(struct archive_entry *entry)
{
int size;
struct archive_entry *entry2;
char *p;
size = sizeof(*entry2);
if (entry->ae_acl)
size += strlen(entry->ae_acl) + 1;
if (entry->ae_acl_default)
size += strlen(entry->ae_acl_default) + 1;
if (entry->ae_fflags)
size += strlen(entry->ae_fflags) + 1;
if (entry->ae_gname)
size += strlen(entry->ae_gname) + 1;
if (entry->ae_hardlink)
size += strlen(entry->ae_hardlink) + 1;
if (entry->ae_pathname)
size += strlen(entry->ae_pathname) + 1;
if (entry->ae_symlink)
size += strlen(entry->ae_symlink) + 1;
if (entry->ae_uname)
size += strlen(entry->ae_uname) + 1;
entry2 = malloc(size);
*entry2 = *entry;
/* Copy all of the strings from the original. */
p = entry2->buff;
if (entry->ae_acl) {
entry2->ae_acl = p;
strcpy(p, entry->ae_acl);
p += strlen(p) + 1;
}
if (entry->ae_acl_default) {
entry2->ae_acl_default = p;
strcpy(p, entry->ae_acl_default);
p += strlen(p) + 1;
}
if (entry->ae_fflags) {
entry2->ae_fflags = p;
strcpy(p, entry->ae_fflags);
p += strlen(p) + 1;
}
if (entry->ae_gname) {
entry2->ae_gname = p;
strcpy(p, entry->ae_gname);
p += strlen(p) + 1;
}
if (entry->ae_hardlink) {
entry2->ae_hardlink = p;
strcpy(p, entry->ae_hardlink);
p += strlen(p) + 1;
}
if (entry->ae_pathname) {
entry2->ae_pathname = p;
strcpy(p, entry->ae_pathname);
p += strlen(p) + 1;
}
if (entry->ae_symlink) {
entry2->ae_symlink = p;
strcpy(p, entry->ae_symlink);
p += strlen(p) + 1;
}
if (entry->ae_uname) {
entry2->ae_uname = p;
strcpy(p, entry->ae_uname);
p += strlen(p) + 1;
}
return (entry2);
}
struct archive_entry *
archive_entry_dup(struct archive_entry *entry)
{
struct archive_entry *entry2;
entry2 = malloc(sizeof(*entry2));
*entry2 = *entry;
return (entry2);
}
void
archive_entry_free(struct archive_entry *entry)
{
free(entry);
}
struct archive_entry *
archive_entry_new(void)
{
struct archive_entry *entry;
entry = malloc(sizeof(*entry));
if(entry == NULL)
return (NULL);
archive_entry_clear(entry);
return (entry);
}
/*
* Functions for reading fields from an archive_entry.
*/
const char *
archive_entry_acl(struct archive_entry *entry)
{
return (entry->ae_acl);
}
const char *
archive_entry_acl_default(struct archive_entry *entry)
{
return (entry->ae_acl_default);
}
dev_t
archive_entry_devmajor(struct archive_entry *entry)
{
return (major(entry->ae_stat.st_rdev));
}
dev_t
archive_entry_devminor(struct archive_entry *entry)
{
return (minor(entry->ae_stat.st_rdev));
}
const char *
archive_entry_fflags(struct archive_entry *entry)
{
return (entry->ae_fflags);
}
const char *
archive_entry_gname(struct archive_entry *entry)
{
return (entry->ae_gname);
}
const char *
archive_entry_hardlink(struct archive_entry *entry)
{
return (entry->ae_hardlink);
}
mode_t
archive_entry_mode(struct archive_entry *entry)
{
return (entry->ae_stat.st_mode);
}
const char *
archive_entry_pathname(struct archive_entry *entry)
{
return (entry->ae_pathname);
}
int64_t
archive_entry_size(struct archive_entry *entry)
{
return (entry->ae_stat.st_size);
}
const struct stat *
archive_entry_stat(struct archive_entry *entry)
{
return (&entry->ae_stat);
}
const char *
archive_entry_symlink(struct archive_entry *entry)
{
return (entry->ae_symlink);
}
int
archive_entry_tartype(struct archive_entry *entry)
{
return (entry->ae_tartype);
}
const char *
archive_entry_uname(struct archive_entry *entry)
{
return (entry->ae_uname);
}
/*
* Functions to set archive_entry properties.
*/
/*
* Note "copy" not "set" here. The "set" functions that accept a pointer
* only store the pointer; they don't copy the underlying object.
*/
void
archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
{
entry->ae_stat = *st;
}
void
archive_entry_set_acl(struct archive_entry *entry, const char *acl)
{
entry->ae_acl = acl;
}
void
archive_entry_set_acl_default(struct archive_entry *entry, const char *acl)
{
entry->ae_acl_default = acl;
}
void
archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
{
dev_t d;
d = entry->ae_stat.st_rdev;
entry->ae_stat.st_rdev = makedev(m, minor(d));
}
void
archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
{
dev_t d;
d = entry->ae_stat.st_rdev;
entry->ae_stat.st_rdev = makedev( major(d), m);
}
void
archive_entry_set_fflags(struct archive_entry *entry, const char *flags)
{
entry->ae_fflags = flags;
}
void
archive_entry_set_gid(struct archive_entry *entry, gid_t g)
{
entry->ae_stat.st_gid = g;
}
void
archive_entry_set_gname(struct archive_entry *entry, const char *name)
{
entry->ae_gname = name;
}
void
archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
{
entry->ae_hardlink = target;
}
void
archive_entry_set_mode(struct archive_entry *entry, mode_t m)
{
entry->ae_stat.st_mode = m;
}
void
archive_entry_set_pathname(struct archive_entry *entry, const char *name)
{
entry->ae_pathname = name;
}
void
archive_entry_set_size(struct archive_entry *entry, int64_t s)
{
entry->ae_stat.st_size = s;
}
void
archive_entry_set_symlink(struct archive_entry *entry, const char *link)
{
entry->ae_symlink = link;
}
void
archive_entry_set_tartype(struct archive_entry *entry, char t)
{
entry->ae_tartype = t;
}
void
archive_entry_set_uid(struct archive_entry *entry, uid_t u)
{
entry->ae_stat.st_uid = u;
}
void
archive_entry_set_uname(struct archive_entry *entry, const char *name)
{
entry->ae_uname = name;
}