⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ufs_namei.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
	 */        /* remove from LRU chain */	*ncp->nc_prev = ncp->nc_nxt;	if (ncp->nc_nxt)		ncp->nc_nxt->nc_prev = ncp->nc_prev;	else		nchtail = ncp->nc_prev;	/* remove from hash chain */	remque(ncp);	/* insert at head of LRU list (first to grab) */	ncp->nc_nxt = nchhead;	ncp->nc_prev = &nchhead;	nchhead->nc_prev = &ncp->nc_nxt;	nchhead = ncp;	/* and make a dummy hash chain */	ncp->nc_forw = ncp;	ncp->nc_back = ncp;	ncp->nc_id = 0;}dirbad(gp, offset, how)	struct gnode *gp;	off_t offset;	char *how;{	printf("%s: bad dir ino %d at offset %d: %s\n",	    FS(gp)->fs_fsmnt, gp->g_number, offset, how);}/* * Do consistency checking on a directory entry: *	record length must be multiple of 4 *	record length must not be non-negative *	entry must fit in rest of its DIRBLKSIZ block *	record must be large enough to contain entry *	name is not longer than MAXNAMLEN *	name must be as long as advertised, and null terminated */dirbadentry(ep, entryoffsetinblock)	register struct direct *ep;	int entryoffsetinblock;{	register int i;	if ((ep->d_reclen & 0x3) != 0 || ep->d_reclen <= 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);	return (ep->d_name[i]);}/* * Write a directory entry after a call to namei, using the parameters * which it left in the u. area.  The argument gp is the inode which * the new directory entry will refer to.  The u. area field ndp->ni_pdir 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. */direnter(gp, ndp)	struct gnode *gp;	register struct nameidata *ndp;{	register struct direct *ep, *nep;	register struct gnode *dp = (struct gnode *)ndp->ni_pdir;	struct buf *bp;	int loc, spacefree, error = 0;	u_int dsize;	int newentrysize;	char *dirbuf;	char *tcp;	gassert(dp);	/*	 * If POSIX, make sure non directory entries being	 * added do not have trailing slashes.	 */	if (u.u_procp->p_progenv == A_POSIX) {		if ((gp->g_mode & GFMT) != GFDIR) {			tcp = ndp->ni_dirp;			while (*tcp)				tcp++;			tcp--;			if (*tcp == '/') {				gput(dp);				u.u_error = ENOTDIR;				return (u.u_error);			}		}	}	ndp->ni_dent.d_ino = gp->g_number;	newentrysize = DIRSIZ(&ndp->ni_dent);	if (ndp->ni_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 (ndp->ni_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, 1, (int *)0);		if (DIRBLKSIZ > FS(dp)->fs_fsize)			panic("wdir: blksize"); /* XXX - should grow w/bmap() */		else			dp->g_size = roundup(dp->g_size, DIRBLKSIZ);		gput(dp);		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.	 */	/*	 * Increase size of directory if entry eats into new space.	 * This should never push the size past a new multiple of	 * DIRBLKSIZE.	 *	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.	 */	if (ndp->ni_offset + ndp->ni_count > dp->g_size)		dp->g_size = ndp->ni_offset + ndp->ni_count;	/*	 * Get the block containing the space for the new directory	 * entry.  Should return error by result instead of u.u_error.	 */	bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf);	if (bp == 0) {		gput(dp);		return (u.u_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.	 */	ep = (struct direct *)dirbuf;	dsize = DIRSIZ(ep);	spacefree = ep->d_reclen - dsize;	for (loc = ep->d_reclen; loc < ndp->ni_count; ) {		nep = (struct direct *)(dirbuf + loc);		if (ep->d_ino) {			/* trim the existing slot */			ep->d_reclen = dsize;			ep = (struct direct *)((char *)ep + dsize);		} else {			/* overwrite; nothing there; header is ours */			spacefree += dsize;			}		dsize = DIRSIZ(nep);		spacefree += nep->d_reclen - dsize;		loc += nep->d_reclen;		bcopy((caddr_t)nep, (caddr_t)ep, dsize);	}	/*	 * Update the pointer fields in the previous entry (if any),	 * copy in the new entry, and write out the block.	 */	if (ep->d_ino == 0) {		if (spacefree + dsize < newentrysize)			panic("wdir: compact1");		ndp->ni_dent.d_reclen = spacefree + dsize;	} else {		if (spacefree < newentrysize)			panic("wdir: compact2");		ndp->ni_dent.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);	bwrite(bp);	dp->g_flag |= GUPD|GCHG;	if (ndp->ni_endoff && ndp->ni_endoff < dp->g_size)		ufs_gtrunc(dp, (u_long) ndp->ni_endoff, (struct ucred *) 0);	gput(dp);	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 * 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 * 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;{	register struct gnode *dp = (struct gnode *)ndp->ni_pdir;	register struct buf *bp;	struct direct *ep;	gassert(dp);	if (ndp->ni_count == 0) {		/*		 * First entry in block: set d_ino to zero.		 */		ndp->ni_dent.d_ino = 0;		(void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,		    (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);	} else {		/*		 * Collapse new free space into previous entry.		 */		bp = blkatoff(dp, (int)(ndp->ni_offset - ndp->ni_count),			(char **)&ep);		if (bp == 0)			return (0);		ep->d_reclen += ndp->ni_dent.d_reclen;		bwrite(bp);		dp->g_flag |= GUPD|GCHG;	}	return (1);}/* * Rewrite an existing directory entry to point at the inode * supplied.  The parameters describing the directory entry are * set up by a call to namei. */dirrewrite(dp, gp, ndp)	struct gnode *dp, *gp;	struct nameidata *ndp;{	char *tcp;	/*	 * If POSIX, make sure non directory entries being	 * added do not have trailing slashes.	 */	if (u.u_procp->p_progenv == A_POSIX) {		if ((gp->g_mode & GFMT) != GFDIR) {			tcp = ndp->ni_dirp;			while (*tcp)				tcp++;			tcp--;			if (*tcp == '/') {				gput(dp);				u.u_error = ENOTDIR;				return (u.u_error);			}		}	}	ndp->ni_dent.d_ino = gp->g_number;	u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,		(int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);	gput(dp);}/* * Return buffer with contents of block "offset" * from the beginning of directory "gp".  If "res" * is non-zero, fill it in with a pointer to the * remaining space in the directory. */struct buf *blkatoff(gp, offset, res)	register struct gnode *gp;	register off_t offset;	char **res;{	register struct fs *fs = FS(gp);	register daddr_t lbn = lblkno(fs, offset);	register struct buf *bp;	register daddr_t bn;	int bsize = blksize(fs, gp, lbn);	bn = ufs_bmap(gp, (int)lbn, B_READ, bsize, 0, 0);	if (u.u_error)		return (0);	if (bn == (daddr_t)(-1)) {		dirbad(gp, offset, "hole in dir");		return (0);	}	bp = bread(gp->g_dev, bn, bsize, (struct gnode *) NULL);	if (bp->b_flags & B_ERROR) {		brelse(bp);		return (0);	}	if (res)		*res = bp->b_un.b_addr + blkoff(fs, offset);	return (bp);}/* * Check if a directory is empty or not. * Inode supplied must be locked. * * Using a struct dirtemplate here is not precisely * what we want, but better than using a struct direct. * * NB: does not handle corrupted directories. */dirempty(gp, parentino)	register struct gnode *gp;	gno_t parentino;{	register off_t off;	struct dirtemplate dbuf;	register struct direct *dp = (struct direct *)&dbuf;	int error, count;#define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)	for (off = 0; off < gp->g_size; off += dp->d_reclen) {		error = rdwri(UIO_READ, gp, (caddr_t)dp, MINDIRSIZ, 		    off, 1, &count);		/*		 * Since we read MINDIRSIZ, residual must		 * be 0 unless we're at end of file.		 */		if (error || count != 0) 			return (0);		if (dp->d_reclen <= 0)			return (0);		/* skip empty entries */		if (dp->d_ino == 0)			continue;		/* accept only "." and ".." */		if (dp->d_namlen > 2) 			return (0);		if (dp->d_name[0] != '.') 			return (0);		/*		 * At this point d_namlen must be 1 or 2.		 * 1 implies ".", 2 implies ".." if second		 * char is also "."		 */		if (dp->d_namlen == 1)			continue;		if (dp->d_name[1] == '.' && dp->d_ino == parentino)			continue;		return (0);	}	return (1);}/* * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. * The target is always gput() before returning. *//* this routine is ok for it's purposes.  it should eventually go away * since it is only used by rename */checkpath(source, target, flag)	struct gnode *source, *target;	int flag;{	struct dirtemplate dirbuf;	register struct gnode *gp;	int error = 0;	gp = target;	gassert(gp);	if (gp->g_number == source->g_number) {		/*		 * This condition used to return EEXIST. However,		 * ufs_rename is the only invoker, and it called		 * with target being a parent directory of the		 * target_gp. This condition matches the EINVAL		 * return below during the first iteration of the		 * for loop. So we will return EINVAL.		 */		error = EINVAL;		goto out;	}	if (gp->g_number == ROOTINO)		goto out;	for (;;) {		if ((gp->g_mode&GFMT) != GFDIR) {			error = ENOTDIR;			break;		}		error = rdwri(UIO_READ, gp, (caddr_t)&dirbuf,			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);		if (error != 0)			break;		if (dirbuf.dotdot_namlen != 2 ||		    dirbuf.dotdot_name[0] != '.' ||		    dirbuf.dotdot_name[1] != '.') {			error = ENOTDIR;			break;		}		if (dirbuf.dotdot_ino == source->g_number) {			error = EINVAL;			break;		}		if (dirbuf.dotdot_ino == ROOTINO)			break;		gput(gp);		gp = (struct gnode *)gget(gp->g_mp, dirbuf.dotdot_ino, 					  flag, NULL);		if (gp == NULL) {			error = u.u_error;			break;		}	}out:	if (error == ENOTDIR)		printf("checkpath: .. not a directory\n");	if (gp != NULL)		gput(gp);	return (error);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -