-
- /* FALL THRU */
- case LF_OLDNORMAL:
- case LF_NORMAL:
- case LF_CONTIG:
- /*
- * Appears to be a file.
- * See if it's really a directory.
- */
- namelen = strlen(skipcrud+head->header.name)-1;
- if (head->header.name[skipcrud+namelen] == '/')
- goto really_dir;
-
- /* FIXME, deal with protection issues */
- again_file:
- openflag = (f_keep?
- O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
- O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
- | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
- /*
- * JK - The last | is a kludge to solve the problem
- * the O_APPEND flag causes with files we are
- * trying to make sparse: when a file is opened
- * with O_APPEND, it writes to the last place
- * that something was written, thereby ignoring
- * any lseeks that we have done. We add this
- * extra condition to make it able to lseek when
- * a file is sparse, i.e., we don't open the new
- * file with this flag. (Grump -- this bug caused
- * me to waste a good deal of time, I might add)
- */
-
- if(f_exstdout) {
- fd = 1;
- goto extract_file;
+ }
+ errno = EEXIST;
+ }
+
+ if (maybe_recoverable (file_name, &interdir_made))
+ continue;
+
+ if (errno != EEXIST)
+ {
+ mkdir_error (file_name);
+ return 1;
+ }
+ break;
+ }
+
+ if (status == 0
+ || old_files_option == DEFAULT_OLD_FILES
+ || old_files_option == OVERWRITE_OLD_FILES)
+ delay_set_stat (file_name, ¤t_stat_info.stat,
+ MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
+ (status == 0
+ ? ARCHIVED_PERMSTATUS
+ : UNKNOWN_PERMSTATUS));
+
+ return status;
+}
+
+
+static int
+open_output_file (char *file_name, int typeflag)
+{
+ int fd;
+ int openflag = (O_WRONLY | O_BINARY | O_CREAT
+ | (old_files_option == OVERWRITE_OLD_FILES
+ ? O_TRUNC
+ : O_EXCL));
+ mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
+
+#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_info.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 */
+
+ return fd;
+}
+
+static int
+extract_file (char *file_name, int typeflag)
+{
+ int fd;
+ off_t size;
+ union block *data_block;
+ int status;
+ size_t count;
+ size_t written;
+ int interdir_made = 0;
+
+ /* FIXME: deal with protection issues. */
+
+ if (to_stdout_option)
+ fd = STDOUT_FILENO;
+ else
+ {
+ do
+ fd = open_output_file (file_name, typeflag);
+ while (fd < 0 && maybe_recoverable (file_name, &interdir_made));
+
+ if (fd < 0)
+ {
+ open_error (file_name);
+ return 1;
+ }
+ }
+
+ if (current_stat_info.is_sparse)
+ sparse_extract_file (fd, ¤t_stat_info, &size);
+ else
+ for (size = current_stat_info.stat.st_size; size > 0; )
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_stat_info.file_name);
+ save_totsize = current_stat_info.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); /* FIXME: shouldn't we
+ restore from backup? */
+ 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)
+ return 0;
+
+ status = close (fd);
+ if (status < 0)
+ close_error (file_name);
+
+ set_stat (file_name, ¤t_stat_info.stat, 0, 0,
+ (old_files_option == OVERWRITE_OLD_FILES ?
+ UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS),
+ typeflag);
+
+ return status;
+}
+
+static int
+extract_link (char *file_name, int typeflag)
+{
+ char const *link_name = safer_name_suffix (current_stat_info.link_name, true);
+ int interdir_made = 0;
+
+ do
+ {
+ struct stat st1, st2;
+ int e;
+ int status = link (link_name, file_name);
+ e = errno;
+
+ if (status == 0)
+ {
+ struct delayed_symlink *ds = delayed_symlink_head;
+ if (ds && lstat (link_name, &st1) == 0)
+ for (; ds; ds = ds->next)
+ if (ds->dev == st1.st_dev
+ && ds->ino == st1.st_ino
+ && ds->mtime == st1.st_mtime)
+ {
+ struct string_list *p = xmalloc (offsetof (struct string_list, string)
+ + strlen (file_name) + 1);
+ strcpy (p->string, file_name);
+ p->next = ds->sources;
+ ds->sources = p;
+ break;