X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fincremen.c;h=557df3090d502ce0074121f8501c4eb44af3a072;hb=dd549cc257c7ec9e0780f649ac8ae384a84baba0;hp=5a7e23d795a56b66dcc252a34067f0aa247e6952;hpb=7c43775f4f667c435c9f67cbaf4738b3bcd59c03;p=chaz%2Ftar diff --git a/src/incremen.c b/src/incremen.c index 5a7e23d..557df30 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -1,21 +1,22 @@ /* GNU dump extensions to tar. - Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2009, 2013 + 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 - Free Software Foundation; either version 3, or (at your option) any later - version. + This file is part of GNU tar. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - Public License for more details. + GNU tar is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + GNU tar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include #include @@ -608,6 +609,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st, exclusion_tag_warning (name_buffer, tag_file_name, _("contents not dumped")); directory->children = NO_CHILDREN; + directory->tagfile = tag_file_name; break; case exclusion_tag_under: @@ -679,15 +681,13 @@ makedumpdir (struct directory *directory, const char *dir) if (loc) { if (directory->tagfile) - *new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ? - ' ' : 'I'; + *new_dump_ptr = 'I'; else *new_dump_ptr = ' '; new_dump_ptr++; } else if (directory->tagfile) - *new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ? - ' ' : 'I'; + *new_dump_ptr++ = 'I'; else *new_dump_ptr++ = 'Y'; /* New entry */ @@ -698,9 +698,26 @@ makedumpdir (struct directory *directory, const char *dir) *new_dump_ptr = 0; directory->idump = directory->dump; directory->dump = dumpdir_create0 (new_dump, NULL); + free (new_dump); free (array); } +/* Create a dumpdir containing only one entry: that for the + tagfile. */ +static void +maketagdumpdir (struct directory *directory) +{ + size_t len = strlen (directory->tagfile) + 1; + char *new_dump = xmalloc (len + 2); + new_dump[0] = 'Y'; + memcpy (new_dump + 1, directory->tagfile, len); + new_dump[len + 1] = 0; + + directory->idump = directory->dump; + directory->dump = dumpdir_create0 (new_dump, NULL); + free (new_dump); +} + /* Recursively scan the directory identified by ST. */ struct directory * scan_directory (struct tar_stat_info *st) @@ -728,86 +745,94 @@ scan_directory (struct tar_stat_info *st) nbuf = namebuf_create (dir); - if (dirp && directory->children != NO_CHILDREN) + if (dirp) { - char *entry; /* directory entry being scanned */ - struct dumpdir_iter *itr; - - makedumpdir (directory, dirp); - - for (entry = dumpdir_first (directory->dump, 1, &itr); - entry; - entry = dumpdir_next (itr)) + if (directory->children != NO_CHILDREN) { - char *full_name = namebuf_name (nbuf, entry + 1); - - if (*entry == 'I') /* Ignored entry */ - *entry = 'N'; - else if (excluded_name (full_name)) - *entry = 'N'; - else - { - int fd = st->fd; - void (*diag) (char const *) = 0; - struct tar_stat_info stsub; - tar_stat_init (&stsub); + char *entry; /* directory entry being scanned */ + struct dumpdir_iter *itr; - if (fd < 0) - { - errno = - fd; - diag = open_diag; - } - else if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0) - diag = stat_diag; - else if (S_ISDIR (stsub.stat.st_mode)) - { - int subfd = subfile_open (st, entry + 1, open_read_flags); - if (subfd < 0) - diag = open_diag; - else - { - stsub.fd = subfd; - if (fstat (subfd, &stsub.stat) != 0) - diag = stat_diag; - } - } + makedumpdir (directory, dirp); - if (diag) - { - file_removed_diag (full_name, false, diag); - *entry = 'N'; - } - else if (S_ISDIR (stsub.stat.st_mode)) - { - int pd_flag = 0; - if (!recursion_option) - pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN; - else if (directory->children == ALL_CHILDREN) - pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN; - *entry = 'D'; - - stsub.parent = st; - procdir (full_name, &stsub, pd_flag, entry); - restore_parent_fd (&stsub); - } - else if (one_file_system_option && device != stsub.stat.st_dev) + for (entry = dumpdir_first (directory->dump, 1, &itr); + entry; + entry = dumpdir_next (itr)) + { + char *full_name = namebuf_name (nbuf, entry + 1); + + if (*entry == 'I') /* Ignored entry */ *entry = 'N'; - else if (*entry == 'Y') - /* New entry, skip further checks */; - /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */ - else if (OLDER_STAT_TIME (stsub.stat, m) - && (!after_date_option - || OLDER_STAT_TIME (stsub.stat, c))) + else if (excluded_name (full_name)) *entry = 'N'; else - *entry = 'Y'; + { + int fd = st->fd; + void (*diag) (char const *) = 0; + struct tar_stat_info stsub; + tar_stat_init (&stsub); - tar_stat_destroy (&stsub); + if (fd < 0) + { + errno = - fd; + diag = open_diag; + } + else if (fstatat (fd, entry + 1, &stsub.stat, + fstatat_flags) != 0) + diag = stat_diag; + else if (S_ISDIR (stsub.stat.st_mode)) + { + int subfd = subfile_open (st, entry + 1, + open_read_flags); + if (subfd < 0) + diag = open_diag; + else + { + stsub.fd = subfd; + if (fstat (subfd, &stsub.stat) != 0) + diag = stat_diag; + } + } + + if (diag) + { + file_removed_diag (full_name, false, diag); + *entry = 'N'; + } + else if (S_ISDIR (stsub.stat.st_mode)) + { + int pd_flag = 0; + if (!recursion_option) + pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN; + else if (directory->children == ALL_CHILDREN) + pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN; + *entry = 'D'; + + stsub.parent = st; + procdir (full_name, &stsub, pd_flag, entry); + restore_parent_fd (&stsub); + } + else if (one_file_system_option && + device != stsub.stat.st_dev) + *entry = 'N'; + else if (*entry == 'Y') + /* New entry, skip further checks */; + /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */ + else if (OLDER_STAT_TIME (stsub.stat, m) + && (!after_date_option + || OLDER_STAT_TIME (stsub.stat, c))) + *entry = 'N'; + else + *entry = 'Y'; + + tar_stat_destroy (&stsub); + } } + free (itr); } - free (itr); + else if (directory->tagfile) + maketagdumpdir (directory); } - + namebuf_free (nbuf); free (dirp); @@ -1078,106 +1103,84 @@ read_obstack (FILE *fp, struct obstack *stk, size_t *pcount) return c; } -/* Read from file FP a nul-terminated string and convert it to - intmax_t. Return the resulting value in PVAL. Assume '-' has - already been read. +/* Read from file FP a null-terminated string and convert it to an + integer. FIELDNAME is the intended use of the integer, useful for + diagnostics. MIN_VAL and MAX_VAL are its minimum and maximum + permissible values; MIN_VAL must be nonpositive and MAX_VAL positive. + Store into *PVAL the resulting value, converted to intmax_t. Throw a fatal error if the string cannot be converted or if the - converted value is less than MIN_VAL. */ + converted value is out of range. -static void -read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval) + Return true if successful, false if end of file. */ + +static bool +read_num (FILE *fp, char const *fieldname, + intmax_t min_val, uintmax_t max_val, intmax_t *pval) { - int c; - size_t i; + int i; char buf[INT_BUFSIZE_BOUND (intmax_t)]; - char *ep; - buf[0] = '-'; + char offbuf[INT_BUFSIZE_BOUND (off_t)]; + char minbuf[INT_BUFSIZE_BOUND (intmax_t)]; + char maxbuf[INT_BUFSIZE_BOUND (intmax_t)]; + int conversion_errno; + int c = getc (fp); + bool negative = c == '-'; - for (i = 1; ISDIGIT (c = getc (fp)); i++) + for (i = 0; (i == 0 && negative) || ISDIGIT (c); i++) { - if (i == sizeof buf - 1) - FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file"))); buf[i] = c; - } - - if (c < 0) - { - if (ferror (fp)) - FATAL_ERROR ((0, errno, _("Read error in snapshot file"))); - else - FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file"))); - } - - buf[i] = 0; - errno = 0; - *pval = strtoimax (buf, &ep, 10); - if (c || errno || *pval < min_val) - FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file"))); -} - -/* Read from file FP a nul-terminated string and convert it to - uintmax_t. Return an intmax_t representation of the resulting - value in PVAL. Assume C has already been read. - - Throw a fatal error if the string cannot be converted or if the - converted value exceeds MAX_VAL. - - Return the last character read or EOF on end of file. */ - -static int -read_unsigned_num (int c, FILE *fp, uintmax_t max_val, intmax_t *pval) -{ - size_t i; - uintmax_t u; - char buf[UINTMAX_STRSIZE_BOUND], *ep; - - for (i = 0; ISDIGIT (c); i++) - { if (i == sizeof buf - 1) - FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file"))); - buf[i] = c; + FATAL_ERROR ((0, 0, + _("%s: byte %s: %s %.*s... too long"), + quotearg_colon (listed_incremental_option), + offtostr (ftello (fp), offbuf), + fieldname, i + 1, buf)); c = getc (fp); } + buf[i] = 0; + if (c < 0) { if (ferror (fp)) - FATAL_ERROR ((0, errno, _("Read error in snapshot file"))); - else if (i == 0) - return c; - else - FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file"))); + read_fatal (listed_incremental_option); + if (i != 0) + FATAL_ERROR ((0, 0, "%s: %s", + quotearg_colon (listed_incremental_option), + _("Unexpected EOF in snapshot file"))); + return false; } - buf[i] = 0; - errno = 0; - u = strtoumax (buf, &ep, 10); - if (c || errno || max_val < u) - FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file"))); - *pval = represent_uintmax (u); - return c; -} - -/* Read from file FP a nul-terminated string and convert it to - an integer in the range MIN_VAL..MAXVAL. Return the resulting - value, converted to intmax_t, in PVAL. MINVAL must be nonpositive. - - Throw a fatal error if the string cannot be converted or if the - converted value is out of range. + if (c) + FATAL_ERROR ((0, 0, + _("%s: byte %s: %s %s followed by invalid byte 0x%02x"), + quotearg_colon (listed_incremental_option), + offtostr (ftello (fp), offbuf), + fieldname, buf, c)); - Return the last character read or EOF on end of file. */ + *pval = strtosysint (buf, NULL, min_val, max_val); + conversion_errno = errno; -static int -read_num (FILE *fp, intmax_t min_val, uintmax_t max_val, intmax_t *pval) -{ - int c = getc (fp); - if (c == '-') + switch (conversion_errno) { - read_negative_num (fp, min_val, pval); - return 0; + case ERANGE: + FATAL_ERROR ((0, conversion_errno, + _("%s: byte %s: (valid range %s..%s)\n\t%s %s"), + quotearg_colon (listed_incremental_option), + offtostr (ftello (fp), offbuf), + imaxtostr (min_val, minbuf), + umaxtostr (max_val, maxbuf), fieldname, buf)); + default: + FATAL_ERROR ((0, conversion_errno, + _("%s: byte %s: %s %s"), + quotearg_colon (listed_incremental_option), + offtostr (ftello (fp), offbuf), fieldname, buf)); + case 0: + break; } - return read_unsigned_num (c, fp, max_val, pval); + + return true; } /* Read from FP two NUL-terminated strings representing a struct @@ -1188,15 +1191,20 @@ read_num (FILE *fp, intmax_t min_val, uintmax_t max_val, intmax_t *pval) static void read_timespec (FILE *fp, struct timespec *pval) { - intmax_t i; - int c = read_num (fp, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &i); - pval->tv_sec = i; + intmax_t s, ns; - if (c || read_num (fp, 0, BILLION - 1, &i)) - FATAL_ERROR ((0, 0, "%s: %s", - quotearg_colon (listed_incremental_option), - _("Unexpected EOF in snapshot file"))); - pval->tv_nsec = i; + if (read_num (fp, "sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &s) + && read_num (fp, "nsec", 0, BILLION - 1, &ns)) + { + pval->tv_sec = s; + pval->tv_nsec = ns; + } + else + { + FATAL_ERROR ((0, 0, "%s: %s", + quotearg_colon (listed_incremental_option), + _("Unexpected EOF in snapshot file"))); + } } /* Read incremental snapshot format 2 */ @@ -1204,6 +1212,7 @@ static void read_incr_db_2 (void) { struct obstack stk; + char offbuf[INT_BUFSIZE_BOUND (off_t)]; obstack_init (&stk); @@ -1220,20 +1229,20 @@ read_incr_db_2 (void) char *content; size_t s; - if (read_num (listed_incremental_stream, 0, 1, &i)) + if (! read_num (listed_incremental_stream, "nfs", 0, 1, &i)) return; /* Normal return */ nfs = i; read_timespec (listed_incremental_stream, &mtime); - if (read_num (listed_incremental_stream, - TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i)) + if (! read_num (listed_incremental_stream, "dev", + TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i)) break; dev = i; - if (read_num (listed_incremental_stream, - TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i)) + if (! read_num (listed_incremental_stream, "ino", + TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i)) break; ino = i; @@ -1245,8 +1254,9 @@ read_incr_db_2 (void) while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1) ; if (getc (listed_incremental_stream) != 0) - FATAL_ERROR ((0, 0, "%s: %s", + FATAL_ERROR ((0, 0, _("%s: byte %s: %s"), quotearg_colon (listed_incremental_option), + offtostr (ftello (listed_incremental_stream), offbuf), _("Missing record terminator"))); content = obstack_finish (&stk);