ufs_dir.c
来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 278 行
C
278 行
#ifndef lintstatic char sccsid[] = "@(#)ufs_dir.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. *//* * Directory manipulation routines. * From outside this file, only dirlook, direnter and dirremove * should be called. */#include <sys/param.h>#include "boot/systm.h"#include <sys/user.h>#include <sys/vfs.h>#include "boot/vnode.h"#include <sys/buf.h>#include <sys/uio.h>#include <sys/dnlc.h>#include "boot/inode.h"#include <ufs/fs.h>#include <ufs/mount.h>#include <ufs/fsdir.h>#ifdef QUOTA#include <ufs/quota.h>#endif#ifdef NFS_BOOT#include <mon/sunromvec.h>#undef uextern struct user u;static int dump_debug = 20;#endif /* NFS_BOOT *//* * A virgin directory. */struct dirtemplate mastertemplate = { 0, 12, 1, ".", 0, DIRBLKSIZ - 12, 2, ".."};#define LDIRSIZ(len) \ ((sizeof (struct direct) - (MAXNAMLEN+1)) + ((len+1 + 3) &~ 3))struct buf *blkatoff();int dirchk = 0;/* * Look for a certain name in a directory * On successful return, *ipp will point to the (locked) inode. */dirlook(dp, namep, ipp) register struct inode *dp; register char *namep; /* name */ register struct inode **ipp;{ register struct buf *bp = 0; /* a buffer of directory entries */ register struct direct *ep; /* the current directory entry */ register struct inode *ip; int entryoffsetinblock; /* offset of ep in bp's buffer */ int numdirpasses; /* strategy for directory search */ int endsearch; /* offset to end directory search */ int namlen = strlen(namep); /* length of name */ int offset; int error; register int i; /* * Check accessiblity of directory. */ if ((dp->i_mode&IFMT) != IFDIR) { dprint(dump_debug, 6, "dirlook: not a directory 0x%x\n", dp); return (ENOTDIR); } if (error = iaccess(dp, IEXEC)) { dprint(dump_debug, 6, "dirlook: no access 0x%x\n", dp); return (error); } ilock(dp); if (dp->i_diroff > dp->i_size) { dp->i_diroff = 0; } if (dp->i_diroff == 0) { offset = 0; numdirpasses = 1; } else { offset = dp->i_diroff; entryoffsetinblock = blkoff(dp->i_fs, offset); if (entryoffsetinblock != 0) { bp = blkatoff(dp, (off_t)offset, (char **)0); if (bp == 0) { error = u.u_error; goto bad; } } numdirpasses = 2; } endsearch = roundup(dp->i_size, DIRBLKSIZ);searchloop: while (offset < endsearch) { /* * If offset is on a block boundary, * read the next directory block. * Release previous if it exists. */ if (blkoff(dp->i_fs, offset) == 0) { if (bp != NULL) brelse(bp); bp = blkatoff(dp, (off_t)offset, (char **)0); if (bp == 0) { error = u.u_error; /* XXX */ goto bad; } entryoffsetinblock = 0; } ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); /* * Inline expansion of dirmangled for speed. */ i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 || ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen || dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep->d_name, (int)ep->d_namlen))) { dirbad(dp, "mangled entry", entryoffsetinblock); offset += i; entryoffsetinblock += i; continue; } /* * Check for a name match. * We must get the target inode before unlocking * the directory to insure that the inode will not be removed * before we get it. We prevent deadlock by always fetching * inodes from the root, moving down the directory tree. Thus * when following backward pointers ".." we must unlock the * parent directory before getting the requested directory. * There is a potential race condition here if both the current * and parent directories are removed before the `iget' for the * inode associated with ".." returns. We hope that this * occurs infrequently since we can't avoid this race condition * without implementing a sophisticated deadlock detection * algorithm. Note also that this simple deadlock detection * scheme will not work if the file system has any hard links * other than ".." that point backwards in the directory * structure. * See comments at head of file about deadlocks. */ if (ep->d_ino && ep->d_namlen == namlen && *namep == *ep->d_name && /* fast chk 1st chr */ bcmp(namep, ep->d_name, (int)ep->d_namlen) == 0) { dp->i_diroff = offset; if (namlen == 2 && namep[0] == '.' && namep[1] == '.') { iunlock(dp); /* race to get the inode */ ip = iget(dp->i_dev, dp->i_fs, ep->d_ino); if (ip == NULL) { error = u.u_error; goto bad2; } } else if (dp->i_number == ep->d_ino) { VN_HOLD(ITOV(dp)); /* want ourself, "." */ ip = dp; } else { ip = iget(dp->i_dev, dp->i_fs, ep->d_ino); iunlock(dp); if (ip == NULL) { error = u.u_error; goto bad2; } } *ipp = ip; dp->i_diroff = 0; brelse(bp); return (0); } offset += ep->d_reclen; entryoffsetinblock += ep->d_reclen; } /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; offset = 0; endsearch = dp->i_diroff; goto searchloop; } error = ENOENT;bad: iunlock(dp);bad2: if (bp) { dp->i_diroff = 0; brelse(bp); } return (error);}/* * 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. */struct buf *blkatoff(ip, offset, res) struct inode *ip; off_t offset; char **res;{ register struct fs *fs; daddr_t lbn; int bsize; daddr_t bn; register struct buf *bp; fs = ip->i_fs; lbn = lblkno(fs, offset); bsize = blksize(fs, ip, lbn); bn = fsbtodb(fs, bmap(ip, lbn, B_READ)); if (bn < 0) { dirbad(ip, "nonexixtent directory block", (int)offset); u.u_error = ENOENT; } if (u.u_error) { return (0); } bp = bread(ip->i_devvp, bn, bsize); if (bp->b_flags & B_ERROR) { brelse(bp); return (0); } if (res) *res = bp->b_un.b_addr + blkoff(fs, offset); return (bp);}dirbad(ip, how, offset) struct inode *ip; char *how; int offset;{ printf("%s: bad dir ino %d at offset %d: %s\n", ip->i_fs->fs_fsmnt, ip->i_number, offset, how);}dirbadname(sp, l) register char *sp; register int l;{ register char c; while (l--) { /* check for nulls or high bit */ c = *sp++; if ((c == 0) || (c & 0200)) { return (1); } } return (*sp); /* check for terminating null */}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?