X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fincremen.c;h=cd32e196aed99bf5b17f55595387bb973f27d15c;hb=785cdec4450a1459fdbb90df1344b69be34e0059;hp=372061dd12a3aadb4f51524482e7066107dd6df9;hpb=138fc7e67e3d9845cd7d81aad0e9c7724784f9b9;p=debian%2Ftar diff --git a/src/incremen.c b/src/incremen.c index 372061dd..cd32e196 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -60,6 +60,7 @@ struct dumpdir /* Dump directory listing */ /* Directory attributes. */ struct directory { + struct directory *next; struct timespec mtime; /* Modification time */ dev_t device_number; /* device number for directory */ ino_t inode_number; /* inode number for directory */ @@ -72,7 +73,7 @@ struct directory the original directory structure */ const char *tagfile; /* Tag file, if the directory falls under exclusion_tag_under */ - char name[1]; /* file name of directory */ + char *name; /* file name of directory */ }; struct dumpdir * @@ -80,13 +81,14 @@ dumpdir_create0 (const char *contents, const char *cmask) { struct dumpdir *dump; size_t i, total, ctsize, len; - const char *p; + char *p; + const char *q; - for (i = 0, total = 0, ctsize = 1, p = contents; *p; total++, p += len) + for (i = 0, total = 0, ctsize = 1, q = contents; *q; total++, q += len) { - len = strlen (p) + 1; + len = strlen (q) + 1; ctsize += len; - if (!cmask || strchr (cmask, *p)) + if (!cmask || strchr (cmask, *q)) i++; } dump = xmalloc (sizeof (*dump) + ctsize); @@ -196,6 +198,7 @@ dumpdir_size (const char *p) } +static struct directory *dirhead, *dirtail; static Hash_table *directory_table; static Hash_table *directory_meta_table; @@ -247,18 +250,68 @@ static struct directory * make_directory (const char *name) { size_t namelen = strlen (name); - size_t size = offsetof (struct directory, name) + namelen + 1; - struct directory *directory = xmalloc (size); + struct directory *directory = xmalloc (sizeof (*directory)); + directory->next = NULL; directory->dump = directory->idump = NULL; directory->orig = NULL; directory->flags = false; - strcpy (directory->name, name); - if (namelen && ISSLASH (directory->name[namelen - 1])) - directory->name[namelen - 1] = 0; + if (namelen && ISSLASH (name[namelen - 1])) + namelen--; + directory->name = xmalloc (namelen + 1); + memcpy (directory->name, name, namelen); + directory->name[namelen] = 0; directory->tagfile = NULL; return directory; } +static void +free_directory (struct directory *dir) +{ + free (dir->name); + free (dir); +} + +static struct directory * +attach_directory (const char *name) +{ + struct directory *dir = make_directory (name); + if (dirtail) + dirtail->next = dir; + else + dirhead = dir; + dirtail = dir; + return dir; +} + + +static void +replace_prefix (char **pname, const char *samp, size_t slen, + const char *repl, size_t rlen) +{ + char *name = *pname; + size_t nlen = strlen (name); + if (nlen > slen && memcmp (name, samp, slen) == 0 && ISSLASH (name[slen])) + { + if (rlen > slen) + { + name = xrealloc (name, nlen - slen + rlen + 1); + *pname = name; + } + memmove (name + rlen, name + slen, nlen - slen + 1); + memcpy (name, repl, rlen); + } +} + +void +dirlist_replace_prefix (const char *pref, const char *repl) +{ + struct directory *dp; + size_t pref_len = strlen (pref); + size_t repl_len = strlen (repl); + for (dp = dirhead; dp; dp = dp->next) + replace_prefix (&dp->name, pref, pref_len, repl, repl_len); +} + /* 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 @@ -268,7 +321,7 @@ note_directory (char const *name, struct timespec mtime, dev_t dev, ino_t ino, bool nfs, bool found, const char *contents) { - struct directory *directory = make_directory (name); + struct directory *directory = attach_directory (name); directory->mtime = mtime; directory->device_number = dev; @@ -311,7 +364,7 @@ find_directory (const char *name) { struct directory *dir = make_directory (name); struct directory *ret = hash_lookup (directory_table, dir); - free (dir); + free_directory (dir); return ret; } } @@ -330,7 +383,7 @@ find_directory_meta (dev_t dev, ino_t ino) dir->device_number = dev; dir->inode_number = ino; ret = hash_lookup (directory_meta_table, dir); - free (dir); + free_directory (dir); return ret; } } @@ -354,11 +407,14 @@ update_parent_directory (const char *name) free (p); } +#define PD_VERBOSE 0x10 +#define PD_FORCE_CHILDREN 0x20 +#define PD_CHILDREN(f) ((f) & 3) + static struct directory * procdir (char *name_buffer, struct stat *stat_data, dev_t device, - enum children children, - bool verbose, + int flag, char *entry) { struct directory *directory; @@ -386,12 +442,16 @@ procdir (char *name_buffer, struct stat *stat_data, stat_data->st_ino); if (d) { - if (verbose_option) - WARN ((0, 0, _("%s: Directory has been renamed from %s"), - quotearg_colon (name_buffer), - quote_n (1, d->name))); - directory->orig = d; - DIR_SET_FLAG (directory, DIRF_RENAMED); + if (strcmp (d->name, name_buffer)) + { + if (verbose_option) + WARN ((0, 0, _("%s: Directory has been renamed from %s"), + quotearg_colon (name_buffer), + quote_n (1, d->name))); + directory->orig = d; + DIR_SET_FLAG (directory, DIRF_RENAMED); + dirlist_replace_prefix (d->name, name_buffer); + } directory->children = CHANGED_CHILDREN; } else @@ -426,18 +486,22 @@ procdir (char *name_buffer, struct stat *stat_data, if (d) { - if (verbose) - WARN ((0, 0, _("%s: Directory has been renamed from %s"), - quotearg_colon (name_buffer), - quote_n (1, d->name))); - directory->orig = d; - DIR_SET_FLAG (directory, DIRF_RENAMED); + if (strcmp (d->name, name_buffer)) + { + if (flag & PD_VERBOSE) + WARN ((0, 0, _("%s: Directory has been renamed from %s"), + quotearg_colon (name_buffer), + quote_n (1, d->name))); + directory->orig = d; + DIR_SET_FLAG (directory, DIRF_RENAMED); + dirlist_replace_prefix (d->name, name_buffer); + } directory->children = CHANGED_CHILDREN; } else { DIR_SET_FLAG (directory, DIRF_NEW); - if (verbose) + if (flag & PD_VERBOSE) WARN ((0, 0, _("%s: Directory is new"), quotearg_colon (name_buffer))); directory->children = @@ -456,43 +520,48 @@ procdir (char *name_buffer, struct stat *stat_data, /* ... except if it was explicitely given in the command line */ && !is_individual_file (name_buffer)) directory->children = NO_CHILDREN; - else if (children == ALL_CHILDREN) - directory->children = ALL_CHILDREN; - + else if (flag & PD_FORCE_CHILDREN) + { + directory->children = PD_CHILDREN(flag); + if (directory->children == NO_CHILDREN) + *entry = 'N'; + } + DIR_SET_FLAG (directory, DIRF_INIT); - { - const char *tag_file_name; - - switch (check_exclusion_tags (name_buffer, &tag_file_name)) - { - case exclusion_tag_all: - /* This warning can be duplicated by code in dump_file0, but only - in case when the topmost directory being archived contains - an exclusion tag. */ - exclusion_tag_warning (name_buffer, tag_file_name, - _("directory not dumped")); - if (entry) - *entry = 'N'; - directory->children = NO_CHILDREN; - break; - - case exclusion_tag_contents: - exclusion_tag_warning (name_buffer, tag_file_name, - _("contents not dumped")); - directory->children = NO_CHILDREN; - break; + if (directory->children != NO_CHILDREN) + { + const char *tag_file_name; - case exclusion_tag_under: - exclusion_tag_warning (name_buffer, tag_file_name, - _("contents not dumped")); - directory->tagfile = tag_file_name; - break; + switch (check_exclusion_tags (name_buffer, &tag_file_name)) + { + case exclusion_tag_all: + /* This warning can be duplicated by code in dump_file0, but only + in case when the topmost directory being archived contains + an exclusion tag. */ + exclusion_tag_warning (name_buffer, tag_file_name, + _("directory not dumped")); + if (entry) + *entry = 'N'; + directory->children = NO_CHILDREN; + break; - case exclusion_tag_none: - break; - } - } + case exclusion_tag_contents: + exclusion_tag_warning (name_buffer, tag_file_name, + _("contents not dumped")); + directory->children = NO_CHILDREN; + break; + + case exclusion_tag_under: + exclusion_tag_warning (name_buffer, tag_file_name, + _("contents not dumped")); + directory->tagfile = tag_file_name; + break; + + case exclusion_tag_none: + break; + } + } return directory; } @@ -584,7 +653,7 @@ scan_directory (char *dir, dev_t device) size_t name_length; /* used length in name_buffer */ struct stat stat_data; struct directory *directory; - + if (! dirp) savedir_error (dir); @@ -606,8 +675,7 @@ scan_directory (char *dir, dev_t device) return NULL; } - directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false, - NULL); + directory = procdir (name_buffer, &stat_data, device, 0, NULL); if (dirp && directory->children != NO_CHILDREN) { @@ -646,10 +714,13 @@ scan_directory (char *dir, dev_t device) if (S_ISDIR (stat_data.st_mode)) { + int pd_flag = (verbose_option ? PD_VERBOSE : 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'; - procdir (name_buffer, &stat_data, device, - directory->children, - verbose_option, entry); + procdir (name_buffer, &stat_data, device, pd_flag, entry); } else if (one_file_system_option && device != stat_data.st_dev) @@ -701,12 +772,9 @@ obstack_code_rename (struct obstack *stk, char *from, char *to) obstack_grow (stk, s, strlen (s) + 1); } -static bool -rename_handler (void *data, void *proc_data) +static void +store_rename (struct directory *dir, struct obstack *stk) { - struct directory *dir = data; - struct obstack *stk = proc_data; - if (DIR_IS_RENAMED (dir)) { struct directory *prev, *p; @@ -745,7 +813,6 @@ rename_handler (void *data, void *proc_data) obstack_code_rename (stk, "", prev->name); } } - return true; } const char * @@ -753,8 +820,9 @@ append_incremental_renames (const char *dump) { struct obstack stk; size_t size; - - if (directory_table == NULL) + struct directory *dp; + + if (dirhead == NULL) return dump; obstack_init (&stk); @@ -766,7 +834,9 @@ append_incremental_renames (const char *dump) else size = 0; - hash_do_for_each (directory_table, rename_handler, &stk); + for (dp = dirhead; dp; dp = dp->next) + store_rename (dp, &stk); + if (obstack_object_size (&stk) != size) { obstack_1grow (&stk, 0);