+ if (verbose_option)
+ print_header (-1);
+
+ file_name = safer_name_suffix (current_file_name, 0);
+
+ apply_nonancestor_delayed_set_stat (file_name, 0);
+
+ /* Take a safety backup of a previously existing file. */
+
+ if (backup_option && !to_stdout_option)
+ if (!maybe_backup_file (file_name, 0))
+ {
+ int e = errno;
+ ERROR ((0, e, _("%s: Was unable to backup this file"),
+ quotearg_colon (file_name)));
+ skip_member ();
+ return;
+ }
+
+ /* Extract the archive entry according to its type. */
+
+ typeflag = current_header->header.typeflag;
+ switch (typeflag)
+ {
+ case GNUTYPE_SPARSE:
+ file_size = OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
+ if (! fill_in_sparse_array ())
+ return;
+ /* Fall through. */
+
+ case AREGTYPE:
+ case REGTYPE:
+ case CONTTYPE:
+
+ /* Appears to be a file. But BSD tar uses the convention that a slash
+ suffix means a directory. */
+
+ if (current_trailing_slash)
+ goto really_dir;
+
+ /* FIXME: deal with protection issues. */
+
+ again_file:
+ openflag = (O_WRONLY | O_BINARY | O_CREAT
+ | (old_files_option == OVERWRITE_OLD_FILES
+ ? O_TRUNC
+ : O_EXCL));
+ mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
+
+ if (to_stdout_option)
+ {
+ fd = STDOUT_FILENO;
+ goto extract_file;
+ }
+
+ if (! prepare_to_extract (file_name, 0))
+ {
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ }
+
+#if O_CTG
+ /* Contiguous files (on the Masscomp) have to specify the size in
+ the open call that creates them. */
+
+ if (typeflag == CONTTYPE)
+ fd = open (file_name, openflag | O_CTG, mode, current_stat.st_size);
+ else
+ fd = open (file_name, openflag, mode);
+
+#else /* not O_CTG */
+ if (typeflag == CONTTYPE)
+ {
+ static int conttype_diagnosed;
+
+ if (!conttype_diagnosed)
+ {
+ conttype_diagnosed = 1;
+ WARN ((0, 0, _("Extracting contiguous files as regular files")));
+ }
+ }
+ fd = open (file_name, openflag, mode);
+
+#endif /* not O_CTG */
+
+ if (fd < 0)
+ {
+ if (maybe_recoverable (file_name, &interdir_made))
+ goto again_file;
+
+ open_error (file_name);
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ }
+
+ extract_file:
+ if (typeflag == GNUTYPE_SPARSE)
+ {
+ char *name;
+ size_t name_length_bis;
+
+ /* Kludge alert. NAME is assigned to header.name because
+ during the extraction, the space that contains the header
+ will get scribbled on, and the name will get munged, so any
+ error messages that happen to contain the filename will look
+ REAL interesting unless we do this. */
+
+ name_length_bis = strlen (file_name) + 1;
+ name = xmalloc (name_length_bis);
+ memcpy (name, file_name, name_length_bis);
+ size = extract_sparse_file (fd, name,
+ current_stat.st_size, file_size);
+ free (sparsearray);
+ }
+ else
+ for (size = current_stat.st_size; size > 0; )
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = current_stat.st_size;
+ save_sizeleft = size;
+ }
+
+ /* Locate data, determine max length writeable, write it,
+ block that we have used the data, then check if the write
+ worked. */
+
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ break; /* FIXME: What happens, then? */
+ }
+
+ written = available_space_after (data_block);
+
+ if (written > size)
+ written = size;
+ errno = 0;
+ count = full_write (fd, data_block->buffer, written);
+ size -= count;
+
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (count != written)
+ {
+ write_error_details (file_name, count, written);
+ break;
+ }
+ }
+
+ skip_file (size);
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+
+ /* If writing to stdout, don't try to do anything to the filename;
+ it doesn't exist, or we don't want to touch it anyway. */
+
+ if (to_stdout_option)
+ break;
+
+ status = close (fd);
+ if (status < 0)
+ {
+ close_error (file_name);
+ if (backup_option)
+ undo_last_backup ();
+ }