X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fextract.c;h=f348b822ed6620c2dcdd3854cdd460e9dc1166eb;hb=75bf036edc1425eb66dcc9623846c7204f943ce6;hp=815f7f6b208e3e5d06b3fda0f7b1c294e4fed369;hpb=2bda83b48d8a6807632312403561b11b79048443;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index 815f7f6..f348b82 100644 --- a/src/extract.c +++ b/src/extract.c @@ -19,9 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "system.h" +#include #include #include +#include #if HAVE_UTIME_H # include @@ -113,8 +114,20 @@ extr_init (void) we_are_root = geteuid () == 0; same_permissions_option += we_are_root; same_owner_option += we_are_root; - xalloc_fail_func = extract_finish; + /* 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. */ @@ -315,7 +328,7 @@ delay_set_stat (char const *file_name, struct stat const *stat_info, } /* Update the delayed_set_stat info for an intermediate directory - created on the path to DIR. The intermediate directory turned + 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 @@ -354,8 +367,8 @@ repair_delayed_set_stat (char const *dir, static int make_directories (char *file_name) { - char *cursor0 = file_name + FILESYSTEM_PREFIX_LEN (file_name); - char *cursor; /* points into path */ + char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); + char *cursor; /* points into the file name */ int did_something = 0; /* did we do anything yet? */ int mode; int invert_permissions; @@ -372,7 +385,7 @@ make_directories (char *file_name) if (cursor == cursor0 || ISSLASH (cursor[-1])) continue; - /* Avoid mkdir where last part of path is "." or "..". */ + /* Avoid mkdir where last part of file name is "." or "..". */ if (cursor[-1] == '.' && (cursor == cursor0 + 1 || ISSLASH (cursor[-2]) @@ -380,7 +393,7 @@ make_directories (char *file_name) && (cursor == cursor0 + 2 || ISSLASH (cursor[-3]))))) continue; - *cursor = '\0'; /* truncate the path there */ + *cursor = '\0'; /* truncate the name there */ mode = MODE_RWX & ~ newdir_umask; invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ mode; status = mkdir (file_name, mode ^ invert_permissions); @@ -449,7 +462,9 @@ prepare_to_extract (char const *file_name) switch (old_files_option) { case UNLINK_FIRST_OLD_FILES: - if (!remove_any_file (file_name, recursive_unlink_option) + if (!remove_any_file (file_name, + recursive_unlink_option ? RECURSIVE_REMOVE_OPTION + : ORDINARY_REMOVE_OPTION) && errno && errno != ENOENT) { unlink_error (file_name); @@ -506,7 +521,7 @@ maybe_recoverable (char *file_name, int *interdir_made) case NO_OVERWRITE_DIR_OLD_FILES: case OVERWRITE_OLD_FILES: { - int r = remove_any_file (file_name, 0); + int r = remove_any_file (file_name, ORDINARY_REMOVE_OPTION); errno = EEXIST; return r; } @@ -618,9 +633,9 @@ extract_archive (void) print_header (¤t_stat_info, -1); file_name = safer_name_suffix (current_stat_info.file_name, false); - if (strip_path_elements) + if (strip_name_components) { - size_t prefix_len = stripped_prefix_len (file_name, strip_path_elements); + size_t prefix_len = stripped_prefix_len (file_name, strip_name_components); if (prefix_len == (size_t) -1) { skip_member (); @@ -798,8 +813,7 @@ extract_archive (void) break; if (absolute_names_option - || ! (ISSLASH (current_stat_info.link_name - [FILESYSTEM_PREFIX_LEN (current_stat_info.link_name)]) + || ! (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), @@ -912,11 +926,12 @@ extract_archive (void) /* 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 && stat (link_name, &st1) == 0) + if (ds && lstat (link_name, &st1) == 0) for (; ds; ds = ds->next) if (ds->dev == st1.st_dev && ds->ino == st1.st_ino @@ -932,17 +947,20 @@ extract_archive (void) } 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; - e = errno; - if (stat (link_name, &st1) == 0 - && stat (file_name, &st2) == 0 - && st1.st_dev == st2.st_dev - && st1.st_ino == st2.st_ino) - break; link_error (link_name, file_name); if (backup_option) @@ -1012,7 +1030,7 @@ extract_archive (void) /* Read the entry and delete files that aren't listed in the archive. */ - gnu_restore (file_name); + purge_directory (file_name); } else if (typeflag == GNUTYPE_DUMPDIR) skip_member (); @@ -1193,3 +1211,10 @@ fatal_exit (void) error (TAREXIT_FAILURE, 0, _("Error is not recoverable: exiting now")); abort (); } + +void +xalloc_die (void) +{ + error (0, 0, "%s", _("memory exhausted")); + fatal_exit (); +}