Phillip Susi <[EMAIL PROTECTED]> writes: > Ok, so this allows you to atomically test if the named object is both a > directory and is readable, but why bother?
You might want to bother if you want to test some filesystem code using a shell script. That's what I was doing. I wanted to make sure that O_DIRECTORY worked, even with a symbolic link to a directory. I couldn't do that with the shell and standard utilites, until I added iflag=directory. > The purpose of dd is to transfer data. No, dd has other purposes. For example, you can use dd to reposition standard input without reading it. There's an example of this in the coreutils manual. The original purpose of the shell was to provide a thin layer over operating system services. The idea was that there was a simple scriptable interface to pretty much anything you could do with a system call. This change fits within that tradition. (Obviously the tradition is not always upheld, but that's a different matter.) (One could also argue that the original purpose of 'dd' was to mimic the DD directive of OS/360 JCL <http://www.okstate.edu/cis_info/cis_manual/jcl_data.html>, and the 'directory' flag is also well within this tradition. :-) Anyway, your email caused me to look again at the 'dd' source code and test cases and NEWS, and I installed these further improvements. Thanks. 2006-03-08 Paul Eggert <[EMAIL PROTECTED]> * NEWS: Document dd's new 'directory' and 'nolinks' flags. * src/dd.c (set_fd_flags): Handle file-creation flags on file descriptors, rather than ignoring them. * tests/dd/misc: Add test cases for append, nofollow, directory, and nolinks flags. Simplify redirection to /dev/null in some cases. Index: NEWS =================================================================== RCS file: /fetish/cu/NEWS,v retrieving revision 1.361 diff -p -u -r1.361 NEWS --- NEWS 27 Feb 2006 10:47:56 -0000 1.361 +++ NEWS 8 Mar 2006 18:55:23 -0000 @@ -71,9 +71,18 @@ GNU coreutils NEWS ** New features - dd's new iflag=noatime option causes it to read a file without - updating its access time, on hosts that support this (currently only - Linux kernels, version 2.6.8 and later). + New dd iflag= and oflag= flags: + + 'directory' causes dd to fail unless the file is a directory, on + hosts that support this (e.g., Linux kernels, version 2.1.126 and + later). This has limited utility but is present for completeness. + + 'noatime' causes dd to read a file without updating its access + time, on hosts that support this (e.g., Linux kernels, version + 2.6.8 and later). + + 'nolinks' causes dd to fail if the file has multiple hard links, + on hosts that support this (e.g., Solaris 10 and later). rm now accepts the -I (--interactive=once) option. This new option prompts once if rm is invoked recursively or if more than three Index: src/dd.c =================================================================== RCS file: /fetish/cu/src/dd.c,v retrieving revision 1.191 diff -p -u -r1.191 dd.c --- src/dd.c 6 Mar 2006 07:20:19 -0000 1.191 +++ src/dd.c 8 Mar 2006 18:55:24 -0000 @@ -1325,12 +1325,44 @@ copy_with_unblock (char const *buf, size 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)); } } Index: tests/dd/misc =================================================================== RCS file: /fetish/cu/tests/dd/misc,v retrieving revision 1.5 diff -p -u -r1.5 misc --- tests/dd/misc 8 Mar 2006 18:21:54 -0000 1.5 +++ tests/dd/misc 8 Mar 2006 18:55:24 -0000 @@ -1,8 +1,10 @@ #!/bin/sh # Ensure dd treats `--' properly. -# Also ensure that iflag=noatime works. +# Also test some flag values. tmp_in=dd-in.$$ +tmp_in2=dd-in2.$$ +tmp_sym=dd-sym.$$ tmp_out=dd-out.$$ if test "$VERBOSE" = yes; then @@ -12,21 +14,36 @@ fi test_failure=0 echo data > $tmp_in || test_failure=1 +ln $tmp_in $tmp_in2 || test_failure=1 +ln -s $tmp_in $tmp_sym || test_failure=1 if test $test_failure = 1; then echo 'failure in testing framework' exit 1 fi -dd if=$tmp_in of=$tmp_out > /dev/null 2>&1 || fail=1 +dd if=$tmp_in of=$tmp_out 2> /dev/null || fail=1 cmp $tmp_in $tmp_out || fail=1 rm $tmp_out -dd -- if=$tmp_in of=$tmp_out > /dev/null 2>&1 || fail=1 +dd -- if=$tmp_in of=$tmp_out 2> /dev/null || fail=1 cmp $tmp_in $tmp_out || fail=1 +if dd oflag=append if=$tmp_in of=$tmp_out 2> /dev/null; then + cmp $tmp_in $tmp_out || fail=1 +fi + +if dd iflag=nofollow if=$tmp_in count=0 2> /dev/null; then + dd iflag=nofollow if=$tmp_sym count=0 2> /dev/null && fail=1 +fi + +if dd iflag=directory if=. count=0 2> /dev/null; then + dd iflag=directory count=0 <. 2> /dev/null || fail=1 + dd iflag=directory count=0 <$tmp_in 2> /dev/null && fail=1 +fi + old_ls=`ls -u --full-time $tmp_in` sleep 1 -if dd iflag=noatime if=$tmp_in of=$tmp_out > /dev/null 2>&1; then +if dd iflag=noatime if=$tmp_in of=$tmp_out 2> /dev/null; then new_ls=`ls -u --full-time $tmp_in` if test "x$old_ls" != "x$new_ls"; then echo "dd iflag=noatime updated atime; O_NOATIME bug in your kernel?" >&2 @@ -34,6 +51,12 @@ if dd iflag=noatime if=$tmp_in of=$tmp_o fi fi -rm -f $tmp_in $tmp_out +if dd oflag=nolinks if=$tmp_in of=$tmp_out 2> /dev/null; then + dd iflag=nolinks if=$tmp_in > /dev/null 2>&1 && fail=1 + dd iflag=nolinks < $tmp_in > /dev/null 2>&1 && fail=1 + dd oflag=nolinks < $tmp_in > $tmp_out 2>&1 || fail=1 +fi + +rm -f $tmp_in $tmp_in2 $tmp_sym $tmp_out exit $fail _______________________________________________ Bug-coreutils mailing list Bug-coreutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-coreutils