Sat 24 Apr 2010 10:50:52 AM UTC, original submission:
While looking at the coreutils test suite failures, I found that the new ln fails miserably for hard links:
pochu@strauss:~$ touch a && /home/pochu/coreutils-8.4/src/ln a b
/home/pochu/coreutils-8.4/src/ln: creating hard link `b' => `a': Computer bought the farm
Samuel helped me to debug the problem and found this:
00:09 < youpi> one difference is that the newer ln uses linkat
00:20 < youpi> seems like the AT_SYMLINK_FOLLOW is the culprit, making __file_name_lookup_at return -1 with errno == EINVAL
00:20 < youpi> while __file_name_lookup is supposed to return a port, not -1
00:20 < youpi> resulting to a bogus error handling
00:24 < youpi> it seems to me like the logic in the hurd port is inverted: susv says that by default linkat shouldn't dereference symlinks, i.e. the flags passed by linkat should be O_NOLINK, but if.
AT_SYMLINK_FOLLOW is given, it should be cleared in __file_name_lookup_at()
00:24 < youpi> pochu: could you try this out?
00:25 < youpi> and of course, btw, the EINVAL case should be fixed
00:26 < youpi> (using _hurd_fail is really completely bogus here)
00:27 < youpi> (just setting errno to EINVAL and returning MACH_PORT_NULL should be fine)
00:35 < pochu> youpi: so, __file_name_lookup_at() is returning -1 (bug), which is then passed to __file_getlinknode(), which sets errno to EMACH_SEND_INVALID_DEST, and __hurd_fail() change it to EIEIO?
00:35 < youpi> probably yes
He was right. I first tested a one liner to return MACH_PORT_NULL instead of -1 in __file_name_lookup_at(),
- return __hurd_fail (EINVAL);
+ return (__hurd_fail (EINVAL), MACH_PORT_NULL);
and with that ln failed with invalid argument:
pochu@strauss:~/coreutils-8.4/src$ LD_LIBRARY_PATH=/home/pochu/lib ./ln /tmp/a /tmp/b
./ln: creating hard link `/tmp/b' => `/tmp/a': Invalid argument
And then I tried to fix the AT_SYMLINK_FOLLOW, and the attached patch make ln work fine and the failing tests to pass.
Basically, _file_name_lookup_at() doesn't allow other AT flags than AT_SYMLINK_NOFOLLOW, and it doesn't default to not follow links, as Samuel said, see http://www.opengroup.org/onlinepubs/9699919799/functions/linkat.html:
"If the AT_SYMLINK_FOLLOW flag is clear in the flag argument and the path1 argument names a symbolic link, a new link is created for the symbolic link path1 and not its target."
|