|
@@ -602,19 +602,435 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Extract a file from the archive. */
|
|
|
+
|
|
|
void
|
|
|
-extract_archive (void)
|
|
|
+extract_dir (char *file_name, int typeflag)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ mode_t mode;
|
|
|
+ int interdir_made = 0;
|
|
|
+
|
|
|
+ if (incremental_option)
|
|
|
+ /* Read the entry and delete files that aren't listed in the archive. */
|
|
|
+ purge_directory (file_name);
|
|
|
+ else if (typeflag == GNUTYPE_DUMPDIR)
|
|
|
+ skip_member ();
|
|
|
+
|
|
|
+ mode = (current_stat_info.stat.st_mode | (we_are_root ? 0 : MODE_WXUSR)) & MODE_RWX;
|
|
|
+
|
|
|
+ status = prepare_to_extract (file_name);
|
|
|
+ if (status == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (status > 0)
|
|
|
+ while ((status = mkdir (file_name, mode)))
|
|
|
+ {
|
|
|
+ if (errno == EEXIST
|
|
|
+ && (interdir_made
|
|
|
+ || old_files_option == DEFAULT_OLD_FILES
|
|
|
+ || old_files_option == OVERWRITE_OLD_FILES))
|
|
|
+ {
|
|
|
+ struct stat st;
|
|
|
+ if (stat (file_name, &st) == 0)
|
|
|
+ {
|
|
|
+ if (interdir_made)
|
|
|
+ {
|
|
|
+ repair_delayed_set_stat (file_name, &st);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (S_ISDIR (st.st_mode))
|
|
|
+ {
|
|
|
+ mode = st.st_mode & ~ current_umask;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ errno = EEXIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (maybe_recoverable (file_name, &interdir_made))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (errno != EEXIST)
|
|
|
+ {
|
|
|
+ mkdir_error (file_name);
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ 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));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int
|
|
|
+open_output_file (char *file_name, int typeflag)
|
|
|
{
|
|
|
- union block *data_block;
|
|
|
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 void
|
|
|
+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 openflag;
|
|
|
- mode_t mode;
|
|
|
- off_t size;
|
|
|
int interdir_made = 0;
|
|
|
+
|
|
|
+ /* FIXME: deal with protection issues. */
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if (to_stdout_option)
|
|
|
+ fd = STDOUT_FILENO;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (! prepare_to_extract (file_name))
|
|
|
+ {
|
|
|
+ skip_member ();
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fd = open_output_file (file_name, typeflag);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while (fd < 0 && maybe_recoverable (file_name, &interdir_made));
|
|
|
+
|
|
|
+ if (fd < 0)
|
|
|
+ {
|
|
|
+ open_error (file_name);
|
|
|
+ skip_member ();
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ 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;
|
|
|
+
|
|
|
+ status = close (fd);
|
|
|
+ if (status < 0)
|
|
|
+ {
|
|
|
+ close_error (file_name);
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ }
|
|
|
+
|
|
|
+ set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
|
|
+ (old_files_option == OVERWRITE_OLD_FILES
|
|
|
+ ? UNKNOWN_PERMSTATUS
|
|
|
+ : ARCHIVED_PERMSTATUS),
|
|
|
+ typeflag);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+extract_link (char *file_name)
|
|
|
+{
|
|
|
+ char const *link_name;
|
|
|
+ int interdir_made = 0;
|
|
|
+
|
|
|
+ if (!prepare_to_extract (file_name))
|
|
|
+ return;
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ struct stat st1, st2;
|
|
|
+ int e;
|
|
|
+ link_name = safer_name_suffix (current_stat_info.link_name, true);
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else if ((e == EEXIST && strcmp (link_name, file_name) == 0)
|
|
|
+ || (lstat (link_name, &st1) == 0
|
|
|
+ && lstat (file_name, &st2) == 0
|
|
|
+ && st1.st_dev == st2.st_dev
|
|
|
+ && st1.st_ino == st2.st_ino))
|
|
|
+ return;
|
|
|
+
|
|
|
+ errno = e;
|
|
|
+ }
|
|
|
+ while (maybe_recoverable (file_name, &interdir_made));
|
|
|
+
|
|
|
+ if (!(incremental_option && errno == EEXIST))
|
|
|
+ {
|
|
|
+ link_error (link_name, file_name);
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+extract_symlink (char *file_name)
|
|
|
+{
|
|
|
+#ifdef HAVE_SYMLINK
|
|
|
+ int status, fd;
|
|
|
+ int interdir_made = 0;
|
|
|
+
|
|
|
+ if (! prepare_to_extract (file_name))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (absolute_names_option
|
|
|
+ || ! (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
|
|
|
+ || contains_dot_dot (current_stat_info.link_name)))
|
|
|
+ {
|
|
|
+ while (status = symlink (current_stat_info.link_name, file_name),
|
|
|
+ status != 0)
|
|
|
+ if (!maybe_recoverable (file_name, &interdir_made))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (status == 0)
|
|
|
+ set_stat (file_name, ¤t_stat_info.stat, 0, 0, 0, SYMTYPE);
|
|
|
+ else
|
|
|
+ symlink_error (current_stat_info.link_name, 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 (file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0)
|
|
|
+ if (! maybe_recoverable (file_name, &interdir_made))
|
|
|
+ break;
|
|
|
+
|
|
|
+ status = -1;
|
|
|
+ if (fd < 0)
|
|
|
+ open_error (file_name);
|
|
|
+ else if (fstat (fd, &st) != 0)
|
|
|
+ {
|
|
|
+ stat_error (file_name);
|
|
|
+ close (fd);
|
|
|
+ }
|
|
|
+ else if (close (fd) != 0)
|
|
|
+ close_error (file_name);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ struct delayed_set_stat *h;
|
|
|
+ struct delayed_symlink *p = xmalloc (offsetof (struct delayed_symlink, target)
|
|
|
+ + strlen (current_stat_info.link_name)
|
|
|
+ + 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_info.stat.st_uid;
|
|
|
+ p->gid = current_stat_info.stat.st_gid;
|
|
|
+ p->sources = xmalloc (offsetof (struct string_list, string)
|
|
|
+ + strlen (file_name) + 1);
|
|
|
+ p->sources->next = 0;
|
|
|
+ strcpy (p->sources->string, file_name);
|
|
|
+ strcpy (p->target, current_stat_info.link_name);
|
|
|
+
|
|
|
+ h = delayed_set_stat_head;
|
|
|
+ if (h && ! h->after_symlinks
|
|
|
+ && strncmp (file_name, h->file_name, h->file_name_len) == 0
|
|
|
+ && ISSLASH (file_name[h->file_name_len])
|
|
|
+ && (base_name (file_name) == file_name + h->file_name_len + 1))
|
|
|
+ {
|
|
|
+ do
|
|
|
+ {
|
|
|
+ h->after_symlinks = 1;
|
|
|
+
|
|
|
+ if (stat (h->file_name, &st) != 0)
|
|
|
+ stat_error (h->file_name);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ h->stat_info.st_dev = st.st_dev;
|
|
|
+ h->stat_info.st_ino = st.st_ino;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while ((h = h->next) && ! h->after_symlinks);
|
|
|
+ }
|
|
|
+
|
|
|
+ status = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status != 0 && backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+
|
|
|
+#else
|
|
|
+ static int warned_once;
|
|
|
+
|
|
|
+ if (!warned_once)
|
|
|
+ {
|
|
|
+ warned_once = 1;
|
|
|
+ WARN ((0, 0, _("Attempting extraction of symbolic links as hard links")));
|
|
|
+ }
|
|
|
+ extract_link (file_name);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+#if S_IFCHR || S_IFBLK
|
|
|
+static void
|
|
|
+extract_node (char *file_name, int typeflag)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ int interdir_made = 0;
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if (! prepare_to_extract (file_name))
|
|
|
+ return;
|
|
|
+
|
|
|
+ status = mknod (file_name, current_stat_info.stat.st_mode,
|
|
|
+ current_stat_info.stat.st_rdev);
|
|
|
+ }
|
|
|
+ while (status && maybe_recoverable (file_name, &interdir_made));
|
|
|
+
|
|
|
+ if (status != 0)
|
|
|
+ {
|
|
|
+ mknod_error (file_name);
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ set_stat (file_name, ¤t_stat_info.stat, 0, 0, ARCHIVED_PERMSTATUS, typeflag);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#if HAVE_MKFIFO || defined mkfifo
|
|
|
+static void
|
|
|
+extract_fifo (char *file_name, int typeflag)
|
|
|
+{
|
|
|
+ int status;
|
|
|
+ int interdir_made = 0;
|
|
|
+
|
|
|
+ if (! prepare_to_extract (file_name))
|
|
|
+ return;
|
|
|
+
|
|
|
+ while ((status = mkfifo (file_name, current_stat_info.stat.st_mode)))
|
|
|
+ if (!maybe_recoverable (file_name, &interdir_made))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (status == 0)
|
|
|
+ set_stat (file_name, ¤t_stat_info.stat, NULL, 0,
|
|
|
+ ARCHIVED_PERMSTATUS, typeflag);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mkfifo_error (file_name);
|
|
|
+ if (backup_option)
|
|
|
+ undo_last_backup ();
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/* Extract a file from the archive. */
|
|
|
+void
|
|
|
+extract_archive (void)
|
|
|
+{
|
|
|
char typeflag;
|
|
|
char *file_name;
|
|
|
|
|
@@ -666,9 +1082,7 @@ extract_archive (void)
|
|
|
|
|
|
switch (typeflag)
|
|
|
{
|
|
|
- case GNUTYPE_SPARSE:
|
|
|
- /* Fall through. */
|
|
|
-
|
|
|
+ case GNUTYPE_SPARSE: /* FIXME: Shouldn't we call extract_file at once? */
|
|
|
case AREGTYPE:
|
|
|
case REGTYPE:
|
|
|
case CONTTYPE:
|
|
@@ -677,422 +1091,42 @@ extract_archive (void)
|
|
|
suffix means a directory. */
|
|
|
|
|
|
if (current_stat_info.had_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_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
|
|
-
|
|
|
- if (to_stdout_option)
|
|
|
- {
|
|
|
- fd = STDOUT_FILENO;
|
|
|
- goto extract_file;
|
|
|
- }
|
|
|
-
|
|
|
- if (! prepare_to_extract (file_name))
|
|
|
- {
|
|
|
- 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_info.stat.st_size);
|
|
|
+ extract_dir (file_name, typeflag);
|
|
|
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 (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);
|
|
|
- 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 ();
|
|
|
- }
|
|
|
-
|
|
|
- set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
|
|
- (old_files_option == OVERWRITE_OLD_FILES
|
|
|
- ? UNKNOWN_PERMSTATUS
|
|
|
- : ARCHIVED_PERMSTATUS),
|
|
|
- typeflag);
|
|
|
+ extract_file (file_name, typeflag);
|
|
|
break;
|
|
|
|
|
|
case SYMTYPE:
|
|
|
-#ifdef HAVE_SYMLINK
|
|
|
- if (! prepare_to_extract (file_name))
|
|
|
- break;
|
|
|
-
|
|
|
- if (absolute_names_option
|
|
|
- || ! (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
|
|
|
- || contains_dot_dot (current_stat_info.link_name)))
|
|
|
- {
|
|
|
- while (status = symlink (current_stat_info.link_name, file_name),
|
|
|
- status != 0)
|
|
|
- if (!maybe_recoverable (file_name, &interdir_made))
|
|
|
- break;
|
|
|
-
|
|
|
- if (status == 0)
|
|
|
- set_stat (file_name, ¤t_stat_info.stat, 0, 0, 0, SYMTYPE);
|
|
|
- else
|
|
|
- symlink_error (current_stat_info.link_name, 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 (file_name, O_WRONLY | O_CREAT | O_EXCL, 0),
|
|
|
- fd < 0)
|
|
|
- if (! maybe_recoverable (file_name, &interdir_made))
|
|
|
- break;
|
|
|
-
|
|
|
- status = -1;
|
|
|
- if (fd < 0)
|
|
|
- open_error (file_name);
|
|
|
- else if (fstat (fd, &st) != 0)
|
|
|
- {
|
|
|
- stat_error (file_name);
|
|
|
- close (fd);
|
|
|
- }
|
|
|
- else if (close (fd) != 0)
|
|
|
- close_error (file_name);
|
|
|
- else
|
|
|
- {
|
|
|
- struct delayed_set_stat *h;
|
|
|
- struct delayed_symlink *p =
|
|
|
- xmalloc (offsetof (struct delayed_symlink, target)
|
|
|
- + strlen (current_stat_info.link_name) + 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_info.stat.st_uid;
|
|
|
- p->gid = current_stat_info.stat.st_gid;
|
|
|
- p->sources = xmalloc (offsetof (struct string_list, string)
|
|
|
- + strlen (file_name) + 1);
|
|
|
- p->sources->next = 0;
|
|
|
- strcpy (p->sources->string, file_name);
|
|
|
- strcpy (p->target, current_stat_info.link_name);
|
|
|
-
|
|
|
- h = delayed_set_stat_head;
|
|
|
- if (h && ! h->after_symlinks
|
|
|
- && strncmp (file_name, h->file_name, h->file_name_len) == 0
|
|
|
- && ISSLASH (file_name[h->file_name_len])
|
|
|
- && (base_name (file_name)
|
|
|
- == file_name + h->file_name_len + 1))
|
|
|
- {
|
|
|
- do
|
|
|
- {
|
|
|
- h->after_symlinks = 1;
|
|
|
-
|
|
|
- if (stat (h->file_name, &st) != 0)
|
|
|
- stat_error (h->file_name);
|
|
|
- else
|
|
|
- {
|
|
|
- h->stat_info.st_dev = st.st_dev;
|
|
|
- h->stat_info.st_ino = st.st_ino;
|
|
|
- }
|
|
|
- }
|
|
|
- while ((h = h->next) && ! h->after_symlinks);
|
|
|
- }
|
|
|
-
|
|
|
- status = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (status != 0 && backup_option)
|
|
|
- undo_last_backup ();
|
|
|
+ extract_symlink (file_name);
|
|
|
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. */
|
|
|
-#endif
|
|
|
-
|
|
|
+
|
|
|
case LNKTYPE:
|
|
|
- if (! prepare_to_extract (file_name))
|
|
|
- break;
|
|
|
-
|
|
|
- again_link:
|
|
|
- {
|
|
|
- char const *link_name = safer_name_suffix (current_stat_info.link_name,
|
|
|
- true);
|
|
|
- struct stat st1, st2;
|
|
|
- int e;
|
|
|
-
|
|
|
- /* MSDOS does not implement links. However, djgpp's link() actually
|
|
|
- copies the file. */
|
|
|
- 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;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if ((e == EEXIST && strcmp (link_name, file_name) == 0)
|
|
|
- || (lstat (link_name, &st1) == 0
|
|
|
- && lstat (file_name, &st2) == 0
|
|
|
- && st1.st_dev == st2.st_dev
|
|
|
- && st1.st_ino == st2.st_ino))
|
|
|
- break;
|
|
|
-
|
|
|
- errno = e;
|
|
|
- if (maybe_recoverable (file_name, &interdir_made))
|
|
|
- goto again_link;
|
|
|
-
|
|
|
- if (incremental_option && errno == EEXIST)
|
|
|
- break;
|
|
|
-
|
|
|
- link_error (link_name, file_name);
|
|
|
- if (backup_option)
|
|
|
- undo_last_backup ();
|
|
|
- }
|
|
|
+ extract_link (file_name);
|
|
|
break;
|
|
|
|
|
|
#if S_IFCHR
|
|
|
case CHRTYPE:
|
|
|
current_stat_info.stat.st_mode |= S_IFCHR;
|
|
|
- goto make_node;
|
|
|
+ extract_node (file_name, typeflag);
|
|
|
+ break;
|
|
|
#endif
|
|
|
|
|
|
#if S_IFBLK
|
|
|
case BLKTYPE:
|
|
|
current_stat_info.stat.st_mode |= S_IFBLK;
|
|
|
-#endif
|
|
|
-
|
|
|
-#if S_IFCHR || S_IFBLK
|
|
|
- make_node:
|
|
|
- if (! prepare_to_extract (file_name))
|
|
|
- break;
|
|
|
-
|
|
|
- status = mknod (file_name, current_stat_info.stat.st_mode,
|
|
|
- current_stat_info.stat.st_rdev);
|
|
|
- if (status != 0)
|
|
|
- {
|
|
|
- if (maybe_recoverable (file_name, &interdir_made))
|
|
|
- goto make_node;
|
|
|
- mknod_error (file_name);
|
|
|
- if (backup_option)
|
|
|
- undo_last_backup ();
|
|
|
- break;
|
|
|
- };
|
|
|
- set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
|
|
- ARCHIVED_PERMSTATUS, typeflag);
|
|
|
+ extract_node (file_name, typeflag);
|
|
|
break;
|
|
|
#endif
|
|
|
|
|
|
#if HAVE_MKFIFO || defined mkfifo
|
|
|
case FIFOTYPE:
|
|
|
- if (! prepare_to_extract (file_name))
|
|
|
- break;
|
|
|
-
|
|
|
- while (status = mkfifo (file_name, current_stat_info.stat.st_mode),
|
|
|
- status != 0)
|
|
|
- if (!maybe_recoverable (file_name, &interdir_made))
|
|
|
- break;
|
|
|
-
|
|
|
- if (status == 0)
|
|
|
- set_stat (file_name, ¤t_stat_info.stat, NULL, 0,
|
|
|
- ARCHIVED_PERMSTATUS, typeflag);
|
|
|
- else
|
|
|
- {
|
|
|
- mkfifo_error (file_name);
|
|
|
- if (backup_option)
|
|
|
- undo_last_backup ();
|
|
|
- }
|
|
|
+ extract_fifo (file_name, typeflag);
|
|
|
break;
|
|
|
#endif
|
|
|
|
|
|
case DIRTYPE:
|
|
|
case GNUTYPE_DUMPDIR:
|
|
|
- really_dir:
|
|
|
- if (incremental_option)
|
|
|
- {
|
|
|
- /* Read the entry and delete files that aren't listed in the
|
|
|
- archive. */
|
|
|
-
|
|
|
- purge_directory (file_name);
|
|
|
- }
|
|
|
- else if (typeflag == GNUTYPE_DUMPDIR)
|
|
|
- skip_member ();
|
|
|
-
|
|
|
- mode = ((current_stat_info.stat.st_mode
|
|
|
- | (we_are_root ? 0 : MODE_WXUSR))
|
|
|
- & MODE_RWX);
|
|
|
-
|
|
|
- status = prepare_to_extract (file_name);
|
|
|
- if (status == 0)
|
|
|
- break;
|
|
|
- if (status < 0)
|
|
|
- goto directory_exists;
|
|
|
-
|
|
|
- again_dir:
|
|
|
- status = mkdir (file_name, mode);
|
|
|
-
|
|
|
- if (status != 0)
|
|
|
- {
|
|
|
- if (errno == EEXIST
|
|
|
- && (interdir_made
|
|
|
- || old_files_option == DEFAULT_OLD_FILES
|
|
|
- || old_files_option == OVERWRITE_OLD_FILES))
|
|
|
- {
|
|
|
- struct stat st;
|
|
|
- if (stat (file_name, &st) == 0)
|
|
|
- {
|
|
|
- if (interdir_made)
|
|
|
- {
|
|
|
- repair_delayed_set_stat (file_name, &st);
|
|
|
- break;
|
|
|
- }
|
|
|
- if (S_ISDIR (st.st_mode))
|
|
|
- {
|
|
|
- mode = st.st_mode & ~ current_umask;
|
|
|
- goto directory_exists;
|
|
|
- }
|
|
|
- }
|
|
|
- errno = EEXIST;
|
|
|
- }
|
|
|
-
|
|
|
- if (maybe_recoverable (file_name, &interdir_made))
|
|
|
- goto again_dir;
|
|
|
-
|
|
|
- if (errno != EEXIST)
|
|
|
- {
|
|
|
- mkdir_error (file_name);
|
|
|
- if (backup_option)
|
|
|
- undo_last_backup ();
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- directory_exists:
|
|
|
- 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));
|
|
|
+ extract_dir (file_name, typeflag);
|
|
|
break;
|
|
|
|
|
|
case GNUTYPE_VOLHDR:
|
|
@@ -1115,7 +1149,7 @@ extract_archive (void)
|
|
|
|
|
|
case GNUTYPE_LONGNAME:
|
|
|
case GNUTYPE_LONGLINK:
|
|
|
- ERROR ((0, 0, _("Visible long name error")));
|
|
|
+ ERROR ((0, 0, _("Unexpected long name header")));
|
|
|
skip_member ();
|
|
|
if (backup_option)
|
|
|
undo_last_backup ();
|
|
@@ -1125,7 +1159,7 @@ extract_archive (void)
|
|
|
WARN ((0, 0,
|
|
|
_("%s: Unknown file type '%c', extracted as normal file"),
|
|
|
quotearg_colon (file_name), typeflag));
|
|
|
- goto again_file;
|
|
|
+ extract_file (file_name, typeflag);
|
|
|
}
|
|
|
}
|
|
|
|