X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcreate.c;h=cee0b55f36ce7e616e28f2c24c1c3a4ab94a87d1;hb=ed08ef04580c897112c79932a98ac5ccda40425b;hp=d583e7febecdbaee6a96d0fe4bd3acdc4f5ce8b4;hpb=7347b4f5d51c15bb19637ea52e9bf7dff832cc52;p=chaz%2Ftar diff --git a/src/create.c b/src/create.c index d583e7f..cee0b55 100644 --- a/src/create.c +++ b/src/create.c @@ -370,6 +370,16 @@ tar_copy_str (char *dst, const char *src, size_t len) strncpy (dst, src, len); } +/* Same as tar_copy_str, but always terminate with NUL if using + is OLDGNU format */ +static void +tar_name_copy_str (char *dst, const char *src, size_t len) +{ + tar_copy_str (dst, src, len); + if (archive_format == OLDGNU_FORMAT) + dst[len-1] = 0; +} + /* Write a "private" header */ union block * start_private_header (const char *name, size_t size) @@ -379,7 +389,7 @@ start_private_header (const char *name, size_t size) memset (header->buffer, 0, sizeof (union block)); - tar_copy_str (header->header.name, name, NAME_FIELD_SIZE); + tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE); OFF_TO_CHARS (size, header->header.size); time (&t); @@ -402,7 +412,7 @@ write_short_name (struct tar_stat_info *st) { union block *header = find_next_block (); memset (header->buffer, 0, sizeof (union block)); - tar_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE); + tar_name_copy_str (header->header.name, st->file_name, NAME_FIELD_SIZE); return header; } @@ -590,7 +600,9 @@ write_header_name (struct tar_stat_info *st) xheader_store ("path", st, NULL); return write_short_name (st); } - else if (NAME_FIELD_SIZE < strlen (st->file_name)) + else if ((archive_format == OLDGNU_FORMAT + && OLDGNU_NAME_FIELD_SIZE < strlen (st->file_name)) + || NAME_FIELD_SIZE < strlen (st->file_name)) return write_long_name (st); else return write_short_name (st); @@ -847,7 +859,7 @@ dump_regular_file (int fd, struct tar_stat_info *st) if (multi_volume_option) { - assign_string (&save_name, st->file_name); + assign_string (&save_name, st->orig_file_name); save_sizeleft = size_left; save_totsize = st->stat.st_size; } @@ -922,6 +934,47 @@ dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime) } } +/* 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; + int 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) @@ -1012,10 +1065,20 @@ dump_dir0 (char *directory, return; } + if (exclude_caches_option + && check_cache_directory(st->orig_file_name)) + { + if (verbose_option) + WARN ((0, 0, + _("%s: contains a cache directory tag; not dumped"), + quotearg_colon (st->orig_file_name))); + return; + } + { char const *entry; size_t entry_len; - char *name_buf = strdup (st->orig_file_name); + char *name_buf = xstrdup (st->orig_file_name); size_t name_size = strlen (name_buf); size_t name_len = name_size; @@ -1205,7 +1268,9 @@ dump_hard_link (struct tar_stat_info *st) block_ordinal = current_block_ordinal (); assign_string (&st->link_name, link_name); - if (NAME_FIELD_SIZE < strlen (link_name)) + if ((archive_format == OLDGNU_FORMAT + && OLDGNU_NAME_FIELD_SIZE < strlen (link_name)) + || NAME_FIELD_SIZE < strlen (link_name)) write_long_link (st); st->stat.st_size = 0; @@ -1266,7 +1331,7 @@ check_links (void) { if (lp->nlink) { - WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name)); + WARN ((0, 0, _("Missing links to %s.\n"), quote (lp->name))); } } } @@ -1332,7 +1397,7 @@ dump_file0 (struct tar_stat_info *st, char *p, && OLDER_STAT_TIME (st->stat, m) && (!after_date_option || OLDER_STAT_TIME (st->stat, c))) { - if (!incremental_option) + if (!incremental_option && verbose_option) WARN ((0, 0, _("%s: file is unchanged; not dumped"), quotearg_colon (p))); return; @@ -1439,7 +1504,8 @@ dump_file0 (struct tar_stat_info *st, char *p, } buffer[size] = '\0'; assign_string (&st->link_name, buffer); - if (size > NAME_FIELD_SIZE) + if ((archive_format == OLDGNU_FORMAT && size > OLDGNU_NAME_FIELD_SIZE) + || size > NAME_FIELD_SIZE) write_long_link (st); block_ordinal = current_block_ordinal ();