📄 smf_fat.c
字号:
/**********
*
* 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 + -