Subject: hardlink to symlink
To: None <tech-kern@netbsd.org>
From: Hubert Feyrer <feyrer@rfhs8012.fh-regensburg.de>
List: tech-kern
Date: 04/09/1999 05:54:13
Hi,

I've used hardlinks to symlinks under Solaris, and understanding
hardlinks as "just another directory entry" for whatever object
(referenced by i/vnode), was wondering why NetBSD didn't support
this.

Example:
$ ln -s /etc/passwd symlink
$ ln symlink hardlink
ln: hardlink: Cross-device link


It seems this has two causes:
1. the kernel tried to follow the symlink which caused it to abort
   if the target of the symlink was on a different filesystem.

   If the link points to a (valid) file on the same filesystem,
   traversal of the link will result in a hardlink to the target
   file, which may not be what's intended.

   These two cases can be caught by not traversing the symlink.

2. the ln(1) command failed if the symlink didn't point to a valid
   file. Again, not traversing the link here solves this. 

The patches below fix these two errors:

$ ln symlink hardlink
$ ls -lai hardlink symlink
368953 lrwxr-xr-x  2 feyrer  wheel  11 Apr  9 05:52 hardlink -> /etc/passwd
368953 lrwxr-xr-x  2 feyrer  wheel  11 Apr  9 05:52 symlink -> /etc/passwd

I'm not a kernel hacker so I would appreciate any inputs on this.
Else I'll be happy to commit this.


 - Hubert

Index: bin/ln/ln.c
===================================================================
RCS file: /cvsroot/src/bin/ln/ln.c,v
retrieving revision 1.15
diff -u -r1.15 ln.c
--- ln.c	1998/07/28 05:31:25	1.15
+++ ln.c	1999/04/09 03:42:09
@@ -137,7 +137,8 @@
 
 	if (!sflag) {
 		/* If target doesn't exist, quit now. */
-		if (stat(target, &sb)) {
+ /* 		if (stat(target, &sb)) { */ /*HF*/
+		if (lstat(target, &sb)) {
 			warn("%s", target);
 			return (1);
 		}
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.133
diff -u -r1.133 vfs_syscalls.c
--- vfs_syscalls.c	1999/03/31 19:18:45	1.133
+++ vfs_syscalls.c	1999/04/09 03:42:13
@@ -1116,7 +1116,9 @@
 	struct nameidata nd;
 	int error;
 
-	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+	
+ /*HF*//* NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); */
+	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	vp = nd.ni_vp;

-- 
Hubert Feyrer <hubert.feyrer@rz.uni-regensburg.de>