freebsd-dev/sys/ufs/ifs/ifs_lookup.c
Adrian Chadd 0b0c10b48d Initial commit of IFS - a inode-namespaced FFS. Here is a short
description:

How it works:
--

Basically ifs is a copy of ffs, overriding some vfs/vnops. (Yes, hack.)
I didn't see the need in duplicating all of sys/ufs/ffs to get this
off the ground.

File creation is done through a special file - 'newfile' . When newfile
is called, the system allocates and returns an inode. Note that newfile
is done in a cloning fashion:

fd = open("newfile", O_CREAT|O_RDWR, 0644);
fstat(fd, &st);

printf("new file is %d\n", (int)st.st_ino);

Once you have created a file, you can open() and unlink() it by its returned
inode number retrieved from the stat call, ie:

fd = open("5", O_RDWR);

The creation permissions depend entirely if you have write access to the
root directory of the filesystem.

To get the list of currently allocated inodes, VOP_READDIR has been added
which returns a directory listing of those currently allocated.

--

What this entails:

* patching conf/files and conf/options to include IFS as a new compile
  option (and since ifs depends upon FFS, include the FFS routines)

* An entry in i386/conf/NOTES indicating IFS exists and where to go for
  an explanation

* Unstaticize a couple of routines in src/sys/ufs/ffs/ which the IFS
  routines require (ffs_mount() and ffs_reload())

* a new bunch of routines in src/sys/ufs/ifs/ which implement the IFS
  routines. IFS replaces some of the vfsops, and a handful of vnops -
  most notably are VFS_VGET(), VOP_LOOKUP(), VOP_UNLINK() and VOP_READDIR().
  Any other directory operation is marked as invalid.

What this results in:

* an IFS partition's create permissions are controlled by the perm/ownership of
  the root mount point, just like a normal directory

* Each inode has perm and ownership too

* IFS does *NOT* mean an FFS partition can be opened per inode. This is a
  completely seperate filesystem here

* Softupdates doesn't work with IFS, and really I don't think it needs it.
  Besides, fsck's are FAST. (Try it :-)

* Inodes 0 and 1 aren't allocatable because they are special (dump/swap IIRC).
  Inode 2 isn't allocatable since UFS/FFS locks all inodes in the system against
  this particular inode, and unravelling THAT code isn't trivial. Therefore,
  useful inodes start at 3.

Enjoy, and feedback is definitely appreciated!
2000-10-14 03:02:30 +00:00

255 lines
7.3 KiB
C

/*
* Copyright (c) 1999, 2000
* Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95
* $FreeBSD$
*/
#include <machine/limits.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/namei.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ffs/fs.h>
#include <ufs/ifs/ifs_extern.h>
/* true if old FS format...*/
#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
/* Define if you want my debug printfs inside ifs_lookup() */
#undef DEBUG_IFS_LOOKUP
#ifdef DEBUG_IFS_LOOKUP
static char *
getnameiopstr(int nameiop)
{
switch (nameiop) {
case LOOKUP:
return "LOOKUP";
break;
case CREATE:
return "CREATE";
break;
case DELETE:
return "DELETE";
break;
case RENAME:
return "RENAME";
break;
default:
return "unknown";
break;
}
}
#endif
/*
* Convert a path to an inode.
*
* This is HIGHLY simplified - we just take the path fragment given to us,
* attempt to convert it to an inode, and return the inode if we can.
* No permission checking is done here, that is done further up in the
* VFS call layers.
*/
int
ifs_lookup(ap)
struct vop_lookup_args /* {
struct vnode *a_dvp;
struct vnode **a_vpp;
struct componentname *a_cnp;
} */ *ap;
{
struct vnode *vdp; /* vnode for directory being searched */
struct inode *dp; /* inode for directory being searched */
struct vnode *pdp; /* saved dp during symlink work */
struct vnode *tdp; /* returned by VFS_VGET */
struct vnode **vpp = ap->a_vpp;
struct componentname *cnp = ap->a_cnp;
struct ucred *cred = cnp->cn_cred;
struct mount *mp = ap->a_dvp->v_mount;
struct fs *fs = VFSTOUFS(mp)->um_fs;
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
int error, lockparent, wantparent;
struct proc *p = cnp->cn_proc;
ufs_daddr_t inodenum;
char *endp;
*vpp = NULL;
lockparent = flags & LOCKPARENT;
wantparent = flags & (LOCKPARENT|WANTPARENT);
vdp = ap->a_dvp;
dp = VTOI(vdp);
pdp = vdp;
/*
* Firstly, we are NOT dealing with RENAME, at all
*/
if (nameiop == RENAME) {
*vpp = NULL;
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): Denying RENAME nameiop\n");
#endif
return (EPERM);
}
/* Deal with the '.' directory */
/* VOP_UNLOCK(vdp, 0, p); */
if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
/* We don't unlock the parent dir since the're the same */
*vpp = vdp;
VREF(vdp);
/* vn_lock(vdp, LK_SHARED | LK_RETRY, p); */
return (0);
}
/*
* 'newfile' is considered something special .. read below why
* we're returning NULL
*/
if ((cnp->cn_namelen) == 7 && (strncmp(cnp->cn_nameptr, "newfile", 7) == 0)) {
if (nameiop == CREATE) {
/* Check for write permissions in . */
error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
if (error)
return (error);
*vpp = NULL;
if (!lockparent || !(flags & ISLASTCN))
VOP_UNLOCK(pdp, 0, p);
cnp->cn_flags |= SAVENAME;
return (EJUSTRETURN);
} else {
*vpp = NULL;
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): Denying !CREATE on 'newfile'\n");
#endif
return (EPERM);
}
}
/* Grab the hex inode number */
inodenum = strtouq(cnp->cn_nameptr, &endp, 0);
/* Sanity Check */
if (endp != (cnp->cn_nameptr + cnp->cn_namelen)) {
*vpp = NULL;
return (ENOENT);
}
/*
* error check here - inodes 0-2 are considered 'special' even here
* so we will hide it from the user.
*/
if (inodenum <= 2) {
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): Access to disk inode '%d' denied\n",
(int)inodenum);
#endif
return EPERM;
}
/* Check we haven't overflowed the number of inodes in the fs */
if (inodenum > (fs->fs_ncg * fs->fs_ipg)) {
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): disk inode '%d' is outside the disk\n"),
(int)inodenum);
#endif
return EINVAL;
}
/*
* The next bit of code grabs the inode, checks to see whether
* we're allowed to do our nameiop on it. The only one we need
* to check here is CREATE - only allow create on an inode
* that exists.
*
* Comment for VFS-newbies:
* read vn_open() - you'll learn that if you return a name here,
* it assumes you don't need to call VOP_CREATE. Bad juju as
* you now have a vnode that isn't tagged with the right type,
* and it'll panic in the VOP_READ/VOP_WRITE routines..
*/
/*
* If we get here and its a CREATE, then return EPERM if the inode
* doesn't exist.
*/
if ((nameiop == CREATE) &&
(ifs_isinodealloc(VTOI(vdp), inodenum) != IFS_INODE_ISALLOC)) {
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): CREATE on inode %d which doesn't exist\n",
(int)inodenum);
#endif
return EPERM;
#ifdef DEBUG_IFS_LOOKUP
} else if (nameiop == CREATE) {
/* It does exist, allow CREATE */
printf("ifs_lookup(): CREATE on inode %d which exists\n",
(int)inodenum);
}
#else
}
#endif
/*
* Make sure that the inode exists if we're trying to delete or
* modify
*/
if ((nameiop == LOOKUP || nameiop == DELETE) &&
ifs_isinodealloc(VTOI(vdp), inodenum) != IFS_INODE_ISALLOC) {
/* it doesn't exist */
#ifdef DEBUG_IFS_LOOKUP
printf("ifs_lookup(): Inode %d isn't allocated\n", inodenum);
#endif
return ENOENT;
}
/* Now, we can get the vnode */
error = VFS_VGET(vdp->v_mount, (long)inodenum, &tdp);
if (error)
return (error);
if (!lockparent || !(flags & ISLASTCN))
VOP_UNLOCK(pdp, 0, p);
*vpp = tdp;
return (0);
}