X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fincremen.c;h=7130bc22773b40dc7317036278c3407d533f0b0d;hb=cd7bdd4076ca154575bbef85eb2157e59befcfe2;hp=afd19af66ae7e67db457669f3c1e4d1579d345ad;hpb=de328a580ab6f5ff4a3237ce21f1ef0b7dd12984;p=chaz%2Ftar diff --git a/src/incremen.c b/src/incremen.c index afd19af..7130bc2 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 @@ -300,6 +301,24 @@ dirlist_replace_prefix (const char *pref, const char *repl) replace_prefix (&dp->name, pref, pref_len, repl, repl_len); } +void +clear_directory_table (void) +{ + struct directory *dp; + + if (directory_table) + hash_clear (directory_table); + if (directory_meta_table) + hash_clear (directory_meta_table); + for (dp = dirhead; dp; ) + { + struct directory *next = dp->next; + free_directory (dp); + dp = next; + } + dirhead = dirtail = NULL; +} + /* Create and link a new directory entry for directory NAME, having a device number DEV and an inode number INO, with NFS indicating whether it is an NFS device and FOUND indicating whether we have @@ -327,7 +346,8 @@ note_directory (char const *name, struct timespec mtime, if (! ((directory_table || (directory_table = hash_initialize (0, 0, hash_directory_canonical_name, - compare_directory_canonical_names, 0))) + compare_directory_canonical_names, + 0))) && hash_insert (directory_table, directory))) xalloc_die (); @@ -408,7 +428,7 @@ update_parent_directory (struct tar_stat_info *parent) if (directory) { struct stat st; - if (fstatat (parent->fd, ".", &st, fstatat_flags) != 0) + if (fstat (parent->fd, &st) != 0) stat_diag (directory->name); else directory->mtime = get_stat_mtime (&st); @@ -426,9 +446,8 @@ procdir (const char *name_buffer, struct tar_stat_info *st, { struct directory *directory; struct stat *stat_data = &st->stat; - int fd = st->fd; - dev_t device = st->parent ? st->parent->stat.st_dev : 0; bool nfs = NFS_FILE_STAT (*stat_data); + bool perhaps_renamed = false; if ((directory = find_directory (name_buffer)) != NULL) { @@ -483,9 +502,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st, } else { - WARNOPT (WARN_RENAME_DIRECTORY, - (0, 0, _("%s: Directory has been renamed"), - quotearg_colon (name_buffer))); + perhaps_renamed = true; directory->children = ALL_CHILDREN; directory->device_number = stat_data->st_dev; directory->inode_number = stat_data->st_ino; @@ -504,7 +521,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st, stat_data->st_ino); directory = note_directory (name_buffer, - get_stat_mtime(stat_data), + get_stat_mtime (stat_data), stat_data->st_dev, stat_data->st_ino, nfs, @@ -541,18 +558,23 @@ procdir (const char *name_buffer, struct tar_stat_info *st, } } - /* If the directory is on another device and --one-file-system was given, - omit it... */ - if (one_file_system_option && device != stat_data->st_dev - /* ... except if it was explicitely given in the command line */ - && !is_individual_file (name_buffer)) - /* FIXME: - WARNOPT (WARN_XDEV, - (0, 0, - _("%s: directory is on a different filesystem; not dumped"), - quotearg_colon (directory->name))); - */ - directory->children = NO_CHILDREN; + if (one_file_system_option && st->parent + && stat_data->st_dev != st->parent->stat.st_dev) + { + WARNOPT (WARN_XDEV, + (0, 0, + _("%s: directory is on a different filesystem; not dumped"), + quotearg_colon (directory->name))); + directory->children = NO_CHILDREN; + /* If there is any dumpdir info in that directory, remove it */ + if (directory->dump) + { + dumpdir_free (directory->dump); + directory->dump = NULL; + } + perhaps_renamed = false; + } + else if (flag & PD_FORCE_CHILDREN) { directory->children = PD_CHILDREN(flag); @@ -560,13 +582,18 @@ procdir (const char *name_buffer, struct tar_stat_info *st, *entry = 'N'; } + if (perhaps_renamed) + WARNOPT (WARN_RENAME_DIRECTORY, + (0, 0, _("%s: Directory has been renamed"), + quotearg_colon (name_buffer))); + DIR_SET_FLAG (directory, DIRF_INIT); if (directory->children != NO_CHILDREN) { const char *tag_file_name; - switch (check_exclusion_tags (fd, &tag_file_name)) + switch (check_exclusion_tags (st, &tag_file_name)) { case exclusion_tag_all: /* This warning can be duplicated by code in dump_file0, but only @@ -680,8 +707,7 @@ struct directory * scan_directory (struct tar_stat_info *st) { char const *dir = st->orig_file_name; - int fd = st->fd; - char *dirp = 0; + char *dirp = get_directory_entries (st); dev_t device = st->stat.st_dev; bool cmdline = ! st->parent; namebuf_t nbuf; @@ -689,18 +715,6 @@ scan_directory (struct tar_stat_info *st) struct directory *directory; char ch; - int dupfd = dup (fd); - if (0 <= dupfd) - { - dirp = fdsavedir (dupfd); - if (! dirp) - { - int e = errno; - close (dupfd); - errno = e; - } - } - if (! dirp) savedir_error (dir); @@ -734,19 +748,29 @@ scan_directory (struct tar_stat_info *st) *entry = 'N'; else { + int fd = st->fd; void (*diag) (char const *) = 0; struct tar_stat_info stsub; tar_stat_init (&stsub); - if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0) + 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)) { - stsub.fd = openat (fd, entry + 1, open_read_flags); - if (stsub.fd < 0) + int subfd = subfile_open (st, entry + 1, open_read_flags); + if (subfd < 0) diag = open_diag; - else if (fstat (stsub.fd, &stsub.stat) != 0) - diag = stat_diag; + else + { + stsub.fd = subfd; + if (fstat (subfd, &stsub.stat) != 0) + diag = stat_diag; + } } if (diag) @@ -762,7 +786,10 @@ scan_directory (struct tar_stat_info *st) 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'; @@ -784,8 +811,7 @@ scan_directory (struct tar_stat_info *st) namebuf_free (nbuf); - if (dirp) - free (dirp); + free (dirp); return directory; } @@ -835,7 +861,7 @@ store_rename (struct directory *dir, struct obstack *stk) are ignored when hit by this function next time. If the chain forms a cycle, prev points to the entry DIR is renamed from. In this case it still retains DIRF_RENAMED flag, which will be - cleared in the `else' branch below */ + cleared in the 'else' branch below */ for (prev = dir; prev && prev->orig != dir; prev = prev->orig) DIR_CLEAR_FLAG (prev, DIRF_RENAMED); @@ -891,7 +917,8 @@ append_incremental_renames (struct directory *dir) for (dp = dirhead; dp; dp = dp->next) store_rename (dp, &stk); - if (obstack_object_size (&stk) != size) + /* FIXME: Is this the right thing to do when DIR is null? */ + if (dir && obstack_object_size (&stk) != size) { obstack_1grow (&stk, 0); dumpdir_free (dir->dump); @@ -920,8 +947,6 @@ read_incr_db_01 (int version, const char *initbuf) { int n; uintmax_t u; - time_t sec; - long int nsec; char *buf = NULL; size_t bufsize = 0; char *ebuf; @@ -943,21 +968,15 @@ read_incr_db_01 (int version, const char *initbuf) bufsize = strlen (buf) + 1; } - sec = TYPE_MINIMUM (time_t); - nsec = -1; - errno = 0; - u = strtoumax (buf, &ebuf, 10); - if (!errno && TYPE_MAXIMUM (time_t) < u) - errno = ERANGE; - if (errno || buf == ebuf) + newer_mtime_option = decode_timespec (buf, &ebuf, false); + + if (! valid_timespec (newer_mtime_option)) ERROR ((0, errno, "%s:%ld: %s", quotearg_colon (listed_incremental_option), lineno, _("Invalid time stamp"))); else { - sec = u; - if (version == 1 && *ebuf) { char const *buf_ns = ebuf + 1; @@ -971,20 +990,13 @@ read_incr_db_01 (int version, const char *initbuf) quotearg_colon (listed_incremental_option), lineno, _("Invalid time stamp"))); - sec = TYPE_MINIMUM (time_t); + newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t); + newer_mtime_option.tv_nsec = -1; } else - nsec = u; - } - else - { - /* pre-1 incremental format does not contain nanoseconds */ - nsec = 0; + newer_mtime_option.tv_nsec = u; } } - newer_mtime_option.tv_sec = sec; - newer_mtime_option.tv_nsec = nsec; - while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream))) { @@ -1001,20 +1013,12 @@ read_incr_db_01 (int version, const char *initbuf) if (version == 1) { - errno = 0; - u = strtoumax (strp, &ebuf, 10); - if (!errno && TYPE_MAXIMUM (time_t) < u) - errno = ERANGE; - if (errno || strp == ebuf || *ebuf != ' ') - { - ERROR ((0, errno, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid modification time (seconds)"))); - sec = (time_t) -1; - } - else - sec = u; + mtime = decode_timespec (strp, &ebuf, false); strp = ebuf; + if (!valid_timespec (mtime) || *strp != ' ') + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid modification time"))); errno = 0; u = strtoumax (strp, &ebuf, 10); @@ -1025,46 +1029,30 @@ read_incr_db_01 (int version, const char *initbuf) ERROR ((0, errno, "%s:%ld: %s", quotearg_colon (listed_incremental_option), lineno, _("Invalid modification time (nanoseconds)"))); - nsec = -1; + mtime.tv_nsec = -1; } else - nsec = u; - mtime.tv_sec = sec; - mtime.tv_nsec = nsec; + mtime.tv_nsec = u; strp = ebuf; } else - memset (&mtime, 0, sizeof mtime); + mtime.tv_sec = mtime.tv_nsec = 0; - errno = 0; - u = strtoumax (strp, &ebuf, 10); - if (!errno && TYPE_MAXIMUM (dev_t) < u) - errno = ERANGE; - if (errno || strp == ebuf || *ebuf != ' ') - { - ERROR ((0, errno, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid device number"))); - dev = (dev_t) -1; - } - else - dev = u; + dev = strtosysint (strp, &ebuf, + TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t)); strp = ebuf; + if (errno || *strp != ' ') + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid device number"))); - errno = 0; - u = strtoumax (strp, &ebuf, 10); - if (!errno && TYPE_MAXIMUM (ino_t) < u) - errno = ERANGE; - if (errno || strp == ebuf || *ebuf != ' ') - { - ERROR ((0, errno, "%s:%ld: %s", - quotearg_colon (listed_incremental_option), lineno, - _("Invalid inode number"))); - ino = (ino_t) -1; - } - else - ino = u; + ino = strtosysint (strp, &ebuf, + TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t)); strp = ebuf; + if (errno || *strp != ' ') + ERROR ((0, errno, "%s:%ld: %s", + quotearg_colon (listed_incremental_option), lineno, + _("Invalid inode number"))); strp++; unquote_string (strp); @@ -1130,8 +1118,8 @@ read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval) } /* Read from file FP a nul-terminated string and convert it to - uintmax_t. Return the resulting value in PVAL. Assume C has - already been read. + 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. @@ -1139,9 +1127,10 @@ read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval) Return the last character read or EOF on end of file. */ static int -read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval) +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++) @@ -1164,24 +1153,32 @@ read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval) buf[i] = 0; errno = 0; - *pval = strtoumax (buf, &ep, 10); - if (c || errno || max_val < *pval) + 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 - uintmax_t. Return the resulting value in PVAL. + 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 exceeds MAX_VAL. + converted value is out of range. Return the last character read or EOF on end of file. */ static int -read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval) +read_num (FILE *fp, intmax_t min_val, uintmax_t max_val, intmax_t *pval) { - return read_unsigned_num (getc (fp), fp, max_val, pval); + int c = getc (fp); + if (c == '-') + { + read_negative_num (fp, min_val, pval); + return 0; + } + return read_unsigned_num (c, fp, max_val, pval); } /* Read from FP two NUL-terminated strings representing a struct @@ -1192,34 +1189,21 @@ read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval) static void read_timespec (FILE *fp, struct timespec *pval) { - int c = getc (fp); intmax_t i; - uintmax_t u; - - if (c == '-') - { - read_negative_num (fp, TYPE_MINIMUM (time_t), &i); - c = 0; - pval->tv_sec = i; - } - else - { - c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u); - pval->tv_sec = u; - } + int c = read_num (fp, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &i); + pval->tv_sec = i; - if (c || read_num (fp, BILLION - 1, &u)) + 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 = u; + pval->tv_nsec = i; } /* Read incremental snapshot format 2 */ static void read_incr_db_2 (void) { - uintmax_t u; struct obstack stk; obstack_init (&stk); @@ -1228,6 +1212,7 @@ read_incr_db_2 (void) for (;;) { + intmax_t i; struct timespec mtime; dev_t dev; ino_t ino; @@ -1236,20 +1221,22 @@ read_incr_db_2 (void) char *content; size_t s; - if (read_num (listed_incremental_stream, 1, &u)) + if (read_num (listed_incremental_stream, 0, 1, &i)) return; /* Normal return */ - nfs = u; + nfs = i; read_timespec (listed_incremental_stream, &mtime); - if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u)) + if (read_num (listed_incremental_stream, + TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i)) break; - dev = u; + dev = i; - if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u)) + if (read_num (listed_incremental_stream, + TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i)) break; - ino = u; + ino = i; if (read_obstack (listed_incremental_stream, &stk, &s)) break; @@ -1352,8 +1339,7 @@ read_directory_file (void) if (ferror (listed_incremental_stream)) read_error (listed_incremental_option); - if (buf) - free (buf); + free (buf); } /* Output incremental data for the directory ENTRY to the file DATA. @@ -1366,20 +1352,21 @@ write_directory_file_entry (void *entry, void *data) if (DIR_IS_FOUND (directory)) { - char buf[UINTMAX_STRSIZE_BOUND]; + char buf[max (SYSINT_BUFSIZE, INT_BUFSIZE_BOUND (intmax_t))]; char const *s; s = DIR_IS_NFS (directory) ? "1" : "0"; fwrite (s, 2, 1, fp); - s = (TYPE_SIGNED (time_t) - ? imaxtostr (directory->mtime.tv_sec, buf) - : umaxtostr (directory->mtime.tv_sec, buf)); + s = sysinttostr (directory->mtime.tv_sec, TYPE_MINIMUM (time_t), + TYPE_MAXIMUM (time_t), buf); fwrite (s, strlen (s) + 1, 1, fp); - s = umaxtostr (directory->mtime.tv_nsec, buf); + s = imaxtostr (directory->mtime.tv_nsec, buf); fwrite (s, strlen (s) + 1, 1, fp); - s = umaxtostr (directory->device_number, buf); + s = sysinttostr (directory->device_number, + TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), buf); fwrite (s, strlen (s) + 1, 1, fp); - s = umaxtostr (directory->inode_number, buf); + s = sysinttostr (directory->inode_number, + TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), buf); fwrite (s, strlen (s) + 1, 1, fp); fwrite (directory->name, strlen (directory->name) + 1, 1, fp); @@ -1664,11 +1651,10 @@ try_purge_directory (char const *directory_name) { const char *entry; struct stat st; - if (p) - free (p); + free (p); p = new_name (directory_name, cur); - if (deref_stat (false, p, &st)) + if (deref_stat (p, &st) != 0) { if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed dirs and check it here? */