--- linux-2.6/arch/i386/kernel/entry.S-canlink 2003-11-21 20:31:01.000000000 -0800 +++ linux-2.6/arch/i386/kernel/entry.S 2003-12-20 21:33:27.000000000 -0800 @@ -882,5 +882,6 @@ .long sys_utimes .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ + .long sys_flink syscall_table_size=(.-sys_call_table) --- linux-2.6/fs/namei.c-canlink 2003-10-02 13:57:30.000000000 -0700 +++ linux-2.6/fs/namei.c 2003-12-20 21:32:50.000000000 -0800 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1847,10 +1848,11 @@ * with linux 2.0, and to avoid hard-linking to directories * and other special files. --ADM */ -asmlinkage long sys_link(const char __user * oldname, const char __user * newname) +static long link_common(struct vfsmount *old_mnt, struct dentry *old_dentry, + const char __user * newname) { struct dentry *new_dentry; - struct nameidata nd, old_nd; + struct nameidata nd; int error; char * to; @@ -1858,32 +1860,56 @@ if (IS_ERR(to)) return PTR_ERR(to); - error = __user_walk(oldname, 0, &old_nd); - if (error) - goto exit; error = path_lookup(to, LOOKUP_PARENT, &nd); if (error) - goto out; + goto exit; error = -EXDEV; - if (old_nd.mnt != nd.mnt) + if (old_mnt != nd.mnt) goto out_release; new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { - error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); + error = vfs_link(old_dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } up(&nd.dentry->d_inode->i_sem); out_release: path_release(&nd); -out: - path_release(&old_nd); exit: putname(to); return error; } +asmlinkage long sys_link(const char *oldname, const char *newname) +{ + struct nameidata old_nd; + int error; + + error = __user_walk(oldname, 0, &old_nd); + if (!error) { + error = link_common(old_nd.mnt, old_nd.dentry, newname); + path_release(&old_nd); + } + return error; +} + +asmlinkage long sys_flink(unsigned int fd, const char *newname) +{ + struct file *file; + int error = -EBADF; + + file = fget(fd); + if (file) { + error = -EPERM; + if (file->f_flags & O_CANLINK) + error = link_common(file->f_vfsmnt, file->f_dentry, + newname); + fput(file); + } + return error; +} + /* * The worst of all namespace operations - renaming directory. "Perverted" * doesn't even start to describe it. Somebody in UCB had a heck of a trip... --- linux-2.6/include/asm-i386/fcntl.h-canlink 2002-09-26 12:16:53.000000000 -0700 +++ linux-2.6/include/asm-i386/fcntl.h 2003-12-20 21:26:39.000000000 -0800 @@ -14,12 +14,13 @@ #define O_APPEND 02000 #define O_NONBLOCK 04000 #define O_NDELAY O_NONBLOCK -#define O_SYNC 010000 -#define FASYNC 020000 /* fcntl, for BSD compatibility */ -#define O_DIRECT 040000 /* direct disk access hint */ -#define O_LARGEFILE 0100000 -#define O_DIRECTORY 0200000 /* must be a directory */ -#define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ +#define O_DIRECT 040000 /* direct disk access hint */ +#define O_LARGEFILE 0100000 +#define O_DIRECTORY 0200000 /* must be a directory */ +#define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_CANLINK 01000000 /* flink can be used */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ --- linux-2.6/include/asm-i386/unistd.h-canlink 2003-10-02 13:57:30.000000000 -0700 +++ linux-2.6/include/asm-i386/unistd.h 2003-12-20 22:25:21.000000000 -0800 @@ -279,8 +279,9 @@ #define __NR_utimes 271 #define __NR_fadvise64_64 272 #define __NR_vserver 273 +#define __NR_flink 274 -#define NR_syscalls 274 +#define NR_syscalls 275 /* user-visible error numbers are in the range -1 - -124: see */