Page MenuHomeFreeBSD

D57658.diff
No OneTemporary

D57658.diff

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
@@ -3752,12 +3752,13 @@
#ifdef MAC
static int
kern_renameat_mac(struct thread *td, int oldfd, const char *old, int newfd,
- const char *new, enum uio_seg pathseg, struct nameidata *fromnd)
+ const char *new, enum uio_seg pathseg, struct nameidata *fromnd, int op,
+ int ndflags)
{
int error;
- NDINIT_ATRIGHTS(fromnd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
- pathseg, old, oldfd, &cap_renameat_source_rights);
+ NDINIT_ATRIGHTS(fromnd, op, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
+ ndflags, pathseg, old, oldfd, &cap_renameat_source_rights);
if ((error = namei(fromnd)) != 0)
return (error);
error = mac_vnode_check_rename_from(td->td_ucred, fromnd->ni_dvp,
@@ -3782,23 +3783,35 @@
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
uint64_t tondflags;
- int error;
+ int error, fndflags, op;
short irflag;
+ bool exchange;
- if ((flags & ~(AT_RENAME_NOREPLACE)) != 0)
+ if ((flags & ~(AT_RENAME_NOREPLACE | AT_RENAME_EXCHANGE)) != 0)
+ return (EINVAL);
+ if ((flags & (AT_RENAME_NOREPLACE | AT_RENAME_EXCHANGE)) ==
+ (AT_RENAME_NOREPLACE | AT_RENAME_EXCHANGE))
return (EINVAL);
+ if ((flags & AT_RENAME_EXCHANGE) != 0) {
+ op = RENAME;
+ exchange = true;
+ } else {
+ op = DELETE;
+ exchange = false;
+ }
+ fndflags = 0;
again:
tmp = mp = NULL;
bwillwrite();
#ifdef MAC
if (mac_vnode_check_rename_from_enabled()) {
error = kern_renameat_mac(td, oldfd, old, newfd, new, pathseg,
- &fromnd);
+ &fromnd, op, fndflags);
if (error != 0)
return (error);
} else {
#endif
- NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | AUDITVNODE1,
+ NDINIT_ATRIGHTS(&fromnd, op, WANTPARENT | AUDITVNODE1 | fndflags,
pathseg, old, oldfd, &cap_renameat_source_rights);
if ((error = namei(&fromnd)) != 0)
return (error);
@@ -3806,6 +3819,11 @@
}
#endif
fvp = fromnd.ni_vp;
+ if (exchange && fvp == NULL) {
+ NDFREE_PNBUF(&fromnd);
+ vrele(fromnd.ni_dvp);
+ return (ENOENT);
+ }
tondflags = LOCKPARENT | LOCKLEAF | NOCACHE | AUDITVNODE2;
if (fromnd.ni_vp->v_type == VDIR)
tondflags |= WILLBEDIR;
@@ -3844,6 +3862,29 @@
error = EEXIST;
goto out;
}
+ if (exchange) {
+ if (tvp == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+ if (tvp->v_type == VDIR && fndflags == 0) {
+ fndflags = WILLBEDIR;
+again2:
+ NDFREE_PNBUF(&fromnd);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ NDFREE_PNBUF(&tond);
+ VOP_VPUT_PAIR(tdvp, &tvp, true);
+ error = sig_intr();
+ if (error != 0)
+ goto out1;
+ goto again;
+ }
+ if (tvp->v_type != VDIR && fndflags != 0) {
+ fndflags = 0;
+ goto again2;
+ }
+ }
error = vn_start_write(fvp, &mp, V_NOWAIT);
if (error != 0) {
again1:
@@ -3886,12 +3927,15 @@
goto out;
}
if (tvp != NULL) {
- if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
- error = ENOTDIR;
- goto out;
- } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
- error = EISDIR;
- goto out;
+ if (!exchange) {
+ if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ } else if (fvp->v_type != VDIR &&
+ tvp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
}
#ifdef CAPABILITIES
if (newfd != AT_FDCWD && (tond.ni_resflags & NIRES_ABS) == 0) {
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -260,7 +260,9 @@
#define AT_EMPTY_PATH 0x4000 /* Operate on dirfd if path is empty */
#define AT_RENAME_NOREPLACE 0x0001 /* Fail rename if target exists */
+#define AT_RENAME_EXCHANGE 0x0002 /* Atomically exchange 'from' and 'to' */
#define RENAME_NOREPLACE AT_RENAME_NOREPLACE
+#define RENAME_EXCHANGE AT_RENAME_EXCHANGE
#endif /* __BSD_VISIBLE */
/*

File Metadata

Mime Type
text/plain
Expires
Sun, Aug 2, 4:12 AM (20 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35839686
Default Alt Text
D57658.diff (3 KB)

Event Timeline