+#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 (CURRENT_FILE_NAME, openflag, mode);
+
+#endif /* not O_CTG */
+
+ if (fd < 0)
+ {
+ if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ goto again_file;
+
+ open_error (CURRENT_FILE_NAME);
+ if (current_header->oldgnu_header.isextended)
+ skip_extended_headers ();
+ skip_file (current_stat.st_size);
+ 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 (CURRENT_FILE_NAME) + 1;
+ name = xmalloc (name_length_bis);
+ memcpy (name, CURRENT_FILE_NAME, name_length_bis);
+ size = current_stat.st_size;
+ extract_sparse_file (fd, &size, current_stat.st_size, name);
+ }
+ else
+ for (size = current_stat.st_size;
+ size > 0;
+ size -= written)
+ {
+ 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;
+ sstatus = full_write (fd, data_block->buffer, written);
+
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (sstatus == written)
+ continue;
+
+ /* Error in writing to file. Print it, skip to next file in
+ archive. */
+
+ write_error_details (CURRENT_FILE_NAME, sstatus, written);
+ skip_file (size - written);
+ break; /* still do the close, mod time, chmod, etc */
+ }
+
+ 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 (CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ }
+
+ set_stat (CURRENT_FILE_NAME, ¤t_stat, 0,
+ (old_files_option == OVERWRITE_OLD_FILES
+ ? UNKNOWN_PERMSTATUS
+ : ARCHIVED_PERMSTATUS),
+ typeflag);
+ break;
+
+ case SYMTYPE:
+#ifdef HAVE_SYMLINK
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ while (status = symlink (current_link_name, CURRENT_FILE_NAME),
+ status != 0)
+ if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ if (status == 0)
+
+ /* Setting the attributes of symbolic links might, on some systems,
+ change the pointed to file, instead of the symbolic link itself.
+ At least some of these systems have a lchown call, and the
+ set_stat routine knows about this. */
+
+ set_stat (CURRENT_FILE_NAME, ¤t_stat, 0,
+ ARCHIVED_PERMSTATUS, typeflag);
+
+ else
+ {
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot create symlink to %s"),
+ quotearg_colon (CURRENT_FILE_NAME),
+ quote (current_link_name)));
+ if (backup_option)
+ undo_last_backup ();
+ }
+ break;
+
+#else
+ {
+ static int warned_once;
+
+ if (!warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0,
+ _("Attempting extraction of symbolic links as hard links")));
+ }
+ }
+ typeflag = LNKTYPE;
+ /* Fall through. */