📄 smf_fat.c
字号:
FAT_RETURN(drv_no, s_smErr);
cluster_size = s_smInfo[drv_no].pbr.bpb.sectors_per_cluster * SECTOR_SIZE;
total_clusters = (s_smInfo[drv_no].pbr.bpb.total_sectors ? s_smInfo[drv_no].pbr.bpb.total_sectors : s_smInfo[drv_no].pbr.bpb.huge_sectors - 1)
/ s_smInfo[drv_no].pbr.bpb.sectors_per_cluster + 1;
p_info->total_size = total_clusters * s_smInfo[drv_no].pbr.bpb.sectors_per_cluster * SECTOR_SIZE;
p_info->sector_per_cluster = s_smInfo[drv_no].pbr.bpb.sectors_per_cluster;
p_info->sector_size = SECTOR_SIZE;
p_info->used_size = p_info->free_size = p_info->bad_cluster_num = 0;
for (i = 2; i < total_clusters + 2; ++i)
{
fat_val = GET_FAT_TBL(drv_no, i);
if (fat_val == UNUSED_CLUSTER)
p_info->free_size += cluster_size;
else if (fat_val == DEFECTIVE_CLUSTER)
++p_info->bad_cluster_num;
else
p_info->used_size += cluster_size;
}
FAT_RETURN(drv_no, SM_OK);
}
/**********
* Function: smFormatVol
* Remarks:
* - lower layer format, get device info from lower layer,
* set MBR/PBR/FAT, and initialize FAT layer variables
* Parameters:
* . p_vol_name: volumn name that is mounted (ex. "dev0:")
* . p_label: label string
* . format_id: FORMAT_NORMAL, FORMAT_RESCUE
* . p_bad_count (result): number of error blocks
* Notes:
* - do not implements sm_PreFAT as in other API's, but lock is needed
* - format_id is not used now (reserved)
**********/
SM_EXPORT ERR_CODE smFormatVol(const smchar* p_volumn_name, const smchar* p_label, udword format_id, udword* p_bad_count)
{
udword drv_no;
udword i, j;
sSM_INFO sm_info;
const sDEV_INFO* dev_info;
udword pbr_sector;
udword block;
udword sector;
udword offset;
udword changed_pblock;
udword needed_blocks;
udword needed_sectors;
udword fat_sectors;
udword root_sectors;
udword err_count;
ubyte* acFATBuf;
ubyte *p_vol_name = (ubyte *)p_volumn_name;
drv_no = sm_GetDrvNo(p_vol_name);
if (drv_no >= MAX_DRIVE)
return ERR_INVALID_PARAM;
/*
* lower layer format. all physical blocks are erased now.
*/
format_id = (format_id == FORMAT_RESCUE) ? LPT_FORMAT_RESCUE : LPT_FORMAT_NORMAL;
s_smErr = smlFormatVol(drv_no, format_id, &err_count);
if (s_smErr != SM_OK)
return s_smErr;
*p_bad_count = err_count;
/*
* get device info
*/
s_smErr = smlGetDeviceInfo(drv_no, &dev_info);
if (s_smErr != SM_OK)
return s_smErr;
fat_sectors = (dev_info->allS <= 128000)
? (((dev_info->LBpV + 2) * 3 / 2 - 1) / dev_info->szS + 1)
: (((dev_info->LBpV + 2) * 2 - 1) / dev_info->szS + 1);
root_sectors = (ROOT_DIR_ENTRY * 32 - 1) / SECTOR_SIZE + 1;
needed_sectors = 1 + 2 * fat_sectors + root_sectors;
/* let 0th block reserved only for MBR */
needed_blocks = (needed_sectors - 1) / dev_info->SpB + 2;
pbr_sector = needed_blocks * dev_info->SpB - needed_sectors;
/* set MBR values */
sm_info.mbr.partition_entry[0].def_boot = 0x80;
sm_info.mbr.partition_entry[0].start_cyl = (pbr_sector / dev_info->SpH) / dev_info->HpC;
sm_info.mbr.partition_entry[0].start_head = (pbr_sector / dev_info->SpH) % dev_info->HpC;
sm_info.mbr.partition_entry[0].start_sector = (pbr_sector % dev_info->SpH) + 1;
sm_info.mbr.partition_entry[0].pt_type = 1; /*??? */
sm_info.mbr.partition_entry[0].end_cyl = dev_info->CpV - 1;
sm_info.mbr.partition_entry[0].end_head = dev_info->HpC - 1;
sm_info.mbr.partition_entry[0].end_sector = dev_info->SpH;
sm_info.mbr.partition_entry[0].start_lba_sector = pbr_sector;
sm_info.mbr.partition_entry[0].total_available_sectors = dev_info->CpV * dev_info->HpC * dev_info->SpH - pbr_sector;
sm_info.mbr.signature = 0x55aa;
/* set PBR values */
SM_MEMCPY(&sm_info.pbr.oem_name[0], "SMFS1.0", 8);
sm_info.pbr.bpb.bytes_per_sector = dev_info->szS;
sm_info.pbr.bpb.sectors_per_cluster = dev_info->SpB;
sm_info.pbr.bpb.reserved_sectors = 1; /*??? */
sm_info.pbr.bpb.fat_num = 2;
sm_info.pbr.bpb.root_entry = ROOT_DIR_ENTRY;
/* sm_info.pbr.bpb.total_sectors
= (dev_info->allS <= 65535) ? dev_info->allS : 0; */
sm_info.pbr.bpb.total_sectors = (sm_info.mbr.partition_entry[0].total_available_sectors <= 65535)
? sm_info.mbr.partition_entry[0].total_available_sectors : 0;
sm_info.pbr.bpb.format_type = 0xf8;
sm_info.pbr.bpb.sectors_in_fat = fat_sectors;
sm_info.pbr.bpb.sectors_per_track = dev_info->SpH; /*??? */
sm_info.pbr.bpb.head_num = dev_info->HpC;
sm_info.pbr.bpb.hidden_sectors = pbr_sector;
/* sm_info.pbr.bpb.huge_sectors
= (dev_info->allS <= 65535) ? 0 : dev_info->allS; */
sm_info.pbr.bpb.huge_sectors = (sm_info.mbr.partition_entry[0].total_available_sectors <= 65535)
? 0 : sm_info.mbr.partition_entry[0].total_available_sectors;
sm_info.pbr.drive_num = 0x80;
sm_info.pbr.reserved = 0;
sm_info.pbr.ext_boot_signature = 0x29;
sm_info.pbr.vol_id = 0; /*??? */
SM_MEMSET(&sm_info.pbr.vol_label[0], ' ', 11);
for (i = 0; i < 11; ++i)
{
if (p_label[i] == 0)
break;
sm_info.pbr.vol_label[i] = p_label[i];
}
if (dev_info->allS <= 128000) /* 64MB */
sm_info.pbr.file_sys_type = FS_FAT12;
else
sm_info.pbr.file_sys_type = FS_FAT16;
sm_info.pbr.signature = 0x55aa;
/* write MBR & PBR */
s_smErr = sm_WriteSMInfo(drv_no, &sm_info);
if (s_smErr != SM_OK)
return s_smErr;
/*
* register new logical blocks until the end of root_dir_entry
*/
block = (pbr_sector + (2 * sm_info.pbr.bpb.sectors_in_fat) + ((ROOT_DIR_ENTRY * 32 - 1) / SECTOR_SIZE + 1)) / sm_info.pbr.bpb.sectors_per_cluster;
for (i = pbr_sector / sm_info.pbr.bpb.sectors_per_cluster + 1; i <= block; ++i)
{
smlGetNewSpecifiedBlock(drv_no, i, &changed_pblock);
}
/*
* FAT table write
*/
acFATBuf = SMB_ALLOC_BUF();
if (!acFATBuf)
return ERR_OUT_OF_MEMORY;
SM_MEMSET(acFATBuf, 0, SECTOR_SIZE);
block = (pbr_sector + 1) / sm_info.pbr.bpb.sectors_per_cluster;
offset = ((pbr_sector + 1) % sm_info.pbr.bpb.sectors_per_cluster) * SECTOR_SIZE;
for (i = 0; i < 2; ++i)
{
acFATBuf[0] = 0xf8;
acFATBuf[1] = 0xff;
acFATBuf[2] = 0xff;
s_smErr = smlWriteBlock(drv_no, block, offset, acFATBuf, SECTOR_SIZE);
if (s_smErr != SM_OK)
{
SMB_FREE_BUF(acFATBuf);
return s_smErr;
}
offset += SECTOR_SIZE;
if (offset >= sm_info.pbr.bpb.sectors_per_cluster * SECTOR_SIZE)
{
++block;
offset = 0;
}
acFATBuf[0] = 0;
acFATBuf[1] = 0;
acFATBuf[2] = 0;
for (j = 1; j < sm_info.pbr.bpb.sectors_in_fat; ++j)
{
s_smErr = smlWriteBlock(drv_no, block, offset, acFATBuf, SECTOR_SIZE);
if (s_smErr != SM_OK)
{
SMB_FREE_BUF(acFATBuf);
return s_smErr;
}
offset += SECTOR_SIZE;
if (offset >= sm_info.pbr.bpb.sectors_per_cluster * SECTOR_SIZE)
{
++block;
offset = 0;
}
}
}
/*
* Root Dir Entry write (empty)
*/
SM_MEMSET(acFATBuf, 0, SECTOR_SIZE);
sector = root_sectors;
for (i = 0; i < sector; ++i)
{
s_smErr = smlWriteBlock(drv_no, block, offset, acFATBuf, SECTOR_SIZE);
if (s_smErr != SM_OK)
{
SMB_FREE_BUF(acFATBuf);
return s_smErr;
}
offset += SECTOR_SIZE;
if (offset >= sm_info.pbr.bpb.sectors_per_cluster * SECTOR_SIZE)
{
++block;
offset = 0;
}
}
SMB_FREE_BUF(acFATBuf);
/*
* FAT variables initialize
*/
sm_FATInit(drv_no);
return SM_OK;
}
/**********
* Function: smMountVol
* Remarks:
* - maps string volumn name to the drive. Default name is
* "dev0", .., "dev99"
* Parameters
* . drv_no: drive number that is initialized in configuration file
* . p_vol_name: string volumn name that is mapped to the drive
**********/
SM_EXPORT ERR_CODE smMountVol(udword drv_no, const smchar* p_volumn_name)
{
ubyte *p_vol_name = (ubyte *)p_volumn_name;
if (SM_STRLEN((char*)p_vol_name) > MAX_DRIVE_NAME_LEN)
return ERR_INVALID_PARAM;
SM_STRCPY((char*)s_drvName[drv_no], (char*)p_vol_name);
return SM_OK;
}
/**********
* Function: smUnmountVol
* Remarks:
* - reverts to the default string volumn name
* (ex. "dev0", .., "dev99")
* Parameters
* . drv_no: drive number that is initialized in configuration file
**********/
SM_EXPORT ERR_CODE smUnmountVol(udword drv_no)
{
ubyte name[10];
SM_STRCPY((char*)name, "dev");
if (drv_no < 10)
{
name[4] = (ubyte)drv_no + '0';
name[5] = 0;
}
#if (MAX_DRIVE >= 10)
else if (drv_no < 100)
{
name[4] = drv_no / 10 + '0';
name[5] = drv_no % 10 + '0';
name[6] = 0;
}
else
{
name[4] = drv_no / 100 + '0';
name[5] = (drv_no / 10) % 10 + '0';
name[6] = drv_no % 10 + '0';
name[7] = 0;
}
#endif
SM_STRCPY((char*)s_drvName[drv_no], (char*)name);
return SM_OK;
}
/**********
* Function: smMoveFile
* Remarks:
* - move a file or directory to a new directory
* - old path and new path should be on the same volume
* - new path must not already exist
* Parameters
* . old_name: path of old file or directory
* . new_name: path of new file or directory
**********/
SM_EXPORT ERR_CODE smMoveFile(const smchar* old_name, const smchar* new_name)
{
udword drv_no;
F_HANDLE h_dir;
F_HANDLE h_new_dir;
F_HANDLE h_file;
ubyte fileInfo[32];
udword cluster;
udword offset;
ubyte oldName[MAX_FILE_NAME_LEN + 1];
ubyte newName[MAX_FILE_NAME_LEN + 1];
ubyte * oldPath = (ubyte *)old_name;
ubyte * newPath = (ubyte *)new_name;
sFILE_STAT sStat;
#ifdef LONG_FILE_NAME_ENABLE
uword* p_unicode;
ubyte fat_name[13];
#endif
drv_no = sm_GetDrvNo(oldPath);
if (drv_no >= MAX_DRIVE)
return ERR_INVALID_PARAM;
/* if different volumes, fail */
if (drv_no != sm_GetDrvNo(newPath))
return ERR_INVALID_PARAM;
s_smErr = sm_PreFAT(drv_no);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, s_smErr);
/* check if old & new directories are the same. */
s_smErr = sm_CheckPath(drv_no, oldPath, PATH_EXCEPT_LAST, &h_dir);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, ERR_FILE_NOT_EXIST);
s_smErr = sm_CheckPath(drv_no, newPath, PATH_EXCEPT_LAST, &h_new_dir);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, ERR_FILE_EXIST);
/* check if newPath exist. if so, fail */
s_smErr = sm_CheckPath(drv_no, newPath, PATH_FULL, &h_file);
if (s_smErr == SM_OK)
FAT_RETURN(drv_no, s_smErr);
sm_ExtractLastName(oldPath, oldName);
sm_ExtractLastName(newPath, newName);
/* retrieve old file or directory info */
s_smErr = sm_FindEntryInDirectory(drv_no, FIND_FILE_NAME, h_dir, (udword)oldName, fileInfo, &cluster, &offset);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, s_smErr);
/* delete old file */
s_smErr = sm_DeleteFromDirEntry(drv_no, h_dir, oldName);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, s_smErr);
/* create new directory entry */
sStat.attr = fileInfo[11];
sStat.cluster = fileInfo[26] | ((udword)fileInfo[27] << 8);
sStat.size = fileInfo[28] | ((udword)fileInfo[29] << 8) | ((udword)fileInfo[30] << 16) | ((udword)fileInfo[31] << 24);
sStat.time.year = 1980 + ((fileInfo[25] >> 1) & 0x7f);
sStat.time.month = ((fileInfo[25] << 3) & 0x08) | ((fileInfo[24] >> 5) & 0x07);
sStat.time.day = fileInfo[24] & 0x1f;
sStat.time.hour = (fileInfo[23] >> 3) & 0x1f;
sStat.time.min = ((fileInfo[23] << 3) & 0x38) | ((fileInfo[22] >> 5) & 0x07);
sStat.time.sec = fileInfo[22] & 0x1f;
sStat.time.msec = 0;
#ifdef LONG_FILE_NAME_ENABLE
p_unicode = (uword*)SM_MALLOC(MAX_FILE_NAME_LEN+2);
if(p_unicode == NULL)
{
FAT_RETURN(drv_no, ERR_OUT_OF_MEMORY);
}
if(sm_ConvertToFATName(newName, fat_name))
{
SM_MBS_TO_UNICODE(p_unicode, newName, 0);
s_smErr = sm_AddToDirEntry(drv_no, h_new_dir, newName, p_unicode, &sStat, 0, 0, 0);
}
else
s_smErr = sm_AddToDirEntry(drv_no, h_new_dir, newName, NULL, &sStat, 0, 0, 0);
SM_FREE(p_unicode);
#else
s_smErr = sm_AddToDirEntry(drv_no, h_new_dir, newName, NULL, &sStat, 0, 0, 0);
#endif
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, s_smErr);
FAT_RETURN(drv_no, SM_OK);
}
/**********
* Function: smRenameFile
* Remarks:
* - rename a file or directory
* - old path and new path should have the same parent path
* - new path must not already exist
* Parameters
* . old_name: path of old file or directory
* . new_name: path of new file or directory
* Notes
* - smRemoveFile deletes old_name and create new_name, but smRenameFile
* just renames old_name to new_name at the same position
* - This API is not recommended to use in normal case. It could have a lot of overheads
* that shifts the whole block contents in the worst case
**********/
SM_EXPORT ERR_CODE smRenameFile(const smchar* old_name, const smchar* new_name)
{
udword drv_no;
F_HANDLE h_dir;
F_HANDLE h_new_dir;
F_HANDLE h_file;
ubyte fileInfo[32];
udword cluster;
udword offset;
sFILE_STAT sStat;
ubyte oldName[MAX_FILE_NAME_LEN + 1];
ubyte newName[MAX_FILE_NAME_LEN + 1];
ubyte * oldPath = (ubyte *)old_name;
ubyte * newPath = (ubyte *)new_name;
#ifdef LONG_FILE_NAME_ENABLE
uword* p_unicode;
ubyte fat_name[13];
#endif
drv_no = sm_GetDrvNo(oldPath);
if (drv_no >= MAX_DRIVE)
return ERR_INVALID_PARAM;
/* if different volumes, fail */
if (drv_no != sm_GetDrvNo(newPath))
return ERR_INVALID_PARAM;
s_smErr = sm_PreFAT(drv_no);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, s_smErr);
/* check if old & new directories are the same. */
s_smErr = sm_CheckPath(drv_no, oldPath, PATH_EXCEPT_LAST, &h_dir);
if (s_smErr != SM_OK)
FAT_RETURN(drv_no, ERR_FILE_NOT_EXIST);
s_smErr = sm_CheckPath(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -