Description: Fix bug in --owner and --group options Unless the --owner or --group option specified names that could be resolved to ID numbers then the --owner or --group option would fail. . This patch allows --owner and --group to specify names that are unknown on the system where the tar is created. It is also careful to continue to accept actual ID numbers as arguments to --owner and --group as well as names. . This patch has been created by dpkg-source during the package build. Here's the last changelog entry, hopefully it gives details on why those changes were made: . tar (1.25-3.1) unstable; urgency=low . * Non-maintainer upload. * Make --owner=OWNER and --group=GROUP options accept owners and groups that do not exist on the system. . The person named in the Author field signed this changelog entry. Author: Thayne Harbaugh Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=136231 Last-Updated: 2011-08-08 --- a/src/create.c +++ b/src/create.c @@ -760,10 +760,10 @@ /* Override some stat fields, if requested to do so. */ - if (owner_option != (uid_t) -1) - st->stat.st_uid = owner_option; - if (group_option != (gid_t) -1) - st->stat.st_gid = group_option; + if (owner_option) + st->stat.st_uid = owner_option_id; + if (group_option) + st->stat.st_gid = group_option_id; if (mode_option) st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL) @@ -922,8 +922,15 @@ } else { - uid_to_uname (st->stat.st_uid, &st->uname); - gid_to_gname (st->stat.st_gid, &st->gname); + if (owner_option) + st->uname = xstrdup (owner_option); + else + uid_to_uname (st->stat.st_uid, &st->uname); + + if (group_option) + st->gname = xstrdup (group_option); + else + gid_to_gname (st->stat.st_gid, &st->gname); if (archive_format == POSIX_FORMAT && (strlen (st->uname) > UNAME_FIELD_SIZE --- a/src/common.h +++ b/src/common.h @@ -158,8 +158,9 @@ }; /* Specified value to be put into tar file in place of stat () results, or - just -1 if such an override should not take place. */ -GLOBAL gid_t group_option; + just NULL if such an override should not take place. */ +GLOBAL const char *group_option; +GLOBAL gid_t group_option_id; GLOBAL bool ignore_failed_read_option; @@ -230,8 +231,9 @@ GLOBAL bool one_file_system_option; /* Specified value to be put into tar file in place of stat () results, or - just -1 if such an override should not take place. */ -GLOBAL uid_t owner_option; + just NULL if such an override should not take place. */ +GLOBAL const char *owner_option; +GLOBAL uid_t owner_option_id; GLOBAL bool recursive_unlink_option; --- a/src/tar.c +++ b/src/tar.c @@ -1836,18 +1836,45 @@ break; case GROUP_OPTION: - if (! (strlen (arg) < GNAME_FIELD_SIZE - && gname_to_gid (arg, &group_option))) - { - uintmax_t g; - if (xstrtoumax (arg, 0, 10, &g, "") == LONGINT_OK - && g == (gid_t) g) - group_option = g; - else - FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg), - _("Invalid group"))); - } - break; + { + char *endptr; + unsigned long val; + + group_option = arg; + errno = 0; + val = strtoul(arg, &endptr, 10); + group_option_id = (gid_t)val; + + if (!endptr) + { + /* strtoul() should never return NULL in endptr */ + FATAL_ERROR ((0, 0, _("Internal error parsing group option '%s'"), + quotearg_colon (arg))); + } + else if (! *endptr) + { + /* Full strtoul() conversion occured . . . */ + if (ERANGE == errno || group_option_id != val) + { + /* . . . but it overflowed UL. */ + FATAL_ERROR ((0, 0, _("Conversion overflow for group option '%s'"), + quotearg_colon (arg))); + } + /* . . . and it was good and already stored in group_option_id. */ + } + else if (strlen (arg) >= GNAME_FIELD_SIZE) + { + /* It is a username that overflows. */ + FATAL_ERROR ((0, 0, _("Group name '%s' too long (max characters is %d)"), + quotearg_colon (arg), GNAME_FIELD_SIZE - 1)); + } + else if (! gname_to_gid (group_option, &group_option_id)) + { + /* It is a groupname that fails look-up. */ + group_option_id = -1; + } + } + break; case MODE_OPTION: mode_option = mode_compile (arg); @@ -1922,18 +1948,45 @@ break; case OWNER_OPTION: - if (! (strlen (arg) < UNAME_FIELD_SIZE - && uname_to_uid (arg, &owner_option))) - { - uintmax_t u; - if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK - && u == (uid_t) u) - owner_option = u; - else - FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg), - _("Invalid owner"))); - } - break; + { + char *endptr; + unsigned long val; + + owner_option = arg; + errno = 0; + val = strtoul(arg, &endptr, 10); + owner_option_id = (uid_t)val; + + if (!endptr) + { + /* strtoul() should never return NULL in endptr */ + FATAL_ERROR ((0, 0, _("Internal error parsing owner option '%s'"), + quotearg_colon (arg))); + } + else if (! *endptr) + { + /* Full strtoul() conversion occurred . . . */ + if (ERANGE == errno || owner_option_id != val) + { + /* . . . but it overflowed UL. */ + FATAL_ERROR ((0, 0, _("Conversion overflow for owner '%s'"), + quotearg_colon (arg))); + } + /* . . . and it was good and already stored in owner_option_id. */ + } + else if (strlen (arg) >= GNAME_FIELD_SIZE) + { + /* It is a username that overflows. */ + FATAL_ERROR ((0, 0, _("Owner name '%s' too long (max characters is %d)"), + quotearg_colon (arg), UNAME_FIELD_SIZE - 1)); + } + else if (! uname_to_uid (owner_option, &owner_option_id)) + { + /* It is a username that fails look-up. */ + owner_option_id = -1; + } + } + break; case QUOTE_CHARS_OPTION: for (;*arg; arg++) @@ -2241,8 +2293,10 @@ tar_sparse_major = 1; tar_sparse_minor = 0; - owner_option = -1; - group_option = -1; + owner_option = NULL; + owner_option_id = -1; + group_option = NULL; + group_option_id = -1; check_device_option = true;