X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=291d9950dd3737325326ce73af26cfc7004267aa;hb=cbc51277aa4de1f41434ba073f2e4546ead63005;hp=6141748a7228dc01d4f1272147f340fb5857b358;hpb=d36f5a3cc3280d6c4a58367bf51b527d5c14ac04;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 6141748..291d995 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -262,7 +262,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) char *dir = NULL; char *base = NULL; char pidbuf[UINTMAX_STRSIZE_BOUND]; - char const *pptr; + char const *pptr = NULL; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *nptr = NULL; @@ -335,13 +335,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) break; case 'n': - if (nptr) - { - q = stpcpy (q, nptr); - p += 2; - break; - } - /* else fall through */ + q = stpcpy (q, nptr); + p += 2; + break; + default: *q++ = *p++; @@ -460,7 +457,8 @@ xheader_write_global (struct xheader *xhdr) } } -void xheader_xattr_init (struct tar_stat_info *st) +void +xheader_xattr_init (struct tar_stat_info *st) { st->xattr_map = NULL; st->xattr_map_size = 0; @@ -469,9 +467,11 @@ void xheader_xattr_init (struct tar_stat_info *st) st->acls_a_len = 0; st->acls_d_ptr = NULL; st->acls_d_len = 0; + st->cntx_name = NULL; } -void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size) +void +xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size) { size_t scan = 0; @@ -485,9 +485,10 @@ void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size) free (xattr_map); } -static void xheader_xattr__add (struct xattr_array **xattr_map, - size_t *xattr_map_size, - const char *key, const char *val, size_t len) +static void +xheader_xattr__add (struct xattr_array **xattr_map, + size_t *xattr_map_size, + const char *key, const char *val, size_t len) { size_t pos = (*xattr_map_size)++; @@ -498,8 +499,47 @@ static void xheader_xattr__add (struct xattr_array **xattr_map, (*xattr_map)[pos].xval_len = len; } -void xheader_xattr_add(struct tar_stat_info *st, - const char *key, const char *val, size_t len) +/* This is reversal function for xattr_encode_keyword. See comment for + xattr_encode_keyword() for more info. */ +static void +xattr_decode_keyword (char *keyword) +{ + char *kpr, *kpl; /* keyword pointer left/right */ + kpr = kpl = keyword; + + for (;;) + { + if (*kpr == '%') + { + if (kpr[1] == '3' && kpr[2] == 'D') + { + *kpl = '='; + kpr += 3; + kpl ++; + continue; + } + else if (kpr[1] == '2' && kpr[2] == '5') + { + *kpl = '%'; + kpr += 3; + kpl ++; + continue; + } + } + + *kpl = *kpr; + + if (*kpr == 0) + break; + + kpr++; + kpl++; + } +} + +void +xheader_xattr_add (struct tar_stat_info *st, + const char *key, const char *val, size_t len) { size_t klen = strlen (key); char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1); @@ -513,8 +553,9 @@ void xheader_xattr_add(struct tar_stat_info *st, free (xkey); } -void xheader_xattr_copy(const struct tar_stat_info *st, - struct xattr_array **xattr_map, size_t *xattr_map_size) +void +xheader_xattr_copy (const struct tar_stat_info *st, + struct xattr_array **xattr_map, size_t *xattr_map_size) { size_t scan = 0; @@ -806,15 +847,71 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size) while (size > 0); } +/* xattr_encode_keyword() substitutes '=' ~~> '%3D' and '%' ~~> '%25' + in extended attribute keywords. This is needed because the '=' character + has special purpose in extended attribute header - it splits keyword and + value part of header. If there was the '=' occurrence allowed inside + keyword, there would be no unambiguous way how to decode this extended + attribute. + + (http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html) + */ +static char * +xattr_encode_keyword(const char *keyword) +{ + static char *encode_buffer = NULL; + static size_t encode_buffer_size = 0; + size_t bp; /* keyword/buffer pointers */ + + if (!encode_buffer) + { + encode_buffer_size = 256; + encode_buffer = xmalloc (encode_buffer_size); + } + else + *encode_buffer = 0; + + for (bp = 0; *keyword != 0; ++bp, ++keyword) + { + char c = *keyword; + + if (bp + 2 /* enough for URL encoding also.. */ >= encode_buffer_size) + { + encode_buffer = x2realloc (encode_buffer, &encode_buffer_size); + } + + if (c == '%') + { + strcpy (encode_buffer + bp, "%25"); + bp += 2; + } + else if (c == '=') + { + strcpy (encode_buffer + bp, "%3D"); + bp += 2; + } + else + encode_buffer[bp] = c; + } + + encode_buffer[bp] = 0; + + return encode_buffer; +} + static void xheader_print_n (struct xheader *xhdr, char const *keyword, char const *value, size_t vsize) { - size_t len = strlen (keyword) + vsize + 3; /* ' ' + '=' + '\n' */ size_t p; size_t n = 0; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *np; + size_t len, klen; + + keyword = xattr_encode_keyword (keyword); + klen = strlen (keyword); + len = klen + vsize + 3; /* ' ' + '=' + '\n' */ do { @@ -826,7 +923,7 @@ xheader_print_n (struct xheader *xhdr, char const *keyword, x_obstack_grow (xhdr, np, n); x_obstack_1grow (xhdr, ' '); - x_obstack_grow (xhdr, keyword, strlen (keyword)); + x_obstack_grow (xhdr, keyword, klen); x_obstack_1grow (xhdr, '='); x_obstack_grow (xhdr, value, vsize); x_obstack_1grow (xhdr, '\n'); @@ -1087,8 +1184,6 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) return true; } - - static void code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) { @@ -1554,6 +1649,20 @@ volume_filename_decoder (struct tar_stat_info *st, decode_string (&continued_file_name, arg); } +static void +xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void const *data) +{ + code_string (st->cntx_name, keyword, xhdr); +} + +static void +xattr_selinux_decoder (struct tar_stat_info *st, + char const *keyword, char const *arg, size_t size) +{ + decode_string (&st->cntx_name, arg); +} + static void xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword, struct xheader *xhdr, void const *data) @@ -1598,11 +1707,20 @@ static void xattr_decoder (struct tar_stat_info *st, char const *keyword, char const *arg, size_t size) { - char *xstr = NULL; + char *xstr, *xkey; + + /* copy keyword */ + size_t klen_raw = strlen (keyword); + xkey = alloca (klen_raw + 1); + memcpy (xkey, keyword, klen_raw + 1) /* including null-terminating */; + + /* copy value */ + xstr = alloca (size + 1); + memcpy (xstr, arg, size + 1); /* separator included, for GNU tar '\n' */; - xstr = xmemdup(arg, size + 1); - xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size); - free(xstr); + xattr_decode_keyword (xkey); + + xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size); } static void @@ -1703,6 +1821,11 @@ struct xhdr_tab const xhdr_tab[] = { { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, XHDR_PROTECTED | XHDR_GLOBAL, false }, + /* We get the SELinux value from filecon, so add a namespace for SELinux + instead of storing it in SCHILY.xattr.* (which would be RAW). */ + { "RHT.security.selinux", + xattr_selinux_coder, xattr_selinux_decoder, 0, false }, + /* ACLs, use the star format... */ { "SCHILY.acl.access", xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },