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

📄 ufs_lookup.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * If rewriting (RENAME), return the inode and the	 * information required to rewrite the present directory	 * Must get inode of directory entry to verify it's a	 * regular file, or empty directory.	 */	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 == dp->i_ino)			return (EISDIR);		if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp))			return (error);		*vpp = tdp;		cnp->cn_flags |= SAVENAME;		if (!lockparent)			VOP_UNLOCK(vdp);		return (0);	}	/*	 * 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	 * 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 VFS_VGET for the	 * inode associated with ".." returns.  We hope that this occurs	 * infrequently since we cannot 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.	 */	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);		}		*vpp = tdp;	} else if (dp->i_number == dp->i_ino) {		VREF(vdp);	/* we want ourself, ie "." */		*vpp = vdp;	} else {		if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp))			return (error);		if (!lockparent || !(flags & ISLASTCN))			VOP_UNLOCK(pdp);		*vpp = tdp;	}	/*	 * Insert name into cache if appropriate.	 */	if (cnp->cn_flags & MAKEENTRY)		cache_enter(vdp, *vpp, cnp);	return (0);}voidufs_dirbad(ip, offset, how)	struct inode *ip;	doff_t offset;	char *how;{	struct mount *mp;	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");}/* * Do consistency checking on a directory entry: *	record length must be multiple of 4 *	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 */intufs_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(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 * 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. */intufs_direnter(ip, dvp, cnp)	struct inode *ip;	struct vnode *dvp;	register struct componentname *cnp;{	register struct direct *ep, *nep;	register struct inode *dp;	struct buf *bp;	struct direct newdir;	struct iovec aiov;	struct uio auio;	u_int dsize;	int error, loc, newentrysize, spacefree;	char *dirbuf;#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 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 (dp->i_offset & (DIRBLKSIZ - 1))			panic("ufs_direnter: newblk");		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);			dp->i_flag |= IN_CHANGE;		}		return (error);	}	/*	 * 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.	 */	/*	 * 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 (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 = 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 dp->i_offset to	 * dp->i_offset + dp->i_count would yield the	 * space.	 */	ep = (struct direct *)dirbuf;	dsize = DIRSIZ(FSFMT(dvp), ep);	spacefree = ep->d_reclen - dsize;	for (loc = ep->d_reclen; loc < dp->i_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(FSFMT(dvp), 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("ufs_direnter: compact1");		newdir.d_reclen = spacefree + dsize;	} else {		if (spacefree < newentrysize)			panic("ufs_direnter: compact2");		newdir.d_reclen = spacefree;		ep->d_reclen = dsize;		ep = (struct direct *)((char *)ep + dsize);	}	bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);	error = VOP_BWRITE(bp);	dp->i_flag |= IN_CHANGE | IN_UPDATE;	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 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 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. */intufs_dirremove(dvp, cnp)	struct vnode *dvp;	struct componentname *cnp;{	register struct inode *dp;	struct direct *ep;	struct buf *bp;	int error;	dp = VTOI(dvp);	if (dp->i_count == 0) {		/*		 * First entry in block: set d_ino to zero.		 */		if (error =		    VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp))			return (error);		ep->d_ino = 0;		error = VOP_BWRITE(bp);		dp->i_flag |= IN_CHANGE | IN_UPDATE;		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 |= IN_CHANGE | IN_UPDATE;	return (error);}/* * 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. */intufs_dirrewrite(dp, ip, cnp)	struct inode *dp, *ip;	struct componentname *cnp;{	struct buf *bp;	struct direct *ep;	struct vnode *vdp = ITOV(dp);	int error;	if (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp))		return (error);	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 |= IN_CHANGE | IN_UPDATE;	return (error);}/* * 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. */intufs_dirempty(ip, parentino, cred)	register struct inode *ip;	ino_t parentino;	struct ucred *cred;{	register off_t off;	struct dirtemplate dbuf;	register struct direct *dp = (struct direct *)&dbuf;	int error, count, namlen;#define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)	for (off = 0; off < ip->i_size; off += dp->d_reclen) {		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.		 */		if (error || count != 0)			return (0);		/* avoid infinite loops */		if (dp->d_reclen == 0)			return (0);		/* skip empty entries */		if (dp->d_ino == 0)			continue;		/* accept only "." and ".." */#		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 namlen must be 1 or 2.		 * 1 implies ".", 2 implies ".." if second		 * char is also "."		 */		if (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 vput before returning. */intufs_checkpath(source, target, cred)	struct inode *source, *target;	struct ucred *cred;{	struct vnode *vp;	int error, rootino, namlen;	struct dirtemplate dirbuf;	vp = ITOV(target);	if (target->i_number == source->i_number) {		error = EEXIST;		goto out;	}	rootino = ROOTINO;	error = 0;	if (target->i_number == rootino)		goto out;	for (;;) {		if (vp->v_type != VDIR) {			error = ENOTDIR;			break;		}		error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,			sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,			IO_NODELOCKED, cred, (int *)0, (struct proc *)0);		if (error != 0)			break;#		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;			break;		}		if (dirbuf.dotdot_ino == source->i_number) {			error = EINVAL;			break;		}		if (dirbuf.dotdot_ino == rootino)			break;		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 (vp != NULL)		vput(vp);	return (error);}

⌨️ 快捷键说明

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