+ struct utimbuf utimbuf;
+
+ if (!symlink_flag)
+ {
+ /* We do the utime before the chmod because some versions of utime are
+ broken and trash the modes of the file. */
+
+ if (!touch_option)
+ {
+ /* We set the accessed time to `now', which is really the time we
+ started extracting files, unless incremental_option is used, in
+ which case .st_atime is used. */
+
+ /* FIXME: incremental_option should set ctime too, but how? */
+
+ if (incremental_option)
+ utimbuf.actime = stat_info->st_atime;
+ else
+ utimbuf.actime = now;
+
+ utimbuf.modtime = stat_info->st_mtime;
+
+ if (utime (file_name, &utimbuf) < 0)
+ ERROR ((0, errno,
+ _("%s: Could not change access and modification times"),
+ file_name));
+ }
+
+ /* Some systems allow non-root users to give files away. Once this
+ done, it is not possible anymore to change file permissions, so we
+ have to set permissions prior to possibly giving files away. */
+
+ set_mode (file_name, stat_info);
+ }
+
+ /* If we are root, set the owner and group of the extracted file, so we
+ extract as the original owner. Or else, if we are running as a user,
+ leave the owner and group as they are, so we extract as that user. */
+
+ if (we_are_root || same_owner_option)
+ {
+#if HAVE_LCHOWN
+
+ /* When lchown exists, it should be used to change the attributes of
+ the symbolic link itself. In this case, a mere chown would change
+ the attributes of the file the symbolic link is pointing to, and
+ should be avoided. */
+
+ if (symlink_flag)
+ {
+ if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+ ERROR ((0, errno, _("%s: Cannot lchown to uid %lu gid %lu"),
+ file_name,
+ (unsigned long) stat_info->st_uid,
+ (unsigned long) stat_info->st_gid));
+ }
+ else
+ {
+ if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+ ERROR ((0, errno, _("%s: Cannot chown to uid %lu gid %lu"),
+ file_name,
+ (unsigned long) stat_info->st_uid,
+ (unsigned long) stat_info->st_gid));
+ }
+
+#else /* not HAVE_LCHOWN */
+
+ if (!symlink_flag)
+
+ if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+ ERROR ((0, errno, _("%s: Cannot chown to uid %lu gid %lu"),
+ file_name,
+ (unsigned long) stat_info->st_uid,
+ (unsigned long) stat_info->st_gid));
+
+#endif/* not HAVE_LCHOWN */
+
+ if (!symlink_flag)
+
+ /* On a few systems, and in particular, those allowing to give files
+ away, changing the owner or group destroys the suid or sgid bits.
+ So let's attempt setting these bits once more. */
+
+ if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))
+ set_mode (file_name, stat_info);
+ }
+}
+
+/*-----------------------------------------------------------------------.
+| After a file/link/symlink/directory creation has failed, see if it's |
+| because some required directory was not present, and if so, create all |
+| required directories. Return non-zero if a directory was created. |
+`-----------------------------------------------------------------------*/
+
+static int
+make_directories (char *file_name)
+{
+ char *cursor; /* points into path */
+ int did_something = 0; /* did we do anything yet? */
+ int saved_errno = errno; /* remember caller's errno */
+ int status;
+
+ for (cursor = strchr (file_name, '/');
+ cursor;
+ cursor = strchr (cursor + 1, '/'))
+ {
+ /* Avoid mkdir of empty string, if leading or double '/'. */
+
+ if (cursor == file_name || cursor[-1] == '/')
+ continue;
+
+ /* Avoid mkdir where last part of path is '.'. */
+
+ if (cursor[-1] == '.' && (cursor == file_name + 1 || cursor[-2] == '/'))
+ continue;
+
+ *cursor = '\0'; /* truncate the path there */
+ status = mkdir (file_name, ~newdir_umask & MODE_RWX);
+
+ if (status == 0)
+ {
+ print_for_mkdir (file_name, cursor - file_name,
+ ~newdir_umask & MODE_RWX);
+ did_something = 1;
+
+ *cursor = '/';
+ continue;
+ }
+
+ *cursor = '/';
+
+ if (errno == EEXIST
+#if MSDOS
+ /* Turbo C mkdir gives a funny errno. */
+ || errno == EACCES
+#endif
+ )
+ /* Directory already exists. */
+ continue;
+
+ /* Some other error in the mkdir. We return to the caller. */
+ break;
+ }
+
+ errno = saved_errno; /* FIXME: errno should be read-only */
+ return did_something; /* tell them to retry if we made one */
+}
+
+/*--------------------------------------------------------------------.
+| Unlink the destination, if we are supposed to do so. |
+| Return zero if extraction should not proceed. |
+`--------------------------------------------------------------------*/
+
+static int
+unlink_destination (char const *file_name)
+{
+ if (unlink_first_option
+ && !remove_any_file (file_name, recursive_unlink_option)
+ && errno != ENOENT)
+ {
+ ERROR ((0, errno, _("Cannot remove %s"), file_name));
+ return 0;
+ }
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------.
+| Attempt repairing what went wrong with the extraction. Delete an |
+| already existing file or create missing intermediate directories. |
+| Return nonzero if we somewhat increased our chances at a successful |
+| extraction. errno is properly restored on zero return. |
+`--------------------------------------------------------------------*/
+
+static int
+maybe_recoverable (char *file_name)