+#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 (CURRENT_FILE_NAME, openflag | O_CTG,
+ mode, current_stat.st_size);
+ else
+ fd = open (CURRENT_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 (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);
+ 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 (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;
+
+ if (absolute_names_option
+ || (current_link_name[0] != '/'
+ && ! contains_dot_dot (current_link_name)))
+ {
+ while (status = symlink (current_link_name, CURRENT_FILE_NAME),
+ status != 0)
+ if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ if (status == 0)
+ set_stat (CURRENT_FILE_NAME, ¤t_stat, 0, 0, SYMTYPE);
+ else
+ symlink_error (current_link_name, CURRENT_FILE_NAME);
+ }
+ else
+ {
+ /* This symbolic link is potentially dangerous. Don't
+ create it now; instead, create a placeholder file, which
+ will be replaced after other extraction is done. */
+ struct stat st;
+
+ while (fd = open (CURRENT_FILE_NAME, O_WRONLY | O_CREAT | O_EXCL, 0),
+ fd < 0)
+ if (! maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ status = -1;
+ if (fd < 0)
+ open_error (CURRENT_FILE_NAME);
+ else if (fstat (fd, &st) != 0)
+ {
+ stat_error (CURRENT_FILE_NAME);
+ close (fd);
+ }
+ else if (close (fd) != 0)
+ close_error (CURRENT_FILE_NAME);
+ else
+ {
+ size_t filelen = strlen (CURRENT_FILE_NAME);
+ size_t linklen = strlen (current_link_name);
+ struct delayed_symlink *p =
+ xmalloc (sizeof *p + filelen + linklen + 1);
+ p->next = delayed_symlink_head;
+ delayed_symlink_head = p;
+ p->dev = st.st_dev;
+ p->ino = st.st_ino;
+ p->mtime = st.st_mtime;
+ p->uid = current_stat.st_uid;
+ p->gid = current_stat.st_gid;
+ memcpy (p->names, CURRENT_FILE_NAME, filelen + 1);
+ memcpy (p->names + filelen + 1, current_link_name, linklen + 1);
+ status = 0;
+ }
+ }
+
+ if (status != 0 && 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. */