/* 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.
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. */
}
\f
-
+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;
+}
+\f
/* Extractor functions for various member types */
static int
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;