Page MenuHomeFreeBSD

D55539.id172807.diff
No OneTemporary

D55539.id172807.diff

diff --git a/include/stdio.h b/include/stdio.h
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -398,6 +398,7 @@
char *fgetln(FILE *, size_t *);
const char *fmtcheck(const char *, const char *) __format_arg(2);
int fpurge(FILE *);
+int renameat2(int, const char *, int, const char *, unsigned int);
void setbuffer(FILE *, char *, int);
int setlinebuf(FILE *);
int vasprintf(char **, const char *, __va_list)
diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys
--- a/lib/libsys/Makefile.sys
+++ b/lib/libsys/Makefile.sys
@@ -513,7 +513,8 @@
MLINKS+=recv.2 recvfrom.2 \
recv.2 recvmmsg.2 \
recv.2 recvmsg.2
-MLINKS+=rename.2 renameat.2
+MLINKS+=rename.2 renameat.2 \
+ rename.2 renameat2.2
MLINKS+=rtprio.2 rtprio_thread.2
MLINKS+=sched_get_priority_max.2 sched_get_priority_min.2 \
sched_get_priority_max.2 sched_rr_get_interval.2
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -393,6 +393,7 @@
FBSD_1.9 {
pdrfork;
pdrfork_thread;
+ renameat2;
};
FBSDprivate_1.0 {
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -474,6 +474,7 @@
typedef int (__sys_kexec_load_t)(uint64_t, u_long, struct kexec_segment *, u_long);
typedef int (__sys_pdrfork_t)(int *, int, int);
typedef int (__sys_pdwait_t)(int, int *, int, struct __wrusage *, struct __siginfo *);
+typedef int (__sys_renameat2_t)(int, const char *, int, const char *, int);
_Noreturn void __sys__exit(int rval);
int __sys_fork(void);
@@ -883,6 +884,7 @@
int __sys_kexec_load(uint64_t entry, u_long nseg, struct kexec_segment * segments, u_long flags);
int __sys_pdrfork(int * fdp, int pdflags, int rfflags);
int __sys_pdwait(int fd, int * status, int options, struct __wrusage * wrusage, struct __siginfo * info);
+int __sys_renameat2(int oldfd, const char * old, int newfd, const char * new, int flags);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/rename.2 b/lib/libsys/rename.2
--- a/lib/libsys/rename.2
+++ b/lib/libsys/rename.2
@@ -39,6 +39,16 @@
.Fn rename "const char *from" "const char *to"
.Ft int
.Fn renameat "int fromfd" "const char *from" "int tofd" "const char *to"
+.In sys/fcntl.h
+.In stdio.h
+.Ft int
+.Fo renameat2
+.Fa "int fromfd"
+.Fa "const char *from"
+.Fa "int tofd"
+.Fa "const char *to"
+.Fa "unsigned int flags"
+.Fc
.Sh DESCRIPTION
The
.Fn rename
@@ -112,32 +122,28 @@
.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
-.\".Pa a ,
-.\"say
-.\".Pa a/foo ,
-.\"being a hard link to directory
-.\".Pa b ,
-.\"and an entry in
-.\"directory
-.\".Pa b ,
-.\"say
-.\".Pa b/bar ,
-.\"being a hard link
-.\"to directory
-.\".Pa a .
-.\"When such a loop exists and two separate processes attempt to
-.\"perform
-.\".Ql rename a/foo b/bar
-.\"and
-.\".Ql rename b/bar a/foo ,
-.\"respectively,
-.\"the system may deadlock attempting to lock
-.\"both directories for modification.
-.\"Hard links to directories should be
-.\"replaced by symbolic links by the system administrator.
+.Pp
+The
+.Fn renameat2
+system call takes additional
+.Fa flags
+argument.
+If
+.Fa flags
+is zero, the
+.Fn renameat2
+call operates same as
+.Fn renameat .
+Additionally, the following flags can be specified:
+.Bl -tag -width AT_RENAME_NOREPLACE
+.It Dv AT_RENAME_NOREPLACE
+If the path specified by
+.Fa tofd
+and
+.Fa to
+exists, the request fails with the error
+.Er EEXIST .
+.El
.Sh RETURN VALUES
.Rv -std rename
.Sh ERRORS
@@ -324,6 +330,23 @@
.Dv CAP_RENAMEAT_TARGET
right.
.El
+.Pp
+In addition to the errors returned by the
+.Fn renameat ,
+the
+.Fn renameat2
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EEXIST
+The path specified as the
+.Fa to
+already exists.
+.It Bq Er EOPNOTSUPP
+One of the
+.Fa flags
+specified is not supported by the filesystem where the renamed file
+is located.
+.El
.Sh SEE ALSO
.Xr chflags 2 ,
.Xr open 2 ,
@@ -341,3 +364,7 @@
.Fn renameat
system call appeared in
.Fx 8.0 .
+The
+.Fn renameat2
+system call appeared in
+.Fx 16.0 .
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -823,4 +823,6 @@
__sys_pdrfork;
_pdwait;
__sys_pdwait;
+ _renameat2;
+ __sys_renameat2;
};
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -519,4 +519,5 @@
#define FREEBSD32_SYS_jail_remove_jd 598
#define FREEBSD32_SYS_pdrfork 600
#define FREEBSD32_SYS_freebsd32_pdwait 601
-#define FREEBSD32_SYS_MAXSYSCALL 602
+#define FREEBSD32_SYS_renameat2 602
+#define FREEBSD32_SYS_MAXSYSCALL 603
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -607,4 +607,5 @@
"#599", /* 599 = kexec_load */
"pdrfork", /* 600 = pdrfork */
"freebsd32_pdwait", /* 601 = freebsd32_pdwait */
+ "renameat2", /* 602 = renameat2 */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -669,4 +669,5 @@
{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 599 = freebsd32_kexec_load */
{ .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */
{ .sy_narg = AS(freebsd32_pdwait_args), .sy_call = (sy_call_t *)freebsd32_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = freebsd32_pdwait */
+ { .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3447,6 +3447,17 @@
*n_args = 5;
break;
}
+ /* renameat2 */
+ case 602: {
+ struct renameat2_args *p = params;
+ iarg[a++] = p->oldfd; /* int */
+ uarg[a++] = (intptr_t)p->old; /* const char * */
+ iarg[a++] = p->newfd; /* int */
+ uarg[a++] = (intptr_t)p->new; /* const char * */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 5;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9314,6 +9325,28 @@
break;
};
break;
+ /* renameat2 */
+ case 602:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11242,6 +11275,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* renameat2 */
+ case 602:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -811,7 +811,7 @@
{
return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
- args->to, UIO_USERSPACE));
+ args->to, UIO_USERSPACE, 0));
}
#endif
@@ -833,7 +833,9 @@
linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
{
int olddfd, newdfd;
+ u_int atflags;
+ atflags = 0;
if (args->flags != 0) {
if (args->flags & ~(LINUX_RENAME_EXCHANGE |
LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT))
@@ -842,6 +844,10 @@
args->flags & (LINUX_RENAME_NOREPLACE |
LINUX_RENAME_WHITEOUT))
return (EINVAL);
+ if ((args->flags & LINUX_RENAME_NOREPLACE) != 0) {
+ args->flags &= ~LINUX_RENAME_NOREPLACE;
+ atflags |= AT_RENAME_NOREPLACE;
+ }
#if 0
/*
* This spams the console on Ubuntu Focal.
@@ -849,8 +855,10 @@
* What's needed here is a general mechanism to let users know
* about missing features without hogging the system.
*/
- linux_msg(td, "renameat2 unsupported flags 0x%x",
- args->flags);
+ if (args->flags != 0) {
+ linux_msg(td, "renameat2 unsupported flags 0x%x",
+ args->flags);
+ }
#endif
return (EINVAL);
}
@@ -858,7 +866,7 @@
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
return (kern_renameat(td, olddfd, args->oldname, newdfd,
- args->newname, UIO_USERSPACE));
+ args->newname, UIO_USERSPACE, atflags));
}
#ifdef LINUX_LEGACY_SYSCALLS
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -5527,6 +5527,11 @@
}
#endif
+ if (error == 0) {
+ if (ap->a_flags != 0)
+ error = EOPNOTSUPP;
+ }
+
if (error == 0)
error = zfs_do_rename(fdvp, &fvp, ap->a_fcnp, tdvp, &tvp,
ap->a_tcnp, ap->a_fcnp->cn_cred);
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2254,6 +2254,10 @@
err = EXTERROR(EXDEV, "Cross-device rename");
goto out;
}
+ if (ap->a_flags != 0) {
+ err = EOPNOTSUPP;
+ goto out;
+ }
cache_purge(fvp);
/*
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -49,12 +49,12 @@
* October 1992
*/
-#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/clock.h>
#include <sys/dirent.h>
+#include <sys/fcntl.h>
#include <sys/lock.h>
#include <sys/lockf.h>
#include <sys/malloc.h>
@@ -970,6 +970,11 @@
goto abortit;
}
+ if ((ap->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
+ error = EOPNOTSUPP;
+ goto abortit;
+ }
+
/*
* If source and dest are the same, do nothing.
*/
@@ -1036,6 +1041,11 @@
vrele(tvp);
tvp = NULL;
}
+ if (error == 0 && tvp != NULL &&
+ (ap->a_flags & AT_RENAME_NOREPLACE) != 0) {
+ error = EEXIST;
+ goto unlock;
+ }
if (error == 0) {
nip = NULL;
error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT,
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -2196,6 +2196,12 @@
error = EXDEV;
goto out;
}
+
+ if (ap->a_flags != 0) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
nmp = VFSTONFS(fvp->v_mount);
if (fvp == tvp) {
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1715,7 +1715,7 @@
if (error == 0) {
error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
&fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
- &tondp->ni_cnd);
+ &tondp->ni_cnd, 0);
lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
vfs_rel(mp);
} else {
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -741,7 +741,8 @@
ltvp = NULL;
}
- error = VOP_RENAME(lfdvp, lfvp, ap->a_fcnp, ltdvp, ltvp, ap->a_tcnp);
+ error = VOP_RENAME(lfdvp, lfvp, ap->a_fcnp, ltdvp, ltvp, ap->a_tcnp,
+ ap->a_flags);
vrele(fdvp);
vrele(fvp);
vrele(tdvp);
diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -2084,6 +2084,11 @@
goto out;
}
+ if (ap->a_flags != 0) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
/* warning if you are renaming to the same name */
if (fvp == tvp)
error = 0;
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
--- a/sys/fs/smbfs/smbfs_vnops.c
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -577,6 +577,11 @@
goto out;
}
+ if (ap->a_flags != 0) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
if (tvp && vrefcnt(tvp) > 1) {
error = EBUSY;
goto out;
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -993,6 +993,11 @@
goto out;
}
+ if ((v->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
/* If source and target are the same file, there is nothing to do. */
if (fvp == tvp) {
error = 0;
@@ -1013,9 +1018,14 @@
"tmpfs_rename: fdvp not locked");
ASSERT_VOP_ELOCKED(tdvp,
"tmpfs_rename: tdvp not locked");
- if (tvp != NULL)
+ if (tvp != NULL) {
ASSERT_VOP_ELOCKED(tvp,
"tmpfs_rename: tvp not locked");
+ if ((v->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
+ error = EEXIST;
+ goto out_locked;
+ }
+ }
if (fvp == tvp) {
error = 0;
goto out_locked;
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -1413,6 +1413,11 @@
goto unionfs_rename_abort;
}
+ if (ap->a_flags != 0) {
+ error = EOPNOTSUPP;
+ goto unionfs_rename_abort;
+ }
+
/* Renaming a file to itself has no effect. */
if (fvp == tvp)
goto unionfs_rename_abort;
@@ -1581,7 +1586,7 @@
if (rfvp == rtvp)
goto unionfs_rename_abort;
- error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
+ error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp, ap->a_flags);
if (error == 0) {
if (rtvp != NULL && rtvp->v_type == VDIR)
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -668,4 +668,5 @@
{ .sy_narg = AS(kexec_load_args), .sy_call = (sy_call_t *)sys_kexec_load, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 599 = kexec_load */
{ .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */
{ .sy_narg = AS(pdwait_args), .sy_call = (sy_call_t *)sys_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = pdwait */
+ { .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
};
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -607,4 +607,5 @@
"kexec_load", /* 599 = kexec_load */
"pdrfork", /* 600 = pdrfork */
"pdwait", /* 601 = pdwait */
+ "renameat2", /* 602 = renameat2 */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3420,5 +3420,13 @@
_Out_opt_ _Contains_long_ptr_ struct __siginfo *info
);
}
-
+602 AUE_RENAMEAT STD|CAPENABLED {
+ int renameat2(
+ int oldfd,
+ _In_z_ const char *old,
+ int newfd,
+ _In_z_ const char *new,
+ int flags
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3544,6 +3544,17 @@
*n_args = 5;
break;
}
+ /* renameat2 */
+ case 602: {
+ struct renameat2_args *p = params;
+ iarg[a++] = p->oldfd; /* int */
+ uarg[a++] = (intptr_t)p->old; /* const char * */
+ iarg[a++] = p->newfd; /* int */
+ uarg[a++] = (intptr_t)p->new; /* const char * */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 5;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9488,6 +9499,28 @@
break;
};
break;
+ /* renameat2 */
+ case 602:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland const char *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11511,6 +11544,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* renameat2 */
+ case 602:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3720,7 +3720,7 @@
{
return (kern_renameat(td, AT_FDCWD, uap->from, AT_FDCWD,
- uap->to, UIO_USERSPACE));
+ uap->to, UIO_USERSPACE, 0));
}
#ifndef _SYS_SYSPROTO_H_
@@ -3736,7 +3736,15 @@
{
return (kern_renameat(td, uap->oldfd, uap->old, uap->newfd, uap->new,
- UIO_USERSPACE));
+ UIO_USERSPACE, 0));
+}
+
+int
+sys_renameat2(struct thread *td, struct renameat2_args *uap)
+{
+
+ return (kern_renameat(td, uap->oldfd, uap->old, uap->newfd, uap->new,
+ UIO_USERSPACE, uap->flags));
}
#ifdef MAC
@@ -3766,7 +3774,7 @@
int
kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
- const char *new, enum uio_seg pathseg)
+ const char *new, enum uio_seg pathseg, u_int flags)
{
struct mount *mp, *tmp;
struct vnode *tvp, *fvp, *tdvp;
@@ -3775,6 +3783,8 @@
int error;
short irflag;
+ if ((flags & ~(AT_RENAME_NOREPLACE)) != 0)
+ return (EINVAL);
again:
tmp = mp = NULL;
bwillwrite();
@@ -3810,6 +3820,11 @@
}
tdvp = tond.ni_dvp;
tvp = tond.ni_vp;
+ if (tvp != NULL && (flags & AT_RENAME_NOREPLACE) != 0) {
+ error = EEXIST;
+ tmp = mp = NULL;
+ goto out;
+ }
error = vn_start_write(fvp, &mp, V_NOWAIT);
if (error != 0) {
again1:
@@ -3887,7 +3902,7 @@
out:
if (error == 0) {
error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
- tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
+ tond.ni_dvp, tond.ni_vp, &tond.ni_cnd, flags);
NDFREE_PNBUF(&fromnd);
NDFREE_PNBUF(&tond);
} else {
@@ -3902,9 +3917,12 @@
vrele(fromnd.ni_dvp);
vrele(fvp);
}
- lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0);
- vfs_rel(tmp);
- vn_finished_write(mp);
+ if (tmp != NULL) {
+ lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(tmp);
+ }
+ if (mp != NULL)
+ vn_finished_write(mp);
out1:
if (error == ERESTART)
return (0);
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -336,6 +336,7 @@
IN WILLRELE struct vnode *tdvp;
IN WILLRELE struct vnode *tvp;
IN struct componentname *tcnp;
+ IN u_int flags;
};
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -245,6 +245,9 @@
#define AT_RESOLVE_BENEATH 0x2000 /* Do not allow name resolution
to walk out of dirfd */
#define AT_EMPTY_PATH 0x4000 /* Operate on dirfd if path is empty */
+
+#define AT_RENAME_NOREPLACE 0x0001
+#define RENAME_NOREPLACE AT_RENAME_NOREPLACE
#endif /* __BSD_VISIBLE */
/*
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -540,4 +540,5 @@
#define SYS_kexec_load 599
#define SYS_pdrfork 600
#define SYS_pdwait 601
-#define SYS_MAXSYSCALL 602
+#define SYS_renameat2 602
+#define SYS_MAXSYSCALL 603
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -443,4 +443,5 @@
jail_remove_jd.o \
kexec_load.o \
pdrfork.o \
- pdwait.o
+ pdwait.o \
+ renameat2.o
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -305,7 +305,7 @@
int kern_recvit(struct thread *td, int s, struct msghdr *mp,
enum uio_seg fromseg, struct mbuf **controlp);
int kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
- const char *new, enum uio_seg pathseg);
+ const char *new, enum uio_seg pathseg, u_int flags);
int kern_sched_getparam(struct thread *td, struct thread *targettd,
struct sched_param *param);
int kern_sched_getscheduler(struct thread *td, struct thread *targettd,
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1925,6 +1925,13 @@
char wrusage_l_[PADL_(struct __wrusage *)]; struct __wrusage * wrusage; char wrusage_r_[PADR_(struct __wrusage *)];
char info_l_[PADL_(struct __siginfo *)]; struct __siginfo * info; char info_r_[PADR_(struct __siginfo *)];
};
+struct renameat2_args {
+ char oldfd_l_[PADL_(int)]; int oldfd; char oldfd_r_[PADR_(int)];
+ char old_l_[PADL_(const char *)]; const char * old; char old_r_[PADR_(const char *)];
+ char newfd_l_[PADL_(int)]; int newfd; char newfd_r_[PADR_(int)];
+ char new_l_[PADL_(const char *)]; const char * new; char new_r_[PADR_(const char *)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
int sys__exit(struct thread *, struct _exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2334,6 +2341,7 @@
int sys_kexec_load(struct thread *, struct kexec_load_args *);
int sys_pdrfork(struct thread *, struct pdrfork_args *);
int sys_pdwait(struct thread *, struct pdwait_args *);
+int sys_renameat2(struct thread *, struct renameat2_args *);
#ifdef COMPAT_43
@@ -3335,6 +3343,7 @@
#define SYS_AUE_kexec_load AUE_NULL
#define SYS_AUE_pdrfork AUE_PDRFORK
#define SYS_AUE_pdwait AUE_PDWAIT
+#define SYS_AUE_renameat2 AUE_RENAMEAT
#undef PAD_
#undef PADL_
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1255,6 +1255,7 @@
struct vnode *a_tdvp;
struct vnode *a_tvp;
struct componentname *a_tcnp;
+ u_int a_flags;
} */ *ap)
{
struct vnode *tvp = ap->a_tvp;
@@ -1293,6 +1294,12 @@
goto releout;
}
+ if ((ap->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
+ error = EOPNOTSUPP;
+ mp = NULL;
+ goto releout;
+ }
+
fdvp_s = fvp_s = tdvp_s = tvp_s = SEQC_MOD;
relock:
/*
@@ -1387,6 +1394,11 @@
}
}
+ if (tvp != NULL && (ap->a_flags & AT_RENAME_NOREPLACE) != 0) {
+ error = EEXIST;
+ goto unlockout;
+ }
+
if (DOINGSUJ(fdvp) &&
(seqc_in_modify(fdvp_s) || !vn_seqc_consistent(fdvp, fdvp_s) ||
seqc_in_modify(fvp_s) || !vn_seqc_consistent(fvp, fvp_s) ||

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 28, 4:58 AM (12 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29053404
Default Alt Text
D55539.id172807.diff (22 KB)

Event Timeline