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

📄 util.c

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

#include "shared\vxddebug.h"
#include "util.h"
#include "dir.h"
#include "unixstat.h"


#define IS_WILDCHAR(c) ( (c)=='?' || (c)=='*' )

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


	/* 
	 * Linear day numbers of the respective 1sts in non-leap years. 
	 * JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec 
	 */
static long sDay_N[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
char 		sBadChars[] = "*?<>\\$+=;";
		  

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

/* Cool Long to Short file name conversion routine.
 *
 * PRE:
 * If isFCB is true --> ShortName must be at least 11 bytes long
 * otherwise is must be at least 13 bytes long
 *
 * POST:
 * When converting LFN to 8.3 names, we will prevent name clashes due
 * to case sensitivity, that is, filename.c and Filename.c cannot both
 * convert to FILENAME.C. Either one of them has to be converted to
 * FILENA~1.C (or something like that). Since in UNIX file systems,
 * lower cased file names are more natural, we apply the following
 * conversion rule: if a filename contains an _uppercased_ character,
 * it will have a numerical tail appended (the ~1). Of course, filenames
 * that have too long file name (>8) or extention lenghts (>3) or
 * contain invalid characters will have a numerical tail appended as
 * well.
 *
 * IN:
 *	LfnName		: pointer to LfnName, it not be zero terminated
 *	LfnNameLen	: lenght of LfnName (excluding a possible '\0')
 *	isFCB		: specifies whether or not the converted shortname
 *					will be in FCB format
 * OUT:
 *	ShortName	: pointer to a buffer for the converted shortname
 */
static BOOL LongToUpperShort(char *LfnName, int LfnNameLen, char *ShortName)
{
	char		*pc;
	char		c;
	int			i;
	BOOL		isconverted;

	isconverted = FALSE;
	pc = ShortName;

		/*
		 * . and .. need no conversion
		 */
	if (isDotOrDotDot(LfnName, LfnNameLen))
	{
		strncpy(ShortName, LfnName, LfnNameLen);
		ShortName[LfnNameLen] = 0;
		return FALSE;
	}

		/*
		 * convert hidden files (starting with a dot) to underscore
		 */
	if (LfnName[0]=='.')
	{
		LfnName++;
		LfnNameLen--;
		*pc++ = '_';
	}

		/*
		 * copy filename part
		 */
	for (i=0 ; i<8 && LfnNameLen ; i++)
	{
		c = *LfnName++;
		LfnNameLen--;

			/*
			 * if '.' we found the extention
			 */
		if (c=='.')
			break;

			/*
			 * if c is present in the bad character list, we
			 * convert it to an underscore
			 */
		if (strchr(sBadChars, c))
		{
			isconverted = TRUE;
			c = '_';
		}
		else if (isalpha(c))
			if (isupper(c))
				isconverted = TRUE;
			else
				c = toupper(c);

		*pc++ = c;
	}
		
		/*
		 * If we scanned 8 characters, the filename still
		 * contains characters and we do not see a '.'
		 * the filename part is too long
		 */
	if (i==8 && LfnNameLen && (*LfnName != '.'))
		isconverted = TRUE;

		/*
		 * search dot for extension of the filename
		 */
	for(; LfnNameLen && c!='.' ; LfnNameLen--, c=*LfnName++)
		;

		/*
		 * copy extension
		 */
	if (c == '.')
		*pc++ = '.';

		/*
		 * copy the extension part
		 */
	for (i=0 ; i<3 && LfnNameLen ; i++)
	{
		c = *LfnName++;
		LfnNameLen--;

			/*
			 * if c is present in the bad character list or is a
			 * '.' (a second '.'), we convert it to 
			 * an underscore
			 */
		if (c == '.' || strchr(sBadChars, c))
		{
			isconverted = TRUE;
			c = '_';
		}
		else if (isalpha(c))
			if (isupper(c))
				isconverted = TRUE;
			else
				c = toupper(c);

		*pc++ = c;
	}

		/*
		 * If, at this point, the filename still contains characters
		 * the file extension part is too long
		 */
	if (LfnNameLen)
		isconverted = TRUE;

	*pc = 0;

	return isconverted;
}

/*
 * Append a numerical tail to a filename. This mat cause the loss
 * of some characters.
 *
 * PRE:
 *
 * POST
 * IN:
 *	ShortName	: pointer to a shortname
 *	Offset		: numerical tail
 *	isFCB		: whether or not ShortName is in FCB format
 * OUT:
 *	ShortName	: the converted shortname (that is, with the numerical
 *					tail appended)
 */
static void AppendNumericalTail(char *ShortName, ULONG Tail)
{
	char		*pc;
	int			tailstart, taillength, shift, extlength, filenamelength;


		/*
		 * tail is ~x where x = Offset mod 100, this means that
		 * the tail is ~1 until ~99. It's length is 2 or 3
		 */
	taillength = Tail < 10 ? 2 : 3;

		/*
		 * Search . or eos (it's the end od the num tail)
		 */
	if (!(pc = strchr(ShortName, '.')))
		pc = memchr(ShortName, 0, 14);

		/*
		 * determine where to start the tail and if the
		 * we need to overwrite or shift some char
		 */
	filenamelength = pc - ShortName;
	shift = 8 - filenamelength;
	if (shift > taillength)
		shift = taillength;
	tailstart = filenamelength + taillength;
	tailstart = (filenamelength + taillength > 8) ?
		8 - taillength:
		filenamelength;
		

		/*
		 * See if we need to shift the extention
		 */
	if (shift)
	{
		extlength = strlen(pc) + 1;	// copy eos as well
		memmove(pc + shift, pc , extlength);
	}

		/*
		 * Append the tail
		 */
	pc = ShortName + tailstart;
	*pc++ = '~';
	if (Tail > 9)
		*pc++ = (char) ((Tail / 10) + '0');
	*pc = (char) ((Tail % 10) + '0');
}




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


/* 
 * This comes strait from the Linux kernel source. I took it from
 * the msdos filesystem. Nasty piece of code, but it works :-)
 */
dos_time dateUnix2Dos(ULONG UnixDate)
{
	long		day, year, nl_day, month;
	ULONG		time, date;
	dos_time	dt;

	time = (UnixDate % 60)/2+(((UnixDate/60) % 60) << 5)+
		(((UnixDate/3600) % 24) << 11);
	day = UnixDate/86400l-3652;
	year = day/365;
	if ((year+3)/4+365*year > day) 
		year--;
	day -= (year+3)/4+365*year;
	if (day == 59 && !(year & 3)) 
	{
		nl_day = day;
		month = 2;
	}
	else 
	{
		nl_day = (year & 3) || day <= 59 ? day : day-1;
		for (month=0; month < 12; month++)
			if (sDay_N[month] > nl_day) 
				break;
	}
	date = nl_day-sDay_N[month-1]+1+(month << 5)+(year << 9);

	dt.dt_time = (USHORT) time;
	dt.dt_date = (USHORT) date;

	return dt;
}



/*
 * Convert A LFN Filename to a 8.3 filename
 *
 * IN:
 * pLfnName			: Name of an ext2 directory entry
 * EntryLen			: Length of bytes of pLfnName
 *
 * OUT:
 * ShortName		: ASCIIZ 8.3 filename
 *
 */
void LfnToShortName(char *EntryName, int EntryLen, char *ShortName, int Offset)
{
	USHORT		uni_lfn[MAX_PATH];
	USHORT		uni_short[14];
	_QWORD		qword;
	DWORD		rval;

		/*
		 * Convert to Unicode Short FileName, make sure we do not
		 * convert . or ..
		 */
	if (isDotOrDotDot(EntryName, EntryLen))
	{
		strncpy(ShortName, EntryName, EntryLen);
		ShortName[EntryLen] = 0;
	}
	else
	{
			/*
			 * Convert BCS LFN to Unicode LFN FileName
			 */
		BCSToUni(uni_lfn, EntryName, EntryLen, BCS_OEM, &qword);
		uni_lfn[qword.ddLower >> 1] = 0;

			/*
			 * Create the Unicode 8.3 name
			 */
		rval = CreateBasis(uni_short, uni_lfn, qword.ddLower);
		if (rval & (BASIS_LOSS | BASIS_UPCASE | BASIS_TRUNC))
			AppendBasisTail(uni_short, (INT) Offset%100);

			/*
			 * Convert to BCS
			 */
		UniToBCS(ShortName, uni_short, 2 * ustrlen(uni_short), 12, BCS_OEM, &qword);
		ShortName[qword.ddLower] = 0;
	}
}


/*
 * Compare an EntryName with a string that contains wildcards (* and ?)
 *
 * IN:
 * EntryName		: Name of an ext2 directory entry
 * ToBeMatchedName	: Match string (possibly containing wildcards)
 * MatchFlags		: Flags that specify the match scheme
 *
 * OUT:
 *
 * RETURN
 * success			: non - 0
 * failure			: 0
 */
int isEntryMatch(char *EntryName, char *ToBeMatchedName, int MatchFlags, int EntryLen)
{
	char	*EntryNameEnd = EntryName + EntryLen;
	char	c1, c2;
		
	while (EntryName<EntryNameEnd && *ToBeMatchedName)
	{
		switch (*ToBeMatchedName)
		{
			case '*':
					/*
					 * Wildcard match
					 *
					 * First, look for the first non wildcard
					 */
				while (*ToBeMatchedName == '*' || *ToBeMatchedName == '?')
					ToBeMatchedName++;

					/*
					 * If we end with wildcards, we have a match
					 */
				if (*ToBeMatchedName == 0)
					return 1;

					/*
					 * Next, scan the entryname for the non-wild
					 * card character
					 */
				EntryName = memchr(EntryName, *ToBeMatchedName, EntryNameEnd-EntryName);
				if (!EntryName)
					return 0;

					/*
					 * Continue search at next character
					 */
				EntryName++;
				ToBeMatchedName++;
				break;

			case '?':
				ToBeMatchedName++;
				EntryName++;
				break;
			default:
					/*
					 * Simple case-insensitive char comparison
					 * toupper has side-effects :-)
					 */
				c1 = *EntryName++;
				c2 = *ToBeMatchedName++;
				//if (toupper(*EntryName++) != toupper(*ToBeMatchedName++))
				if (toupper(c1) != toupper(c2))
					return 0;
		}
	}

		/*
		 * We ended the while loop, this means 
		 * 1. Only ToBeMatchedName is empty
		 * 2. Only EntryName is empty
		 * 3. They are both empty
		 * 
		 */
	if (EntryName<EntryNameEnd)
	{

			/*
			 * 1. Only ToBeMatchedName is empty
			 */
		return 0;
	}
	else
	{

				/*
				 * 2. Only EntryName is empty
				 * 3. They are both empty
				 *
				 * We only have a match if only wildcards are
				 * left in ToBeMatchedName (or it is empty)
				 */
		while (*ToBeMatchedName)
		{
			if (*ToBeMatchedName == '*' || *ToBeMatchedName == '?')
				ToBeMatchedName++;
			else
				return 0;
		}
		return 1;
	}

		/*
		 * Cannot reach here
		 */
	return 0;

}


/*
 * Convert an Unicode Path name to a BcsPathName, also, 
 * The converted directory is absolute (starting with root)
 * even if the Unicode pathname is relative to the current 
 * directory. It accepts \ and / as directory separators.
 * The pathnames may be separated by both \ and / but are
 * all converted to / (to facilitate the following of symbolic
 * links)
 * The converted pathname does not start with the root /
 * So, "Q:\usr\local\bin" results in "usr/local/bin"
 *
 * IN:
 * UniPath	: pointer to unicode pathname, it may be
 *			  relative to the current directory
 *
 * OUT:
 * BcsPath	: pointer to bcs pathname (absolute to root)
 * 
 * RETURNS
 * BcsPath	: pointer to bcs pathname (absolute to root)
 */
char* GetBcsPath(int Drive, USHORT *UniPath, char *BcsPath)
{
	char			cur_dir[MAX_PATH];
	char			*pc;
	_QWORD			qword;
	
		/*
		 * Skip drive letter
		 */
	if ( ((UCHAR) UniCharToOEM(UniPath[1])) == ':' )
		UniPath+=2;

		/*
		 * Absolute path?
		 */
	if ( ((UCHAR) *UniPath) == '\\' || ((UCHAR) *UniPath) == '/')
	{
			/*
			 * Skip root character
			 */
		UniPath++;
		UniToBCS(BcsPath, UniPath, 2 * ustrlen(UniPath), MAX_PATH-1, BCS_OEM, &qword);
		BcsPath[qword.ddLower] = 0;
	}
	else
	{
			/*
			 * We translate the path relative to the current directory
			 */
		cur_dir[0] = 0;
		if (IFSMgr_Win32GetVMCurdir(Drive, cur_dir) != 0)
		{
			VxdDebugPrint(D_ERROR, "GetBcsPath could not get current dir from IFS");
			return 0;
		}
			/*
			 * append a directory separator, unless we are the root
			 * directory
			 */
		if (*cur_dir)
			strcat(cur_dir, "/");

		UniToBCS(BcsPath, UniPath, 2 * ustrlen(UniPath), MAX_PATH-1, BCS_OEM, &qword);
		BcsPath[qword.ddLower] = 0;

		strcat(cur_dir, BcsPath);
		strcpy(BcsPath, cur_dir);
	}

		/*
		 * fixup separators
		 */
	pc = BcsPath;
	while (*pc)
	{
		if (*pc == '\\')
			*pc = '/';
		pc++;
	}

	VxdDebugPrint(D_DIR, "GetBcsPath=%s", BcsPath);
	return BcsPath;
}


/*
 * Translate Unix file attributes to Win 95 attributes
 *
 * IN:
 *	Ext2Inode	: pointer to ext2_inode structure
 *	FileName	: pointer to Filename, need not be zero terminated and
 *					 may be zero
 *	NameLen		: lenght of the filename (if Filename not zero)
 *
 * OUT:
 *	<none>
 *
 * RETURNS
 * Returns the Win 95 for this inode. If the filename starts with a
 * dot and it is not . or .. we set the hidden attribute
 */







void BcsToUniParsed(char *BcsDirName, PUSHORT UniParsed)
{
	USHORT		len, fileoffset, pathlen;
	PUSHORT		unipath;
	char		*pathstart, *pathend;
	_QWORD		result;

	pathstart = pathend = BcsDirName;
	unipath = UniParsed+2;
	fileoffset = 4;
	len = 0;
	if (*pathstart)
	{	
		while(pathend)
		{
				/*
				 * Stop criterium is reached iff pathend == 0,
				 * that is, there are no more path separators
				 */
			if ((pathend = strchr(pathstart, '/')))
			{
				pathlen = pathend - pathstart;
			}
			else
			{
				pathlen = strlen(pathstart);
				fileoffset = unipath - UniParsed;
			}
			BCSToUni(unipath+1, pathstart, pathlen, BCS_OEM, &result);
			*unipath = (USHORT) result.ddLower + 2;
			len += *unipath;
			unipath += (*unipath) >> 1;

				/*
				 * Continue search
				 */
			pathstart = pathend + 1;
		}
	}
	
	(*unipath) = 0;
	UniParsed[0] = len;
	UniParsed[1] = fileoffset;

}


void LongToShort(char *LfnName, int LfnNameLen, char *ShortName, ULONG Tail)
{
	char	c;
	int		len;

	*ShortName = 0;
	if (LongToUpperShort(LfnName, LfnNameLen, ShortName))
		AppendNumericalTail(ShortName, Tail%100);

	if ( (len = strlen(ShortName) > 12) )
	{
			/*
			 * panic mode to see if conversion went well.
			 * Also, use a cludge a pass missing feature in
			 * VtoolsD printf (%*s) for non-zero terminated trings
			 */
		c = LfnName[LfnNameLen-1];
		LfnName[LfnNameLen-1] = 0;
		VxdDebugPrint(D_ERROR, "PANIC, LongToShort: %s%c --> %s, len=%i",
			LfnName, (int) c, ShortName, len);
		LfnName[LfnNameLen-1] = c;
		VxdDebugFlush();
	}
}


char* strnchr(char *str, char c, int len)
{
	while(*str && len)
	{
		if (*str == c)
			return str;
		str++;
		len--;
	}

	return 0;
}

/*
 * Convert an input string to a lowercase character string.
 * Return TRUE iff the input string does _not_ contain
 * lower cased characters.
 * Output string is not zero-terminated
 */
BOOL StrConvAndTestToLower(char *Dst, char *Src, int Len)
{
	char	c;

	while (Len)
	{
		c = *Src++;
		if (isalpha(c))
		{
			if (islower(c))
				return FALSE;
			*Dst++ = tolower(c);
		}
		else
			*Dst++ = c;
		Len--;
	}
	return TRUE;
}


void StrToUpper(char *Src, int Len)
{
	char	c;

	while (Len--)
	{
		c = *Src;
		if (isalpha(c))
			*Src++ = toupper(c);
		else
			Src++;
	}
}


BOOL isDotOrDotDot(char *FileName, int Len)
{
	if (FileName[0] == '.')
	{
		if (Len == 1)
			return TRUE;
		else if (FileName[1] == '.' && Len == 2)
			return TRUE;
	}

	return FALSE;
}

void SmartConvertDots2QuestionMark(char *FileName)
{
	char	*pc;

	pc = strchr(FileName + 1, '.');
	while(pc)
	{
		if ( IS_WILDCHAR( *(pc-1)) || IS_WILDCHAR(*(pc+1)) )
			*pc = '?';
		pc = strchr(pc + 1, '.');
	}
}

⌨️ 快捷键说明

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