Subject: Re: mkdir with trailing / (patch proposed)
To: Bill Studenmund <wrstuden@netbsd.org>
From: Matthew Orgass <darkstar@pgh.net>
List: tech-kern
Date: 05/09/2002 16:36:44
On Mon, 6 May 2002, Bill Studenmund wrote:
> On Sun, 5 May 2002, Matthew Orgass wrote:
> > I'd be happy to provide a revised patch once its decided what should be
> > done. My previous patch was incorrect in that it allowed pathnames with a
> > trailing slash to refer to symlinks (under emulation only), which is
> > forbidden.
>
> Well, fix that and let's see it. :-) Changing native behavior is real easy
> with any of these patches once we have lookup() fixed.
Ok, here is the update. I also checked the Linux source and found that
they haven't allowed trailing slashes on regular files in any 2.X kernels.
I thought I had seen mention of a Linux binary that wanted to do this, but
trying to find it again I've only seen reference to mkdir. Unless someone
knows of a Linux app that really wants the old behavior it's probably
better to restrict it in Linux emul too.
Matthew Orgass
darkstar@pgh.net
Index: sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.136
diff -u -r1.136 proc.h
--- proc.h 2002/01/11 21:16:27 1.136
+++ proc.h 2002/05/08 22:10:50
@@ -91,9 +91,9 @@
struct emul {
const char *e_name; /* Symbolic name */
const char *e_path; /* Extra emulation path (NULL if none)*/
-#ifndef __HAVE_MINIMAL_EMUL
int e_flags; /* Miscellaneous flags, see above */
/* Syscall handling function */
+#ifndef __HAVE_MINIMAL_EMUL
const int *e_errno; /* Errno array */
int e_nosys; /* Offset of the nosys() syscall */
int e_nsysent; /* Number of system call entries */
@@ -127,6 +127,8 @@
* Emulation miscelaneous flags
*/
#define EMUL_HAS_SYS___syscall 0x001 /* Has SYS___syscall */
+#define EMUL_TSLASHOK 0x002 /* Trailing slashes always valid */
+#define EMUL_TSLASHMK 0x004 /* Trailing slashes ok on mkdir */
/*
* Description of a process.
Index: kern/vfs_lookup.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/vfs_lookup.c,v
retrieving revision 1.39
diff -u -r1.39 vfs_lookup.c
--- vfs_lookup.c 2001/12/08 04:09:59 1.39
+++ vfs_lookup.c 2002/05/08 22:10:53
@@ -107,6 +107,10 @@
#endif
cwdi = cnp->cn_proc->p_cwdi;
+ /* Some systems allow trailing slashes on all files */
+ if (cnp->cn_proc->p_emul->e_flags & EMUL_TSLASHOK)
+ cnp->cn_flags |= TSLASHOK;
+
/*
* Get a buffer for the name to be translated, and copy the
* name into the buffer.
@@ -420,6 +424,16 @@
else
cnp->cn_flags &= ~MAKEENTRY;
cnp->cn_flags |= ISLASTCN;
+
+ /* The treatment of trailing slashes differs between
+ * systems and standards. By default they can refer only
+ * to existing directories. With TSLASHOK, they will be
+ * ignored. SUSv3 specifies that they should be treated
+ * as '/.', which is not currently implemented. */
+ if (cnp->cn_flags & TSLASHOK) {
+ cnp->cn_flags &= ~REQUIREDIR;
+ cnp->cn_flags |= FOLLOW;
+ }
} else {
cnp->cn_flags |= MAKEENTRY;
cnp->cn_flags &= ~ISLASTCN;
Index: ufs/ufs/ufs_lookup.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/ufs/ufs_lookup.c,v
retrieving revision 1.38
diff -u -r1.38 ufs_lookup.c
--- ufs_lookup.c 2001/12/18 10:57:23 1.38
+++ ufs_lookup.c 2002/05/08 22:11:00
@@ -697,7 +697,8 @@
#endif
newdirp->d_ino = ip->i_number;
newdirp->d_namlen = cnp->cn_namelen;
- memcpy(newdirp->d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1);
+ memcpy(newdirp->d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen);
+ newdirp->d_name[cnp->cn_namelen] = 0;
if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0)
newdirp->d_type = IFTODT(ip->i_ffs_mode);
else {
Index: ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.85
diff -u -r1.85 ufs_vnops.c
--- ufs_vnops.c 2001/12/23 16:16:59 1.85
+++ ufs_vnops.c 2002/05/08 22:11:03
@@ -729,7 +729,8 @@
newdir.d_ino = WINO;
newdir.d_namlen = cnp->cn_namelen;
memcpy(newdir.d_name, cnp->cn_nameptr,
- (unsigned)cnp->cn_namelen + 1);
+ (unsigned)cnp->cn_namelen);
+ newdir.d_name[cnp->cn_namelen] = 0;
newdir.d_type = DT_WHT;
error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL);
break;
Index: ufs/ext2fs/ext2fs_lookup.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ufs/ext2fs/ext2fs_lookup.c,v
retrieving revision 1.18
diff -u -r1.18 ext2fs_lookup.c
--- ext2fs_lookup.c 2001/11/08 02:39:07 1.18
+++ ext2fs_lookup.c 2002/05/08 22:11:06
@@ -778,7 +778,8 @@
} else {
newdir.e2d_type = 0;
};
- memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1);
+ memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen);
+ newdir.e2d_name[cnp->cn_namelen] = 0;
newentrysize = EXT2FS_DIRSIZ(cnp->cn_namelen);
if (dp->i_count == 0) {
/*
Index: compat/aout/aout_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/aout/aout_exec.c,v
retrieving revision 1.13
diff -u -r1.13 aout_exec.c
--- aout_exec.c 2001/11/13 02:07:52 1.13
+++ aout_exec.c 2002/05/08 22:11:06
@@ -65,8 +65,8 @@
struct emul emul_netbsd_aout = {
"netbsd",
"/emul/aout",
-#ifndef __HAVE_MINIMAL_EMUL
EMUL_HAS_SYS___syscall,
+#ifndef __HAVE_MINIMAL_EMUL
NULL,
AOUT_SYS_syscall,
AOUT_SYS_MAXSYSCALL,
Index: compat/freebsd/freebsd_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/freebsd/freebsd_exec.c,v
retrieving revision 1.17
diff -u -r1.17 freebsd_exec.c
--- freebsd_exec.c 2001/11/13 02:08:06 1.17
+++ freebsd_exec.c 2002/05/08 22:11:06
@@ -53,8 +53,8 @@
const struct emul emul_freebsd = {
"freebsd",
"/emul/freebsd",
+ EMUL_HAS_SYS___syscall | EMUL_TSLASHMK,
#ifndef __HAVE_MINIMAL_EMUL
- EMUL_HAS_SYS___syscall,
NULL,
FREEBSD_SYS_syscall,
FREEBSD_SYS_MAXSYSCALL,
Index: compat/ibcs2/ibcs2_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/ibcs2/ibcs2_exec.c,v
retrieving revision 1.49
diff -u -r1.49 ibcs2_exec.c
--- ibcs2_exec.c 2001/11/13 02:08:22 1.49
+++ ibcs2_exec.c 2002/05/08 22:11:06
@@ -72,8 +72,8 @@
const struct emul emul_ibcs2 = {
"ibcs2",
"/emul/ibcs2",
+ EMUL_TSLASHMK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
native_to_ibcs2_errno,
IBCS2_SYS_syscall,
IBCS2_SYS_MAXSYSCALL,
Index: compat/irix/irix_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/irix/irix_exec.c,v
retrieving revision 1.12
diff -u -r1.12 irix_exec.c
--- irix_exec.c 2002/02/21 21:53:00 1.12
+++ irix_exec.c 2002/05/08 22:11:07
@@ -75,8 +75,8 @@
const struct emul emul_irix_o32 = {
"irix o32",
"/emul/irix",
+ EMUL_TSLASHMK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
native_to_irix_errno,
IRIX_SYS_syscall,
IRIX_SYS_MAXSYSCALL,
Index: compat/linux/common/linux_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_exec.c,v
retrieving revision 1.57
diff -u -r1.57 linux_exec.c
--- linux_exec.c 2002/03/16 20:43:53 1.57
+++ linux_exec.c 2002/05/08 22:11:07
@@ -115,8 +115,8 @@
const struct emul emul_linux = {
"linux",
"/emul/linux",
+ EMUL_TSLASHMK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
(int*)native_to_linux_errno,
LINUX_SYS_syscall,
LINUX_SYS_MAXSYSCALL,
Index: compat/mach/mach_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/mach/mach_exec.c,v
retrieving revision 1.5
diff -u -r1.5 mach_exec.c
--- mach_exec.c 2001/11/13 02:09:02 1.5
+++ mach_exec.c 2002/05/08 22:11:08
@@ -64,8 +64,8 @@
const struct emul emul_mach = {
"mach",
"/emul/mach",
-#ifndef __HAVE_MINIMAL_EMUL
0,
+#ifndef __HAVE_MINIMAL_EMUL
0,
SYS_syscall,
SYS_MAXSYSCALL,
Index: compat/netbsd32/netbsd32_netbsd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/netbsd32/netbsd32_netbsd.c,v
retrieving revision 1.63
diff -u -r1.63 netbsd32_netbsd.c
--- netbsd32_netbsd.c 2002/03/16 20:43:54 1.63
+++ netbsd32_netbsd.c 2002/05/08 22:11:13
@@ -107,8 +107,8 @@
const struct emul emul_netbsd32 = {
"netbsd32",
"/emul/netbsd32",
-#ifndef __HAVE_MINIMAL_EMUL
0,
+#ifndef __HAVE_MINIMAL_EMUL
NULL,
netbsd32_SYS_syscall,
netbsd32_SYS_MAXSYSCALL,
Index: compat/osf1/osf1_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/osf1/osf1_exec.c,v
retrieving revision 1.28
diff -u -r1.28 osf1_exec.c
--- osf1_exec.c 2001/11/13 02:09:12 1.28
+++ osf1_exec.c 2002/05/08 22:11:13
@@ -55,8 +55,8 @@
const struct emul emul_osf1 = {
"osf1",
"/emul/osf1",
+ EMUL_TSLASHMK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
(int *)osf1_errno_rxlist,
OSF1_SYS_syscall,
OSF1_SYS_MAXSYSCALL,
Index: compat/pecoff/pecoff_emul.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/pecoff/pecoff_emul.c,v
retrieving revision 1.1
diff -u -r1.1 pecoff_emul.c
--- pecoff_emul.c 2002/03/25 06:44:46 1.1
+++ pecoff_emul.c 2002/05/08 22:11:13
@@ -74,8 +74,8 @@
const struct emul emul_pecoff = {
"pecoff",
"/emul/pecoff",
-#ifndef __HAVE_MINIMAL_EMUL
EMUL_HAS_SYS___syscall,
+#ifndef __HAVE_MINIMAL_EMUL
0,
PECOFF_SYS_syscall,
PECOFF_SYS_MAXSYSCALL,
Index: compat/svr4/svr4_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/svr4/svr4_exec.c,v
retrieving revision 1.47
diff -u -r1.47 svr4_exec.c
--- svr4_exec.c 2001/11/13 02:09:21 1.47
+++ svr4_exec.c 2002/05/08 22:11:13
@@ -61,8 +61,8 @@
const struct emul emul_svr4 = {
"svr4",
"/emul/svr4",
+ EMUL_TSLASHOK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
native_to_svr4_errno,
SVR4_SYS_syscall,
SVR4_SYS_MAXSYSCALL,
Index: compat/svr4_32/svr4_32_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/svr4_32/svr4_32_exec.c,v
retrieving revision 1.7
diff -u -r1.7 svr4_32_exec.c
--- svr4_32_exec.c 2001/11/13 02:09:27 1.7
+++ svr4_32_exec.c 2002/05/08 22:11:14
@@ -63,8 +63,8 @@
const struct emul emul_svr4_32 = {
"svr4_32",
"/emul/svr4_32",
+ EMUL_TSLASHOK,
#ifndef __HAVE_MINIMAL_EMUL
- 0,
native_to_svr4_errno,
SVR4_32_SYS_syscall,
SVR4_32_SYS_MAXSYSCALL,
Index: compat/ultrix/ultrix_misc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/ultrix/ultrix_misc.c,v
retrieving revision 1.76
diff -u -r1.76 ultrix_misc.c
--- ultrix_misc.c 2002/03/16 23:55:57 1.76
+++ ultrix_misc.c 2002/05/08 22:11:15
@@ -163,8 +163,8 @@
const struct emul emul_ultrix = {
"ultrix",
"/emul/ultrix",
-#ifndef __HAVE_MINIMAL_EMUL
0,
+#ifndef __HAVE_MINIMAL_EMUL
NULL,
ULTRIX_SYS_syscall,
ULTRIX_SYS_MAXSYSCALL,
Index: sys/namei.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/namei.h,v
retrieving revision 1.25
diff -u -r1.25 namei.h
--- namei.h 2001/12/08 04:10:00 1.25
+++ namei.h 2002/05/08 22:13:40
@@ -111,6 +111,7 @@
#define NOCACHE 0x0020 /* name must not be left in cache */
#define FOLLOW 0x0040 /* follow symbolic links */
#define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */
+#define TSLASHOK 0x0080 /* trailing slash allowed on non-dir */
#define MODMASK 0x00fc /* mask of operational modifiers */
/*
* Namei parameter descriptors.
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/vfs_syscalls.c,v
retrieving revision 1.173
diff -u -r1.173 vfs_syscalls.c
--- vfs_syscalls.c 2001/11/12 15:25:41 1.173
+++ vfs_syscalls.c 2002/05/08 22:23:12
@@ -2825,8 +2825,9 @@
if ((error = namei(&fromnd)) != 0)
return (error);
fvp = fromnd.ni_vp;
- NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
- UIO_USERSPACE, to, p);
+ NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
+ ((fvp->v_type == VDIR) && (p->p_emul->e_flags & EMUL_TSLASHMK) ?
+ TSLASHOK : 0), UIO_USERSPACE, to, p);
if ((error = namei(&tond)) != 0) {
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
@@ -2913,7 +2914,14 @@
int error;
struct nameidata nd;
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
+#ifdef DIAGNOSTIC
+ if (!p)
+ panic("mkdir: no proc!\n");
+#endif
+
+ NDINIT(&nd, CREATE, LOCKPARENT | (p->p_emul->e_flags &
+ EMUL_TSLASHMK ? TSLASHOK : 0), UIO_USERSPACE, SCARG(uap,
+ path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;