diff options
author | kientzle <kientzle@FreeBSD.org> | 2004-03-19 22:37:06 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2004-03-19 22:37:06 +0000 |
commit | ef0d6eb5985e7a4f4fd2f0f42925e8328b8cf004 (patch) | |
tree | 31fad164e4fe18412497337d4c8e1a7e7c792609 /lib/libarchive/archive_entry.c | |
parent | edf0b18239fcd09677972580f323c10d3a59afab (diff) | |
download | FreeBSD-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.c | 347 |
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 |