Topic: cp mv ln

When I install a kernel in openbsd, make install does:

ln /bsd /obsd
cp bsd /nbsd
mv /nbsd /bsd

Would it have the same result to have done:

ln /bsd /obsd
cp bsd /bsd

?

Re: cp mv ln

No, the second variant would overwrite /obsd. Create some dummy text files and try it with those.

Re: cp mv ln

That's interesting. I assumed cp creates new data on disk and then gives it a name in the directory (links it's name to the data on disk), replacing the one that exists. The word "file" in the man pages confuses me, because I'm not sure if it refers to the name or the data.

I see the man page says that cp replaces the content of the target file if it exists already, which matches what you said.

I had thought that -f meant "force an overwrite" (meaning unlinking the file name and then relinking it to the new data on disk), as opposed to refusing to copy if the target exists already. In GNU cp, -f has the same meaning as --force. I've wondered what is making it that cp overwrites files even when I'm not using -f, but never looked into it. I didn't understand how cp works.

The POSIX description of cp says -f should unlink the file if it exists and then proceed. That seems to match the man page on linux and openbsd.

However, the -f option in GNU cp seems to work differently than in bsd cp. On linux:

echo a > a
echo b > b
ln a c
cp -f b a
cat c

prints 'b'. An openbsd it prints 'a'.

So, maybe GNU cp doesn't treat -f correctly.

Re: cp mv ln

It appears the -f parameter really does lead to some subtle differences. Weird.

On Linux:

$ echo a > a; echo b > b; chmod 000 a; ln a c; cp -f b a; chmod 666 c; cat c
a
$ rm a b c
$ echo a > a; echo b > b; chmod 666 a; ln a c; cp -f b a; chmod 666 c; cat c
b

On FreeBSD:

$ echo a > a; echo b > b; chmod 000 a; ln a c; cp -f b a; chmod 666 c; cat c
a
$ rm a b c
$ echo a > a; echo b > b; chmod 666 a; ln a c; cp -f b a; chmod 666 c; cat c
a

I guess what this means is: don't use cp -f in scripts that need to be portable.

Re: cp mv ln

Btw, it turns out that Linux is more POSIXly correct here. The wording in the POSIX standard is:

IEEE Std 1003.1, 2004 Edition, Base Definitions & Shell Utilities, cp wrote:

If the attempt to obtain a file descriptor fails and the -f option is in effect, cp shall attempt to remove the file by performing actions equivalent to the unlink() function defined in the System Interfaces volume of IEEE Std 1003.1-2001 called using dest_file as the path argument. If this attempt succeeds, cp shall continue with step 3b.

Re: cp mv ln

I don't understand what you mean. If a is unlinked, c should still be linked. So, shouldn't it be correct that cp -f b a would not change the content of c?

Re: cp mv ln

Yes, you're absolutely right. The difference is that Linux (and POSIX) say that cp -f should only unlink a if it can't be opened for writing. If it can be opened for writing, the contents of a (and thus the contents of c, which is linked to the same file) are overwritten.

Re: cp mv ln

Ah, okay. I wonder what the rationale is for the POSIX interpretation of -f. In mv, -f just means overwrite without asking, as opposed to -i. The different meaning of cp -f based on the file permissions seems non-obvious and strange to me.

I mean, I think it is strange that it doesn't work the way I assumed it did: If the target file exists and the copy is to be done (based on -f and -i), then unlink the target and proceed.

Last edited by queshaw (2008-05-06 21:52:12)