X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/7604aef44a5e70c254cbf42aa87dccac42aee338..e3b1aef51b44c1dabf00fbf91603d9a4cc7c56a9:/usr/src/sys/ufs/ffs/ufs_lookup.c diff --git a/usr/src/sys/ufs/ffs/ufs_lookup.c b/usr/src/sys/ufs/ffs/ufs_lookup.c index 08f88bd2eb..17572c4855 100644 --- a/usr/src/sys/ufs/ffs/ufs_lookup.c +++ b/usr/src/sys/ufs/ffs/ufs_lookup.c @@ -2,32 +2,32 @@ * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% * - * @(#)ufs_lookup.c 7.7 (Berkeley) %G% + * @(#)ufs_lookup.c 7.52 (Berkeley) %G% */ -#include "param.h" -#include "user.h" -#include "buf.h" -#include "file.h" -#include "vnode.h" -#include "../ufs/inode.h" -#include "../ufs/fs.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include -struct vnode *cache_lookup(); struct nchstats nchstats; +#ifdef DIAGNOSTIC int dirchk = 1; +#else +int dirchk = 0; +#endif + +#define FSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) /* * Convert a component of a pathname into a pointer to a locked inode. @@ -35,16 +35,16 @@ int dirchk = 1; * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation (see comments in code below). * - * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on - * whether the name is to be looked up, created, renamed, or deleted. + * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending + * on whether the name is to be looked up, created, renamed, or deleted. * When CREATE, RENAME, or DELETE is specified, information usable in * creating, renaming, or deleting a directory entry may be calculated. * If flag has LOCKPARENT or'ed into it and the target of the pathname * exists, lookup returns both the target and its parent directory locked. * When creating or renaming and LOCKPARENT is specified, the target may * not be ".". When deleting and LOCKPARENT is specified, the target may - * be "."., but the caller must check to ensure it does an vrele and iput - * instead of two iputs. + * be "."., but the caller must check to ensure it does an vrele and vput + * instead of two vputs. * * Overall outline of ufs_lookup: * @@ -64,46 +64,54 @@ int dirchk = 1; * * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. */ -ufs_lookup(vp, ndp) - struct vnode *vp; - register struct nameidata *ndp; +int +ufs_lookup(ap) + struct vop_lookup_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + } */ *ap; { - register struct vnode *vdp; /* vnode copy of dp */ - register struct inode *dp = 0; /* the directory we are searching */ - register struct fs *fs; /* file system that directory is in */ - struct buf *bp = 0; /* a buffer of directory entries */ + register struct vnode *vdp; /* vnode for directory being searched */ + register struct inode *dp; /* inode for directory being searched */ + struct buf *bp; /* a buffer of directory entries */ register struct direct *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer */ enum {NONE, COMPACT, FOUND} slotstatus; - int slotoffset = -1; /* offset of area with free space */ + doff_t slotoffset; /* offset of area with free space */ int slotsize; /* size of area at slotoffset */ int slotfreespace; /* amount of space free in slot */ int slotneeded; /* size of the entry we're seeking */ int numdirpasses; /* strategy for directory search */ - int endsearch; /* offset to end directory search */ - int prevoff; /* ndp->ni_offset of previous entry */ - struct inode *pdp; /* saved dp during symlink work */ - struct inode *tdp; /* returned by iget */ - off_t enduseful; /* pointer past last used dir slot */ - int flag; /* LOOKUP, CREATE, RENAME, or DELETE */ + doff_t endsearch; /* offset to end directory search */ + doff_t prevoff; /* prev entry dp->i_offset */ + struct vnode *pdp; /* saved dp during symlink work */ + struct vnode *tdp; /* returned by VFS_VGET */ + doff_t enduseful; /* pointer past last used dir slot */ + u_long bmask; /* block offset mask */ int lockparent; /* 1 => lockparent flag is set */ int wantparent; /* 1 => wantparent or lockparent flag */ - int error; - - ndp->ni_dvp = vp; - ndp->ni_vp = NULL; - dp = VTOI(vp); - fs = dp->i_fs; - lockparent = ndp->ni_nameiop & LOCKPARENT; - flag = ndp->ni_nameiop & OPFLAG; - wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); + int namlen, error; + struct vnode **vpp = ap->a_vpp; + struct componentname *cnp = ap->a_cnp; + struct ucred *cred = cnp->cn_cred; + int flags = cnp->cn_flags; + int nameiop = cnp->cn_nameiop; + + bp = NULL; + slotoffset = -1; + *vpp = NULL; + vdp = ap->a_dvp; + dp = VTOI(vdp); + lockparent = flags & LOCKPARENT; + wantparent = flags & (LOCKPARENT|WANTPARENT); /* * Check accessiblity of directory. */ - if ((dp->i_mode&IFMT) != IFDIR) + if ((dp->i_mode & IFMT) != IFDIR) return (ENOTDIR); - if (error = iaccess(dp, IEXEC, ndp->ni_cred)) + if (error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) return (error); /* @@ -113,25 +121,49 @@ ufs_lookup(vp, ndp) * check the name cache to see if the directory/name pair * we are looking for is known already. */ - if (vdp = cache_lookup(ndp)) { + if (error = cache_lookup(vdp, vpp, cnp)) { + int vpid; /* capability number of vnode */ + + if (error == ENOENT) + return (error); /* * Get the next vnode in the path. - * See comment above `IUNLOCK' code for + * See comment below starting `Step through' for * an explaination of the locking protocol. */ - pdp = dp; - dp = VTOI(vdp); - if (pdp == dp) { - vdp->v_count++; - } else if (ndp->ni_isdotdot) { - IUNLOCK(pdp); - igrab(dp); + pdp = vdp; + dp = VTOI(*vpp); + vdp = *vpp; + vpid = vdp->v_id; + if (pdp == vdp) { /* lookup on "." */ + VREF(vdp); + error = 0; + } else if (flags & ISDOTDOT) { + VOP_UNLOCK(pdp); + error = vget(vdp); + if (!error && lockparent && (flags & ISLASTCN)) + error = VOP_LOCK(pdp); } else { - igrab(dp); - IUNLOCK(pdp); + error = vget(vdp); + if (!lockparent || error || !(flags & ISLASTCN)) + VOP_UNLOCK(pdp); } - ndp->ni_vp = vdp; - return (0); + /* + * Check that the capability number did not change + * while we were waiting for the lock. + */ + if (!error) { + if (vpid == vdp->v_id) + return (0); + vput(vdp); + if (lockparent && pdp != vdp && (flags & ISLASTCN)) + VOP_UNLOCK(pdp); + } + if (error = VOP_LOCK(pdp)) + return (error); + vdp = pdp; + dp = VTOI(pdp); + *vpp = NULL; } /* @@ -141,10 +173,12 @@ ufs_lookup(vp, ndp) * case it doesn't already exist. */ slotstatus = FOUND; - if ((flag == CREATE || flag == RENAME) && *ndp->ni_next == 0) { + slotfreespace = slotsize = slotneeded = 0; + if ((nameiop == CREATE || nameiop == RENAME) && + (flags & ISLASTCN)) { slotstatus = NONE; - slotfreespace = 0; - slotneeded = DIRSIZ(&ndp->ni_dent); + slotneeded = (sizeof(struct direct) - MAXNAMLEN + + cnp->cn_namelen + 3) &~ 3; } /* @@ -158,35 +192,35 @@ ufs_lookup(vp, ndp) * profiling time and hence has been removed in the interest * of simplicity. */ - if (flag != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) { - ndp->ni_offset = 0; + bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + if (nameiop != LOOKUP || dp->i_diroff == 0 || + dp->i_diroff > dp->i_size) { + entryoffsetinblock = 0; + dp->i_offset = 0; numdirpasses = 1; } else { - ndp->ni_offset = dp->i_diroff; - entryoffsetinblock = blkoff(fs, ndp->ni_offset); - if (entryoffsetinblock != 0) { - error = blkatoff(dp, ndp->ni_offset, (char **)0, &bp); - if (error) - return (error); - } + dp->i_offset = dp->i_diroff; + if ((entryoffsetinblock = dp->i_offset & bmask) && + (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) + return (error); numdirpasses = 2; nchstats.ncs_2passes++; } + prevoff = dp->i_offset; endsearch = roundup(dp->i_size, DIRBLKSIZ); enduseful = 0; searchloop: - while (ndp->ni_offset < endsearch) { + while (dp->i_offset < endsearch) { /* - * If offset is on a block boundary, - * read the next directory block. - * Release previous if it exists. + * If offset is on a block boundary, read the next directory + * block. Release previous if it exists. */ - if (blkoff(fs, ndp->ni_offset) == 0) { + if ((dp->i_offset & bmask) == 0) { if (bp != NULL) brelse(bp); - error = blkatoff(dp, ndp->ni_offset, (char **)0, &bp); - if (error) + if (error = + VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) return (error); entryoffsetinblock = 0; } @@ -208,12 +242,12 @@ searchloop: */ ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); if (ep->d_reclen == 0 || - dirchk && dirbadentry(ep, entryoffsetinblock)) { + dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock)) { int i; - dirbad(dp, ndp->ni_offset, "mangled entry"); + ufs_dirbad(dp, dp->i_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); - ndp->ni_offset += i; + dp->i_offset += i; entryoffsetinblock += i; continue; } @@ -228,19 +262,19 @@ searchloop: int size = ep->d_reclen; if (ep->d_ino != 0) - size -= DIRSIZ(ep); + size -= DIRSIZ(FSFMT(vdp), ep); if (size > 0) { if (size >= slotneeded) { slotstatus = FOUND; - slotoffset = ndp->ni_offset; + slotoffset = dp->i_offset; slotsize = ep->d_reclen; } else if (slotstatus == NONE) { slotfreespace += size; if (slotoffset == -1) - slotoffset = ndp->ni_offset; + slotoffset = dp->i_offset; if (slotfreespace >= slotneeded) { slotstatus = COMPACT; - slotsize = ndp->ni_offset + + slotsize = dp->i_offset + ep->d_reclen - slotoffset; } } @@ -251,25 +285,33 @@ searchloop: * Check for a name match. */ if (ep->d_ino) { - if (ep->d_namlen == ndp->ni_dent.d_namlen && - !bcmp(ndp->ni_ptr, ep->d_name, - (unsigned)ep->d_namlen)) { +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (vdp->v_mount->mnt_maxsymlinklen > 0) + namlen = ep->d_namlen; + else + namlen = ep->d_type; +# else + namlen = ep->d_namlen; +# endif + if (namlen == cnp->cn_namelen && + !bcmp(cnp->cn_nameptr, ep->d_name, + (unsigned)namlen)) { /* * Save directory entry's inode number and - * reclen in ndp->ni_dent, and release + * reclen in ndp->ni_ufs area, and release * directory buffer. */ - ndp->ni_dent.d_ino = ep->d_ino; - ndp->ni_dent.d_reclen = ep->d_reclen; + dp->i_ino = ep->d_ino; + dp->i_reclen = ep->d_reclen; brelse(bp); goto found; } } - prevoff = ndp->ni_offset; - ndp->ni_offset += ep->d_reclen; + prevoff = dp->i_offset; + dp->i_offset += ep->d_reclen; entryoffsetinblock += ep->d_reclen; if (ep->d_ino) - enduseful = ndp->ni_offset; + enduseful = dp->i_offset; } /* notfound: */ /* @@ -278,7 +320,7 @@ searchloop: */ if (numdirpasses == 2) { numdirpasses--; - ndp->ni_offset = 0; + dp->i_offset = 0; endsearch = dp->i_diroff; goto searchloop; } @@ -289,33 +331,34 @@ searchloop: * directory has not been removed, then can consider * allowing file to be created. */ - if ((flag == CREATE || flag == RENAME) && - *ndp->ni_next == 0 && dp->i_nlink != 0) { + if ((nameiop == CREATE || nameiop == RENAME) && + (flags & ISLASTCN) && dp->i_nlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ - if (error = iaccess(dp, IWRITE, ndp->ni_cred)) + if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) return (error); /* * Return an indication of where the new directory * entry should be put. If we didn't find a slot, - * then set ndp->ni_count to 0 indicating that the new - * slot belongs at the end of the directory. If we found - * a slot, then the new entry can be put in the range - * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) + * then set dp->i_count to 0 indicating + * that the new slot belongs at the end of the + * directory. If we found a slot, then the new entry + * can be put in the range from dp->i_offset to + * dp->i_offset + dp->i_count. */ if (slotstatus == NONE) { - ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ); - ndp->ni_count = 0; - enduseful = ndp->ni_offset; + dp->i_offset = roundup(dp->i_size, DIRBLKSIZ); + dp->i_count = 0; + enduseful = dp->i_offset; } else { - ndp->ni_offset = slotoffset; - ndp->ni_count = slotsize; + dp->i_offset = slotoffset; + dp->i_count = slotsize; if (enduseful < slotoffset + slotsize) enduseful = slotoffset + slotsize; } - ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ); + dp->i_endoff = roundup(enduseful, DIRBLKSIZ); dp->i_flag |= IUPD|ICHG; /* * We return with the directory locked, so that @@ -324,13 +367,22 @@ searchloop: * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. + * The pathname buffer is saved so that the name + * can be obtained later. * * NB - if the directory is unlocked, then this * information cannot be used. */ + cnp->cn_flags |= SAVENAME; if (!lockparent) - IUNLOCK(dp); + VOP_UNLOCK(vdp); + return (EJUSTRETURN); } + /* + * Insert name into cache (as non-existent) if appropriate. + */ + if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) + cache_enter(vdp, *vpp, cnp); return (ENOENT); found: @@ -340,9 +392,9 @@ found: * Check that directory length properly reflects presence * of this entry. */ - if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { - dirbad(dp, ndp->ni_offset, "i_size too small"); - dp->i_size = entryoffsetinblock + DIRSIZ(ep); + if (entryoffsetinblock + DIRSIZ(FSFMT(vdp), ep) > dp->i_size) { + ufs_dirbad(dp, dp->i_offset, "i_size too small"); + dp->i_size = entryoffsetinblock + DIRSIZ(FSFMT(vdp), ep); dp->i_flag |= IUPD|ICHG; } @@ -351,8 +403,8 @@ found: * If the final component of path name, save information * in the cache as to where the entry was found. */ - if (*ndp->ni_next == '\0' && flag == LOOKUP) - dp->i_diroff = ndp->ni_offset &~ (DIRBLKSIZ - 1); + if ((flags & ISLASTCN) && nameiop == LOOKUP) + dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); /* * If deleting, and at end of pathname, return @@ -361,47 +413,45 @@ found: * the directory (in ndp->ni_dvp), otherwise we go * on and lock the inode, being careful with ".". */ - if (flag == DELETE && *ndp->ni_next == 0) { + if (nameiop == DELETE && (flags & ISLASTCN)) { /* * Write access to directory required to delete files. */ - if (error = iaccess(dp, IWRITE, ndp->ni_cred)) + if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) return (error); /* - * Return pointer to current entry in ndp->ni_offset, + * Return pointer to current entry in dp->i_offset, * and distance past previous entry (if there - * is a previous entry in this block) in ndp->ni_count. - * Save directory inode pointer in ndp->ni_pdir for dirremove(). + * is a previous entry in this block) in dp->i_count. + * Save directory inode pointer in ndp->ni_dvp for dirremove(). */ - if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) - ndp->ni_count = 0; + if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) + dp->i_count = 0; else - ndp->ni_count = ndp->ni_offset - prevoff; - vdp = ITOV(dp); - if (dp->i_number == ndp->ni_dent.d_ino) { - vdp->v_count++; - } else { - pdp = dp; - if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) - return (error); - vdp = ITOV(tdp); - /* - * If directory is "sticky", then user must own - * the directory, or the file in it, else he - * may not delete it (unless he's root). This - * implements append-only directories. - */ - if ((pdp->i_mode & ISVTX) && - ndp->ni_cred->cr_uid != 0 && - ndp->ni_cred->cr_uid != pdp->i_uid && - tdp->i_uid != ndp->ni_cred->cr_uid) { - iput(tdp); - return (EPERM); - } + dp->i_count = dp->i_offset - prevoff; + if (dp->i_number == dp->i_ino) { + VREF(vdp); + *vpp = vdp; + return (0); } - ndp->ni_vp = vdp; + if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) + return (error); + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. + */ + if ((dp->i_mode & ISVTX) && + cred->cr_uid != 0 && + cred->cr_uid != dp->i_uid && + VTOI(tdp)->i_uid != cred->cr_uid) { + vput(tdp); + return (EPERM); + } + *vpp = tdp; if (!lockparent) - IUNLOCK(pdp); + VOP_UNLOCK(vdp); return (0); } @@ -411,25 +461,27 @@ found: * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ - if (flag == RENAME && wantparent && *ndp->ni_next == 0) { - if (error = iaccess(dp, IWRITE, ndp->ni_cred)) + if (nameiop == RENAME && wantparent && + (flags & ISLASTCN)) { + if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) return (error); /* * Careful about locking second inode. * This can only occur if the target is ".". */ - if (dp->i_number == ndp->ni_dent.d_ino) + if (dp->i_number == dp->i_ino) return (EISDIR); - if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) + if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) return (error); - ndp->ni_vp = ITOV(tdp); + *vpp = tdp; + cnp->cn_flags |= SAVENAME; if (!lockparent) - IUNLOCK(dp); + VOP_UNLOCK(vdp); return (0); } /* - * Step through the translation in the name. We do not `iput' the + * Step through the translation in the name. We do not `vput' the * directory because we may need it again if a symbolic link * is relative to the current directory. Instead we save it * unlocked as "pdp". We must get the target inode before unlocking @@ -447,42 +499,51 @@ found: * work if the file system has any hard links other than ".." * that point backwards in the directory structure. */ - pdp = dp; - if (ndp->ni_isdotdot) { - IUNLOCK(pdp); /* race to get the inode */ - if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) { - ILOCK(pdp); + pdp = vdp; + if (flags & ISDOTDOT) { + VOP_UNLOCK(pdp); /* race to get the inode */ + if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) { + VOP_LOCK(pdp); + return (error); + } + if (lockparent && (flags & ISLASTCN) && + (error = VOP_LOCK(pdp))) { + vput(tdp); return (error); } - ndp->ni_vp = ITOV(tdp); - } else if (dp->i_number == ndp->ni_dent.d_ino) { - vdp = ITOV(dp); - vdp->v_count++; /* we want ourself, ie "." */ - ndp->ni_vp = vdp; + *vpp = tdp; + } else if (dp->i_number == dp->i_ino) { + VREF(vdp); /* we want ourself, ie "." */ + *vpp = vdp; } else { - if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) + if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) return (error); - IUNLOCK(pdp); - ndp->ni_vp = ITOV(tdp); + if (!lockparent || !(flags & ISLASTCN)) + VOP_UNLOCK(pdp); + *vpp = tdp; } /* * Insert name into cache if appropriate. */ - if (ndp->ni_makeentry) - cache_enter(ndp); + if (cnp->cn_flags & MAKEENTRY) + cache_enter(vdp, *vpp, cnp); return (0); } - -dirbad(ip, offset, how) +void +ufs_dirbad(ip, offset, how) struct inode *ip; - off_t offset; + doff_t offset; char *how; { + struct mount *mp; - printf("%s: bad dir ino %d at offset %d: %s\n", - ip->i_fs->fs_fsmnt, ip->i_number, offset, how); + mp = ITOV(ip)->v_mount; + (void)printf("%s: bad dir ino %d at offset %d: %s\n", + mp->mnt_stat.f_mntonname, ip->i_number, offset, how); + if ((mp->mnt_stat.f_flags & MNT_RDONLY) == 0) + panic("bad dir"); } /* @@ -493,72 +554,124 @@ dirbad(ip, offset, how) * name is not longer than MAXNAMLEN * name must be as long as advertised, and null terminated */ -dirbadentry(ep, entryoffsetinblock) +int +ufs_dirbadentry(dp, ep, entryoffsetinblock) + struct vnode *dp; register struct direct *ep; int entryoffsetinblock; { register int i; + int namlen; +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (dp->v_mount->mnt_maxsymlinklen > 0) + namlen = ep->d_namlen; + else + namlen = ep->d_type; +# else + namlen = ep->d_namlen; +# endif if ((ep->d_reclen & 0x3) != 0 || ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || - ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) - return (1); - for (i = 0; i < ep->d_namlen; i++) - if (ep->d_name[i] == '\0') - return (1); + ep->d_reclen < DIRSIZ(FSFMT(dp), ep) || namlen > MAXNAMLEN) { + /*return (1); */ + printf("First bad\n"); + goto bad; + } + for (i = 0; i < namlen; i++) + if (ep->d_name[i] == '\0') { + /*return (1); */ + printf("Second bad\n"); + goto bad; + } + if (ep->d_name[i]) + goto bad; return (ep->d_name[i]); +bad: + return(1); } /* * Write a directory entry after a call to namei, using the parameters - * which it left in nameidata. The argument ip is the inode which the - * new directory entry will refer to. The nameidata field ndp->ni_dvp - * is a pointer to the directory to be written, which was left locked by - * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate - * how the space for the new entry is to be gotten. + * that it left in nameidata. The argument ip is the inode which the new + * directory entry will refer to. Dvp is a pointer to the directory to + * be written, which was left locked by namei. Remaining parameters + * (dp->i_offset, dp->i_count) indicate how the space for the new + * entry is to be obtained. */ -direnter(ip, ndp) +int +ufs_direnter(ip, dvp, cnp) struct inode *ip; - register struct nameidata *ndp; + struct vnode *dvp; + register struct componentname *cnp; { register struct direct *ep, *nep; - register struct inode *dp = VTOI(ndp->ni_dvp); + register struct inode *dp; struct buf *bp; - int loc, spacefree, error = 0; + struct direct newdir; + struct iovec aiov; + struct uio auio; u_int dsize; - int newentrysize; + int error, loc, newentrysize, spacefree; char *dirbuf; - ndp->ni_dent.d_ino = ip->i_number; - newentrysize = DIRSIZ(&ndp->ni_dent); - if (ndp->ni_count == 0) { +#ifdef DIAGNOSTIC + if ((cnp->cn_flags & SAVENAME) == 0) + panic("direnter: missing name"); +#endif + dp = VTOI(dvp); + newdir.d_ino = ip->i_number; + newdir.d_namlen = cnp->cn_namelen; + bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); + if (dvp->v_mount->mnt_maxsymlinklen > 0) + newdir.d_type = IFTODT(ip->i_mode); + else { + newdir.d_type = 0; +# if (BYTE_ORDER == LITTLE_ENDIAN) + { u_char tmp = newdir.d_namlen; + newdir.d_namlen = newdir.d_type; + newdir.d_type = tmp; } +# endif + } + newentrysize = DIRSIZ(FSFMT(dvp), &newdir); + if (dp->i_count == 0) { /* - * If ndp->ni_count is 0, then namei could find no space in the - * directory. In this case ndp->ni_offset will be on a directory - * block boundary and we will write the new entry into a fresh - * block. + * If dp->i_count is 0, then namei could find no + * space in the directory. Here, dp->i_offset will + * be on a directory block boundary and we will write the + * new entry into a fresh block. */ - if (ndp->ni_offset&(DIRBLKSIZ-1)) + if (dp->i_offset & (DIRBLKSIZ - 1)) panic("wdir: newblk"); - ndp->ni_dent.d_reclen = DIRBLKSIZ; - error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, - newentrysize, ndp->ni_offset, UIO_SYSSPACE, ndp->ni_cred, - (int *)0); - if (DIRBLKSIZ > dp->i_fs->fs_fsize) - panic("wdir: blksize"); /* XXX - should grow w/balloc */ - else + auio.uio_offset = dp->i_offset; + newdir.d_reclen = DIRBLKSIZ; + auio.uio_resid = newentrysize; + aiov.iov_len = newentrysize; + aiov.iov_base = (caddr_t)&newdir; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); + if (DIRBLKSIZ > + VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) + /* XXX should grow with balloc() */ + panic("ufs_direnter: frag size"); + else if (!error) { dp->i_size = roundup(dp->i_size, DIRBLKSIZ); - iput(dp); + dp->i_flag |= ICHG; + } return (error); } /* - * If ndp->ni_count is non-zero, then namei found space for the new - * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count. - * in the directory. To use this space, we may have to compact - * the entries located there, by copying them together towards - * the beginning of the block, leaving the free space in - * one usable chunk at the end. + * If dp->i_count is non-zero, then namei found space + * for the new entry in the range dp->i_offset to + * dp->i_offset + dp->i_count in the directory. + * To use this space, we may have to compact the entries located + * there, by copying them together towards the beginning of the + * block, leaving the free space in one usable chunk at the end. */ /* @@ -568,25 +681,24 @@ direnter(ip, ndp) * * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. */ - if (ndp->ni_offset + ndp->ni_count > dp->i_size) - dp->i_size = ndp->ni_offset + ndp->ni_count; + if (dp->i_offset + dp->i_count > dp->i_size) + dp->i_size = dp->i_offset + dp->i_count; /* * Get the block containing the space for the new directory entry. */ - if (error = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf, &bp)) { - iput(dp); + if (error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) return (error); - } /* - * Find space for the new entry. In the simple case, the - * entry at offset base will have the space. If it does - * not, then namei arranged that compacting the region - * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space. + * Find space for the new entry. In the simple case, the entry at + * offset base will have the space. If it does not, then namei + * arranged that compacting the region dp->i_offset to + * dp->i_offset + dp->i_count would yield the + * space. */ ep = (struct direct *)dirbuf; - dsize = DIRSIZ(ep); + dsize = DIRSIZ(FSFMT(dvp), ep); spacefree = ep->d_reclen - dsize; - for (loc = ep->d_reclen; loc < ndp->ni_count; ) { + for (loc = ep->d_reclen; loc < dp->i_count; ) { nep = (struct direct *)(dirbuf + loc); if (ep->d_ino) { /* trim the existing slot */ @@ -596,7 +708,7 @@ direnter(ip, ndp) /* overwrite; nothing there; header is ours */ spacefree += dsize; } - dsize = DIRSIZ(nep); + dsize = DIRSIZ(FSFMT(dvp), nep); spacefree += nep->d_reclen - dsize; loc += nep->d_reclen; bcopy((caddr_t)nep, (caddr_t)ep, dsize); @@ -608,63 +720,67 @@ direnter(ip, ndp) if (ep->d_ino == 0) { if (spacefree + dsize < newentrysize) panic("wdir: compact1"); - ndp->ni_dent.d_reclen = spacefree + dsize; + newdir.d_reclen = spacefree + dsize; } else { if (spacefree < newentrysize) panic("wdir: compact2"); - ndp->ni_dent.d_reclen = spacefree; + newdir.d_reclen = spacefree; ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); } - bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize); - error = bwrite(bp); + bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize); + error = VOP_BWRITE(bp); dp->i_flag |= IUPD|ICHG; - if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size) - error = itrunc(dp, (u_long)ndp->ni_endoff); - iput(dp); + if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) + error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, + cnp->cn_cred, cnp->cn_proc); return (error); } /* - * Remove a directory entry after a call to namei, using the - * parameters which it left in the u. area. The u. entry - * ni_offset contains the offset into the directory of the - * entry to be eliminated. The ni_count field contains the + * Remove a directory entry after a call to namei, using + * the parameters which it left in nameidata. The entry + * dp->i_offset contains the offset into the directory of the + * entry to be eliminated. The dp->i_count field contains the * size of the previous record in the directory. If this * is 0, the first entry is being deleted, so we need only * zero the inode number to mark the entry as free. If the - * entry isn't the first in the directory, we must reclaim + * entry is not the first in the directory, we must reclaim * the space of the now empty record by adding the record size * to the size of the previous entry. */ -dirremove(ndp) - register struct nameidata *ndp; +int +ufs_dirremove(dvp, cnp) + struct vnode *dvp; + struct componentname *cnp; { - register struct inode *dp = VTOI(ndp->ni_dvp); + register struct inode *dp; struct direct *ep; struct buf *bp; int error; - if (ndp->ni_count == 0) { + dp = VTOI(dvp); + if (dp->i_count == 0) { /* * First entry in block: set d_ino to zero. */ - ndp->ni_dent.d_ino = 0; - error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, - (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, UIO_SYSSPACE, - ndp->ni_cred, (int *)0); - } else { - /* - * Collapse new free space into previous entry. - */ - if (error = blkatoff(dp, ndp->ni_offset - ndp->ni_count, - (char **)&ep, &bp)) { + if (error = + VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) return (error); - } - ep->d_reclen += ndp->ni_dent.d_reclen; - error = bwrite(bp); + ep->d_ino = 0; + error = VOP_BWRITE(bp); dp->i_flag |= IUPD|ICHG; + return (error); } + /* + * Collapse new free space into previous entry. + */ + if (error = VOP_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count), + (char **)&ep, &bp)) + return (error); + ep->d_reclen += dp->i_reclen; + error = VOP_BWRITE(bp); + dp->i_flag |= IUPD|ICHG; return (error); } @@ -673,55 +789,24 @@ dirremove(ndp) * supplied. The parameters describing the directory entry are * set up by a call to namei. */ -dirrewrite(dp, ip, ndp) +int +ufs_dirrewrite(dp, ip, cnp) struct inode *dp, *ip; - struct nameidata *ndp; + struct componentname *cnp; { - - ndp->ni_dent.d_ino = ip->i_number; - return (rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, - (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, UIO_SYSSPACE, - ndp->ni_cred, (int *)0)); -} - -/* - * Return buffer with contents of block "offset" - * from the beginning of directory "ip". If "res" - * is non-zero, fill it in with a pointer to the - * remaining space in the directory. - */ -blkatoff(ip, offset, res, bpp) - struct inode *ip; - off_t offset; - char **res; - struct buf **bpp; -{ - register struct fs *fs = ip->i_fs; - daddr_t lbn = lblkno(fs, offset); - int bsize = blksize(fs, ip, lbn); struct buf *bp; - daddr_t bn; + struct direct *ep; + struct vnode *vdp = ITOV(dp); int error; - *bpp = 0; - if (error = bmap(ip, lbn, &bn, (daddr_t *)0, (int *)0)) - return (error); - if (bn == (daddr_t)-1) { - dirbad(ip, offset, "hole in dir"); - return (EIO); - } -#ifdef SECSIZE - bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize, fs->fs_dbsize); -#else SECSIZE - error = bread(ip->i_devvp, bn, bsize, &bp); - if (error) { - brelse(bp); + if (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) return (error); - } - if (res) - *res = bp->b_un.b_addr + blkoff(fs, offset); - *bpp = bp; - return (0); + ep->d_ino = ip->i_number; + if (vdp->v_mount->mnt_maxsymlinklen > 0) + ep->d_type = IFTODT(ip->i_mode); + error = VOP_BWRITE(bp); + dp->i_flag |= IUPD|ICHG; + return (error); } /* @@ -733,7 +818,8 @@ blkatoff(ip, offset, res, bpp) * * NB: does not handle corrupted directories. */ -dirempty(ip, parentino, cred) +int +ufs_dirempty(ip, parentino, cred) register struct inode *ip; ino_t parentino; struct ucred *cred; @@ -741,12 +827,12 @@ dirempty(ip, parentino, cred) register off_t off; struct dirtemplate dbuf; register struct direct *dp = (struct direct *)&dbuf; - int error, count; + int error, count, namlen; #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) for (off = 0; off < ip->i_size; off += dp->d_reclen) { - error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ, off, - UIO_SYSSPACE, cred, &count); + error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, + UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); /* * Since we read MINDIRSIZ, residual must * be 0 unless we're at end of file. @@ -760,16 +846,24 @@ dirempty(ip, parentino, cred) if (dp->d_ino == 0) continue; /* accept only "." and ".." */ - if (dp->d_namlen > 2) +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) + namlen = dp->d_namlen; + else + namlen = dp->d_type; +# else + namlen = dp->d_namlen; +# endif + if (namlen > 2) return (0); if (dp->d_name[0] != '.') return (0); /* - * At this point d_namlen must be 1 or 2. + * At this point namlen must be 1 or 2. * 1 implies ".", 2 implies ".." if second * char is also "." */ - if (dp->d_namlen == 1) + if (namlen == 1) continue; if (dp->d_name[1] == '.' && dp->d_ino == parentino) continue; @@ -781,35 +875,46 @@ dirempty(ip, parentino, cred) /* * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. - * The target is always iput() before returning. + * The target is always vput before returning. */ -checkpath(source, target, cred) +int +ufs_checkpath(source, target, cred) struct inode *source, *target; struct ucred *cred; { + struct vnode *vp; + int error, rootino, namlen; struct dirtemplate dirbuf; - struct inode *ip; - int error = 0; - ip = target; - if (ip->i_number == source->i_number) { + vp = ITOV(target); + if (target->i_number == source->i_number) { error = EEXIST; goto out; } - if (ip->i_number == ROOTINO) + rootino = ROOTINO; + error = 0; + if (target->i_number == rootino) goto out; for (;;) { - if ((ip->i_mode&IFMT) != IFDIR) { + if (vp->v_type != VDIR) { error = ENOTDIR; break; } - error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, + error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, - cred, (int *)0); + IO_NODELOCKED, cred, (int *)0, (struct proc *)0); if (error != 0) break; - if (dirbuf.dotdot_namlen != 2 || +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (vp->v_mount->mnt_maxsymlinklen > 0) + namlen = dirbuf.dotdot_namlen; + else + namlen = dirbuf.dotdot_type; +# else + namlen = dirbuf.dotdot_namlen; +# endif + if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { error = ENOTDIR; @@ -819,17 +924,19 @@ checkpath(source, target, cred) error = EINVAL; break; } - if (dirbuf.dotdot_ino == ROOTINO) + if (dirbuf.dotdot_ino == rootino) break; - iput(ip); - if (error = iget(ip, dirbuf.dotdot_ino, &ip)) + vput(vp); + if (error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) { + vp = NULL; break; + } } out: if (error == ENOTDIR) printf("checkpath: .. not a directory\n"); - if (ip != NULL) - iput(ip); + if (vp != NULL) + vput(vp); return (error); }