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

📄 smf_fat.c

📁 the test file for GP32 gameboy hack
💻 C
📖 第 1 页 / 共 5 页
字号:
/**********
 *
 * smf_fat.c: SmartMedia File System FAT part
 *
 * Portable File System designed for SmartMedia
 *
 * Created by Kim Hyung Gi (06/99) - kimhg@mmrnd.sec.samsung.co.kr
 * Samsung Electronics, M/M R&D Center, Visual Communication Group
 *
 **********
 *
 * Modified by Lee Jin Woo (1999/08/17)
 *	- Added smfsUserInit() call at the end of smInit() (1999/08/17)
 *
 **********/

#include "smf_cmn.h"
#include "smf_fat.h"
#include "smf_lpt.h"
#include "smf_io.h"
#include "smf_buf.h"


char* acSMFSVersion = "2.22";		/* must be x.xx type */

/**********
 * Macro Definitions
 **********/
#define FAT_RETURN(x, y) \
		do { sm_PostFAT((x));  return (y); } while (0)

#define SET_FAT_TBL(drv_no, offset, value) \
		do { \
			if ((udword)(offset) < s_fatTableIndexCount[(drv_no)]) { \
				s_fat[(drv_no)][(udword)(offset)] = (value); \
			} \
		} while (0)

#define GET_FAT_TBL(drv_no, offset) \
		(((udword)(offset) < s_fatTableIndexCount[(drv_no)]) \
		 	? s_fat[(drv_no)][(udword)(offset)] : 0)


/**********
 * Static Variables
 **********/

static sSM_INFO s_smInfo[MAX_DRIVE];

static uword* s_fat[MAX_DRIVE] = { NULL, };

static udword s_fat1StartSector[MAX_DRIVE];
static udword s_fat1Sectors[MAX_DRIVE];
static udword s_rootStartSector[MAX_DRIVE];
static udword s_rootSectors[MAX_DRIVE];
static udword s_clusterStartSector[MAX_DRIVE];
static udword s_fatTableIndexCount[MAX_DRIVE];

static sOPENED_LIST* s_openedFile[MAX_DRIVE] = { NULL, };
static udword s_fatFlag[MAX_DRIVE];
static ERR_CODE s_smErr;
static udword s_cacheSize[MAX_DRIVE];
static ubyte s_drvName[MAX_DRIVE][MAX_DRIVE_NAME_LEN + 1];

static void (*s_pfCBInserted)(udword);
static void (*s_pfCBEjected)(udword);

static udword bNoFATUpdate[MAX_DRIVE] = {FALSE, };
static udword bInnerNoFATUpdate[MAX_DRIVE] = {FALSE, };
/**********/

/* static funtions */
static void 	sm_FATInitDefaultValue(void);
static ERR_CODE sm_FATInit(udword drv_no);
static ERR_CODE sm_PreFAT(udword drv_no);
static ERR_CODE sm_PostFAT(udword drv_no);
static ERR_CODE sm_WriteSMInfo(udword drv_no, const sSM_INFO* p_sm_info);
static ERR_CODE sm_UpdateBlock(udword drv_no, udword new_block,	udword old_block, udword offset, udword count, const ubyte* p_buf, bool touchAllSectors);
static udword 	sm_GetDrvNo(const ubyte* p_name);
static ERR_CODE sm_CheckPath(udword drv_no, const ubyte* p_file_name, udword check_mode, F_HANDLE* p_handle);
static ERR_CODE sm_FATUpdate(udword drv_no);
static ERR_CODE sm_RemoveFile(udword drv_no, F_HANDLE h_dir, const ubyte* p_name);
static ERR_CODE sm_RemoveFirstBottommostDir(udword drv_no, F_HANDLE h_dir);
static ERR_CODE sm_FindEntryInDirectory(udword drv_no, udword find_mode, F_HANDLE h_parent, udword var_par, ubyte* p_info, udword* p_cluster, udword* p_offset);
static ERR_CODE sm_AddToDirEntry(udword drv_no, F_HANDLE h_dir, const ubyte* long_name, const uword* p_unicode_name, sFILE_STAT* p_stat, udword b_insert, udword cluster, udword offset);
static ERR_CODE sm_ExpandClusterSpace(udword drv_no, F_HANDLE handle, udword cluster, udword offset, udword size);
static ERR_CODE sm_DeleteFromDirEntry(udword drv_no, F_HANDLE h_dir, const ubyte* long_name);
static ERR_CODE sm_AddToOpenedFileList(udword drv_no, sOPENED_LIST* p_list);
static ERR_CODE sm_DeleteFromOpenedFileList(udword drv_no, udword cluster);
static ERR_CODE sm_WriteCacheToDisk(udword drv_no, sOPENED_LIST* p_list);
static ERR_CODE sm_WriteToDisk(udword drv_no, sOPENED_LIST* p_list,	const ubyte* p_buf, udword count);
static ERR_CODE sm_ReadFromDisk(udword drv_no, sOPENED_LIST* p_list, void* p_buf, udword count, udword* p_read_count);
static bool 	sm_ConvertToFATName(const ubyte* p_name, ubyte* p_short_name);
static ERR_CODE sm_GetOpenedList(udword drv_no, udword cluster, udword id, sOPENED_LIST** pp_list);
static bool 	sm_ExtractLastName(const ubyte* p_name, ubyte* p_last_name);
static bool 	sm_FindChar(const ubyte* p_str, ubyte ch, ubyte** p_found);
static bool 	sm_GetTime(sTIME* p_time);
static ERR_CODE sm_GetLongName(udword drv_no, udword h_parent, udword short_cluster, udword offset, uword* p_lname);

/* added by jwlee */
static ERR_CODE sm_addClusters(udword drv_no, udword cluster, udword addedClusterCount);
static ERR_CODE sm_eraseSectors(udword drv_no, udword startSector, udword count);
static ERR_CODE sm_erasePartialBlock(udword drv_no, udword block, udword startOffset, udword count);
static ERR_CODE sm_eraseWholeBlock(udword drv_no, udword block);
static udword 	sm_searchCluster(udword drv_no, udword count, udword* maxCount);
static void 	sm_prepareFileClose(udword drv_no, const sOPENED_LIST* p_list);

/* Cluster layer functions */
SM_EXPORT ERR_CODE smcAllocCluster(udword drv_no, udword* p_cluster);
SM_EXPORT ERR_CODE smcReadCluster(udword drv_no, udword cluster_no, udword offset, void* buf, udword size);
SM_EXPORT ERR_CODE smcWriteCluster(udword drv_no, udword cluster_no, udword offset, const void* buf, udword size);
static ERR_CODE smcSetCluster(udword drv_no, udword cluster_no, ubyte val);
static ERR_CODE smcUpdateBlock(udword drv_no, udword block, udword offset, const void* buf, udword count);

/* Utility functions */
static ubyte 	sm_toUpper(ubyte c);
static void		sm_UnicodeStrToUpper(uword* p_dest, uword* p_src, udword len);


/**********
 * File API definitions
 **********/

/**********
 * Function: smInit
 * Remarks:
 *	- This API must be called when system starts up
 **********/
SM_EXPORT ERR_CODE smInit(void) 
{
	udword drv_no;
	ubyte name[10];
	sTIME now;

	sm_GetTime(&now);
	SM_SRAND(now.sec);

	smbBufPoolInit();

	sm_IOInitDefaultValue();
	sm_LPTInitDefaultValue();
	sm_FATInitDefaultValue();

	/* drive name initialize */
	SM_STRCPY((char*)name, "dev");
	for (drv_no = 0; drv_no < MAX_DRIVE; ++drv_no) 
	{
		if (drv_no < 10) 
		{
			name[3] = (ubyte)drv_no + '0';
			name[4] = 0;
		}
#if (MAX_DRIVE >= 10)
		else if (drv_no < 100) 
		{
			name[3] = (ubyte)(drv_no / 10) + '0';
			name[4] = (ubyte)(drv_no % 10) + '0';
			name[5] = 0;
		}
		else 
		{
			name[3] = (ubyte)(drv_no / 100) + '0';
			name[4] = (ubyte)((drv_no % 100) / 10) + '0';
			name[5] = (ubyte)(drv_no % 10) + '0';
			name[6] = 0;
		}
#endif

		SM_STRCPY((char*)s_drvName[drv_no], (char*)name);
	}

#ifdef SM_MULTITASK
	SM_LOCK_INIT(drv_no);
#endif

	/* perform user initialization */
	if (smfsUserInit() != 0) 
	{
		return ERR_INTERNAL;
	}

	return SM_OK;
}


/**********
 * Function: smCreateFile
 * Remarks:
 *	- creates file and returns the handle of created file
 * Parameters
 *	. p_file_name: file name that should be created
 *					(ex. dev0:\temp\readme.txt)
 *	. fcreate_mode: NOT_IF_EXIST, ALWAYS_CREATE
 *	. p_handle (result): handle of the created file
 **********/
SM_EXPORT ERR_CODE smCreateFile(const smchar* p_filename, udword fcreate_mode, F_HANDLE* p_handle) 
{
	udword drv_no;
	F_HANDLE h_dir;
	udword cluster;
	sOPENED_LIST* p_list;
	ubyte long_name[MAX_FILE_NAME_LEN + 1];
	ubyte dummy_info[32];
	udword offset;
	ubyte *p_file_name = (ubyte *)p_filename;
	sFILE_STAT sStat;
#ifdef	LONG_FILE_NAME_ENABLE
	uword* p_unicode;
	ubyte fat_name[13];
#endif	

	drv_no = sm_GetDrvNo(p_file_name);
	if (drv_no >= MAX_DRIVE) 
		return ERR_INVALID_PARAM;

	s_smErr = sm_PreFAT(drv_no);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	s_smErr = sm_CheckPath(drv_no, p_file_name, PATH_EXCEPT_LAST, &h_dir);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	sm_ExtractLastName(p_file_name, long_name);

	/* check if the same name exists already */
	s_smErr = sm_FindEntryInDirectory(drv_no, FIND_FILE_NAME, h_dir, (udword)long_name, dummy_info, &cluster, &offset);
	if (s_smErr != ERR_NOT_FOUND) 
	{
		if (s_smErr == SM_OK) 
		{
			if (fcreate_mode == ALWAYS_CREATE) 
				sm_RemoveFile(drv_no, h_dir, long_name);
			else 
				FAT_RETURN(drv_no, ERR_FILE_EXIST);
		}
		else 
			FAT_RETURN(drv_no, s_smErr);
	}

	s_smErr = smcAllocCluster(drv_no, &cluster);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	/* FAT table update */
	/* This must be done before another smcAllocCluster() is called */
	SET_FAT_TBL(drv_no, cluster, LAST_CLUSTER);

	/* pOpenedList update */
	p_list = (sOPENED_LIST*)SM_MALLOC(sizeof(sOPENED_LIST));
	if (p_list == NULL) 
	{
		SET_FAT_TBL(drv_no, cluster, UNUSED_CLUSTER);
		FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);
	}

	p_list->prev = NULL;
	p_list->next = NULL;
	p_list->cluster = cluster;
	p_list->h_parent = h_dir;
	p_list->f_ptr = 0;
	p_list->cur_cluster = cluster;
	p_list->old_cur_cluster = 0;
	p_list->size = 0;
	p_list->mode = OPEN_R | OPEN_W;
	p_list->id = 0;
#ifndef WRITE_CACHE_DISABLE
	p_list->cache.f_ptr = 0;
	p_list->cache.count = 0;
	p_list->cache.p_buf = (ubyte*)SM_MALLOC(s_cacheSize[drv_no]);
	if (p_list->cache.p_buf == NULL) 
	{
		SM_FREE(p_list);
		SET_FAT_TBL(drv_no, cluster, UNUSED_CLUSTER);
		FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);
	}
#endif

	s_smErr = sm_AddToOpenedFileList(drv_no, p_list);
	if (s_smErr != SM_OK) 
	{
#ifndef WRITE_CACHE_DISABLE
		SM_FREE(p_list->cache.p_buf);
#endif
		SM_FREE(p_list);
		SET_FAT_TBL(drv_no, cluster, UNUSED_CLUSTER);
		FAT_RETURN(drv_no, s_smErr);
	}

	/* directory contents update */
#ifdef	LONG_FILE_NAME_ENABLE
	p_unicode = (uword*)SM_MALLOC(MAX_FILE_NAME_LEN+2);
	if(p_unicode == NULL)
	{
		sm_DeleteFromOpenedFileList(drv_no, cluster);
		SET_FAT_TBL(drv_no, cluster, UNUSED_CLUSTER);
		FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);
	}

	sStat.attr = ATTRIB_FILE;
	sStat.cluster = cluster;
	sStat.size = 0;
	sm_GetTime(&sStat.time);
	
	if(sm_ConvertToFATName(long_name, fat_name))
	{
		SM_MBS_TO_UNICODE(p_unicode, long_name, 0);	
		s_smErr = sm_AddToDirEntry(drv_no, h_dir, long_name, p_unicode, &sStat, 0, 0, 0);
	}
	else
		s_smErr = sm_AddToDirEntry(drv_no, h_dir, long_name, NULL, &sStat, 0, 0, 0);

	SM_FREE(p_unicode);
#else
	sStat.attr = ATTRIB_FILE;
	sStat.cluster = cluster;
	sStat.size = 0;
	sm_GetTime(&sStat.time);

	s_smErr = sm_AddToDirEntry(drv_no, h_dir, long_name, NULL, &sStat, 0, 0, 0);
#endif	
	if (s_smErr != SM_OK) 
	{
		sm_DeleteFromOpenedFileList(drv_no, cluster);
		SET_FAT_TBL(drv_no, cluster, UNUSED_CLUSTER);
		FAT_RETURN(drv_no, s_smErr);
	}

#ifndef FAT_UPDATE_WHEN_FILE_CLOSE
	/* this can be moved to smCloseFile for speed */
	sm_FATUpdate(drv_no);
#endif
	*p_handle = ((drv_no << 24) & 0xff000000) | ((p_list->id << 16) & 0xff0000) | (cluster & 0xffff);

	FAT_RETURN(drv_no, SM_OK);
}


/**********
 * Function: smOpenFile
 * Remarks:
 *	- open file and returns the handle of opened file
 * Parameters
 *	. p_file_name: file name that should be opened
 *					(ex. dev0:\temp\readme.txt)
 *	. fopen_mode: OPEN_R, OPEN_W (can be ORed)
 *	. p_handle (result): handle of the opened file
 **********/
SM_EXPORT ERR_CODE smOpenFile(const smchar* p_filename, udword fopen_mode, F_HANDLE* p_handle) 
{
	udword drv_no;
	udword cluster;
	F_HANDLE h_dir;
	sOPENED_LIST* p_list;
	ubyte file_info[32];
	ubyte long_name[MAX_FILE_NAME_LEN + 1];
	udword dummy_offset;
	udword id;
	ubyte *p_file_name = (ubyte *)p_filename;

	drv_no = sm_GetDrvNo(p_file_name);
	if (drv_no >= MAX_DRIVE) 
		return ERR_INVALID_PARAM;

	s_smErr = sm_PreFAT(drv_no);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	s_smErr = sm_CheckPath(drv_no, p_file_name, PATH_EXCEPT_LAST, &h_dir);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	sm_ExtractLastName(p_file_name, long_name);

	s_smErr = sm_FindEntryInDirectory(drv_no, FIND_FILE_NAME, h_dir, (udword)long_name, file_info, &cluster, &dummy_offset);
	if (s_smErr != SM_OK) 
		FAT_RETURN(drv_no, s_smErr);

	cluster = (udword)file_info[26] | ((udword)file_info[27] << 8);

	for (id = 0; id < MAX_OPENED_FILE_NUM; ++id) 
	{
		s_smErr = sm_GetOpenedList(drv_no, cluster, id, &p_list);
		if (s_smErr == ERR_FILE_NOT_OPENED)
			break;
	}

	if (id >= MAX_OPENED_FILE_NUM)
		FAT_RETURN(drv_no, ERR_FILE_OPENED);

	/* pOpenedList update */
	p_list = (sOPENED_LIST*)SM_MALLOC(sizeof(sOPENED_LIST));
	if (p_list == NULL)
		FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);

	p_list->prev = NULL;
	p_list->next = NULL;
	p_list->cluster = cluster;
	p_list->h_parent = h_dir;
	p_list->f_ptr = 0;
	p_list->cur_cluster = cluster;
	p_list->old_cur_cluster = 0;
	p_list->size = (udword)file_info[28] | ((udword)file_info[29] << 8)
		| ((udword)file_info[30] << 16) | ((udword)file_info[31] << 24);
	p_list->mode = fopen_mode;
	p_list->id = id;

#ifndef WRITE_CACHE_DISABLE
	p_list->cache.f_ptr = 0;
	p_list->cache.count = 0;
	p_list->cache.p_buf = (ubyte*)SM_MALLOC(s_cacheSize[drv_no]);
	if (p_list->cache.p_buf == NULL) 
	{
		SM_FREE(p_list);
		FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);
	}
#endif

	s_smErr = sm_AddToOpenedFileList(drv_no, p_list);
	if (s_smErr != SM_OK) 
	{
#ifndef WRITE_CACHE_DISABLE
		SM_FREE(p_list->cache.p_buf);
#endif
		SM_FREE(p_list);
		FAT_RETURN(drv_no, s_smErr);
	}

	*p_handle = ((drv_no << 24) & 0xff000000) | ((p_list->id << 16) & 0xff0000) | (cluster & 0xffff);

	FAT_RETURN(drv_no, SM_OK);
}


/**********
 * Function: smReadFile
 * Remarks:
 *	- read the contents from file to p_buf
 * Parameters
 *	. h_file: handle of opened file
 *	. p_buf: data buffer pointer that should be read from the disk
 *	. count: data size that shoul be read from the disk
 *	. p_read_count (result): data size that was read from the disk
 * Notes:
 *	- p_buf must be prepared for the bytes lager than "count"
 **********/
SM_EXPORT ERR_CODE smReadFile(F_HANDLE h_file, void* p_buf,	udword count, udword* p_read_count) 
{
	udword drv_no;
	udword cluster;
	sOPENED_LIST* p_list;
	udword head_count, tail_count;
	udword remaining_count;
	udword read_result;
	udword read_sum;
	udword id;
#ifndef WRITE_CACHE_DISABLE
	udword offset;
	udword cache_count;
#endif

	drv_no = (h_file >> 24) & 0x7f;
	if (drv_no >= MAX_DRIVE) 
		return ERR_INVALID_PARAM;

⌨️ 快捷键说明

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