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

📄 dir.c

📁 Win9x下文件系统驱动的例子(EXT2)源代码。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "vxd.h"

#include "dir.h"
#include "cache.h"
#include "super.h"
#include "inode.h"
#include "block.h"
#include "util.h"
#include "unixstat.h"
#include "shared\vxddebug.h"

	/*
	 * First time I ever wrote two functions with 
	 * cross-dependency :-)
	 */
static TInode* FollowLink(TInode *DirInode, TInode *LinkInode);
static TInode* doDirName2Inode(TInode *DirInode, char *DirName, int DirNameLength);



#define MUSTMATCH(ir_attr,attr)		((((ir_attr & (attr)<<8)	\
										^ ir_attr)				\
										& FILE_ATTRIBUTE_MUSTMATCH) == 0)



/**********************************
 *
 * GLOBAL DATA
 *
 **********************************/

// none


/**********************************
 *
 * STATIC DATA
 *
 **********************************/

static TCache			*sDirCache;
static char				sDirCacheName[] = "DirCache";



/********************************
 *
 * STATIC HELPERS
 *
 *********************************/

static BOOL DirIsEntryNameMatch(TFindContext *FindContext, BOOL isShortName)
{
	int			ShortNameLen;
	BOOL		Succes;

	if (isShortName)
	{
			/*
			 * Search on short Filenames
			 */
		LongToShort(FindContext->FoundDirEntry->name, FindContext->FoundDirEntry->name_len, FindContext->ShortName, FindContext->FoundDirEntry->inode);
		VxdDebugPrint(D_DIR, "shortfilename=%s", FindContext->ShortName);
		ShortNameLen = strlen(FindContext->ShortName);
		Succes = isEntryMatch(FindContext->ShortName, FindContext->SearchName, FindContext->SearchFlags, ShortNameLen);

	}
	else
	{
			/*
			 * Search on LFN Filenames
			 */
		Succes = isEntryMatch(FindContext->FoundDirEntry->name, FindContext->SearchName, FindContext->SearchFlags, FindContext->FoundDirEntry->name_len);
	}

	return Succes;
}


static BOOL DirIsEntryAttribMatch(TFindContext *FindContext, BOOL isShortName)
{
	BOOLEAN			Success;
	ULONG			Attrib;
	BYTE			ExcludeMask;
	Attrib = FindContext->FoundInode->DosAttrib;
		
	if (isShortName)
	{
		if (Attrib)
			Success = (FindContext->SearchFlags & Attrib);
		else
			Success = TRUE;
	}
	else
	{
		ExcludeMask = (~FindContext->SearchFlags) & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_SYSTEM);
		Success = (!(Attrib & ExcludeMask) && MUSTMATCH(FindContext->SearchFlags, Attrib));
	}

	return Success;
}






/*
 * Lookup an directory entry and return the object's inode nr
 *
 * PRE:
 * DirInode is indeed an directory inode. EntryName is zero-terminated
 *
 * POST:
 * <none>
 *
 * IN:
 *	DirInode	: pointer to a fully initialised directory inode 
 *	EntryName	: zero-terminated entry name which is to be looked up
 *
 * OUT:
 *	<none>
 *
 * RETURNS
 *	Succes		: inode number of the entry name
 *	otherwise	: 0
 * 
 */
static ULONG DirLookupEntry(TInode *DirInode, char *EntryName, int NameLen, BOOL isShortName)
{
	char			ShortName[13];
	char			zEntryName[13];
	ULONG			InodeNo, nrBlocks, BlockSize, BlockNo;
	USHORT			RecLen, ShortNameLen;
	TBlock			*Block;
	ext2_dir_entry	*DirEntry;
	ext2_inode		*Ext2Inode;
	char			*DirData;

#ifdef DEBUG
	char			zName[256];

	memcpy(zName, EntryName, NameLen);
	zName[NameLen] = 0;
#endif
	VxdDebugPrint(D_DIR, "DirLookupEntry(%s): inode=(dev=%s, ino=%lu), name=%s", 
			isShortName ? "short" : "lfn",
			DirInode->Super->DeviceName, 
			DirInode->InodeNo,
			zName);

		/*
		 * The EntryName is not zero-terminated
		 */
	if (isShortName)
	{
		memcpy(zEntryName, EntryName, NameLen);
		zEntryName[NameLen] = 0;
	}

	Ext2Inode = InodeLock(DirInode);

		/*
		 * init some locals
		 */
	InodeNo = 0;
	BlockSize = DevGetBlockSize(DirInode->Super->Device);
	nrBlocks = Ext2Inode->i_size / BlockSize;
	
		/*
		 * Sanity check
		 */
	if (nrBlocks * BlockSize != Ext2Inode->i_size)
	{
		VxdDebugPrint(D_ERROR, "DirLookupEntry: i_size=%lu not multiple of BlockSize, done", Ext2Inode->i_size);
		goto lookup_done;
	}


		/*
		 * itterate over directory blocks
		 */
	for (BlockNo=0 ; BlockNo<nrBlocks ; BlockNo++)
	{
		VxdDebugPrint(D_DIR, "DirLookupEntry: looking in block=%lu of blocks=%lu", BlockNo, nrBlocks);

		if (!(Block = InodeGetBlock(DirInode, BlockNo)))
		{
			VxdDebugPrint(D_ERROR, "DirLookupEntry: could not read block %i, continuing on next block", BlockNo);
			continue;
		}
		
			/*
			 * For each block we loop over the contained
			 * directory entries and look for a match.
			 */
		DirData = BlockLock(Block);
		RecLen = 0;

		do
		{
			DirEntry = (ext2_dir_entry *) (DirData + RecLen);

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

				/*
				 * The name we are looking for is short, so
				 * convert the entryname to 8.3
				 * Then do a case-insensitive search
				 */
			if (isShortName)
			{
				LongToShort(DirEntry->name, DirEntry->name_len, ShortName, DirEntry->inode);
				ShortNameLen = strlen(ShortName);
				if (isEntryMatch(ShortName, zEntryName, 0, ShortNameLen))
				{

						/*
						 * Ok, this is the one we need, break
						 * to the exit code
						 */
					InodeNo = DirEntry->inode;
					BlockUnlock(Block);
					goto lookup_done;
				}
				else
				{
					VxdDebugPrint(D_DIR, "DirLookupEntry(short): name=%s, no match", ShortName);
				}
			}
			else
			{
				if (DirEntry->name_len == NameLen)
				{

						/*
						 * We must have an exact match
						 */
					if (strncmp(DirEntry->name, EntryName, NameLen) == 0)
					{
							/*
							 * Ok, this is the one we need, break
							 * to the exit code
							 */
						InodeNo = DirEntry->inode;
						BlockUnlock(Block);
						goto lookup_done;
					}
					else
					{
#ifdef DEBUG
						memcpy(zName, DirEntry->name, DirEntry->name_len);
						zName[DirEntry->name_len] = 0;
						VxdDebugPrint(D_DIR, "DirLookupEntry(lfn): name=%s, no match", zName);
#endif
					}
				}
				else
				{
#ifdef DEBUG
					memcpy(zName, DirEntry->name, DirEntry->name_len);
					zName[DirEntry->name_len] = 0;
					VxdDebugPrint(D_DIR, "DirLookupEntry(lfn): name=%s, len=%i, no len match", zName, DirEntry->name_len);
#endif
				}
			}
			RecLen += DirEntry->rec_len;
		} while (RecLen < BlockSize);

		BlockUnlock(Block);
	}
	
lookup_done:
	VxdDebugPrint(D_DIR, "DirLookupEntry done, ino=%lu", InodeNo);
	InodeUnlock(DirInode);

	return InodeNo;
}


static ULONG DirName2InodeNo(TInode *Inode, char *PathName, int PathLen, BOOL isShortName)
{
	ULONG	InodeNo;

		/*
		 * First, see if it's in the cache
		 */
	InodeNo = 0;
	if (!CacheLookupByName(sDirCache, (ULONG) Inode->Super->Device, Inode->InodeNo, PathName, PathLen, &InodeNo))
	{
			
			/*
			 * No, not in the cache, read the directory
			 */
		InodeNo = DirLookupEntry(Inode, PathName, PathLen, isShortName);
	}

	return InodeNo;
}


/*
 * Get Inode identified by the PathName
 *
 * IN:
 *
 * OUT:
 *
 * RETURNS:
 */
static TInode* doDirName2Inode(TInode *DirInode, char *DirName, int DirNameLength)
{
	char			ShortName[13];
	char			*PathStart, *PathEnd;
	int				PathLen;
	ULONG			InodeNo;
	TInode			*ParentInode;
	TInode			*ChildInode;
	TInode			*FollowedInode;

	char			Name[65];
	
		/*
		 * DirName2Inode explicitly requests for a BCS pathname
		 * and not for a Unicode pathname. This has the disadvantage
		 * that all FSD requests (dir/open/delete etc) have to
		 * do the unicode->bcs conversion themselves. However,
		 * in order to following links, it is easiest to recursively
		 * call DirName2Inode (for absolute links only!). In that
		 * case we simply cannot have a MAX_PATH array on the stack.
		 */

		/*
		 * If path is empty we return the directory inode
		 */
	if (!DirName || !DirNameLength)
		return InodeCloneInode(DirInode);

		/*
		 * If Dir name is absolute, get the root inode
		 */
	if (*DirName == '/')
	{
		DirName++;
		DirNameLength--;
		ParentInode = InodeGetRootInode(DirInode->Super);
	}
	else
		ParentInode = InodeCloneInode(DirInode);

	PathEnd = PathStart = DirName;

	while(DirNameLength)
	{

			/*
			 * Make sure we the inode is a directory
			 */
		if (!S_ISDIR(ParentInode->Mode))
		{
			VxdDebugPrint(D_ERROR, "DirName2Inode: inode(dev=%s, ino=%lu) is not directory", ParentInode->Super->DeviceName, ParentInode->InodeNo);
			ChildInode = 0;
			break;
		}

			/*
			 * Stop criterium is reached iff PathEnd == 0,
			 * that is, there are no more path separators
			 */
		if ((PathEnd = strnchr(PathStart, '/', DirNameLength)))
		{
			PathLen = PathEnd - PathStart;
		}
		else
		{
			PathLen = DirNameLength;
		}

	
			/*
			 * Now, do some serious name 2 inode resolving.
			 */
		if (PathLen > 12)
		{

				/*
				 * This one is easy, it is a pure LFN filename, so
				 * we have to do an exact match 
				 */
			if (!(InodeNo = DirName2InodeNo(ParentInode, PathStart, PathLen, FALSE)))
			{
				ChildInode = 0;
				break;
			}
		}
		else
		{

				/*
				 * More difficult.
				 * The path may be:
				 * a) a name issued by a LFN filename aware app.
				 * b) a converted LFN name (containing a ~)
				 * c) a name issued by a non-LFN aware application
				 *
				 * Case b is simple and can be detected. Case
				 * a and b are indistinguishable.
				 * Consider open "FTP", this could issued from a
				 * dos application that is returned "FTP" (remember
				 * that we return "FTP" in ffirst/fnext calls when
				 * the entryname is "ftp"!!). It could also be
				 * issued by a win32 application and the filename
				 * is indeed "FTP" (its real name)
				 */				
			if (strnchr(PathStart, '~', PathLen))
			{
				if (!(InodeNo = DirName2InodeNo(ParentInode, PathStart, PathLen, TRUE)))
				{
					ChildInode = 0;
					break;
				}
			}
			else
			{
					/*
					 * First try an exact match
					 */
				if (!(InodeNo = DirName2InodeNo(ParentInode, PathStart, PathLen, FALSE)))
				{

						/*
						 * Now, iff the path is _all_ uppercased
						 * we try an exact match with the lower
						 * cased filename
						 */
//					if (StrConvAndTestToLower(ShortName, PathStart, PathLen))
//					{
//						if (!(InodeNo = DirName2InodeNo(ParentInode, ShortName, PathLen, FALSE)))
//						{
//							ChildInode = 0;
//							break;
//						}
//					}
//					else
					{
							/*
							 * Try matching names using short file
							 * names
							 */
						if (!(InodeNo = DirName2InodeNo(ParentInode, PathStart, PathLen, TRUE)))
						{
							ChildInode = 0;
							break;
						}
					}
				}
			}
		}


			/*
			 * Next, Get the TInode of the just found inode
			 */
		if (!(ChildInode = InodeGetInode(ParentInode, InodeNo, PathStart, PathLen)))
		{
			ChildInode = 0;
			break;
		}

			/*

⌨️ 快捷键说明

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