- switch (head->header.linkflag) {
-
- default:
- msg("Unknown file type '%c' for %s, extracted as normal file",
- head->header.linkflag, skipcrud+head->header.name);
- /* FALL THRU */
-
- /*
- * JK - What we want to do if the file is sparse is loop through
- * the array of sparse structures in the header and read in
- * and translate the character strings representing 1) the offset
- * at which to write and 2) how many bytes to write into numbers,
- * which we store into the scratch array, "sparsearray". This
- * array makes our life easier the same way it did in creating
- * the tar file that had to deal with a sparse file.
- *
- * After we read in the first five (at most) sparse structures,
- * we check to see if the file has an extended header, i.e.,
- * if more sparse structures are needed to describe the contents
- * of the new file. If so, we read in the extended headers
- * and continue to store their contents into the sparsearray.
- */
- case LF_SPARSE:
- sp_array_size = 10;
- sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
- for (i = 0; i < SPARSE_IN_HDR; i++) {
- sparsearray[i].offset =
- from_oct(1+12, head->header.sp[i].offset);
- sparsearray[i].numbytes =
- from_oct(1+12, head->header.sp[i].numbytes);
- if (!sparsearray[i].numbytes)
- break;
- }
-
-/* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
-
- if (head->header.isextended) {
- /* read in the list of extended headers
- and translate them into the sparsearray
- as before */
-
- /* static */ int ind = SPARSE_IN_HDR;
-
- for (;;) {
-
- exhdr = findrec();
- for (i = 0; i < SPARSE_EXT_HDR; i++) {
-
- if (i+ind > sp_array_size-1) {
- /*
- * realloc the scratch area
- * since we've run out of room --
- */
- sparsearray = (struct sp_array *)
- realloc(sparsearray,
- 2 * sp_array_size * (sizeof(struct sp_array)));
- sp_array_size *= 2;
- }
- if (!exhdr->ext_hdr.sp[i].numbytes)
- break;
- sparsearray[i+ind].offset =
- from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
- sparsearray[i+ind].numbytes =
- from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
- }
- if (!exhdr->ext_hdr.isextended)
- break;
- else {
- ind += SPARSE_EXT_HDR;
- userec(exhdr);
- }
- }
- userec(exhdr);
- }
-
- /* 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;
+ default:
+ /* Just say we can't do anything about it... */
+
+ return 0;
+ }
+}
+
+/* Fix the statuses of all directories whose statuses need fixing, and
+ which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is
+ nonzero, do this for all such directories; otherwise, stop at the
+ first directory that is marked to be fixed up only after delayed
+ symlinks are applied. */
+static void
+apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
+{
+ size_t file_name_len = strlen (file_name);
+ bool check_for_renamed_directories = 0;
+
+ while (delayed_set_stat_head)
+ {
+ struct delayed_set_stat *data = delayed_set_stat_head;
+ bool skip_this_one = 0;
+ struct stat st;
+ struct stat const *cur_info = 0;
+
+ check_for_renamed_directories |= data->after_symlinks;
+
+ if (after_symlinks < data->after_symlinks
+ || (data->file_name_len < file_name_len
+ && file_name[data->file_name_len]
+ && (ISSLASH (file_name[data->file_name_len])
+ || ISSLASH (file_name[data->file_name_len - 1]))
+ && memcmp (file_name, data->file_name, data->file_name_len) == 0))
+ break;
+
+ if (check_for_renamed_directories)
+ {
+ cur_info = &st;
+ if (stat (data->file_name, &st) != 0)
+ {
+ stat_error (data->file_name);
+ skip_this_one = 1;
+ }
+ else if (! (st.st_dev == data->stat_info.st_dev
+ && (st.st_ino == data->stat_info.st_ino)))
+ {
+ ERROR ((0, 0,
+ _("%s: Directory renamed before its status could be extracted"),
+ quotearg_colon (data->file_name)));
+ skip_this_one = 1;
+ }
+ }
+
+ if (! skip_this_one)
+ set_stat (data->file_name, &data->stat_info, cur_info,
+ data->invert_permissions, data->permstatus, DIRTYPE);
+
+ delayed_set_stat_head = data->next;
+ free (data);
+ }
+}
+
+\f
+
+/* Extractor functions for various member types */
+
+static int
+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;
+
+ 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 0;