]> Dogcows Code - chaz/tar/blobdiff - src/extract.c
tar: remove unused function dir_removed_diag
[chaz/tar] / src / extract.c
index 98236acad29b03260f9df7466edc25dc1d8cc13f..c52c9ce8f13ccd24e0dc45e3da45a7633245db8b 100644 (file)
@@ -609,6 +609,9 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
   switch (e)
     {
     case ELOOP:
+      /* With open ("symlink", O_NOFOLLOW|...), POSIX says errno == ELOOP,
+        but FreeBSD through at least 8.1 uses errno == EMLINK.  */
+    case EMLINK:
       if (! regular
          || old_files_option != OVERWRITE_OLD_FILES || dereference_option)
        break;
@@ -864,6 +867,20 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
        }
     }
 
+  /* If O_NOFOLLOW is needed but does not work, check for a symlink
+     separately.  There's a race condition, but that cannot be avoided
+     on hosts lacking O_NOFOLLOW.  */
+  if (! O_NOFOLLOW && overwriting_old_files && ! dereference_option)
+    {
+      struct stat st;
+      if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0
+         && S_ISLNK (st.st_mode))
+       {
+         errno = ELOOP;
+         return -1;
+       }
+    }
+
   fd = openat (chdir_fd, file_name, openflag, mode);
   if (0 <= fd)
     {
@@ -1191,7 +1208,7 @@ static int
 extract_node (char *file_name, int typeflag)
 {
   bool interdir_made = false;
-  mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
+  mode_t mode = (current_stat_info.stat.st_mode & (MODE_RWX | S_IFBLK | S_IFCHR)
                 & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
 
   while (mknodat (chdir_fd, file_name, mode, current_stat_info.stat.st_rdev)
This page took 0.023921 seconds and 4 git commands to generate.