+ 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;
+ }
+
+ {
+ char const *entry;
+ size_t entry_len;
+ char *name_buf = strdup (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);
+ const char *q;
+
+ collect_and_sort_names ();
+
+ while ((p = name_from_list ()) != NULL)