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

📄 ufs_namei.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
					dp->g_flag |= GINCOMPLETE;					return(dp);				}				/*				 * 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 ((ndp->ni_pdir->g_mode & GSVTX) &&				    u.u_uid != 0 &&				    u.u_uid != ndp->ni_pdir->g_uid &&				    dp->g_uid != u.u_uid) {					gput(ndp->ni_pdir);					u.u_error = EPERM;					goto bad;				}				/*				 * POSIX check. Only directories can have				 * trailing slashes.				 */				if (((dp->g_mode & GFMT) != GFDIR) &&				     trailing_slashes) {					gput(ndp->ni_pdir);                                        u.u_error = ENOTDIR;                                        goto bad;                                }			}		}		/*		 * Check cache one more time		 */		smp_lock(&lk_namecache, LK_RETRY);del_again:		nhp = &nchash[NHASH(hash, (ndp->ni_pdir)->g_number, (ndp->ni_pdir)->g_dev)];		for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;		    ncp = ncp->nc_forw) {			if (ncp->nc_ino == (ndp->ni_pdir)->g_number &&			    ncp->nc_dev == (ndp->ni_pdir)->g_dev &&			    ncp->nc_nlen == ndp->ni_dent.d_namlen &&			    !bcmp(ncp->nc_name, ndp->ni_dent.d_name,				ncp->nc_nlen)) {				expunge_cache(ncp);				goto del_again;			}		}		smp_unlock(&lk_namecache);		dp->g_flag &= ~GINCOMPLETE;		ndp->ni_cp = cp;		return (dp);	}	/*	 * Special handling for ".." allowing chdir out of mounted	 * file system: indirect .. in root inode to reevaluate	 * in directory file system was mounted on.	 */	if (isdotdot) {		if (dp == u.u_rdir) {			ndp->ni_dent.d_ino = dp->g_number;			makeentry = 0;		} else if (ndp->ni_dent.d_ino == ROOTINO &&		   dp->g_number == ROOTINO) {			if(dp->g_dev == rootdev) {				while(*cp == '/')					cp++;				ndp->ni_pdir = dp = rootdir;				ndp->ni_cp = cp;				dp->g_flag &= ~GINCOMPLETE;				if(*cp)					goto dirloop2;				return(dp);			}			mp = dp->g_mp;			gput(dp);			dp = mp->m_gnodp;			gref(dp);			cp -= 2;     /* back over .. */			gfs_lock(dp);			if(dp->g_mp->m_fstype != GT_ULTRIX) {				ndp->ni_pdir = dp;				ndp->ni_cp = cp;				dp->g_flag |= GINCOMPLETE;				return(dp);			}			goto dirloop2;		}	}	/*	 * 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 ((flag == CREATE && lockparent) && *cp == 0) {		if (access(dp, GWRITE))			goto bad;		ndp->ni_pdir = dp;		/* for dirrewrite() */		/*		 * Careful about locking second inode. 		 * This can only occur if the target is ".". 		 */		if (dp->g_number == ndp->ni_dent.d_ino) {			u.u_error = EISDIR;		/* XXX */			goto bad;		}		dp = gget(dp->g_mp, ndp->ni_dent.d_ino, nomount, NULL);		if (dp == NULL) {			gput(ndp->ni_pdir);			goto bad;		}		if(dp->g_mp->m_fstype != GT_ULTRIX) {			ndp->ni_cp = cp;			gput(ndp->ni_pdir);			ndp->ni_pdir = dp;			dp->g_flag |= GINCOMPLETE;			return(dp);		}		if (((dp->g_mode & GFMT) != GFDIR) && trailing_slashes) {			gput(ndp->ni_pdir);			u.u_error = ENOTDIR;			goto bad;		}		dp->g_flag &= ~GINCOMPLETE;		ndp->ni_cp = cp;		return (dp);	}	/*	 * Put a partial entry into the hash chain. We do this	 * while we have the parent directory locked, in case	 * there is a DELETE waiting on the gnode. The DELETE process	 * could be blocked in two places. The first place is where	 * the cache is being searched. In this case the partial entry will	 * be expunged, and we will know not to complete the entry	 * further down. The second place where a DELETE could be blocked	 * is during a gget() of dp, before it rewrites the dir. Since	 * a DELETE will recheck the cache before it exits, this	 * partial entry will be expunged, and again we will know	 * not to complete it further down.	 */	if (makeentry) {		if (ncp != NULL)			panic("ufs_namei: duplicating cache");		smp_lock(&lk_namecache, LK_RETRY);		/*		 * Search cache and verify entry will not be a		 * duplicate.		 */		nhp = &nchash[NHASH(hash, dp->g_number, dp->g_dev)];		for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;		    ncp = ncp->nc_forw) {			if (ncp->nc_ino == dp->g_number &&			    ncp->nc_dev == dp->g_dev &&			    ncp->nc_nlen == ndp->ni_dent.d_namlen &&			    !bcmp(ncp->nc_name, ndp->ni_dent.d_name,				ncp->nc_nlen)) {				smp_unlock(&lk_namecache);				ncp = NULL;				makeentry = 0;				goto check_slink;			}		}		/*		 * free the cache slot at head of lru chain		 */		if (ncp = nchhead) {			/*		 	 * 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 old hash chain 			 */			remque(ncp);			/*			 * Null out fields that will be filled			 * in later (maybe).			 */			ncp->nc_idev = NULL;			ncp->nc_ip = NULL;			ncp->nc_id = NULL;			/* 			 * fill in what we know			 */			ncp->nc_ino = dp->g_number;	/* parents inum */			ncp->nc_dev = dp->g_dev;	/* & device */			ncp->nc_nlen = ndp->ni_dent.d_namlen;			bcopy(ndp->ni_dent.d_name, ncp->nc_name, ncp->nc_nlen);			/*			 *  link at end of lru chain			 */			ncp->nc_nxt = NULL;			ncp->nc_prev = nchtail;			*nchtail = ncp;			nchtail = &ncp->nc_nxt;			/* 			 * and insert on hash chain			 */			insque(ncp, nhp);		}		smp_unlock(&lk_namecache);	}check_slink:	/*	 * About to check for symbolic link, which may require us to 	 * massage the	 * name before we continue translation.  We do not `gput' the	 * directory because we may need it again if the 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 `iget' 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 = dp;	if (isdotdot) {		ufs_gunlock(pdp);	/* race to get the inode */			dp = gget(dp->g_mp, ndp->ni_dent.d_ino, nomount, NULL);				if (dp == NULL)			goto bad2;				if(dp->g_mp->m_fstype != GT_ULTRIX) {			grele(ndp->ni_pdir);			ndp->ni_cp = cp;			ndp->ni_pdir = dp;			dp->g_flag |= GINCOMPLETE;			return(dp);		}	} else if (dp->g_number == ndp->ni_dent.d_ino) {		gref(dp);	/* we want ourself, ie "." */	} else {		dp = gget(dp->g_mp, ndp->ni_dent.d_ino, nomount, NULL);		ufs_gunlock(pdp);		if (dp == NULL)			goto bad2;		if(dp->g_mp->m_fstype != GT_ULTRIX) {			(void)grele(pdp);			ndp->ni_cp = cp;			ndp->ni_pdir = dp;			dp->g_flag |= GINCOMPLETE;			return(dp);		}	}	/*	 * insert name into cache if appropriate	 */	if (makeentry) {		smp_lock(&lk_namecache, LK_RETRY);		/*		 * Check if partial cache entry is still on hash		 * chain. If it isn't, a DELETE has or is occuring,		 * and we shouldn't add it. If partial entry is still		 * on chain, verify that there are no duplicates.		 */		nhp = &nchash[NHASH(hash, pdp->g_number, pdp->g_dev)];		for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;		    ncp = ncp->nc_forw) {			if (ncp->nc_ino == pdp->g_number &&			    ncp->nc_dev == pdp->g_dev &&			    ncp->nc_nlen == ndp->ni_dent.d_namlen &&			    !bcmp(ncp->nc_name, ndp->ni_dent.d_name,				ncp->nc_nlen))					break;		}		if (ncp == (struct nch *)nhp) {			/*			 * A DELETE process expunged our entry			 * from cache. Continue without completing			 * the entry.			 */			smp_unlock(&lk_namecache);			ncp = NULL;			goto haveino;		}		/*		 * If dp is a mount point, we are an NFS server; dont put		 * underlying info into cache.		 */		if (dp->g_flag & GMOUNT) {			expunge_cache(ncp);			smp_unlock(&lk_namecache);			makeentry = 0;			ncp = NULL;			goto haveino;		}		/*		 * Fill in the rest of the entry		 */		ncp->nc_ino = pdp->g_number;	/* parents inum */		ncp->nc_dev = pdp->g_dev;	/* & device */		ncp->nc_idev = dp->g_dev;	/* our device */		ncp->nc_ip = dp;		ncp->nc_id = dp->g_id;		/* identifier */		ncp->nc_nlen = ndp->ni_dent.d_namlen;		bcopy(ndp->ni_dent.d_name, ncp->nc_name, ncp->nc_nlen);		smp_unlock(&lk_namecache);	}haveino:	mp = dp->g_mp;	/*	 * Check for symbolic link	 */	if ((dp->g_mode & GFMT) == GFLNK &&	    ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) {		u_int pathlen = strlen(cp) + 1;#define OSF_FASTLINK 0x0001		if (dp->g_size + pathlen >= MAXPATHLEN - 1) {			u.u_error = ENAMETOOLONG;			goto bad2;		}		if (++ndp->ni_slcnt > MAXSYMLINKS) {			u.u_error = ELOOP;			goto bad2;		}		ovbcopy(cp, ndp->ni_dirp + dp->g_size, pathlen);		if (G_TO_I(dp)->di_flags & OSF_FASTLINK)			u.u_error = ovbcopy(G_TO_I(dp)->di_db, ndp->ni_dirp,				      dp->g_size);		else			u.u_error = rdwri(UIO_READ, dp, ndp->ni_dirp, 					  (int)dp->g_size, 0, 1, (int *)0);		if (u.u_error)			goto bad2;		cp = ndp->ni_dirp;		gput(dp);		if (*cp == '/') {			grele(pdp);			while (*cp == '/')				cp++;			if ((dp = u.u_rdir) == NULL)				dp = rootdir;			if(dp->g_mp->m_fstype != GT_ULTRIX) {				gref(dp);			        GLOCK(dp);				ndp->ni_pdir = dp;				ndp->ni_cp = cp;				dp->g_flag |= GINCOMPLETE;				return(dp);			}			gref(dp);			ufs_glock(dp);		} else {			dp = pdp;			ufs_glock(dp);		}		mp = dp->g_mp;		goto dirloop;	}	/*	 * Not a symbolic link.  If more pathname,	 * continue at next component, else return.	 */		/* 	 * for nomount, if we are at a mount point and there is more	 * pathname to translate, we need to terminate the name translation,	 * set u.u_error and return	 */		if(*cp && nomount && (dp->g_flag & GMOUNT)) {		u.u_error = ENOENT;		goto bad2;	}	if (*cp == '/') {		while (*cp == '/')			cp++;		grele(pdp);		goto dirloop;	}	if (lockparent)		ndp->ni_pdir = pdp;	else		grele(pdp);	dp->g_flag &= ~GINCOMPLETE;	ndp->ni_cp = cp;	return (dp);bad2:	grele(pdp);bad:	if (bp)		brelse(bp);	if (dp) {		dp->g_flag &= ~GINCOMPLETE;				gput(dp);	}	ndp->ni_cp = cp;	return (NULL);}expunge_cache(ncp)	struct nch *ncp;{	nchstats.ncs_expunged++;	/*	 * Last component and we are renaming or deleting,	 * the cache entry is invalid, or otherwise don't	 * want cache entry to exist. NOTE: the entry could	 * have been reused while we were doing other stuff,	 * but this is still safe since every namecache struct	 * is always linked into both chains. The worst that	 * can happen is that we disturb the normal LRU	 * pattern, which isn't worth the trouble to avoid.

⌨️ 快捷键说明

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