📄 incremen.c
字号:
/* Prepare space for new dumpdir */ new_dump = xmalloc (len); new_dump_ptr = new_dump; /* Fill in the dumpdir template */ for (i = 0; i < dirsize; i++) { const char *loc = dumpdir_locate (dump, array[i]); if (loc) { if (directory->tagfile) *new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ? ' ' : 'I'; else *new_dump_ptr = ' '; new_dump_ptr++; } else if (directory->tagfile) *new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ? ' ' : 'I'; else *new_dump_ptr++ = 'Y'; /* New entry */ /* Copy the file name */ for (p = array[i]; (*new_dump_ptr++ = *p++); ) ; } *new_dump_ptr = 0; directory->idump = directory->dump; directory->dump = dumpdir_create0 (new_dump, NULL); free (array);}/* Recursively scan the given directory. */static const char *scan_directory (char *dir, dev_t device){ char *dirp = savedir (dir); /* for scanning directory */ char *name_buffer; /* directory, `/', and directory member */ size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */ size_t name_length; /* used length in name_buffer */ struct stat stat_data; struct directory *directory; if (! dirp) savedir_error (dir); name_buffer_size = strlen (dir) + NAME_FIELD_SIZE; name_buffer = xmalloc (name_buffer_size + 2); strcpy (name_buffer, dir); if (! ISSLASH (dir[strlen (dir) - 1])) strcat (name_buffer, "/"); name_length = strlen (name_buffer); if (deref_stat (dereference_option, name_buffer, &stat_data)) { stat_diag (name_buffer); /* FIXME: used to be children = CHANGED_CHILDREN; but changed to: */ free (name_buffer); free (dirp); return NULL; } directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false, NULL); if (dirp && directory->children != NO_CHILDREN) { char *entry; /* directory entry being scanned */ size_t entrylen; /* length of directory entry */ dumpdir_iter_t itr; makedumpdir (directory, dirp); for (entry = dumpdir_first (directory->dump, 1, &itr); entry; entry = dumpdir_next (itr)) { entrylen = strlen (entry); if (name_buffer_size <= entrylen - 1 + name_length) { do name_buffer_size += NAME_FIELD_SIZE; while (name_buffer_size <= entrylen - 1 + name_length); name_buffer = xrealloc (name_buffer, name_buffer_size + 2); } strcpy (name_buffer + name_length, entry + 1); if (*entry == 'I') /* Ignored entry */ *entry = 'N'; else if (excluded_name (name_buffer)) *entry = 'N'; else { if (deref_stat (dereference_option, name_buffer, &stat_data)) { stat_diag (name_buffer); *entry = 'N'; continue; } if (S_ISDIR (stat_data.st_mode)) { *entry = 'D'; procdir (name_buffer, &stat_data, device, directory->children, verbose_option, entry); } else if (one_file_system_option && device != stat_data.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 (stat_data, m) && (!after_date_option || OLDER_STAT_TIME (stat_data, c))) *entry = 'N'; else *entry = 'Y'; } } free (itr); } free (name_buffer); if (dirp) free (dirp); return directory->dump ? directory->dump->contents : NULL;}const char *get_directory_contents (char *dir, dev_t device){ return scan_directory (dir, device);}static voidobstack_code_rename (struct obstack *stk, char *from, char *to){ char *s; s = from[0] == 0 ? from : safer_name_suffix (from, false, absolute_names_option); obstack_1grow (stk, 'R'); obstack_grow (stk, s, strlen (s) + 1); s = to[0] == 0 ? to: safer_name_suffix (to, false, absolute_names_option); obstack_1grow (stk, 'T'); obstack_grow (stk, s, strlen (s) + 1);}static boolrename_handler (void *data, void *proc_data){ struct directory *dir = data; struct obstack *stk = proc_data; if (DIR_IS_RENAMED (dir)) { struct directory *prev, *p; /* Detect eventual cycles and clear DIRF_RENAMED flag, so these entries 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 */ for (prev = dir; prev && prev->orig != dir; prev = prev->orig) DIR_CLEAR_FLAG (prev, DIRF_RENAMED); if (prev == NULL) { for (p = dir; p && p->orig; p = p->orig) obstack_code_rename (stk, p->orig->name, p->name); } else { char *temp_name; DIR_CLEAR_FLAG (prev, DIRF_RENAMED); /* Break the cycle by using a temporary name for one of its elements. First, create a temp name stub entry. */ temp_name = dir_name (dir->name); obstack_1grow (stk, 'X'); obstack_grow (stk, temp_name, strlen (temp_name) + 1); obstack_code_rename (stk, dir->name, ""); for (p = dir; p != prev; p = p->orig) obstack_code_rename (stk, p->orig->name, p->name); obstack_code_rename (stk, "", prev->name); } } return true;}const char *append_incremental_renames (const char *dump){ struct obstack stk; size_t size; if (directory_table == NULL) return dump; obstack_init (&stk); if (dump) { size = dumpdir_size (dump) - 1; obstack_grow (&stk, dump, size); } else size = 0; hash_do_for_each (directory_table, rename_handler, &stk); if (obstack_object_size (&stk) != size) { obstack_1grow (&stk, 0); dump = obstack_finish (&stk); } else obstack_free (&stk, NULL); return dump;}static FILE *listed_incremental_stream;/* Version of incremental format snapshots (directory files) used by this tar. Currently it is supposed to be a single decimal number. 0 means incremental snapshots as per tar version before 1.15.2. The current tar version supports incremental versions from 0 up to TAR_INCREMENTAL_VERSION, inclusive. It is able to create only snapshots of TAR_INCREMENTAL_VERSION */#define TAR_INCREMENTAL_VERSION 2/* Read incremental snapshot formats 0 and 1 */static voidread_incr_db_01 (int version, const char *initbuf){ int n; uintmax_t u; time_t sec; long int nsec; char *buf = 0; size_t bufsize; char *ebuf; long lineno = 1; if (version == 1) { if (getline (&buf, &bufsize, listed_incremental_stream) <= 0) { read_error (listed_incremental_option); free (buf); return; } ++lineno; } else { buf = strdup (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) 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; errno = 0; u = strtoumax (buf_ns, &ebuf, 10); if (!errno && BILLION <= u) errno = ERANGE; if (errno || buf_ns == ebuf) { ERROR ((0, errno, "%s:%ld: %s", quotearg_colon (listed_incremental_option), lineno, _("Invalid time stamp"))); sec = TYPE_MINIMUM (time_t); } else nsec = u; } else { /* pre-1 incremental format does not contain nanoseconds */ nsec = 0; } } newer_mtime_option.tv_sec = sec; newer_mtime_option.tv_nsec = nsec; while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream))) { dev_t dev; ino_t ino; bool nfs = buf[0] == '+'; char *strp = buf + nfs; struct timespec mtime; lineno++; if (buf[n - 1] == '\n') buf[n - 1] = '\0'; 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; strp = ebuf; errno = 0; u = strtoumax (strp, &ebuf, 10); if (!errno && BILLION <= u) errno = ERANGE; if (errno || strp == ebuf || *ebuf != ' ') { ERROR ((0, errno, "%s:%ld: %s", quotearg_colon (listed_incremental_option), lineno, _("Invalid modification time (nanoseconds)"))); nsec = -1; } else nsec = u; mtime.tv_sec = sec; mtime.tv_nsec = nsec; strp = ebuf; } else memset (&mtime, 0, sizeof mtime); 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; strp = ebuf; 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; strp = ebuf; strp++; unquote_string (strp); note_directory (strp, mtime, dev, ino, nfs, false, NULL); } free (buf);}/* Read a nul-terminated string from FP and store it in STK. Store the number of bytes read (including nul terminator) in PCOUNT. Return the last character read or EOF on end of file. */static intread_obstack (FILE *fp, struct obstack *stk, size_t *pcount){ int c; size_t i; for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++) obstack_1grow (stk, c); obstack_1grow (stk, 0); *pcount = i; 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. Throw a fatal error if the string cannot be converted or if the converted value is less than MIN_VAL. */static voidread_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval){ int c; size_t i; char buf[INT_BUFSIZE_BOUND (intmax_t)]; char *ep; buf[0] = '-'; for (i = 1; ISDIGIT (c = getc (fp)); 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 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 intread_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval){ size_t i; 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; c = getc (fp); } 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"))); } buf[i] = 0; errno = 0; *pval = strtoumax (buf, &ep, 10); if (c || errno || max_val < *pval) FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file"))); return c;}/* Read from file FP a nul-terminated string and convert it to uintmax_t. Return the resulting value in PVAL. 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 intread_num (FILE *fp, uintmax_t max_val, uintmax_t *pval){ return read_unsigned_num (getc (fp), fp, max_val, pval);}/* Read from FP two NUL-terminated strings representing a struct timespec. Return the resulting value in PVAL. Throw a fatal error if the string cannot be converted. */static voidread_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -