X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fextract.c;h=408208392ab64a69afd7a116c4c12960117ba5f2;hb=729b91adb1607a329be9b886b425874c04f38fbd;hp=c89ebd01e74c4a1acb7abffd0b6fabc3f0e83892;hpb=5249a993776ba32c851cf6eb3734958512d55d11;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index c89ebd0..4082083 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1,7 +1,7 @@ /* Extract files from a tar archive. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000, - 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Written by John Gilmore, on 1985-11-19. @@ -30,11 +30,6 @@ static bool we_are_root; /* true if our effective uid == 0 */ static mode_t newdir_umask; /* umask when creating new directories */ static mode_t current_umask; /* current umask (which is set to 0 if -p) */ -static bool directories_first; /* Directory members precede non-directory - ones in the archive. This is detected for - incremental archives only. This variable - helps correctly restore directory - timestamps */ /* Status of the permissions of a file that we are extracting. */ enum permstatus @@ -120,19 +115,6 @@ extr_init (void) same_permissions_option += we_are_root; same_owner_option += we_are_root; - /* Save 'root device' to avoid purging mount points. - FIXME: Should the same be done after handling -C option ? */ - if (one_file_system_option) - { - struct stat st; - char *dir = xgetcwd (); - - if (deref_stat (true, dir, &st)) - stat_diag (dir); - else - root_device = st.st_dev; - } - /* Option -p clears the kernel umask, so it does not affect proper restoration of file permissions. New intermediate directories will comply with umask at start of program. */ @@ -331,13 +313,13 @@ set_stat (char const *file_name, 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 directories_first - is set by prepare_to_extract. + 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/subdir dir/subdir/file + 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, @@ -446,7 +428,7 @@ make_directories (char *file_name) invert_permissions is zero, because repair_delayed_set_stat may need to update the struct. */ delay_set_stat (file_name, - ¤t_stat_info /* ignored */, + ¤t_stat_info, invert_permissions, INTERDIR_PERMSTATUS); print_for_mkdir (file_name, cursor - file_name, mode); @@ -626,6 +608,19 @@ extract_dir (char *file_name, int typeflag) mode_t mode; int interdir_made = 0; + /* Save 'root device' to avoid purging mount points. */ + if (one_file_system_option && root_device == 0) + { + struct stat st; + char *dir = xgetcwd (); + + if (deref_stat (true, dir, &st)) + stat_diag (dir); + else + root_device = st.st_dev; + free (dir); + } + if (incremental_option) /* Read the entry and delete files that aren't listed in the archive. */ purge_directory (file_name); @@ -652,7 +647,7 @@ extract_dir (char *file_name, int typeflag) } if (S_ISDIR (st.st_mode)) { - mode = st.st_mode & ~ current_umask; + mode = st.st_mode; break; } } @@ -673,12 +668,16 @@ extract_dir (char *file_name, int typeflag) if (status == 0 || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES) - delay_set_stat (file_name, ¤t_stat_info, - MODE_RWX & (mode ^ current_stat_info.stat.st_mode), - (status == 0 - ? ARCHIVED_PERMSTATUS - : UNKNOWN_PERMSTATUS)); - + { + if (status == 0) + delay_set_stat (file_name, ¤t_stat_info, + MODE_RWX & (mode ^ current_stat_info.stat.st_mode), + ARCHIVED_PERMSTATUS); + else /* For an already existing directory, invert_perms must be 0 */ + delay_set_stat (file_name, ¤t_stat_info, + 0, + UNKNOWN_PERMSTATUS); + } return status; } @@ -764,26 +763,26 @@ extract_file (char *file_name, int typeflag) for (size = current_stat_info.stat.st_size; size > 0; ) { mv_size_left (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 -= written; - + set_next_block_after ((union block *) (data_block->buffer + written - 1)); if (count != written) @@ -798,7 +797,7 @@ extract_file (char *file_name, int typeflag) skip_file (size); mv_end (); - + /* 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. */ @@ -1107,8 +1106,8 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) case DIRTYPE: case GNUTYPE_DUMPDIR: *fun = extract_dir; - if (current_stat_info.dumpdir) - directories_first = true; + if (current_stat_info.is_dumpdir) + delay_directory_restore_option = true; break; case GNUTYPE_VOLHDR: @@ -1213,9 +1212,9 @@ extract_archive (void) /* Restore stats for all non-ancestor directories, unless it is an incremental archive. (see NOTICE in the comment to delay_set_stat above) */ - if (!directories_first) + if (!delay_directory_restore_option) apply_nonancestor_delayed_set_stat (file_name, 0); - + /* Take a safety backup of a previously existing file. */ if (backup_option)