X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fextract.c;h=2cc1f7b383a121fb5a6d864e96bf54f8af4a9d95;hp=327b67f0e136e3ba9bbe70c90f3149d13b31139a;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=cd7bdd4076ca154575bbef85eb2157e59befcfe2 diff --git a/src/extract.c b/src/extract.c index 327b67f..2cc1f7b 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1,7 +1,7 @@ /* Extract files from a tar archive. - Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2013 - Free Software Foundation, Inc. + Copyright 1988, 1992-1994, 1996-2001, 2003-2007, 2010, 2012-2014 Free + Software Foundation, Inc. This file is part of GNU tar. @@ -191,6 +191,19 @@ extr_init (void) umask (newdir_umask); /* restore the kernel umask */ current_umask = newdir_umask; } + + /* If the user wants to guarantee that everything is under one directory, + determine its name now and let it be created later. */ + if (one_top_level_option && !one_top_level_dir) + { + char *base = base_name (archive_name_array[0]); + + one_top_level_dir = strip_compression_suffix (base); + free (base); + + if (!one_top_level_dir) + USAGE_ERROR ((0, 0, _("Cannot deduce top-level directory name; please set it explicitly with --one-top-level=DIR"))); + } } /* Use fchmod if possible, fchmodat otherwise. */ @@ -297,7 +310,7 @@ set_mode (char const *file_name, static void check_time (char const *file_name, struct timespec t) { - if (t.tv_sec <= 0) + if (t.tv_sec < 0) WARNOPT (WARN_TIMESTAMP, (0, 0, _("%s: implausibly old time stamp %s"), file_name, tartime (t, true))); @@ -855,7 +868,21 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) } - +static bool +is_directory_link (const char *file_name) +{ + struct stat st; + int e = errno; + int res; + + res = (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 && + S_ISLNK (st.st_mode) && + fstatat (chdir_fd, file_name, &st, 0) == 0 && + S_ISDIR (st.st_mode)); + errno = e; + return res; +} + /* Extractor functions for various member types */ static int @@ -911,10 +938,15 @@ extract_dir (char *file_name, int typeflag) if (errno == EEXIST && (interdir_made + || keep_directory_symlink_option || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES)) { struct stat st; + + if (keep_directory_symlink_option && is_directory_link (file_name)) + return 0; + if (deref_stat (file_name, &st) == 0) { current_mode = st.st_mode; @@ -1341,7 +1373,7 @@ extract_symlink (char *file_name, int typeflag) if (!warned_once) { warned_once = 1; - WARNOPT (WARN_SYMBOLIC_CAST, + WARNOPT (WARN_SYMLINK_CAST, (0, 0, _("Attempting extraction of symbolic links as hard links"))); } @@ -1421,6 +1453,13 @@ extract_failure (char *file_name, int typeflag) return 1; } +static int +extract_skip (char *file_name, int typeflag) +{ + skip_member (); + return 0; +} + typedef int (*tar_extractor_t) (char *file_name, int typeflag); @@ -1501,7 +1540,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) ERROR ((0, 0, _("%s: Cannot extract -- file is continued from another volume"), quotearg_colon (current_stat_info.file_name))); - *fun = extract_failure; + *fun = extract_skip; break; case GNUTYPE_LONGNAME: