summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2006-03-08 18:57:39 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2006-03-08 18:57:39 +0000
commitcf40950274fc2e1cd3d827710ccfd352c614b12d (patch)
treee2c85816c95b84c85bfefb7f1d93fbe6d31e8681 /src
parente190228997c9f33137977ed945d55bd37c1058d6 (diff)
downloadcoreutils-cf40950274fc2e1cd3d827710ccfd352c614b12d.tar.xz
(set_fd_flags): Handle file-creation flags on file
descriptors, rather than ignoring them.
Diffstat (limited to 'src')
-rw-r--r--src/dd.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/src/dd.c b/src/dd.c
index b2bdf118c..b8512fbb5 100644
--- 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));
}
}