X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftar.c;h=f0d8f5bfd06643430815e94abf8bd939e04029ed;hb=1e1fc0336bea2f273b8c6fdb376735ce13887899;hp=782ed3b5328a7778cb7afd786416803e5f3b0cbb;hpb=e985feb292927fcf3602a7acd355105960302c0a;p=chaz%2Ftar diff --git a/src/tar.c b/src/tar.c index 782ed3b..f0d8f5b 100644 --- a/src/tar.c +++ b/src/tar.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -892,12 +892,12 @@ static char const * const backup_file_table[] = { }; static void -add_exclude_array (char const * const * fv) +add_exclude_array (char const * const * fv, int options) { int i; for (i = 0; fv[i]; i++) - add_exclude (excluded, fv[i], 0); + add_exclude (excluded, fv[i], options); } @@ -956,10 +956,13 @@ static void stat_on_signal (int signo) { #ifdef HAVE_SIGACTION +# ifndef SA_RESTART +# define SA_RESTART 0 +# endif struct sigaction act; act.sa_handler = sigstat; sigemptyset (&act.sa_mask); - act.sa_flags = 0; + act.sa_flags = SA_RESTART; sigaction (signo, &act, NULL); #else signal (signo, sigstat); @@ -1014,7 +1017,7 @@ get_date_or_file (struct tar_args *args, const char *option, || *str == '.') { struct stat st; - if (deref_stat (dereference_option, str, &st) != 0) + if (stat (str, &st) != 0) { stat_error (str); USAGE_ERROR ((0, 0, _("Date sample file not found"))); @@ -1023,7 +1026,7 @@ get_date_or_file (struct tar_args *args, const char *option, } else { - if (! get_date (ts, str, NULL)) + if (! parse_datetime (ts, str, NULL)) { WARN ((0, 0, _("Substituting %s for unknown date format %s"), tartime (*ts, false), quote (str))); @@ -1364,6 +1367,58 @@ expand_pax_option (struct tar_args *targs, const char *arg) } +static uintmax_t +parse_owner_group (char *arg, uintmax_t field_max, char const **name_option) +{ + strtol_error err; + uintmax_t u = UINTMAX_MAX; + char *end; + char const *name = 0; + char const *invalid_num = 0; + char *colon = strchr (arg, ':'); + + if (colon) + { + char const *num = colon + 1; + *colon = '\0'; + if (*arg) + name = arg; + if (num && (! (xstrtoumax (num, &end, 10, &u, "") == LONGINT_OK + && u <= field_max))) + invalid_num = num; + } + else + { + uintmax_t u1; + switch ('0' <= *arg && *arg <= '9' + ? xstrtoumax (arg, &end, 10, &u1, "") + : LONGINT_INVALID) + { + default: + name = arg; + break; + + case LONGINT_OK: + if (u1 <= field_max) + { + u = u1; + break; + } + /* Fall through. */ + case LONGINT_OVERFLOW: + invalid_num = arg; + break; + } + } + + if (invalid_num) + FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (invalid_num), + _("Invalid owner or group ID"))); + if (name) + *name_option = name; + return u; +} + #define TAR_SIZE_SUFFIXES "bBcGgkKMmPTtw" static error_t @@ -1769,7 +1824,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case EXCLUDE_BACKUPS_OPTION: - add_exclude_array (backup_file_table); + add_exclude_array (backup_file_table, EXCLUDE_WILDCARDS); break; case EXCLUDE_OPTION: @@ -1804,7 +1859,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; case EXCLUDE_VCS_OPTION: - add_exclude_array (vcs_file_table); + add_exclude_array (vcs_file_table, 0); break; case FORCE_LOCAL_OPTION: @@ -1836,17 +1891,18 @@ parse_opt (int key, char *arg, struct argp_state *state) 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"))); - } + { + uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (gid_t), + &group_name_option); + if (u == UINTMAX_MAX) + { + group_option = -1; + if (group_name_option) + gname_to_gid (group_name_option, &group_option); + } + else + group_option = u; + } break; case MODE_OPTION: @@ -1922,17 +1978,18 @@ parse_opt (int key, char *arg, struct argp_state *state) 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"))); - } + { + uintmax_t u = parse_owner_group (arg, TYPE_MAXIMUM (uid_t), + &owner_name_option); + if (u == UINTMAX_MAX) + { + owner_option = -1; + if (owner_name_option) + uname_to_uid (owner_name_option, &owner_option); + } + else + owner_option = u; + } break; case QUOTE_CHARS_OPTION: @@ -2241,8 +2298,8 @@ decode_options (int argc, char **argv) tar_sparse_major = 1; tar_sparse_minor = 0; - owner_option = -1; - group_option = -1; + owner_option = -1; owner_name_option = NULL; + group_option = -1; group_name_option = NULL; check_device_option = true; @@ -2465,6 +2522,18 @@ decode_options (int argc, char **argv) if (recursive_unlink_option) old_files_option = UNLINK_FIRST_OLD_FILES; + /* Flags for accessing files to be read from or copied into. POSIX says + O_NONBLOCK has unspecified effect on most types of files, but in + practice it never harms and sometimes helps. */ + { + int base_open_flags = + (O_BINARY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK + | (dereference_option ? 0 : O_NOFOLLOW) + | (atime_preserve_option == system_atime_preserve ? O_NOATIME : 0)); + open_read_flags = O_RDONLY | base_open_flags; + open_searchdir_flags = O_SEARCH | O_DIRECTORY | base_open_flags; + } + fstatat_flags = dereference_option ? 0 : AT_SYMLINK_NOFOLLOW; if (subcommand_option == TEST_LABEL_SUBCOMMAND) { @@ -2676,9 +2745,31 @@ tar_stat_init (struct tar_stat_info *st) memset (st, 0, sizeof (*st)); } +/* Close the stream or file descriptor associated with ST, and remove + all traces of it from ST. Return true if successful, false (with a + diagnostic) otherwise. */ +bool +tar_stat_close (struct tar_stat_info *st) +{ + int status = (st->dirstream ? closedir (st->dirstream) + : 0 < st->fd ? close (st->fd) + : 0); + st->dirstream = 0; + st->fd = 0; + + if (status == 0) + return true; + else + { + close_diag (st->orig_file_name); + return false; + } +} + void tar_stat_destroy (struct tar_stat_info *st) { + tar_stat_close (st); free (st->orig_file_name); free (st->file_name); free (st->link_name);