+ if (chown_result == 0)
+ {
+ /* Changing the owner can flip st_mode bits in some cases, so
+ ignore cur_info if it might be obsolete now. */
+ if (cur_info
+ && cur_info->st_mode & S_IXUGO
+ && cur_info->st_mode & (S_ISUID | S_ISGID))
+ cur_info = NULL;
+ }
+ else if (chown_result < 0)
+ chown_error_details (file_name,
+ st->stat.st_uid, st->stat.st_gid);
+ }
+
+ if (typeflag != SYMTYPE)
+ set_mode (file_name, &st->stat, cur_info,
+ invert_permissions, permstatus, typeflag);
+}
+
+/* Remember to restore stat attributes (owner, group, mode and times)
+ for the directory FILE_NAME, using information given in *ST,
+ once we stop extracting files into that directory.
+ If not restoring permissions, remember to invert the
+ INVERT_PERMISSIONS bits from the file's current permissions.
+ PERMSTATUS specifies the status of the file's permissions.
+
+ NOTICE: this works only if the archive has usual member order, i.e.
+ directory, then the files in that directory. Incremental archive have
+ somewhat reversed order: first go subdirectories, then all other
+ members. To help cope with this case the variable
+ delay_directory_restore_option is set by prepare_to_extract.
+
+ If an archive was explicitely created so that its member order is
+ reversed, some directory timestamps can be restored incorrectly,
+ e.g.:
+ tar --no-recursion -cf archive dir dir/file1 foo dir/file2
+*/
+static void
+delay_set_stat (char const *file_name, struct tar_stat_info const *st,
+ mode_t invert_permissions, enum permstatus permstatus)
+{
+ size_t file_name_len = strlen (file_name);
+ struct delayed_set_stat *data =
+ xmalloc (offsetof (struct delayed_set_stat, file_name)
+ + file_name_len + 1);
+ data->next = delayed_set_stat_head;
+ data->dev = st->stat.st_dev;
+ data->ino = st->stat.st_ino;
+ data->mode = st->stat.st_mode;
+ data->uid = st->stat.st_uid;
+ data->gid = st->stat.st_gid;
+ data->atime = st->atime;
+ data->mtime = st->mtime;
+ data->file_name_len = file_name_len;
+ data->invert_permissions = invert_permissions;
+ data->permstatus = permstatus;
+ data->after_links = 0;
+ strcpy (data->file_name, file_name);
+ delayed_set_stat_head = data;
+}
+
+/* Update the delayed_set_stat info for an intermediate directory
+ created within the file name of DIR. The intermediate directory turned
+ out to be the same as this directory, e.g. due to ".." or symbolic
+ links. *DIR_STAT_INFO is the status of the directory. */
+static void
+repair_delayed_set_stat (char const *dir,
+ struct stat const *dir_stat_info)
+{
+ struct delayed_set_stat *data;
+ for (data = delayed_set_stat_head; data; data = data->next)
+ {
+ struct stat st;
+ if (stat (data->file_name, &st) != 0)