cp reports incorrect error (resend with correction)

Denys Vlasenko vda.linux at googlemail.com
Fri Aug 24 14:07:21 UTC 2007


On Thursday 23 August 2007 19:35, Joe Ogulin wrote:
> Sorry... grabbed the wrong link in the previous message
>
> This is the correct one:
> http://bugs.busybox.net/view.php?id=1470


> Run this sequence of commands:
> 
> touch /tmp/foo
> busybox cp /tmp/foo /tmp/nonexistent/path/foo
> 
> This is the error message you get:
> cp: cannot remove '/tmp/nonexistent/path/foo': No such file or directory

Which is true. cp couldn't create it. cp decided to try unlink,
and creating again. unlink didn't work either. cp lets you know that.

> What Linux's cp will say is:
> cp: cannot create regular file `/tmp/nonexistent/path/foo': No such file or directory

Read it again.

Do you really think that "I can't create 'foo', it doesn't exist" is better?
From naive point of view it is silly too: "of course it doesn't exist
before you create it!"

I undoubtedly can fix bbox cp to match GNU message, but code will be bigger
and GNU message is still semi-stupid.

For the record: fix should be here:

static int ask_and_unlink(const char *dest, int flags)
{
        ...
        if (unlink(dest) < 0) {

===> if errno == ENOENT or ENOTDIR, explain that *path* is invalid, not filename <===

                bb_perror_msg("cannot remove '%s'", dest);
                return -1; // error
        }
        return 1; // ok (to try again)
}


> If you have DO_POSIX_CP enabled, you will get:
> '/tmp/nonexistent/path/foo' exists

Okay, that will be fixed like this:

--- libbb/copy_file.c   (revision 19673)
+++ libbb/copy_file.c   (working copy)
@@ -22,25 +22,25 @@

 #define DO_POSIX_CP 0  /* 1 - POSIX behavior, 0 - safe behavior */

-
+// errno must be set to relevant value ("why we cannot create dest?")
+// for POSIX mode to give reasonable error message
 static int ask_and_unlink(const char *dest, int flags)
 {
-       // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
-       // "'file' exists" msg, we want unlink to be done (silently unless -i
-       // is also in effect).
-       // This prevents safe way from asking more questions than POSIX does.
 #if DO_POSIX_CP
        if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
-               fprintf(stderr, "'%s' exists\n", dest);
+               // Either it exists, or the *path* doesnt exist
+               bb_perror_msg("cannot create '%s'", dest);
                return -1;
        }
 #endif
+       // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
+       // "cannot create" msg, we want unlink to be done (silently unless -i).

        // TODO: maybe we should do it only if ctty is present?
        if (flags & FILEUTILS_INTERACTIVE) {
                // We would not do POSIX insanity. -i asks,
                // then _unlinks_ the offender. Presto.
-               // (No opening without O_EXCL, no unlinks only if -f)
+               // (No "opening without O_EXCL", no "unlink only if -f")
                // Or else we will end up having 3 open()s!
                fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
                if (!bb_ask_confirmation())
@@ -280,6 +280,7 @@
        ) {
                // We are lazy here, a bit lax with races...
                if (dest_exists) {
+                       errno = EEXIST;
                        ovr = ask_and_unlink(dest, flags);
                        if (ovr <= 0)
                                return ovr;

--
vda



More information about the busybox mailing list