X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fxheader.c;h=023c0bb262930dd38e4d08f0ddd79ba5079dae37;hb=4ef056729e5dc97952d04590afe33422ff6bb938;hp=965ef160debdb29f2e93f7a49293cb6eb5e1a5ec;hpb=e1286c19891794415af1e5eec59fb297ccf2df37;p=chaz%2Ftar diff --git a/src/xheader.c b/src/xheader.c index 965ef16..023c0bb 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1,6 +1,6 @@ /* POSIX extended headers for tar. - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -157,7 +157,7 @@ xheader_list_destroy (struct keyword_list **root) static void xheader_set_single_keyword (char *kw) { - USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw)); + USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet implemented"), kw)); } static void @@ -225,15 +225,17 @@ xheader_set_option (char *string) to the result of the basename utility on the translated file name. %p The process ID of the pax process. + %n The value of the 3rd argument. %% A '%' character. */ -static char * -xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) +char * +xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) { char *buf; size_t len = strlen (fmt); char *q; const char *p; + char *dirp = NULL; char *dir = NULL; char *base = NULL; char pidbuf[UINTMAX_STRSIZE_BOUND]; @@ -252,9 +254,10 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) case 'd': if (st) { - dir = safer_name_suffix (dir_name (st->orig_file_name), - false, absolute_names_option); - len += strlen (dir) - 1; + if (!dirp) + dirp = dir_name (st->orig_file_name); + dir = safer_name_suffix (dirp, false, absolute_names_option); + len += strlen (dir) - 2; } break; @@ -262,21 +265,18 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) if (st) { base = base_name (st->orig_file_name); - len += strlen (base) - 1; + len += strlen (base) - 2; } break; case 'p': pptr = umaxtostr (getpid (), pidbuf); - len += pidbuf + sizeof pidbuf - 1 - pptr - 1; + len += pidbuf + sizeof pidbuf - 1 - pptr - 2; break; case 'n': - if (allow_n) - { - nptr = umaxtostr (global_header_count + 1, nbuf); - len += nbuf + sizeof nbuf - 1 - nptr - 1; - } + nptr = umaxtostr (n, nbuf); + len += nbuf + sizeof nbuf - 1 - nptr - 2; break; } p++; @@ -316,6 +316,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) { q = stpcpy (q, nptr); p += 2; + break; } /* else fall through */ @@ -329,6 +330,8 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n) *q++ = *p++; } + free (dirp); + /* Do not allow it to end in a slash */ while (q > buf && ISSLASH (q[-1])) q--; @@ -341,7 +344,7 @@ xheader_xhdr_name (struct tar_stat_info *st) { if (!exthdr_name) assign_string (&exthdr_name, "%d/PaxHeaders.%p/%f"); - return xheader_format_name (st, exthdr_name, false); + return xheader_format_name (st, exthdr_name, 0); } #define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n" @@ -361,7 +364,7 @@ xheader_ghdr_name (void) strcat(globexthdr_name, GLOBAL_HEADER_TEMPLATE); } - return xheader_format_name (NULL, globexthdr_name, true); + return xheader_format_name (NULL, globexthdr_name, global_header_count + 1); } void @@ -396,6 +399,9 @@ xheader_write (char type, char *name, struct xheader *xhdr) } while (size > 0); xheader_destroy (xhdr); + + if (type == XGLTYPE) + global_header_count++; } void @@ -414,7 +420,6 @@ xheader_write_global (void) xheader_write (XGLTYPE, name = xheader_ghdr_name (), &extended_header); free (name); - global_header_count++; } @@ -831,8 +836,15 @@ code_time (struct timespec t, char const *keyword, struct xheader *xhdr) xheader_print (xhdr, keyword, code_timespec (t, buf)); } -static bool -decode_time (struct timespec *ts, char const *arg, char const *keyword) +enum decode_time_status + { + decode_time_success, + decode_time_range, + decode_time_bad_header + }; + +static enum decode_time_status +_decode_time (struct timespec *ts, char const *arg, char const *keyword) { time_t s; unsigned long int ns = 0; @@ -848,21 +860,21 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) { intmax_t i = strtoimax (arg, &arg_lim, 10); if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0) - goto out_of_range; + return decode_time_range; s = i; } else { uintmax_t i = strtoumax (arg, &arg_lim, 10); if (TYPE_MAXIMUM (time_t) < i) - goto out_of_range; + return decode_time_range; s = i; } p = arg_lim; if (errno == ERANGE) - goto out_of_range; + return decode_time_range; if (*p == '.') { @@ -890,7 +902,7 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) if (ns != 0) { if (s == TYPE_MINIMUM (time_t)) - goto out_of_range; + return decode_time_range; s--; ns = BILLION - ns; } @@ -901,20 +913,34 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) { ts->tv_sec = s; ts->tv_nsec = ns; - return true; + return decode_time_success; } } - ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"), - keyword, arg)); - return false; + return decode_time_bad_header; +} - out_of_range: - out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t), - TYPE_MAXIMUM (time_t)); - return false; +static bool +decode_time (struct timespec *ts, char const *arg, char const *keyword) +{ + switch (_decode_time (ts, arg, keyword)) + { + case decode_time_success: + return true; + case decode_time_bad_header: + ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"), + keyword, arg)); + return false; + case decode_time_range: + out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t), + TYPE_MAXIMUM (time_t)); + return false; + } + return true; } + + static void code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) { @@ -1244,7 +1270,7 @@ sparse_map_decoder (struct tar_stat_info *st, char const *arg, else { ERROR ((0, 0, _("Malformed extended header: excess %s=%s"), - "GNU.sparse.numbytes", arg)); + keyword, arg)); return; } } @@ -1317,7 +1343,7 @@ volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size) /* FIXME: Merge with volume_size_coder */ static void volume_offset_coder (struct tar_stat_info const *st, char const *keyword, - struct xheader *xhdr, void const *data) + struct xheader *xhdr, void const *data) { off_t v = *(off_t*)data; code_num (v, keyword, xhdr); @@ -1331,6 +1357,14 @@ volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size) continued_file_offset = u; } +static void +volume_filename_decoder (struct tar_stat_info *st, char const *arg, + size_t size) +{ + decode_string (&continued_file_name, arg); +} + + struct xhdr_tab const xhdr_tab[] = { { "atime", atime_coder, atime_decoder, false }, { "comment", dummy_coder, dummy_decoder, false }, @@ -1374,8 +1408,10 @@ struct xhdr_tab const xhdr_tab[] = { otherwise kept in the size field of a multivolume header. The GNU.volume.offset keeps the offset of the start of this volume, otherwise kept in oldgnu_header.offset. */ - { "GNU.volume.size", volume_size_coder, volume_size_decoder, false }, - { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false }, + { "GNU.volume.filename", volume_label_coder, volume_filename_decoder, + true }, + { "GNU.volume.size", volume_size_coder, volume_size_decoder, true }, + { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true }, { NULL, NULL, NULL, false } };