]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
(set_fd_flags): Handle file-creation flags on file
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 8 Mar 2006 18:57:39 +0000 (18:57 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 8 Mar 2006 18:57:39 +0000 (18:57 +0000)
descriptors, rather than ignoring them.

src/dd.c

index b2bdf118cf87c0c4fea2d3adf1ee33f8c2f06566..b8512fbb52f1ae1b453779acabf4770fdfd407f8 100644 (file)
--- a/src/dd.c
+++ b/src/dd.c
@@ -1325,12 +1325,44 @@ copy_with_unblock (char const *buf, size_t nread)
 static void
 set_fd_flags (int fd, int add_flags, char const *name)
 {
+  /* Ignore file creation flags that are no-ops on file descriptors.  */
+  add_flags &= ~ (O_NOCTTY | O_NOFOLLOW);
+
   if (add_flags)
     {
       int old_flags = fcntl (fd, F_GETFL);
       int new_flags = old_flags | add_flags;
-      if (old_flags < 0
-         || (new_flags != old_flags && fcntl (fd, F_SETFL, new_flags) == -1))
+      bool ok = true;
+      if (old_flags < 0)
+       ok = false;
+      else if (old_flags != new_flags)
+       {
+         if (new_flags & (O_DIRECTORY | O_NOLINKS))
+           {
+             /* NEW_FLAGS contains at least one file creation flag that
+                requires some checking of the open file descriptor.  */
+             struct stat st;
+             if (fstat (fd, &st) != 0)
+               ok = false;
+             else if ((new_flags & O_DIRECTORY) && ! S_ISDIR (st.st_mode))
+               {
+                 errno = ENOTDIR;
+                 ok = false;
+               }
+             else if ((new_flags & O_NOLINKS) && 1 < st.st_nlink)
+               {
+                 errno = EMLINK;
+                 ok = false;
+               }
+             new_flags &= ~ (O_DIRECTORY | O_NOLINKS);
+           }
+
+         if (ok && old_flags != new_flags
+             && fcntl (fd, F_SETFL, new_flags) == -1)
+           ok = false;
+       }
+
+      if (!ok)
        error (EXIT_FAILURE, errno, _("setting flags for %s"), quote (name));
     }
 }