summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_entry.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2004-03-19 22:37:06 +0000
committerkientzle <kientzle@FreeBSD.org>2004-03-19 22:37:06 +0000
commitef0d6eb5985e7a4f4fd2f0f42925e8328b8cf004 (patch)
tree31fad164e4fe18412497337d4c8e1a7e7c792609 /lib/libarchive/archive_entry.c
parentedf0b18239fcd09677972580f323c10d3a59afab (diff)
downloadFreeBSD-src-ef0d6eb5985e7a4f4fd2f0f42925e8328b8cf004.zip
FreeBSD-src-ef0d6eb5985e7a4f4fd2f0f42925e8328b8cf004.tar.gz
Many fixes:
* Disabled shared-library building, as some API breakage is still likely. (I didn't realize it was turned on by default.) If you have an existing /usr/lib/libarchive.so.2, I recommend deleting it. * Pax interchange format now correctly stores and reads UTF8 for extended attributes. In particular, pax format can portably handle arbitrarily long pathnames containing arbitrary characters. * Library compiles cleanly at -O2, -O3, and WARNS=6 on all FreeBSD-CURRENT platforms. * Minor portability improvements inspired by Juergen Lock and Greg Lewis. (Less reliance on stdint.h, isolating of various portability-challenged constructs.) * archive_entry transparently converts multi-byte <-> wide character strings, allowing clients and format handlers to deal with either one, as appropriate. * Support for reading 'L' and 'K' entries in standard tar archives for star compatibility. * Recognize (but don't yet handle) ACL entries from Solaris tar. * Pushed format-specific data for format readers down into format-specific storage and out of library-global storage. This should make it easier to maintain individual formats without mucking with the core library management. * Documentation updates to track the above changes. * Updates to tar.5 to correct a few mistakes and add some additional information about GNU tar and Solaris tar formats. Notes: * The basic 'tar' reader is getting more general; there's not much point in keeping the 'gnutar' reader separate. Merging the two would lose a bunch of duplicate code. * The libc ACL support is looking increasingly inadequate for my needs here. I might need to assemble some fairly significant code for parsing and building ACLs. <sigh>
Diffstat (limited to 'lib/libarchive/archive_entry.c')
-rw-r--r--lib/libarchive/archive_entry.c347
1 files changed, 244 insertions, 103 deletions
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c
index 268afe6..b9a86c1 100644
--- a/lib/libarchive/archive_entry.c
+++ b/lib/libarchive/archive_entry.c
@@ -32,12 +32,35 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_DMALLOC
#include <dmalloc.h>
#endif
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
#include "archive_entry.h"
/*
+ * Handle wide character (i.e., Unicode) and non-wide character
+ * strings transparently.
+ *
+ */
+
+struct aes {
+ const char *aes_mbs;
+ char *aes_mbs_alloc;
+ const wchar_t *aes_wcs;
+ wchar_t *aes_wcs_alloc;
+};
+
+void aes_clean(struct aes *);
+void aes_copy(struct aes *dest, struct aes *src);
+const char * aes_get_mbs(struct aes *);
+const wchar_t * aes_get_wcs(struct aes *);
+void aes_set_mbs(struct aes *, const char *mbs);
+void aes_set_wcs(struct aes *, const wchar_t *wcs);
+void aes_copy_wcs(struct aes *, const wchar_t *wcs);
+
+/*
* Description of an archive entry.
*
* Basically, this is a "struct stat" with a few text fields added in.
@@ -70,124 +93,175 @@ struct archive_entry {
int ae_tartype;
/*
- * Note: If you add any more string fields, update
- * archive_entry_clone accordingly.
+ * Use aes here so that we get transparent mbs<->wcs conversions.
*/
- 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 aes ae_acl; /* ACL text */
+ struct aes ae_acl_default; /* default ACL */
+ struct aes ae_fflags; /* Text fflags per fflagstostr(3) */
+ struct aes ae_gname; /* Name of owning group */
+ struct aes ae_hardlink; /* Name of target for hardlink */
+ struct aes ae_pathname; /* Name of entry */
+ struct aes ae_symlink; /* symlink contents */
+ struct aes ae_uname; /* Name of owner */
};
-struct archive_entry *
-archive_entry_clear(struct archive_entry *entry)
+void
+aes_clean(struct aes *aes)
{
- memset(entry, 0, sizeof(*entry));
- entry->ae_tartype = -1;
- return entry;
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ memset(aes, 0, sizeof(*aes));
}
-struct archive_entry *
-archive_entry_clone(struct archive_entry *entry)
+void
+aes_copy(struct aes *dest, struct aes *src)
{
- 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;
+ *dest = *src;
+ if (src->aes_mbs_alloc != NULL) {
+ dest->aes_mbs_alloc = strdup(src->aes_mbs_alloc);
+ dest->aes_mbs = dest->aes_mbs_alloc;
}
- if (entry->ae_acl_default) {
- entry2->ae_acl_default = p;
- strcpy(p, entry->ae_acl_default);
- p += strlen(p) + 1;
+ if (src->aes_wcs_alloc != NULL) {
+ dest->aes_wcs_alloc = malloc((wcslen(src->aes_wcs_alloc) + 1)
+ * sizeof(wchar_t));
+ dest->aes_wcs = dest->aes_wcs_alloc;
+ wcscpy(dest->aes_wcs_alloc, src->aes_wcs);
}
+}
- if (entry->ae_fflags) {
- entry2->ae_fflags = p;
- strcpy(p, entry->ae_fflags);
- p += strlen(p) + 1;
+const char *
+aes_get_mbs(struct aes *aes)
+{
+ if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) {
+ /*
+ * XXX Need to estimate the number of byte in the
+ * multi-byte form. Assume that, on average, wcs
+ * chars encode to no more than 3 bytes. There must
+ * be a better way... XXX
+ */
+ int mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
+ aes->aes_mbs_alloc = malloc(mbs_length);
+ aes->aes_mbs = aes->aes_mbs_alloc;
+ wcstombs(aes->aes_mbs_alloc, aes->aes_wcs, mbs_length - 1);
+ aes->aes_mbs_alloc[mbs_length - 1] = 0;
}
-
- if (entry->ae_gname) {
- entry2->ae_gname = p;
- strcpy(p, entry->ae_gname);
- p += strlen(p) + 1;
+ return (aes->aes_mbs);
+}
+
+const wchar_t *
+aes_get_wcs(struct aes *aes)
+{
+ if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) {
+ /*
+ * No single byte will be more than one wide character,
+ * so this length estimate will always be big enough.
+ */
+ int wcs_length = strlen(aes->aes_mbs);
+ aes->aes_wcs_alloc
+ = malloc((wcs_length + 1) * sizeof(wchar_t));
+ aes->aes_wcs = aes->aes_wcs_alloc;
+ mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length);
+ aes->aes_wcs_alloc[wcs_length] = 0;
}
+ return (aes->aes_wcs);
+}
- if (entry->ae_hardlink) {
- entry2->ae_hardlink = p;
- strcpy(p, entry->ae_hardlink);
- p += strlen(p) + 1;
+void
+aes_set_mbs(struct aes *aes, const char *mbs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
}
-
- if (entry->ae_pathname) {
- entry2->ae_pathname = p;
- strcpy(p, entry->ae_pathname);
- p += strlen(p) + 1;
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
}
+ aes->aes_mbs = mbs;
+ aes->aes_wcs = NULL;
+}
- if (entry->ae_symlink) {
- entry2->ae_symlink = p;
- strcpy(p, entry->ae_symlink);
- p += strlen(p) + 1;
+void
+aes_set_wcs(struct aes *aes, const wchar_t *wcs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
+ }
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
}
+ aes->aes_mbs = NULL;
+ aes->aes_wcs = wcs;
+}
- if (entry->ae_uname) {
- entry2->ae_uname = p;
- strcpy(p, entry->ae_uname);
- p += strlen(p) + 1;
+void
+aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
+{
+ if (aes->aes_mbs_alloc) {
+ free(aes->aes_mbs_alloc);
+ aes->aes_mbs_alloc = NULL;
}
+ if (aes->aes_wcs_alloc) {
+ free(aes->aes_wcs_alloc);
+ aes->aes_wcs_alloc = NULL;
+ }
+ aes->aes_mbs = NULL;
+ aes->aes_wcs_alloc = malloc((wcslen(wcs) + 1) * sizeof(wchar_t));
+ wcscpy(aes->aes_wcs_alloc, wcs);
+ aes->aes_wcs = aes->aes_wcs_alloc;
+}
- return (entry2);
+struct archive_entry *
+archive_entry_clear(struct archive_entry *entry)
+{
+ aes_clean(&entry->ae_acl);
+ aes_clean(&entry->ae_acl_default);
+ aes_clean(&entry->ae_fflags);
+ aes_clean(&entry->ae_gname);
+ aes_clean(&entry->ae_hardlink);
+ aes_clean(&entry->ae_pathname);
+ aes_clean(&entry->ae_symlink);
+ aes_clean(&entry->ae_uname);
+ memset(entry, 0, sizeof(*entry));
+ entry->ae_tartype = -1;
+ return entry;
}
struct archive_entry *
-archive_entry_dup(struct archive_entry *entry)
+archive_entry_clone(struct archive_entry *entry)
{
struct archive_entry *entry2;
+ /* Allocate new structure and copy over all of the fields. */
entry2 = malloc(sizeof(*entry2));
- *entry2 = *entry;
+ entry2->ae_stat = entry->ae_stat;
+ entry2->ae_tartype = entry->ae_tartype;
+
+ aes_copy(&entry2->ae_acl ,&entry->ae_acl);
+ aes_copy(&entry2->ae_acl_default ,&entry->ae_acl_default);
+ aes_copy(&entry2->ae_fflags ,&entry->ae_fflags);
+ aes_copy(&entry2->ae_gname ,&entry->ae_gname);
+ aes_copy(&entry2->ae_hardlink ,&entry->ae_hardlink);
+ aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
+ aes_copy(&entry2->ae_symlink ,&entry->ae_symlink);
+ aes_copy(&entry2->ae_uname ,&entry->ae_uname);
+
return (entry2);
}
void
archive_entry_free(struct archive_entry *entry)
{
+ archive_entry_clear(entry);
free(entry);
}
@@ -199,11 +273,11 @@ archive_entry_new(void)
entry = malloc(sizeof(*entry));
if(entry == NULL)
return (NULL);
- archive_entry_clear(entry);
+ memset(entry, 0, sizeof(*entry));
+ entry->ae_tartype = -1;
return (entry);
}
-
/*
* Functions for reading fields from an archive_entry.
*/
@@ -211,14 +285,14 @@ archive_entry_new(void)
const char *
archive_entry_acl(struct archive_entry *entry)
{
- return (entry->ae_acl);
+ return (aes_get_mbs(&entry->ae_acl));
}
const char *
archive_entry_acl_default(struct archive_entry *entry)
{
- return (entry->ae_acl_default);
+ return (aes_get_mbs(&entry->ae_acl_default));
}
dev_t
@@ -237,19 +311,19 @@ archive_entry_devminor(struct archive_entry *entry)
const char *
archive_entry_fflags(struct archive_entry *entry)
{
- return (entry->ae_fflags);
+ return (aes_get_mbs(&entry->ae_fflags));
}
const char *
archive_entry_gname(struct archive_entry *entry)
{
- return (entry->ae_gname);
+ return (aes_get_mbs(&entry->ae_gname));
}
const char *
archive_entry_hardlink(struct archive_entry *entry)
{
- return (entry->ae_hardlink);
+ return (aes_get_mbs(&entry->ae_hardlink));
}
mode_t
@@ -261,7 +335,13 @@ archive_entry_mode(struct archive_entry *entry)
const char *
archive_entry_pathname(struct archive_entry *entry)
{
- return (entry->ae_pathname);
+ return (aes_get_mbs(&entry->ae_pathname));
+}
+
+const wchar_t *
+archive_entry_pathname_w(struct archive_entry *entry)
+{
+ return (aes_get_wcs(&entry->ae_pathname));
}
int64_t
@@ -279,7 +359,7 @@ archive_entry_stat(struct archive_entry *entry)
const char *
archive_entry_symlink(struct archive_entry *entry)
{
- return (entry->ae_symlink);
+ return (aes_get_mbs(&entry->ae_symlink));
}
int
@@ -291,7 +371,7 @@ archive_entry_tartype(struct archive_entry *entry)
const char *
archive_entry_uname(struct archive_entry *entry)
{
- return (entry->ae_uname);
+ return (aes_get_mbs(&entry->ae_uname));
}
/*
@@ -311,14 +391,25 @@ archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
void
archive_entry_set_acl(struct archive_entry *entry, const char *acl)
{
- entry->ae_acl = acl;
+ aes_set_mbs(&entry->ae_acl, acl);
}
+void
+archive_entry_copy_acl_w(struct archive_entry *entry, const wchar_t *acl)
+{
+ aes_copy_wcs(&entry->ae_acl, acl);
+}
void
archive_entry_set_acl_default(struct archive_entry *entry, const char *acl)
{
- entry->ae_acl_default = acl;
+ aes_set_mbs(&entry->ae_acl_default, acl);
+}
+
+void
+archive_entry_copy_acl_default_w(struct archive_entry *entry, const wchar_t *acl)
+{
+ aes_copy_wcs(&entry->ae_acl_default, acl);
}
void
@@ -342,7 +433,13 @@ archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
void
archive_entry_set_fflags(struct archive_entry *entry, const char *flags)
{
- entry->ae_fflags = flags;
+ aes_set_mbs(&entry->ae_fflags, flags);
+}
+
+void
+archive_entry_copy_fflags_w(struct archive_entry *entry, const wchar_t *flags)
+{
+ aes_copy_wcs(&entry->ae_fflags, flags);
}
void
@@ -354,13 +451,25 @@ archive_entry_set_gid(struct archive_entry *entry, gid_t g)
void
archive_entry_set_gname(struct archive_entry *entry, const char *name)
{
- entry->ae_gname = name;
+ aes_set_mbs(&entry->ae_gname, name);
+}
+
+void
+archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_gname, name);
}
void
archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
{
- entry->ae_hardlink = target;
+ aes_set_mbs(&entry->ae_hardlink, target);
+}
+
+void
+archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
+{
+ aes_copy_wcs(&entry->ae_hardlink, target);
}
void
@@ -372,7 +481,13 @@ archive_entry_set_mode(struct archive_entry *entry, mode_t m)
void
archive_entry_set_pathname(struct archive_entry *entry, const char *name)
{
- entry->ae_pathname = name;
+ aes_set_mbs(&entry->ae_pathname, name);
+}
+
+void
+archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_pathname, name);
}
void
@@ -382,9 +497,15 @@ archive_entry_set_size(struct archive_entry *entry, int64_t s)
}
void
-archive_entry_set_symlink(struct archive_entry *entry, const char *link)
+archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
+{
+ aes_set_mbs(&entry->ae_symlink, linkname);
+}
+
+void
+archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
{
- entry->ae_symlink = link;
+ aes_copy_wcs(&entry->ae_symlink, linkname);
}
void
@@ -402,6 +523,26 @@ archive_entry_set_uid(struct archive_entry *entry, uid_t u)
void
archive_entry_set_uname(struct archive_entry *entry, const char *name)
{
- entry->ae_uname = name;
+ aes_set_mbs(&entry->ae_uname, name);
+}
+
+void
+archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
+{
+ aes_copy_wcs(&entry->ae_uname, name);
}
+#if TEST
+int
+main(int argc, char **argv)
+{
+ struct aes aes;
+
+ memset(&aes, 0, sizeof(aes));
+ aes_clean(&aes);
+ aes_set_mbs(&aes, "ÈÈÈabc");
+ wprintf("%S\n", L"abcdef");
+ wprintf("%S\n",aes_get_wcs(&aes));
+ return (0);
+}
+#endif
OpenPOWER on IntegriCloud