ufs_lookup.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,062 行 · 第 1/3 页

C
1,062
字号
					 * Note that we wouldn't expect to					 * shrink the directory while rewriting					 * an existing entry anyway.					 */					enduseful = endsearch;					ap->a_cnp->cn_flags |= ISWHITEOUT;					numdirpasses--;					goto notfound;				}				dp->i_ino = ep->d_ino;				dp->i_reclen = ep->d_reclen;				brelse(bp);				goto found;			}		}		prevoff = dp->i_offset;		dp->i_offset += ep->d_reclen;		entryoffsetinblock += ep->d_reclen;		if (ep->d_ino)			enduseful = dp->i_offset;	}notfound:	/*	 * 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--;		dp->i_offset = 0;		endsearch = dp->i_diroff;		goto searchloop;	}	if (bp != NULL)		brelse(bp);	/*	 * If creating, and at end of pathname and current	 * directory has not been removed, then can consider	 * allowing file to be created.	 */	if ((nameiop == CREATE || nameiop == RENAME ||	     (nameiop == DELETE &&	      (ap->a_cnp->cn_flags & DOWHITEOUT) &&	      (ap->a_cnp->cn_flags & ISWHITEOUT))) &&	    (flags & ISLASTCN) && dp->i_nlink != 0) {		/*		 * Access for write is interpreted as allowing		 * creation of files in the directory.		 */		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);		if (error)			return (error);		/*		 * Return an indication of where the new directory		 * entry should be put.  If we didn't find a slot,		 * 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) {			dp->i_offset = roundup(dp->i_size, DIRBLKSIZ);			dp->i_count = 0;			enduseful = dp->i_offset;		} else if (nameiop == DELETE) {			dp->i_offset = slotoffset;			if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)				dp->i_count = 0;			else				dp->i_count = dp->i_offset - prevoff;		} else {			dp->i_offset = slotoffset;			dp->i_count = slotsize;			if (enduseful < slotoffset + slotsize)				enduseful = slotoffset + slotsize;		}		dp->i_endoff = roundup(enduseful, DIRBLKSIZ);		dp->i_flag |= IN_CHANGE | IN_UPDATE;		/*		 * We return with the directory locked, so that		 * the parameters we set up above will still be		 * valid if we actually decide to do a direnter().		 * 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)			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:	if (numdirpasses == 2)		nchstats.ncs_pass2++;	/*	 * Check that directory length properly reflects presence	 * of this entry.	 */	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 |= IN_CHANGE | IN_UPDATE;	}	/*	 * Found component in pathname.	 * If the final component of path name, save information	 * in the cache as to where the entry was found.	 */	if ((flags & ISLASTCN) && nameiop == LOOKUP)		dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);	/*	 * If deleting, and at end of pathname, return	 * parameters which can be used to remove file.	 * If the wantparent flag isn't set, we return only	 * the directory (in ndp->ni_dvp), otherwise we go	 * on and lock the inode, being careful with ".".	 */	if (nameiop == DELETE && (flags & ISLASTCN)) {		/*		 * Write access to directory required to delete files.		 */		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);		if (error)			return (error);		/*		 * Return pointer to current entry in dp->i_offset,		 * and distance past previous entry (if there		 * is a previous entry in this block) in dp->i_count.		 * Save directory inode pointer in ndp->ni_dvp for dirremove().		 */		if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)			dp->i_count = 0;		else			dp->i_count = dp->i_offset - prevoff;		if (dp->i_number == dp->i_ino) {			VREF(vdp);			*vpp = vdp;			return (0);		}		error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);		if (error)			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)			VOP_UNLOCK(vdp);		return (0);	}	/*	 * 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)) {		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);		if (error)			return (error);		/*		 * Careful about locking second inode.		 * This can only occur if the target is ".".		 */		if (dp->i_number == dp->i_ino)			return (EISDIR);		error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);		if (error)			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 */		error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);		if (error) {			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 {		error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);		if (error)			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;	}	if (ep->d_ino == 0)		return (0);	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 (0);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 inode *dp;	struct direct newdir;#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	}	return (ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc));}

⌨️ 快捷键说明

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