From owner-freebsd-current Sun Jul 30 02:48:11 1995 Return-Path: current-owner Received: (from majordom@localhost) by freefall.cdrom.com (8.6.11/8.6.6) id CAA01370 for current-outgoing; Sun, 30 Jul 1995 02:48:11 -0700 Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.34]) by freefall.cdrom.com (8.6.11/8.6.6) with ESMTP id CAA01308 for ; Sun, 30 Jul 1995 02:47:56 -0700 Received: (from bde@localhost) by godzilla.zeta.org.au (8.6.9/8.6.9) id TAA02305; Sun, 30 Jul 1995 19:45:24 +1000 Date: Sun, 30 Jul 1995 19:45:24 +1000 From: Bruce Evans Message-Id: <199507300945.TAA02305@godzilla.zeta.org.au> To: bde@zeta.org.au, markd@grizzly.com, terry@cs.weber.edu Subject: Re: kern/169: Errors from mkdir & mv when directories paths end with "/" Cc: current@freebsd.org Sender: current-owner@freebsd.org Precedence: bulk I have finally got my 1.1.5 fixes for trailing slashes working in 2.x. They make FreeBSD work the same as SunOS for normal cases and better (most like hpux) for symlinks. Mark Diekhans wrote a long time ago (24 Jan 1995): >>>>>> "Bruce" == Bruce Evans writes: > Bruce> [mv foo baz/] > >> (2) Moved to baz/foo > Bruce> I should have asked for this to be done with a syscall - mv(1) >Yes, much more useful, enclosed.. >>>>>> "Terry" == Terry Lambert writes: > Terry> [ ... tables of sco, hpux, and sun behaviour ... ] Would it be too > Terry> much trouble to put a BSD line in these tables? 8-). >I though you guys had this all memorized :-) No problem, enclosed.. >"mkdir foo/" and "mv foo/ baz" (command and system call: > | mkdir | mv | mkdir | rename > | cmd | cmd | call | call > ------------------------------------------------------------ > sco | ok | ok | ok | ok > hpux | ok | ok | ok | fails * > sun | ok | ok | ok | ok > FreeBSD | No such file | Is a dir | No such file | Is a dir Linux | No such file | ok | No such file | Op not permitted new-FreeBSD | ok | ok | ok | ok > * HPUX returns "not owner" on a rename call of a directory regardless > of the trailing /. >rename ("foo", "baz/"); (foo is a directory): > baz: | does not | existing | empty | nonempty > | exist | file | dir | directory > --------------------------------------------------------------- > sco | RENAMED | Not a dir | REPLACED | File exists > hpux | RENAMED | Not a dir | REPLACED | File exists > sun | RENAMED | Not a dir | REPLACED | Dir not empty > FreeBSD | No such file | Is a dir | Is a dir | Is a dir Linux | No such file | Not a dir | Op not perm| Op not perm new-FreeBSD | RENAMED | Not a dir | REPLACED | Dir not empty > baz is a symlink to: > | does not | existing | empty | nonempty > | exist | file | dir | directory > --------------------------------------------------------------- > sco | Not a dir | Not a dir | Not a dir | Not a dir > hpux | RENAMED | Not a dir | RENAMED | File exists > sun | Not a dir | Not a dir | Not a dir | Not a dir > FreeBSD | Is a dir | Is a dir | Is a dir | Is a dir Linux | No such file | Not a dir | Op not perm| Op not perm new-FreeBSD | RENAMED | Not a dir | RENAMED | Dir not empty ----- rmdir("baz/"); ----- ----- unlink("baz/"); ----- baz: | does not | existing | does not | existing | exist | file | exist | file --------------------------------------------------------------- FreeBSD | No such file | Is a dir | No such file | Is a dir Linux | No such file | Not a dir | No such file | Not a dir new-FreeBSD | No such file | Not a dir | No such file | Not a dir Other new (and maybe old) behaviour: rename("existing-file", "non-existing-dir/"): ENOENT rename("existing-file/", "non-existing-dir"): ENOTDIR rmdir("symlink-to-existing-dir/"): succeeds Bruce diff -c2 src/sys/kern/vfs_lookup.c~ src/sys/kern/vfs_lookup.c *** src/sys/kern/vfs_lookup.c~ Wed May 31 20:55:21 1995 --- src/sys/kern/vfs_lookup.c Sun Jul 30 16:18:03 1995 *************** *** 258,261 **** --- 271,275 ---- int wantparent; /* 1 => wantparent or lockparent flag */ int rdonly; /* lookup read-only flag bit */ + int trailing_slash; int error = 0; struct componentname *cnp = &ndp->ni_cnd; *************** *** 303,306 **** --- 317,339 ---- ndp->ni_pathlen -= cnp->cn_namelen; ndp->ni_next = cp; + + /* + * Replace multiple slashes by a single slash and trailing slashes + * by a null. This must be done before VOP_LOOKUP() because some + * fs's don't know about trailing slashes. Remember if there were + * trailing slashes to handle symlinks, existing non-directories + * and non-existing files that won't be directories specially later. + */ + trailing_slash = 0; + while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { + cp++; + ndp->ni_pathlen--; + if (*cp == '\0') { + trailing_slash = 1; + *ndp->ni_next = '\0'; /* XXX for direnter() ... */ + } + } + ndp->ni_next = cp; + cnp->cn_flags |= MAKEENTRY; if (*cp == '\0' && docache == 0) *************** *** 407,410 **** --- 440,448 ---- goto bad; } + if (*cp == '\0' && trailing_slash && + !(cnp->cn_flags & WILLBEDIR)) { + error = ENOENT; + goto bad; + } /* * We return with ni_vp NULL to indicate that the entry *************** *** 438,444 **** */ if ((dp->v_type == VLNK) && ! ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { cnp->cn_flags |= ISSYMLINK; return (0); } --- 476,491 ---- */ if ((dp->v_type == VLNK) && ! ((cnp->cn_flags & FOLLOW) || trailing_slash || ! *ndp->ni_next == '/')) { cnp->cn_flags |= ISSYMLINK; return (0); + } + + /* + * Check for bogus trailing slashes. + */ + if (trailing_slash && dp->v_type != VDIR) { + error = ENOTDIR; + goto bad2; } diff -c2 src/sys/kern/vfs_syscalls.c~ src/sys/kern/vfs_syscalls.c *** src/sys/kern/vfs_syscalls.c~ Fri Jul 14 02:05:22 1995 --- src/sys/kern/vfs_syscalls.c Fri Jul 14 02:06:18 1995 *************** *** 835,838 **** --- 835,840 ---- nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; + if (vp->v_type == VDIR) + nd.ni_cnd.cn_flags |= WILLBEDIR; nd.ni_dirp = uap->link; error = namei(&nd); *************** *** 1820,1823 **** --- 1822,1827 ---- NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, UIO_USERSPACE, uap->to, p); + if (fromnd.ni_vp->v_type == VDIR) + tond.ni_cnd.cn_flags |= WILLBEDIR; error = namei(&tond); if (error) { *************** *** 1905,1908 **** --- 1919,1923 ---- NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); + nd.ni_cnd.cn_flags |= WILLBEDIR; error = namei(&nd); if (error) diff -c2 src/sys/sys/namei.h~ src/sys/sys/namei.h *** src/sys/sys/namei.h~ Sun Jul 30 00:45:36 1995 --- src/sys/sys/namei.h Sun Jul 30 00:46:05 1995 *************** *** 135,138 **** --- 135,139 ---- #define ISLASTCN 0x08000 /* this is last component of pathname */ #define ISSYMLINK 0x10000 /* symlink needs interpretation */ + #define WILLBEDIR 0x20000 /* new files will be dirs; allow trailing / */ #define PARAMASK 0xfff00 /* mask of parameter descriptors */ /*