+ 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;
+
+ if (!is_avoided_name (st->orig_file_name))
+ {
+ union block *blk = NULL;
+ off_t block_ordinal = current_block_ordinal ();
+ st->stat.st_size = 0; /* force 0 size on dir */
+
+ blk = start_header (st);
+ if (!blk)
+ return;
+
+ if (incremental_option)
+ blk->header.typeflag = GNUTYPE_DUMPDIR;
+ else /* if (standard_option) */
+ blk->header.typeflag = DIRTYPE;
+
+ /* If we're gnudumping, we aren't done yet so don't close it. */
+
+ if (!incremental_option)
+ finish_header (st, blk, block_ordinal);
+ else if (gnu_list_name->dir_contents)
+ {
+ off_t size_left;
+ off_t totsize;
+ size_t bufsize;
+ ssize_t count;
+ const char *buffer, *p_buffer;
+
+ block_ordinal = current_block_ordinal ();
+ buffer = gnu_list_name->dir_contents; /* FOO */
+ totsize = 0;
+ if (buffer)
+ for (p_buffer = buffer; *p_buffer; )
+ {
+ size_t size = strlen (p_buffer) + 1;
+ totsize += size;
+ p_buffer += size;
+ }
+ totsize++;
+ OFF_TO_CHARS (totsize, blk->header.size);
+ finish_header (st, blk, block_ordinal);
+ p_buffer = buffer;
+ size_left = totsize;
+ while (size_left > 0)
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, st->orig_file_name);
+ save_sizeleft = size_left;
+ save_totsize = totsize;
+ }
+ blk = find_next_block ();
+ bufsize = available_space_after (blk);
+ if (size_left < bufsize)
+ {
+ bufsize = size_left;
+ count = bufsize % BLOCKSIZE;
+ if (count)
+ memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
+ }
+ memcpy (blk->buffer, p_buffer, bufsize);
+ size_left -= bufsize;
+ p_buffer += bufsize;
+ set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ return;
+ }
+ }
+
+ if (!recursion_option)
+ return;
+
+ if (one_file_system_option
+ && !top_level
+ && parent_device != st->stat.st_dev)
+ {
+ if (verbose_option)
+ WARN ((0, 0,
+ _("%s: file is on a different filesystem; not dumped"),
+ quotearg_colon (st->orig_file_name)));
+ 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 = xstrdup (st->orig_file_name);
+ size_t name_size = strlen (name_buf);
+ size_t name_len = name_size;
+
+ /* 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);
+ }
+}
+
+/* Ensure exactly one trailing slash. */
+static void
+ensure_slash (char **pstr)
+{
+ size_t len = strlen (*pstr);
+ while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
+ len--;
+ if (!ISSLASH ((*pstr)[len]))
+ *pstr = xrealloc (*pstr, len + 2);
+ (*pstr)[len++] = '/';
+ (*pstr)[len] = '\0';
+}
+
+static bool
+dump_dir (struct tar_stat_info *st, int top_level, dev_t parent_device)
+{
+ char *directory;
+
+ directory = savedir (st->orig_file_name);
+ if (!directory)
+ {
+ savedir_diag (st->orig_file_name);
+ return false;
+ }
+
+ ensure_slash (&st->orig_file_name);
+ ensure_slash (&st->file_name);
+
+ dump_dir0 (directory, st, top_level, parent_device);
+
+ free (directory);
+ return true;
+}
+
+\f
+/* Main functions of this module. */
+
+void
+create_archive (void)
+{
+ char *p;
+
+ open_archive (ACCESS_WRITE);
+ xheader_write_global ();
+
+ if (incremental_option)
+ {
+ size_t buffer_size = 1000;
+ char *buffer = xmalloc (buffer_size);