From 718e2707a8b32ca010629d0de6cd5e9b3e4233f8 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 31 Jul 2010 22:46:31 +0200
Subject: [PATCH] Add a renameat(2) system call.

Based-on: FreeBSD
---
 bin/ln/symlink.7          |    4 +-
 include/stdio.h           |    3 +-
 lib/libc/sys/Makefile.inc |    2 +-
 lib/libc/sys/rename.2     |   82 +++++++++++++++++++++++++++++++++++++++++++--
 sys/kern/init_sysent.c    |    1 +
 sys/kern/syscalls.c       |    1 +
 sys/kern/syscalls.master  |    2 +
 sys/kern/vfs_syscalls.c   |   32 +++++++++++++++++-
 sys/sys/syscall-hide.h    |    1 +
 sys/sys/syscall.h         |    3 +-
 sys/sys/syscall.mk        |    3 +-
 sys/sys/sysproto.h        |   10 +++++
 sys/sys/sysunion.h        |    1 +
 13 files changed, 134 insertions(+), 11 deletions(-)

diff --git a/bin/ln/symlink.7 b/bin/ln/symlink.7
index e2c8aeb..c4f345a 100644
--- a/bin/ln/symlink.7
+++ b/bin/ln/symlink.7
@@ -31,9 +31,8 @@
 .\"
 .\"	@(#)symlink.7	8.3 (Berkeley) 3/31/94
 .\" $FreeBSD: src/bin/ln/symlink.7,v 1.13.2.7 2003/03/03 19:04:46 trhodes Exp $
-.\" $DragonFly: src/bin/ln/symlink.7,v 1.2 2003/06/17 04:22:50 dillon Exp $
 .\"
-.Dd March 31, 1994
+.Dd July 31, 2010
 .Dt SYMLINK 7
 .Os
 .Sh NAME
@@ -446,6 +445,7 @@ whether specified on the command line or encountered in the tree walk.
 .Xr lstat 2 ,
 .Xr readlink 2 ,
 .Xr rename 2 ,
+.Xr renameat 2 ,
 .Xr symlink 2 ,
 .Xr unlink 2 ,
 .Xr fts 3 ,
diff --git a/include/stdio.h b/include/stdio.h
index 473e91a..2f241ad 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -35,7 +35,6 @@
  *
  *	@(#)stdio.h	8.5 (Berkeley) 4/29/95
  * $FreeBSD: src/include/stdio.h,v 1.78 2009/03/25 08:07:52 das Exp $
- * $DragonFly: src/include/stdio.h,v 1.14 2008/06/05 17:53:10 swildner Exp $
  */
 
 #ifndef	_STDIO_H_
@@ -298,7 +297,7 @@ char	*tempnam(const char *, const char *);
 #if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
 ssize_t	 getdelim(char ** __restrict, size_t * __restrict, int,
 		  FILE * __restrict);
-/* int	 renameat(int, const char *, int, const char *); */
+int	 renameat(int, const char *, int, const char *);
 int	 vdprintf(int, const char * __restrict, __va_list);
 
 /*
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index ad18aa4..e4a0d39 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -1,6 +1,5 @@
 #	@(#)Makefile.inc	8.3 (Berkeley) 10/24/94
 # $FreeBSD: src/lib/libc/sys/Makefile.inc,v 1.75.2.7 2003/04/22 17:31:18 trhodes Exp $
-# $DragonFly: src/lib/libc/sys/Makefile.inc,v 1.39 2008/11/11 00:55:49 pavalos Exp $
 
 # sys sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys ${.CURDIR}/../libc/sys
@@ -137,6 +136,7 @@ MLINKS+=open.2 openat.2
 MLINKS+=pathconf.2 fpathconf.2
 MLINKS+=read.2 pread.2 read.2 preadv.2 read.2 readv.2
 MLINKS+=recv.2 recvfrom.2 recv.2 recvmsg.2
+MLINKS+=rename.2 renameat.2
 MLINKS+=rtprio.2 lwp_rtprio.2
 .if !defined(NO_P1003_1B)
 MLINKS+=sched_get_priority_max.2 sched_get_priority_min.2 \
diff --git a/lib/libc/sys/rename.2 b/lib/libc/sys/rename.2
index f06d358..a133a62 100644
--- a/lib/libc/sys/rename.2
+++ b/lib/libc/sys/rename.2
@@ -31,9 +31,8 @@
 .\"
 .\"     @(#)rename.2	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD: src/lib/libc/sys/rename.2,v 1.8.2.7 2001/12/14 18:34:01 ru Exp $
-.\" $DragonFly: src/lib/libc/sys/rename.2,v 1.2 2003/06/17 04:26:47 dillon Exp $
 .\"
-.Dd June 4, 1993
+.Dd July 31, 2010
 .Dt RENAME 2
 .Os
 .Sh NAME
@@ -45,6 +44,8 @@
 .In stdio.h
 .Ft int
 .Fn rename "const char *from" "const char *to"
+.Ft int
+.Fn renameat "int fromfd" "const char *from" "int tofd" "const char *to"
 .Sh DESCRIPTION
 .Fn Rename
 causes the link named
@@ -74,6 +75,37 @@ If the final component of
 is a symbolic link,
 the symbolic link is renamed,
 not the file or directory to which it points.
+.Pp
+The
+.Fn renameat
+system call is equivalent to
+.Fn rename
+except in the case where either
+.Fa from
+or
+.Fa to
+specifies a relative path.
+If
+.Fa from
+is a relative path, the file to be renamed is located
+relative to the directory associated with the file descriptor
+.Fa fromfd
+instead of the current working directory.
+If the
+.Fa to
+is a relative path, the same happens only relative to the directory associated
+with
+.Fa tofd .
+If the
+.Fn renameat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fromfd
+or
+.Fa tofd
+parameter, the current working directory is used in the determination
+of the file for the respective path parameter.
 .\".Sh CAVEAT
 .\"The system can deadlock if a loop in the file system graph is present.
 .\"This loop takes the form of an entry in directory
@@ -190,11 +222,55 @@ or
 .Fa To
 is a directory and is not empty.
 .El
+.Pp
+In addition to the errors returned by the
+.Fn rename ,
+the
+.Fn renameat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa from
+argument does not specify an absolute path and the
+.Fa fromfd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching, or the
+.Fa to
+argument does not specify an absolute path and the
+.Fa tofd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa from
+argument is not an absolute path and
+.Fa fromfd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory, or the
+.Fa to
+argument is not an absolute path and
+.Fa tofd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
 .Sh SEE ALSO
 .Xr open 2 ,
 .Xr symlink 7
 .Sh STANDARDS
 The
 .Fn rename
-function call is expected to conform to
+system call is expected to conform to
 .St -p1003.1-96 .
+The
+.Fn renameat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn renameat
+system call appeared in
+.Dx 2.7 .
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index a205b57..f77200e 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -553,4 +553,5 @@ struct sysent sysent[] = {
 	{ AS(mq_receive_args), (sy_call_t *)sys_mq_receive },	/* 517 = mq_receive */
 	{ AS(mq_timedsend_args), (sy_call_t *)sys_mq_timedsend },	/* 518 = mq_timedsend */
 	{ AS(mq_timedreceive_args), (sy_call_t *)sys_mq_timedreceive },	/* 519 = mq_timedreceive */
+	{ AS(renameat_args), (sy_call_t *)sys_renameat },	/* 520 = renameat */
 };
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index bf958e9..4995180 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -527,4 +527,5 @@ const char *syscallnames[] = {
 	"mq_receive",			/* 517 = mq_receive */
 	"mq_timedsend",			/* 518 = mq_timedsend */
 	"mq_timedreceive",			/* 519 = mq_timedreceive */
+	"renameat",			/* 520 = renameat */
 };
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 9bab4cc..13610de 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -729,3 +729,5 @@
 519	STD	POSIX	{ ssize_t mq_timedreceive(mqd_t mqdes, \
 				  char *msg_ptr, size_t msg_len, unsigned *msg_prio, \
 				  const struct timespec *abs_timeout); }
+520	STD	POSIX	{ int renameat(int oldfd, char *old, int newfd, \
+				  char *new); }
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 20807c7..1dd4087 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -37,7 +37,6 @@
  *
  *	@(#)vfs_syscalls.c	8.13 (Berkeley) 4/15/94
  * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.135 2008/11/11 00:55:49 pavalos Exp $
  */
 
 #include <sys/param.h>
@@ -3738,6 +3737,37 @@ sys_rename(struct rename_args *uap)
 	return (error);
 }
 
+/*
+ * renameat_args(int oldfd, char *old, int newfd, char *new)
+ *
+ * Rename files using paths relative to the directories associated with
+ * oldfd and newfd.  Source and destination must either both be directories,
+ * or both not be directories.  If target is a directory, it must be empty.
+ *
+ * MPALMOSTSAFE
+ */
+int
+sys_renameat(struct renameat_args *uap)
+{
+	struct nlookupdata oldnd, newnd;
+	struct file *oldfp, *newfp;
+	int error;
+
+	get_mplock();
+	error = nlookup_init_at(&oldnd, &oldfp, uap->oldfd, uap->old,
+	    UIO_USERSPACE, 0);
+	if (error == 0) {
+		error = nlookup_init_at(&newnd, &newfp, uap->newfd, uap->new,
+		    UIO_USERSPACE, 0);
+		if (error == 0)
+			error = kern_rename(&oldnd, &newnd);
+		nlookup_done(&newnd);
+	}
+	nlookup_done(&oldnd);
+	rel_mplock();
+	return (error);
+}
+
 int
 kern_mkdir(struct nlookupdata *nd, int mode)
 {
diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h
index d85c943..b44ef8c 100644
--- a/sys/sys/syscall-hide.h
+++ b/sys/sys/syscall-hide.h
@@ -350,3 +350,4 @@ HIDE_POSIX(mq_send)
 HIDE_POSIX(mq_receive)
 HIDE_POSIX(mq_timedsend)
 HIDE_POSIX(mq_timedreceive)
+HIDE_POSIX(renameat)
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index dba8aea..c6b9698 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -359,4 +359,5 @@
 #define	SYS_mq_receive	517
 #define	SYS_mq_timedsend	518
 #define	SYS_mq_timedreceive	519
-#define	SYS_MAXSYSCALL	520
+#define	SYS_renameat	520
+#define	SYS_MAXSYSCALL	521
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index 45bb7cd..dc7a249 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -298,4 +298,5 @@ MIASM =  \
 	mq_send.o \
 	mq_receive.o \
 	mq_timedsend.o \
-	mq_timedreceive.o
+	mq_timedreceive.o \
+	renameat.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index a2f70e6..d9a1438 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -2280,6 +2280,15 @@ struct	mq_timedreceive_args {
 	unsigned *	msg_prio;	char msg_prio_[PAD_(unsigned *)];
 	const struct timespec *	abs_timeout;	char abs_timeout_[PAD_(const struct timespec *)];
 };
+struct	renameat_args {
+#ifdef _KERNEL
+	struct sysmsg sysmsg;
+#endif
+	int	oldfd;	char oldfd_[PAD_(int)];
+	char *	old;	char old_[PAD_(char *)];
+	int	newfd;	char newfd_[PAD_(int)];
+	char *	new;	char new_[PAD_(char *)];
+};
 
 #ifdef COMPAT_43
 
@@ -2886,6 +2895,7 @@ int	sys_mq_send (struct mq_send_args *);
 int	sys_mq_receive (struct mq_receive_args *);
 int	sys_mq_timedsend (struct mq_timedsend_args *);
 int	sys_mq_timedreceive (struct mq_timedreceive_args *);
+int	sys_renameat (struct renameat_args *);
 
 #endif /* !_SYS_SYSPROTO_H_ */
 #undef PAD_
diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h
index a0df514..df077c1 100644
--- a/sys/sys/sysunion.h
+++ b/sys/sys/sysunion.h
@@ -406,4 +406,5 @@ union sysunion {
 	struct	mq_receive_args mq_receive;
 	struct	mq_timedsend_args mq_timedsend;
 	struct	mq_timedreceive_args mq_timedreceive;
+	struct	renameat_args renameat;
 };
-- 
1.6.6.1

