X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcreate.c;h=a9cf981df748827ae5033bf813db1d9f81eb691b;hb=3fe0f0d7f87777815e100766e0633fa5ec0321e7;hp=23e9efdbd302f8537c872d4561b69280ae04fa54;hpb=9bf87b195e732d03db5efc8850ac5e29a2538df9;p=chaz%2Ftar diff --git a/src/create.c b/src/create.c index 23e9efd..a9cf981 100644 --- a/src/create.c +++ b/src/create.c @@ -1,13 +1,13 @@ /* Create a tar archive. Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. 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 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -34,36 +34,53 @@ struct link char name[1]; }; -struct exclude_tag +struct exclusion_tag { const char *name; size_t length; - struct exclude_tag *next; + enum exclusion_tag_type type; + bool (*predicate) (const char *name); + struct exclusion_tag *next; }; -static struct exclude_tag *exclude_tags; +static struct exclusion_tag *exclusion_tags; void -add_exclude_tag (const char *name) +add_exclusion_tag (const char *name, enum exclusion_tag_type type, + bool (*predicate) (const char *name)) { - struct exclude_tag *tag = xmalloc (sizeof tag[0]); - tag->next = exclude_tags; + struct exclusion_tag *tag = xmalloc (sizeof tag[0]); + tag->next = exclusion_tags; tag->name = name; + tag->type = type; + tag->predicate = predicate; tag->length = strlen (name); - exclude_tags = tag; + exclusion_tags = tag; } -static bool -check_exclude_tags (char *dirname) +static void +exclusion_tag_warning (const char *dirname, const char *tagname, + const char *message) +{ + if (verbose_option) + WARN ((0, 0, + _("%s: contains a cache directory tag %s; %s"), + quotearg_colon (dirname), + quotearg_n (1, tagname), + message)); +} + +static enum exclusion_tag_type +check_exclusion_tags (char *dirname, const char **tag_file_name) { static char *tagname; static size_t tagsize; - struct exclude_tag *tag; + struct exclusion_tag *tag; size_t dlen = strlen (dirname); char *nptr = NULL; char *ret = NULL; - for (tag = exclude_tags; tag; tag = tag->next) + for (tag = exclusion_tags; tag; tag = tag->next) { size_t size = dlen + tag->length + 1; if (size > tagsize) @@ -78,18 +95,45 @@ check_exclude_tags (char *dirname) nptr = tagname + dlen; } strcpy (nptr, tag->name); - if (access (tagname, F_OK) == 0) + if (access (tagname, F_OK) == 0 + && (!tag->predicate || tag->predicate (tagname))) { - if (verbose_option) - WARN ((0, 0, - _("%s: contains a cache directory tag %s; not dumped"), - quotearg_colon (dirname), - quotearg_n (1, tag->name))); - return true; + if (tag_file_name) + *tag_file_name = tag->name; + return tag->type; } } - return false; + return exclusion_tag_none; +} + +/* Exclusion predicate to test if the named file (usually "CACHEDIR.TAG") + contains a valid header, as described at: + http://www.brynosaurus.com/cachedir + Applications can write this file into directories they create + for use as caches containing purely regenerable, non-precious data, + allowing us to avoid archiving them if --exclude-caches is specified. */ + +#define CACHEDIR_SIGNATURE "Signature: 8a477f597d28d172789f06886806bc55" +#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1) + +bool +cachedir_file_p (const char *name) +{ + bool tag_present = false; + int fd = open (name, O_RDONLY); + if (fd >= 0) + { + static char tagbuf[CACHEDIR_SIGNATURE_SIZE]; + + if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE) + == CACHEDIR_SIGNATURE_SIZE + && memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0) + tag_present = true; + + close (fd); + } + return tag_present; } @@ -667,10 +711,10 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) char *p; int type; - if (extended_header.buffer || extended_header.stk == NULL) + if (st->xhdr.buffer || st->xhdr.stk == NULL) return old_header; - xheader_finish (&extended_header); + xheader_finish (&st->xhdr); memcpy (hp.buffer, old_header, sizeof (hp)); if (global) { @@ -682,7 +726,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) type = XHDTYPE; p = xheader_xhdr_name (st); } - xheader_write (type, p, &extended_header); + xheader_write (type, p, &st->xhdr); free (p); header = find_next_block (); memcpy (header, &hp.buffer, sizeof (hp.buffer)); @@ -1043,53 +1087,13 @@ dump_regular_file (int fd, struct tar_stat_info *st) } -/* Look in directory DIRNAME for a cache directory tag file - with the magic name "CACHEDIR.TAG" and a standard header, - as described at: - http://www.brynosaurus.com/cachedir - Applications can write this file into directories they create - for use as caches containing purely regenerable, non-precious data, - allowing us to avoid archiving them if --exclude-caches is specified. */ - -#define CACHEDIR_SIGNATURE "Signature: 8a477f597d28d172789f06886806bc55" -#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1) - -static bool -check_cache_directory (char *dirname) -{ - static char tagname[] = "CACHEDIR.TAG"; - char *tagpath; - int fd; - bool tag_present = false; - - tagpath = xmalloc (strlen (dirname) + strlen (tagname) + 1); - strcpy (tagpath, dirname); - strcat (tagpath, tagname); - - fd = open (tagpath, O_RDONLY); - if (fd >= 0) - { - static char tagbuf[CACHEDIR_SIGNATURE_SIZE]; - - if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE) - == CACHEDIR_SIGNATURE_SIZE - && memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0) - tag_present = true; - - close (fd); - } - - free (tagpath); - - return tag_present; -} - static void dump_dir0 (char *directory, struct tar_stat_info *st, int top_level, dev_t parent_device) { dev_t our_device = st->stat.st_dev; - + const char *tag_file_name; + if (!is_avoided_name (st->orig_file_name)) { union block *blk = NULL; @@ -1171,34 +1175,60 @@ dump_dir0 (char *directory, WARN ((0, 0, _("%s: file is on a different filesystem; not dumped"), quotearg_colon (st->orig_file_name))); - return; } - - { - char const *entry; - size_t entry_len; - char *name_buf = xstrdup (st->orig_file_name); - size_t name_size = strlen (name_buf); - size_t name_len = name_size; + else + { + char *name_buf; + size_t name_size; + + switch (check_exclusion_tags (st->orig_file_name, &tag_file_name)) + { + case exclusion_tag_none: + case exclusion_tag_all: + { + char const *entry; + size_t entry_len; + size_t name_len; - /* Now output all the files in the directory. */ - /* FIXME: Should speed this up by cd-ing into the dir. */ + name_buf = xstrdup (st->orig_file_name); + name_size = name_len = strlen (name_buf); - for (entry = directory; (entry_len = strlen (entry)) != 0; - entry += entry_len + 1) - { - if (name_size < name_len + entry_len) - { - name_size = name_len + entry_len; - name_buf = xrealloc (name_buf, name_size + 1); + /* Now output all the files in the directory. */ + /* FIXME: Should speed this up by cd-ing into the dir. */ + for (entry = directory; (entry_len = strlen (entry)) != 0; + entry += entry_len + 1) + { + if (name_size < name_len + entry_len) + { + name_size = name_len + entry_len; + name_buf = xrealloc (name_buf, name_size + 1); + } + strcpy (name_buf + name_len, entry); + if (!excluded_name (name_buf)) + dump_file (name_buf, 0, our_device); + } + + free (name_buf); } - strcpy (name_buf + name_len, entry); - if (!excluded_name (name_buf)) + break; + + case exclusion_tag_contents: + exclusion_tag_warning (st->orig_file_name, tag_file_name, + _("contents not dumped")); + name_size = strlen (st->orig_file_name) + strlen (tag_file_name) + 1; + name_buf = xmalloc (name_size); + strcpy (name_buf, st->orig_file_name); + strcat (name_buf, tag_file_name); dump_file (name_buf, 0, our_device); - } - - free (name_buf); - } + free (name_buf); + break; + + case exclusion_tag_under: + exclusion_tag_warning (st->orig_file_name, tag_file_name, + _("contents not dumped")); + break; + } + } } /* Ensure exactly one trailing slash. */ @@ -1239,7 +1269,7 @@ create_archive (void) const char *p; open_archive (ACCESS_WRITE); - xheader_write_global (); + buffer_write_global_xheader (); if (incremental_option) { @@ -1544,22 +1574,18 @@ dump_file0 (struct tar_stat_info *st, const char *p, if (is_dir) { + const char *tag_file_name; ensure_slash (&st->orig_file_name); ensure_slash (&st->file_name); - if (exclude_caches_option - && check_cache_directory (st->orig_file_name)) + if (check_exclusion_tags (st->orig_file_name, &tag_file_name) + == exclusion_tag_all) { - if (verbose_option) - WARN ((0, 0, - _("%s: contains a cache directory tag; not dumped"), - quotearg_colon (st->orig_file_name))); + exclusion_tag_warning (st->orig_file_name, tag_file_name, + _("directory not dumped")); return; } - if (check_exclude_tags (st->orig_file_name)) - return; - ok = dump_dir (fd, st, top_level, parent_device); /* dump_dir consumes FD if successful. */ @@ -1619,7 +1645,10 @@ dump_file0 (struct tar_stat_info *st, const char *p, if (ok) { - if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0 + if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0 + /* Original ctime will change if the file is a directory and + --remove-files is given */ + && !(remove_files_option && is_dir)) || original_size < final_stat.st_size) { WARN ((0, 0, _("%s: file changed as we read it"),