+ /* Note: It is important to do this before the call to write_extended(),
+ so that the actual ustar header is printed */
+ if (verbose_option
+ && header->header.typeflag != GNUTYPE_LONGLINK
+ && header->header.typeflag != GNUTYPE_LONGNAME
+ && header->header.typeflag != XHDTYPE
+ && header->header.typeflag != XGLTYPE)
+ {
+ /* These globals are parameters to print_header, sigh. */
+
+ current_header = header;
+ current_format = archive_format;
+ print_header (st, block_ordinal);
+ }
+
+ header = write_extended (false, st, header);
+ simple_finish_header (header);
+}
+\f
+
+void
+pad_archive (off_t size_left)
+{
+ union block *blk;
+ while (size_left > 0)
+ {
+ mv_size_left (size_left);
+ blk = find_next_block ();
+ memset (blk->buffer, 0, BLOCKSIZE);
+ set_next_block_after (blk);
+ size_left -= BLOCKSIZE;
+ }
+}
+
+static enum dump_status
+dump_regular_file (int fd, struct tar_stat_info *st)
+{
+ off_t size_left = st->stat.st_size;
+ off_t block_ordinal;
+ union block *blk;
+
+ block_ordinal = current_block_ordinal ();
+ blk = start_header (st);
+ if (!blk)
+ return dump_status_fail;
+
+ /* Mark contiguous files, if we support them. */
+ if (archive_format != V7_FORMAT && S_ISCTG (st->stat.st_mode))
+ blk->header.typeflag = CONTTYPE;
+
+ finish_header (st, blk, block_ordinal);
+
+ mv_begin (st);
+ while (size_left > 0)
+ {
+ size_t bufsize, count;
+
+ mv_size_left (size_left);
+
+ blk = find_next_block ();
+
+ bufsize = available_space_after (blk);
+
+ if (size_left < bufsize)
+ {
+ /* Last read -- zero out area beyond. */
+ bufsize = size_left;
+ count = bufsize % BLOCKSIZE;
+ if (count)
+ memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
+ }
+
+ count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
+ if (count == SAFE_READ_ERROR)
+ {
+ read_diag_details (st->orig_file_name,
+ st->stat.st_size - size_left, bufsize);
+ pad_archive (size_left);
+ return dump_status_short;
+ }
+ size_left -= count;
+ if (count)
+ set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
+
+ if (count != bufsize)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ memset (blk->buffer + count, 0, bufsize - count);
+ WARN ((0, 0,
+ ngettext ("%s: File shrank by %s byte; padding with zeros",
+ "%s: File shrank by %s bytes; padding with zeros",
+ size_left),
+ quotearg_colon (st->orig_file_name),
+ STRINGIFY_BIGINT (size_left, buf)));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_DIFFERS;
+ pad_archive (size_left - (bufsize-count));
+ return dump_status_short;
+ }
+ }
+ return dump_status_ok;
+}
+
+\f
+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;
+ 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 && archive_format != POSIX_FORMAT)
+ 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)
+ {
+ if (archive_format == POSIX_FORMAT)
+ {
+ xheader_store ("GNU.dumpdir", st, gnu_list_name->dir_contents);
+ finish_header (st, blk, block_ordinal);
+ }
+ else
+ {
+ 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;
+ if (buffer)
+ totsize = dumpdir_size (buffer);
+ else
+ totsize = 0;
+ OFF_TO_CHARS (totsize, blk->header.size);
+ finish_header (st, blk, block_ordinal);
+ p_buffer = buffer;
+ size_left = totsize;
+
+ mv_begin (st);
+ mv_total_size (totsize);
+ while (size_left > 0)
+ {
+ mv_size_left (size_left);
+ 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);