Subject: Re: Linux emulation and mkdir with trailing /
To: Alan Barrett <apb@cequrux.com>
From: Bill Studenmund <wrstuden@zembu.com>
List: tech-kern
Date: 09/25/2000 11:13:21
On Mon, 25 Sep 2000, Alan Barrett wrote:

> If bar is a non-directory file, why would you expect to be able to
> open "bar/" (with a trailing slash)?  What's the point of the trailing
> slash?
> 
> I expect '/' to mark directories.  My expectation is based on
> observing patterns of behaviour.  The only use I know for slashes in a
> unix-like filesystem is to mark the root of the filesystem and to
> separate components where all components (except perhaps the last) are
> directory names.  In my limited experience, I have never encountered
> any use for a trailing slash after a non-directory file name, nor seen
> anybody deliberately put trailing slashes after a non-directory file
> name.  Whenever I have seen a slash in a filename, the slash has been
> used either to indicate the root of the filesystem, or to mark the
> thing before the slash as a directory.  Whenever I have seen other
> people use trailing slashes in filenames on a unix-like system, those
> other people have intended to name a directory.  I observe that I get
> errors from "touch foo/" and not from "touch foo" (if foo did not
> previously exist).  I observe that "mv foo bar/" fails if bar does not
> exist as a directory.  All this makes me expect that a trailing slash
> should be permitted on a directory name but illegal on a non-directory
> name.
> 
> I might not have non-BSD historical precedent on my side, but I surely
> have the principle of least astonishment on my side.  Allowing "bar/"
> to refer to a non-directory file is very astonishing to people
> familiar with the way '/' is usually used in filenames.

I agree with Alan here.

As I understand it, the desired behavior is

"mkdir /foo/bar/" will work when only /foo exists.

We don't need to hack mkdir to do this. A much cleaner way is to change
lookup(), since it after all is returning the error.

I think the code to change is:

                /*
                 * If this was not the last component, or there were trailing
                 * slashes, then the name must exist.
                 */
                if (cnp->cn_flags & REQUIREDIR) {
                        error = ENOENT;
                        goto bad;
                }

which is around line 465 of sys/kern/vfs_lookup.c. If we made it:

if ((cnp->cn_flags & REQUIREDIR) &&
	(~cnp->cn_flags & (ISLASTCN & CREATE_DIR))) {

where CREATE_DIR is a new flag for namei. The logic is that if we are
creating a directory, and we have hit the last component and the name
doesn't exist, then it's ok to return what we've got (a locked parent
dir and a NULL vpp).

(We want to return an error if we require a directory (there were slashes
after this name) and we either aren't at the end of the name (ISLASTCN
isn't set) or someone tried to create a file which had a / at the end of
the name (CREATE_DIR not set since we aren't called by a directory-making
syscall).)

Thoughts?

Take care,

Bill