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

📄 dir.c

📁 Win9x下文件系统驱动的例子(EXT2)源代码。
💻 C
📖 第 1 页 / 共 2 页
字号:
			 * If ChildInode is a symbolic link then
			 * follow the link
			 */
		if (S_ISLNK(ChildInode->Mode))
		{
			memcpy(Name, PathStart, PathLen);
			Name[PathLen] = 0;
			VxdDebugPrint(D_DIR, "doDirName2Inode: Found symlink name=%s, mode=0x%x", Name, (int) ChildInode->Mode);

			if ((FollowedInode = FollowLink(ParentInode, ChildInode)))
			{
				InodeRelease(ChildInode);
				ChildInode = FollowedInode;
			}
		}

			/*
			 * Whether or not we followed a link (successful
			 * or not), ChildInode points to the inode we need
			 */

			/*
			 * Continue search
			 */
		PathStart = PathEnd + 1;
		if (DirNameLength == PathLen)
			DirNameLength = 0;
		else
			DirNameLength -= (PathLen + 1);
		InodeRelease(ParentInode);
		ParentInode = InodeCloneInode(ChildInode);
	}

	InodeRelease(ParentInode);
		
	return ChildInode;
}



static TInode* FollowLink(TInode *DirInode, TInode *SymLinkInode)
{
	char		*TargetName;
	TInode		*FollowedInode;
	ext2_inode	*Ext2Inode;
	TBlock		*FirstBlock;
	char		Name[65];

	VxdDebugPrint(D_DIR, "FollowLink: start");
	
	Ext2Inode = InodeLock(SymLinkInode);
	

		/*
		 * First get the filename of the file object the
		 * link is pointing to
		 */
	TargetName = 0;
	FirstBlock = 0;
	if (Ext2Inode->i_size <= 64)
	{
		TargetName = (char *) Ext2Inode->i_block;
		memcpy(Name, TargetName, Ext2Inode->i_size);
		Name[Ext2Inode->i_size] = 0;
		VxdDebugPrint(D_DIR, "Direct link name=%s", Name);
	}
	else
	{
		if ((FirstBlock = InodeGetBlock(SymLinkInode, 0)))
		{
			TargetName = (char *) BlockLock(FirstBlock);
		}
	}

		/*
		 * If we have a name, resolve it
		 */
	
	if (TargetName)
	{
		if (!(FollowedInode = doDirName2Inode(DirInode, TargetName, (int) Ext2Inode->i_size)))
		{
			VxdDebugPrint(D_DIR, "FollowLink: target not found");
		}
		else
			VxdDebugPrint(D_DIR, "FollowLink: target found");
	}
	else
	{
		VxdDebugPrint(D_DIR, "FollowLink: no targetname found");
		FollowedInode = 0;
	}

	
		/*
		 * Clean up if necessary
		 */
	if (FirstBlock)
	{
		BlockUnlock(FirstBlock);
		BlockRelease(FirstBlock);
	}
	InodeUnlock(SymLinkInode);

	VxdDebugPrint(D_DIR, "FollowLink: done");

	return FollowedInode;
}




/**********************************
 *
 * INTERFACE ROUTINES
 *
 **********************************/



/*
 * Get Inode identified by the PathName
 *
 * IN:
 *
 * OUT:
 *
 * RETURNS:
 */
TInode* DirName2Inode(TSuperBlock *Super, char *DirName)
{
	TInode			*RootInode;
	TInode			*TargetInode;
	
	VxdDebugPrint(D_DIR, "DirName2Inode: device=%s, dir=%s", Super->DeviceName, DirName);

	RootInode = InodeGetRootInode(Super);
	TargetInode = doDirName2Inode(RootInode, DirName, DirName ? strlen(DirName) : 0);
	InodeRelease(RootInode);
		
	VxdDebugPrint(D_DIR, "DirName2Inode: done, ino=%lu", 
		TargetInode ? TargetInode->InodeNo : 0);

	return TargetInode;
}



/*
 * DirFindEntry searches for a match in a directory
 *
 * PRE:
 * If FindContext->Block is valid it must _not_ be locked.
 * FindContext->FoundInode must _not_ be valid, that is, a client
 * must have released it the previous time.
 *
 * POST:
 * If an entry is found:
 * -	FindContext->Block is locked and must be unlocked _before_
 *		a new DirFindEntry is issued.
 * -	FindContext->FoundEntry points in FindContext->Block->BlockData
 * -	FindContext->FoundInode points to the inode of the found entry,
 *		it must be released _before_ a new DirFindEntry is issued.
 *
 * IN:
 *
 * OUT:
 *
 * RETURNS
 */
BOOL DirFindEntry(TFindContext *FindContext, BOOL isShortName)
{
	TInode			*FollowedInode;
	ULONG			BlockSize;
	char			*DirData;
	BOOL			Succes;
	char			Name[65];
	char			TempName[128];

	VxdDebugPrint(D_DIR, "DirFindEntry, inode=(dev=%s, ino=%lu), search=%s",
			FindContext->Inode->Super->DeviceName,
			FindContext->Inode->InodeNo,
			FindContext->SearchName);

		/*
		 * Loop over all directory entries, starting where we left
		 * off the previous time
		 */
	BlockSize = DevGetBlockSize(FindContext->Inode->Super->Device);

		/*
		 * itterate over directory blocks
		 * Note that FindContext->LogicalBlockNo and FindContext->RecLen
		 * preserve the state of the search
		 */
	for (; FindContext->LogicalBlockNo<FindContext->nrBlocks ; FindContext->LogicalBlockNo++)
	{
		VxdDebugPrint(D_DIR, "DirFindEntry: looking in block=%lu of blocks=%lu", FindContext->LogicalBlockNo, FindContext->nrBlocks);

			/*
			 * See if the current block is present already
			 */
		if (!FindContext->Block)
		{
			if (!(FindContext->Block = InodeGetBlock(FindContext->Inode, FindContext->LogicalBlockNo)))
			{
				VxdDebugPrint(D_ERROR, "DirFindEntry: InodeGetBlock failed BlockNo=%lu, continuing on next block", FindContext->LogicalBlockNo);
				continue;
			}
		}
		
			/*
			 * For each block we loop over the contained
			 * directory entries and look for a match.
			 */
		DirData = BlockLock(FindContext->Block);

		while (FindContext->RecLen < BlockSize)
		{
				/*
				 * Get the next directory entry, mark it as found, and
				 * set RecLen 
				 */
			FindContext->FoundDirEntry = (ext2_dir_entry *) (DirData + FindContext->RecLen);
			FindContext->RecLen += FindContext->FoundDirEntry->rec_len;

				/*
				 * Add each entry to the cache
				 */
			CacheAddByName(sDirCache, (ULONG) FindContext->Inode->Super->Device, FindContext->Inode->InodeNo, FindContext->FoundDirEntry->name, FindContext->FoundDirEntry->name_len, &FindContext->FoundDirEntry->inode);

#ifdef DEBUG
				/*
				 * First see if we have a name match
				 */
			memcpy(TempName, FindContext->FoundDirEntry->name, FindContext->FoundDirEntry->name_len);
			TempName[FindContext->FoundDirEntry->name_len] = 0;
#endif			
			if (DirIsEntryNameMatch(FindContext, isShortName))
			{
				
					/*
					 * Now, get the inode of the found entry and see
					 * if the attributes match
					 */
				if ((FindContext->FoundInode = InodeGetInode(FindContext->Inode, FindContext->FoundDirEntry->inode, FindContext->FoundDirEntry->name, FindContext->FoundDirEntry->name_len)))
				{
				
						/*
						 * If the found inode is a symbolic link then
						 * follow the link first
						 */
					if (S_ISLNK(FindContext->FoundInode->Mode))
					{
						memcpy(Name, FindContext->FoundDirEntry->name, FindContext->FoundDirEntry->name_len);
						Name[FindContext->FoundDirEntry->name_len] = 0;
						VxdDebugPrint(D_DIR, "DirFindEntry: Found symlink name=%s, mode=0x%x", Name, (int) FindContext->FoundInode->Mode);

							/*
							 * If the followed link is a directory, don't follow it
							 * or we have a possible recursion.
							 * For example, on most machines /etc/inet is a sym link to /etc
							 */
						if ((FollowedInode = FollowLink(FindContext->Inode, FindContext->FoundInode)))
						{
							if (!(FollowedInode->DosAttrib & FILE_ATTRIBUTE_DIRECTORY))
							{
								InodeRelease(FindContext->FoundInode);
								FindContext->FoundInode = FollowedInode;
							}
							else
								InodeRelease(FollowedInode);
						}
					}

				
					if (DirIsEntryAttribMatch(FindContext, isShortName))
					{
						Succes = TRUE;

							/*
							 * !!! We leave the FindContext->Block locked !!!
							 */
						goto find_done;
					}
					else
					{
						VxdDebugPrint(D_DIR, "DirFindEntry: named macthed, attrib didn't name=%s, attrib=0x%x", TempName, (int) FindContext->FoundInode->DosAttrib);
						InodeRelease(FindContext->FoundInode);
					}
				}
			}
			else
			{
				VxdDebugPrint(D_DIR, "DirFindEntry: name nor attrib matched, name=%s", TempName);
			}
		}

			/*
			 * unlock and release the block
			 */
		if (FindContext->Block)
		{
			BlockUnlock(FindContext->Block);
			BlockRelease(FindContext->Block);
		}

			/*
			 * Next time, we start at offset 0 in the next block
			 */
		FindContext->Block = 0;
		FindContext->RecLen = 0;
	}
	Succes = FALSE;
	
find_done:
	VxdDebugPrint(D_DIR, "DirFindEntry: done, ino=%lu", 
			Succes ? FindContext->FoundDirEntry->inode : 0);

	return Succes;
}


/*
 * Create a FindContext
 *
 * PRE:
 * DirInode is an directory inode.
 *
 * POST:
 * DirInode is locked. Created FindContext->Block is initialised
 * with logical block 0 of the DirInode. The context variants and
 * invariants are initialised (excluding the "return values")
 *
 * IN:
 *
 * RETURNS:
 */
TFindContext* DirCreateFindContext(TInode *DirInode, char *SearchName, int SearchFlags)
{
	TFindContext	*FindContext = 0;
	ext2_inode		*Ext2Inode;


	VxdDebugPrint(D_DIR, "DirCreateFindContext, inode=(dev=%s, ino=%lu), search=%s",
			DirInode->Super->DeviceName,
			DirInode->InodeNo,
			SearchName);

		/*
		 * Create the find context
		 */
	if (!(FindContext = (TFindContext	*) calloc (1, sizeof(TFindContext))))
	{
		VxdDebugPrint(D_ERROR, "DirCreateFindContext: done, could not malloc TFindContext");
		return 0;
	}

		/*
		 * Read the first logical block beloning to the inode
		 */
	if (!(FindContext->Block = InodeGetBlock(DirInode, 0)))
	{
		VxdDebugPrint(D_ERROR, "DirCreateFindContext: done, could not get block 0");
		free(FindContext);
		return 0;
	}

		/*
		 * Lock the inode
		 */
	Ext2Inode = InodeLock(DirInode);
		
		/*
		 * Setup the find context
		 */
	strcpy(FindContext->SearchName, SearchName);
	FindContext->SearchFlags = SearchFlags;
	FindContext->Inode = DirInode;
	FindContext->nrBlocks = Ext2Inode->i_size / DevGetBlockSize(DirInode->Super->Device);

	VxdDebugPrint(D_DIR, "DirCreateFindContext: done");

	return FindContext;
}


/*
 * Destroy a FindContext (created by Ext2_CreateFindContext)
 * 
 * PRE:
 * FindContext->Inode is locked. If FindContext->Block exists,
 * it is unlocked.
 *
 * POST:
 * FindContext->Inode is unlocked and releases. If FindContext exists
 * it is released. The FindContext is freed.
 *
 * IN:
 * 
 *
 * OUT:
 * 
 * RETURNS
 */
void DirDestroyFindContext(TFindContext *FindContext)
{
	
	VxdDebugPrint(D_DIR, "DirDestroyFindContext, inode=(dev=%s, ino=%lu), search=%s",
			FindContext->Inode->Super->DeviceName,
			FindContext->Inode->InodeNo,
			FindContext->SearchName);
	
		/*
		 * Important!! Release the the block and the inode
		 */
	if (FindContext->Block)
		BlockRelease(FindContext->Block);
	InodeUnlock(FindContext->Inode);
	InodeRelease(FindContext->Inode);
	free(FindContext);

	VxdDebugPrint(D_DIR, "DirDestroyFindContext: done");
}



BOOL DirInitialise(UINT DirCacheSize)
{
	VxdDebugPrint(D_SYSTEM, "DirInitialise: cachesize=%u", DirCacheSize);

		/*
		 * Create the Directory Entry Cache.
		 */
	if (! (sDirCache = CacheCreate(sDirCacheName, DirCacheSize, sizeof(ULONG))))
	{
		VxdDebugPrint(D_ERROR, "DirInitialise: could not create dir cache");
		goto dir_init_1;
	}

	VxdDebugPrint(D_SYSTEM, "DirInitialise: done");

	return TRUE;

dir_init_1:
	VxdDebugPrint(D_SYSTEM, "DirInitialise: done");

	return FALSE;
}




void DirCleanup()
{
	VxdDebugPrint(D_SYSTEM, "DirCleanup");
	
	CacheDestroy(sDirCache);

	VxdDebugPrint(D_SYSTEM, "DirCleanup: done");
}

void DirCacheInfo()
{
	unsigned long	Lookups;
	unsigned long	Hits;

	CacheGetStats(sDirCache, &Lookups, &Hits);
	VxdDebugPrint(D_SYSTEM, "DirCacheInfo: lookup=%lu, hit=%lu, ratio=%lu",
			Lookups, Hits, 
			Lookups? Hits*100/ Lookups: 0);
}

⌨️ 快捷键说明

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