static void obstack_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); }
/* Examine the directories under directory_name and delete any files that were not there at the time of the back-up. */ static bool try_purge_directory (char const *directory_name) { char *current_dir; char *cur, *arc, *p; char *temp_stub = NULL; struct dumpdir *dump; if (!is_dumpdir (¤t_stat_info)) return false; current_dir = savedir (directory_name); if (!current_dir) /* The directory doesn't exist now. It'll be created. In any case, we don't have to delete any files out of it. */ return false; /* Verify if dump directory is sane */ if (!dumpdir_ok (current_stat_info.dumpdir)) return false; /* Process renames */ for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1) { if (*arc == 'X') { #define TEMP_DIR_TEMPLATE "tar.XXXXXX" size_t len = strlen (arc + 1); temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE); memcpy (temp_stub, arc + 1, len); temp_stub[len] = '/'; memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE, sizeof TEMP_DIR_TEMPLATE); if (!mkdtemp (temp_stub)) { ERROR ((0, errno, _("Cannot create temporary directory using template %s"), quote (temp_stub))); free (temp_stub); free (current_dir); return false; } } else if (*arc == 'R') { char *src, *dst; src = arc + 1; arc += strlen (arc) + 1; dst = arc + 1; /* Ensure that neither source nor destination are absolute file names (unless permitted by -P option), and that they do not contain dubious parts (e.g. ../). This is an extra safety precaution. Besides, it might be necessary to extract from archives created with tar versions prior to 1.19. */ if (*src) src = safer_name_suffix (src, false, absolute_names_option); if (*dst) dst = safer_name_suffix (dst, false, absolute_names_option); if (*src == 0) src = temp_stub; else if (*dst == 0) dst = temp_stub; if (!rename_directory (src, dst)) { free (temp_stub); free (current_dir); /* FIXME: Make sure purge_directory(dst) will return immediately */ return false; } } } free (temp_stub); /* Process deletes */ dump = dumpdir_create (current_stat_info.dumpdir); p = NULL; for (cur = current_dir; *cur; cur += strlen (cur) + 1) { const char *entry; struct stat st; if (p) free (p); p = new_name (directory_name, cur); if (deref_stat (false, p, &st)) { if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed dirs and check it here? */ { stat_diag (p); WARN ((0, 0, _("%s: Not purging directory: unable to stat"), quotearg_colon (p))); } continue; } if (!(entry = dumpdir_locate (dump, cur)) || (*entry == 'D' && !S_ISDIR (st.st_mode)) || (*entry == 'Y' && S_ISDIR (st.st_mode))) { if (one_file_system_option && st.st_dev != root_device) { WARN ((0, 0, _("%s: directory is on a different device: not purging"), quotearg_colon (p))); continue; } if (! interactive_option || confirm ("delete", p)) { if (verbose_option) fprintf (stdlis, _("%s: Deleting %s\n"), program_name, quote (p)); if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION)) { int e = errno; ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p))); } } } } free (p); dumpdir_free (dump); free (current_dir); return true; }
char * xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n) { char *buf; size_t len = strlen (fmt); char *q; const char *p; char *dirp = NULL; char *dir = NULL; char *base = NULL; char pidbuf[UINTMAX_STRSIZE_BOUND]; char const *pptr = NULL; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *nptr = NULL; for (p = fmt; *p && (p = strchr (p, '%')); ) { switch (p[1]) { case '%': len--; break; case 'd': if (st) { if (!dirp) dirp = dir_name (st->orig_file_name); dir = safer_name_suffix (dirp, false, absolute_names_option); len += strlen (dir) - 2; } break; case 'f': if (st) { base = last_component (st->orig_file_name); len += strlen (base) - 2; } break; case 'p': pptr = umaxtostr (getpid (), pidbuf); len += pidbuf + sizeof pidbuf - 1 - pptr - 2; break; case 'n': nptr = umaxtostr (n, nbuf); len += nbuf + sizeof nbuf - 1 - nptr - 2; break; } p++; } buf = xmalloc (len + 1); for (q = buf, p = fmt; *p; ) { if (*p == '%') { switch (p[1]) { case '%': *q++ = *p++; p++; break; case 'd': if (dir) q = stpcpy (q, dir); p += 2; break; case 'f': if (base) q = stpcpy (q, base); p += 2; break; case 'p': q = stpcpy (q, pptr); p += 2; break; case 'n': q = stpcpy (q, nptr); p += 2; break; default: *q++ = *p++; if (*p) *q++ = *p++; } } else *q++ = *p++; } free (dirp); /* Do not allow it to end in a slash */ while (q > buf && ISSLASH (q[-1])) q--; *q = 0; return buf; }