www.pudn.com > File_SD_OS.rar > file.C
/****************************************Copyright (c)**************************************************
** 广州周立功单片机发展有限公司
** 研 究 所
** 产品一部
**
** http://www.zlgmcu.com
**
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名: file.c
**创 建 人: 陈明计
**最后修改日期: 2004年4月1日
**描 述: 文件系统的文件基本操作程序
**
**--------------历史版本信息----------------------------------------------------------------------------
** 创建人: 陈明计
** 版 本: v1.00
** 日 期: 2003年9月9日
** 描 述: 原始版本
**
**--------------当前版本修订------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年7月12日
** 描 述: 更正一个BUG
**
**--------------当前版本修订------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年11月4日
** 描 述: 修改多字节读取和写入函数
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#define IN_FILE
#include "config.h"
static MY_FILE FileInfo[MAX_OPEN_FILES]; /* 打开文件信息表 */
extern uint32 _GetFDTInfo(char *FDTName, char *DirFileName);
extern char * FsStrCopy(char *source);
uint8 FS_GetDateTime(SYS_TIME *CurTime);
/*********************************************************************************************************
** 函数名称: FileInit
** 功能描述: 初始化文件指针系统
**
** 输 入: 无
**
** 输 出: 无
**
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void FileInit(void)
{
HANDLE i;
for (i = 0; i < MAX_OPEN_FILES; i++)
{
FileInfo[i].Flags = 0;
}
}
/*********************************************************************************************************
** 函数名称: FindOpenFile
** 功能描述: 查找已打开的指定文件的文件句柄,内部使用
**
** 输 入: Drive:文件所在的逻辑盘号
** DirClus:文件所在目录的开始簇号
** FileName:内部文件名
** 输 出: 文件句柄,Not_Open_FILE为没有打开
**
** 全局变量: FileInfo
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo,
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE FindOpenFile(uint8 Drive, uint32 DirClus, char FileName[11])
{
HANDLE Rt;
MY_FILE *fp;
fp = FileInfo;
for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++)
{
if (fp->Flags != 0)
if (fp->Drive == Drive)
if (fp->DirClus == DirClus)
if (fp->Name[0] == FileName[0])
if (fp->Name[1] == FileName[1])
if (fp->Name[2] == FileName[2])
if (fp->Name[3] == FileName[3])
if (fp->Name[4] == FileName[4])
if (fp->Name[5] == FileName[5])
if (fp->Name[6] == FileName[6])
if (fp->Name[7] == FileName[7])
if (fp->Name[8] == FileName[8])
if (fp->Name[9] == FileName[9])
if (fp->Name[10] == FileName[10])
{
break;
}
fp++;
}
if (Rt >= MAX_OPEN_FILES)
{
Rt = Not_Open_FILE;
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: RemoveFile
** 功能描述: 删除文件
**
** 输 入: DirFileName:用户使用的文件名
**
** 输 出: RETURN_OK:成功
** 其它参考fat.h中关于返回值的说明
** 全局变量: 无
** 调用模块: strupr,_GetFDTInfo,GetDrive,FindFDTInfo,FATDelClusChain,DelFDT
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年4月10日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 RemoveFile(char *DirFileName)
{
uint32 ClusIndex, ClusIndex1;
uint8 Drive, Rt;
char DirName[12];
FDT temp;
uint8 tmp;
DirFileName = FsStrCopy(DirFileName);
strupr(DirFileName); /* 变为大写 */
ClusIndex = _GetFDTInfo(DirName, DirFileName);
Rt = PATH_NOT_FIND;
if (ClusIndex != BAD_CLUS)
{
Drive = GetDrive(DirFileName); /* 获取文件所在逻辑盘号 */
Rt = FindFDTInfo(&temp, Drive, ClusIndex, DirName);
if (Rt == RETURN_OK)
{
Rt = NOT_FIND_FILE;
if ((temp.Attr & ATTR_DIRECTORY) == 0) /* 是文件才删除 */
{
Rt = FILE_LOCK;
tmp = FindOpenFile(Drive, ClusIndex, DirName);
if (tmp >= MAX_OPEN_FILES)
{
/* 文件没有打开才删除 */
ClusIndex1 = temp.FstClusLO + ((uint32)(temp.FstClusHI) << 16);
FATDelClusChain(Drive, ClusIndex1);
Rt = DelFDT(Drive, ClusIndex, DirName);
}
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FindOpenFileW
** 功能描述: 查找以读写方式打开的指定文件的文件句柄,内部使用
**
** 输 入: Drive:文件所在的逻辑盘号
** DirClus:文件所在目录的开始簇号
** FileName:内部文件名
** 输 出: 文件句柄,Not_Open_FILE为没有打开
**
** 全局变量: FileInfo
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo,
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE FindOpenFileW(uint8 Drive, uint32 DirClus, char FileName[11])
{
HANDLE Rt;
MY_FILE *fp;
fp = FileInfo;
for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++)
{
if ((fp->Flags & FILE_FLAGS_WRITE) != 0)
if (fp->Drive == Drive)
if (fp->DirClus == DirClus)
if (fp->Name[0] == FileName[0])
if (fp->Name[1] == FileName[1])
if (fp->Name[2] == FileName[2])
if (fp->Name[3] == FileName[3])
if (fp->Name[4] == FileName[4])
if (fp->Name[5] == FileName[5])
if (fp->Name[6] == FileName[6])
if (fp->Name[7] == FileName[7])
if (fp->Name[8] == FileName[8])
if (fp->Name[9] == FileName[9])
if (fp->Name[10] == FileName[10])
{
break;
}
fp++;
}
if (Rt >= MAX_OPEN_FILES)
{
Rt = Not_Open_FILE;
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: _FileOpenR
** 功能描述: 只读方式打开文件,内部使用
**
** 输 入: DirFileName:用户使用的文件名
**
** 输 出: 文件句柄,Not_Open_FILE为不能打开
**
** 全局变量: FileInfo
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo,
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年4月10日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE _FileOpenR(char *DirFileName)
{
MY_FILE *fp;
HANDLE Rt;
FDT FileFDT;
/* 查找空闲文件登记项 */
for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++)
{
if (FileInfo[Rt].Flags == 0)
{
break;
}
}
if (Rt < MAX_OPEN_FILES)
{
fp = FileInfo + Rt;
/* 获取目录开始簇号和文件名 */
fp->DirClus = _GetFDTInfo(fp->Name, DirFileName);
if (fp->DirClus < BAD_CLUS)
{
fp->Drive = GetDrive(DirFileName); /* 获取文件所在逻辑盘号 */
/* 获取文件信息 */
if (FindFDTInfo(&FileFDT, fp->Drive, fp->DirClus, fp->Name) == RETURN_OK)
{
if ((FileFDT.Attr & ATTR_DIRECTORY) == 0)
{
fp->Flags = FILE_FLAGS_READ;
fp->FileSize = FileFDT.FileSize;
fp->FstClus = FileFDT.FstClusLO | (uint32)FileFDT.FstClusHI << 16;
fp->Clus = fp->FstClus;
fp->Offset = 0;
return Rt;
}
}
}
}
return Not_Open_FILE;
}
/*********************************************************************************************************
** 函数名称: _FileOpenW
** 功能描述: 只写方式打开文件,内部使用
**
** 输 入: DirFileName:用户使用的文件名
**
** 输 出: 文件句柄,Not_Open_FILE为不能打开
**
** 全局变量: FileInfo
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo,
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 严寒亮
** 日 期: 2004年11月5日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE _FileOpenW(char *DirFileName)
{
MY_FILE *fp;
FDT temp;
HANDLE Rt;
uint8 i;
SYS_TIME CurTime,CrtTime; // 保存当前时间日期 yhl
for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++) // 获取空闲的登记项
{
if (FileInfo[Rt].Flags == 0)
{
break;
}
}
if (Rt < MAX_OPEN_FILES)
{
fp = FileInfo + Rt; // 指向获得的空闲登记项
/* 获取目录开始簇号和文件名 */
fp->DirClus = _GetFDTInfo(fp->Name, DirFileName); // 获取该文件的FDT项的首簇号,及文件名
if (fp->DirClus < BAD_CLUS)
{
fp->Drive = GetDrive(DirFileName); /* 获取文件所在逻辑盘号 */
/* 文件已经以读写方式打开,不能再次以读写方式打开 */
if (FindOpenFileW(fp->Drive, fp->DirClus, fp->Name) == Not_Open_FILE)
{
if(FS_GetDateTime(&CurTime) != RETURN_OK) // 获取当前系统时间
{
return GET_TIME_ERR;
}
if (FindFDTInfo(&temp, fp->Drive, fp->DirClus, fp->Name) == RETURN_OK)
{
if ((temp.Attr & ATTR_DIRECTORY) != 0)
{
return Not_Open_FILE; // 如果该文件为目录,则不能删除
}
CrtTime.date = temp.CrtDate; // 保存文件建立时间
CrtTime.time = temp.CrtTime;
CrtTime.msec = temp.CrtTimeTenth;
if (RemoveFile(DirFileName) != RETURN_OK) /* 删除文件 */
{
return Not_Open_FILE;
}
}
else
{
CrtTime = CurTime; // 设置文件建立时间为当前时间
}
/* 创建文件 */
for (i = 0; i < 11; i++) // 创建将要生成文件的FDT项
{
temp.Name[i] = fp->Name[i]; // 复制名字
}
temp.Attr = 0; // 特性为0
temp.FileSize = 0;
temp.NTRes = 0;
/*-------在此加入创建时间的程序---------*/
temp.CrtTimeTenth = CrtTime.msec;
temp.CrtTime = CrtTime.time;
temp.CrtDate = CrtTime.date;
temp.LstAccDate = CurTime.date;
temp.WrtTime = CurTime.time + 1;
temp.WrtDate = CurTime.date;
/*--------------------------------------*/
temp.FstClusLO = 0;
temp.FstClusHI = 0;
if (AddFDT(fp->Drive, fp->DirClus, &temp) == RETURN_OK) /* 增加文件 */
{
/* 设置文件信息 */
fp->Flags = FILE_FLAGS_READ | FILE_FLAGS_WRITE;
fp->FileSize = 0;
fp->FstClus = 0;
fp->Clus = 0;
fp->Offset = 0;
return Rt;
} // if(Add..)
} // if(Find..)
} // if(fp..)
} // if(Rt..)
return Not_Open_FILE;
}
/*********************************************************************************************************
** 函数名称: _FileOpenRW
** 功能描述: 只读写方式打开文件,内部使用
**
** 输 入: DirFileName:用户使用的文件名
**
** 输 出: 文件句柄,Not_Open_FILE为不能打开
**
** 全局变量: 无
** 调用模块: _FileOpenR,_FileOpenW
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE _FileOpenRW(char *DirFileName)
{
HANDLE Rt;
Rt = _FileOpenR(DirFileName);
if (Rt == Not_Open_FILE)
{
Rt = _FileOpenW(DirFileName);
}
else
{
if (FindOpenFileW(FileInfo[Rt].Drive, FileInfo[Rt].DirClus, FileInfo[Rt].Name) == Not_Open_FILE)
{
FileInfo[Rt].Flags |= (FILE_FLAGS_WRITE | FILE_FLAGS_READ);
}
else
{
FileInfo[Rt].Flags = 0;
Rt = Not_Open_FILE;
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileOpen
** 功能描述: 以指定方式打开文件
**
** 输 入: DirFileName:用户使用的文件名
** Type:打开方式
** 输 出: 文件句柄,Not_Open_FILE为不能打开
**
** 全局变量: 无
** 调用模块: _FileOpenR,_FileOpenW,_FileOpenRW
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
HANDLE FileOpen(char *DirFileName, char *Type)
{
HANDLE Rt;
Rt = Not_Open_FILE;
Type = FsStrCopy(Type);
strupr(Type);
if (Type[0] == 'R')
{
if (Type[1] == 'W')
{
DirFileName = FsStrCopy(DirFileName);
strupr(DirFileName);
Rt = _FileOpenRW(DirFileName);
}
else
{
DirFileName = FsStrCopy(DirFileName);
strupr(DirFileName);
Rt = _FileOpenR(DirFileName);
}
return Rt;
}
if (Type[0] == 'W')
{
if (Type[1] == 'R')
{
DirFileName = FsStrCopy(DirFileName);
strupr(DirFileName);
Rt = _FileOpenRW(DirFileName);
}
else
{
DirFileName = FsStrCopy(DirFileName);
strupr(DirFileName);
Rt = _FileOpenW(DirFileName);
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileClose
** 功能描述: 关闭指定文件
**
** 输 入: Handle:文件句柄
**
** 输 出: RETURN_OK:成功
** 其它参考fat.h中关于返回值的说明
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 严寒亮
** 日 期: 2004年11月5日
** 说 明: 增加文件的最后访问时间属性和最后修改时间属性
**------------------------------------------------------------------------------------------------------
** 流 程: 判断文件是否有写状态-Y->取出该文件FDT项-->判断文件大小是否变化-Y->更新FDT中首簇号-->保存FDT项
** 注 意: 关闭文件后,将释放其登记项,并把修改过的扇区回写保存,但其仍占用原来的cache。
********************************************************************************************************/
uint8 FileClose(HANDLE Handle)
{
uint8 Rt;
FDT FileFDT;
MY_FILE *fp;
SYS_TIME CurTime;
Rt = PARAMETER_ERR;
if (Handle < MAX_OPEN_FILES)
{
if(FS_GetDateTime(&CurTime) != RETURN_OK) // 获取当前时间
{
return GET_TIME_ERR;
}
fp = FileInfo + Handle; // 获取该文件的FDT项
Rt = FindFDTInfo(&FileFDT, fp->Drive, fp->DirClus, fp->Name);
if (Rt != RETURN_OK)
{
return Rt;
}
FileFDT.LstAccDate = CurTime.date; // 更新文件最后访问时间
// 如果文件不是以只写方式打开就不需要保存
if ((fp->Flags & FILE_FLAGS_WRITE) == FILE_FLAGS_WRITE)
{
if (FileFDT.FileSize < fp->FileSize) // 查看文件大小是否发生变化
{
FileFDT.FileSize = fp->FileSize;
// 更新文件最后修改时间
FileFDT.WrtTime = CurTime.time + 1; // 修改时间需要加2秒,因为它不能计算到毫秒戳
FileFDT.WrtDate = CurTime.date;
if (FileFDT.FstClusLO == 0)
if (FileFDT.FstClusHI == 0)
{
FileFDT.FstClusLO = fp->FstClus & 0xffff;
FileFDT.FstClusHI = (fp->FstClus >> 16) & 0xffff;
}
}
}
ChangeFDT(fp->Drive, fp->DirClus, &FileFDT); // 将修改后的FDT项保存
fp->Flags = 0;
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileGetCh
** 功能描述: 从文件读一个字节
**
** 输 入: Ch:返回读到的数据
** Handle:文件句柄
** 输 出: RETURN_OK:成功
** 其它参考fat.h中关于返回值的说明
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年4月10日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 FileGetCh(uint8 *Ch, HANDLE Handle)
{
uint32 i, j, SecIndex;
MY_FILE *fp;
Disk_Info * DiskInfo;
uint8 Rt;
uint8 *Buf;
Rt = PARAMETER_ERR;
fp = FileInfo + Handle;
if (Handle < MAX_OPEN_FILES) /* Handle是否有效 */
if (fp->Flags != 0) /* 对应的打开文件信息表是否已使用 */
{
Rt = FILE_EOF;
if (fp->Offset >= fp->FileSize)
{
/* 如果读数据超出文件的长度,看一看谁否有别的程序正在写这个文件 */
/* 如果有,则可能文件的长度有变化,更正之*/
Handle = FindOpenFileW(fp->Drive, fp->DirClus, fp->Name);
if (Handle < MAX_OPEN_FILES)
{
fp->FileSize = FileInfo[Handle].FileSize;
if (fp->Offset == 0)
{
fp->FstClus = FileInfo[Handle].FstClus;
fp->Clus = fp->FstClus;
}
}
}
Rt = FILE_EOF;
if (fp->Offset < fp->FileSize) /* 是否到文件结束 */
{
Rt = NOT_FIND_DISK;
/* 获取文件所在逻辑盘信息 */
DiskInfo = GetDiskInfo(fp->Drive);
if (DiskInfo != NULL)
{
/* 计算数据所在扇区 */
j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec);
i = j / DiskInfo->BytsPerSec;
j = j % DiskInfo->BytsPerSec;
SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +
DiskInfo->DataStartSec + i;
Rt = SECTOR_READ_ERR;
/* 打开扇区 */
Buf = OpenSec(fp->Drive, SecIndex);
if (Buf != NULL)
{
/* 读取扇区数据 */
if (ReadSec(fp->Drive, SecIndex) == RETURN_OK)
{
/* 读取数据 */
*Ch = Buf[j];
/* 调整文件指针 */
fp->Offset++;
j++;
if (j >= DiskInfo->BytsPerSec)
{
i++;
if (i >= DiskInfo->SecPerClus)
{
fp->Clus = FATGetNextClus(fp->Drive, fp->Clus);
}
}
Rt = RETURN_OK;
}
/* 关闭扇区 */
CloseSec(fp->Drive, SecIndex);
}
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileRead
** 功能描述: 读取文件
**
** 输 入: Buf:保存读回的数据
** Size:要读的字节数
** Handle:文件句柄
** 输 出: 实际读到的字节数
**
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint32 FileRead(void *Buf, uint32 Size, HANDLE Handle)
{
uint32 i, j, k, SecIndex;
MY_FILE *fp;
Disk_Info * DiskInfo;
uint32 Rt;
uint8 *Buf1, *Buf2;
Rt = 0;
fp = FileInfo + Handle;
Buf2 = (uint8 *)Buf;
if (Handle < MAX_OPEN_FILES) /* Handle是否有效 */
if (fp->Flags != 0) /* 对应的打开文件信息表是否已使用 */
{
if (fp->Offset + Size >= fp->FileSize)
{
/* 如果读数据超出文件的长度,看一看谁否有别的程序正在写这个文件 */
/* 如果有,则可能文件的长度有变化,更正之*/
Handle = FindOpenFileW(fp->Drive, fp->DirClus, fp->Name);
if (Handle < MAX_OPEN_FILES)
{
fp->FileSize = FileInfo[Handle].FileSize;
if (fp->Offset == 0)
{
fp->FstClus = FileInfo[Handle].FstClus;
fp->Clus = fp->FstClus;
}
}
}
while (Size != 0)
{
if (fp->Offset >= fp->FileSize) /* 是否到文件结束 */
{
break;
}
/* 获取文件所在逻辑盘信息 */
DiskInfo = GetDiskInfo(fp->Drive);
if (DiskInfo == NULL)
{
break;
}
/* 计算数据所在扇区 */
j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec);
i = j / DiskInfo->BytsPerSec;
j = j % DiskInfo->BytsPerSec;
SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +
DiskInfo->DataStartSec + i;
/* 打开扇区 */
Buf1 = OpenSec(fp->Drive, SecIndex);
if (Buf1 == NULL)
{
break;
}
/* 读取扇区数据 */
if (ReadSec(fp->Drive, SecIndex) != RETURN_OK)
{
break;
}
/* 读取数据 */
k = DiskInfo->BytsPerSec - j;
if (Size < k)
{
k = Size;
}
if ((fp->Offset + k) > fp->FileSize)
{
k = fp->FileSize - fp->Offset;
}
Size -= k;
Rt += k;
fp->Offset += k;
memcpy(Buf2, Buf1 + j, k);
Buf2 += k;
/* 关闭扇区 */
CloseSec(fp->Drive, SecIndex);
j += k;
if (j >= DiskInfo->BytsPerSec)
{
i++;
if (i >= DiskInfo->SecPerClus)
{
fp->Clus = FATGetNextClus(fp->Drive, fp->Clus);
}
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FilePutCh
** 功能描述: 写一个字节到文件
**
** 输 入: Ch:要写的数据
** Handle:文件句柄
** 输 出: RETURN_OK:成功
** 其它参考fat.h中关于返回值的说明
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年4月10日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 FilePutCh(uint8 Ch, HANDLE Handle)
{
uint32 i, j, SecIndex;
MY_FILE *fp;
Disk_Info * DiskInfo;
uint8 Rt;
uint8 *Buf;
Rt = PARAMETER_ERR;
fp = FileInfo + Handle;
if (Handle < MAX_OPEN_FILES) /* Handle是否有效 */
if (((fp->Flags) & FILE_FLAGS_WRITE) != 0) /* 文件是否可写 */
{
Rt = FILE_EOF;
if (fp->Offset <= fp->FileSize)
{
Rt = NOT_FIND_DISK;
/* 获取文件所在逻辑盘信息 */
DiskInfo = GetDiskInfo(fp->Drive);
if (DiskInfo != NULL)
{
j = (fp->Offset) % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec);
if (j == 0)
if (fp->Offset == fp->FileSize)
{
i = FATAddClus(fp->Drive, fp->Clus);
if (i >= BAD_CLUS)
{
return DISK_FULL;
}
fp->Clus = i;
if (fp->FstClus == EMPTY_CLUS)
{
fp->FstClus = i;
}
}
/* 计算数据所在扇区 */
i = j / DiskInfo->BytsPerSec;
j = j % DiskInfo->BytsPerSec;
SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus + DiskInfo->DataStartSec + i;
Rt = SECTOR_READ_ERR;
/* 打开扇区 */
Buf = OpenSec(fp->Drive, SecIndex);
if (Buf != NULL)
{
/* 写扇区数据 */
if (ReadSec(fp->Drive, SecIndex) == RETURN_OK)
{
/* 存储数据 */
Buf[j] = Ch;
WriteSec(fp->Drive, SecIndex);
Rt = RETURN_OK;
}
CloseSec(fp->Drive, SecIndex);
}
/* 调整打开文件信息表 */
fp->Offset++;
if (fp->Offset > fp->FileSize)
{
fp->FileSize = fp->Offset;
}
if ((j + 1) >= DiskInfo->BytsPerSec)
{
if ((i + 1) >= DiskInfo->SecPerClus)
if (fp->Offset < fp->FileSize)
{
fp->Clus = FATGetNextClus(fp->Drive, fp->Clus);
}
}
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileWrite
** 功能描述: 写文件
**
** 输 入: Buf:要写的数据
** Size:要写的字节数
** Handle:文件句柄
** 输 出: 实际写的字节数
**
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint32 FileWrite(void *Buf, uint32 Size, HANDLE Handle)
{
uint32 i, j, k, SecIndex;
MY_FILE *fp;
Disk_Info * DiskInfo;
uint32 Rt;
uint8 *Buf1, *Buf2;
if (Size == 0)
{
return 0;
}
Rt = 0;
fp = FileInfo + Handle; // 获得登记项句柄
Buf2 = (uint8 *)Buf; // 数据源
if (Handle < MAX_OPEN_FILES) /* Handle是否有效 */
if (((fp->Flags) & FILE_FLAGS_WRITE) != 0) /* 文件是否可写 */
{
if (fp->Offset > fp->FileSize) // 偏移超出文件范围,返回
{
return 0;
}
while (Size != 0)
{
/* 获取文件所在逻辑盘信息 */
DiskInfo = GetDiskInfo(fp->Drive);
if (DiskInfo == NULL)
{
break;
}
/* 计算数据所在扇区 */
j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec); // 字节偏移量(簇内)
if (j == 0)
if (fp->Offset == fp->FileSize)
{ // 如果指向簇的最后一字节,并且偏移量等于文件大小,即指向文件最后一个字节
i = FATAddClus(fp->Drive, fp->Clus); // 则需要增加新簇
if (i >= BAD_CLUS)
{
return DISK_FULL;
}
fp->Clus = i;
if (fp->FstClus == EMPTY_CLUS)
{
fp->FstClus = i;
}
}
i = j / DiskInfo->BytsPerSec; // 扇区偏移(簇内)
j = j % DiskInfo->BytsPerSec; // 字节偏移(扇区内)
SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +
DiskInfo->DataStartSec + i;
k = DiskInfo->BytsPerSec - j; // 扇区剩余字节
if (Size < k) // 如果该扇区的空闲字节大于要保存的文件大小
{
k = Size;
}
/* 打开扇区 */
Buf1 = OpenSec(fp->Drive, SecIndex);
if (Buf1 == NULL)
{
break;
}
/* 读取扇区数据 */
if (ReadSec(fp->Drive, SecIndex) != RETURN_OK)
{
break;
}
memcpy(Buf1 + j, Buf2, k); // 数据复制,从数据源Buf2复制K字节数据到Buf1+j
Buf2 += k; // 数据源指针加K
/* 关闭扇区 */
WriteSec(fp->Drive, SecIndex); // 设置被修改标记
CloseSec(fp->Drive, SecIndex);
Size -= k; // 剩余待写入数据量减k
Rt += k;
/* 调整文件指针 */
fp->Offset += k; // 写入点指针偏移位置+k
if (fp->Offset > fp->FileSize) // 如果文件增大,更新文件大小值
{
fp->FileSize = fp->Offset;
}
if ((j + k) >= DiskInfo->BytsPerSec)
{
if ((i + 1) >= DiskInfo->SecPerClus)
if (fp->Offset < fp->FileSize)
{
fp->Clus = FATGetNextClus(fp->Drive, fp->Clus);
}
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FileCloseAll
** 功能描述: 关闭所有打开的文件
**
** 输 入: 无
**
** 输 出: 无
**
** 全局变量: FileInfo
** 调用模块: AllCacheWriteBack
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void FileCloseAll(void)
{
uint32 i;
for (i = 0; i < MAX_OPEN_FILES; i++)
{
FileClose(i);
}
AllCacheWriteBack();
}
/*********************************************************************************************************
** 函数名称: FileEof
** 功能描述: 判断文件是否到读\写到文件尾
**
** 输 入: Handle:文件句柄
**
** 输 出: 0:否
** 1:是
** 全局变量: FileInfo
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 FileEof(HANDLE Handle)
{
if (Handle < MAX_OPEN_FILES)
if (FileInfo[Handle].Offset < FileInfo[Handle].FileSize)
{
return 0;
}
return 1;
}
/*********************************************************************************************************
** 函数名称: FileSeek
** 功能描述: 移动文件读\写位置
**
** 输 入: Handle:文件句柄
** offset:移动偏移量
** Whence:移动模式SEEK_SET:从文件头计算SEEK_CUR:从当前位置计算SEEK_END:从文件尾计算
** 输 出: 无
**
** 全局变量: 无
** 调用模块: 无
**
** 作 者: 陈明计
** 日 期: 2003年6月5日
**-------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年4月10日
**------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 日 期: 2004年7月12日
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 FileSeek(HANDLE Handle, int32 offset, uint8 Whence)
{
uint8 Rt;
uint32 i, Clus;
MY_FILE *fp;
Disk_Info * DiskInfo;
Rt = PARAMETER_ERR;
fp = FileInfo + Handle;
if (Handle < MAX_OPEN_FILES) /* Handle是否有效 */
if (fp->Flags != 0) /* 对应的打开文件信息表是否已使用 */
{
Rt = RETURN_OK;
switch (Whence)
{
case SEEK_END: /* 从文件尾计算 */
fp->Offset = fp->FileSize - offset;
offset = -offset;
break;
case SEEK_SET:
fp->Offset = offset;
break;
case SEEK_CUR: /* 从当前位置计算 这里不用break是正确的*/
i = fp->Offset + offset;
break;
default:
Rt = PARAMETER_ERR;
break;
}
/* 改变当前簇号 */
if (Rt == RETURN_OK)
{
if (fp->Offset > fp->FileSize)
{
if (offset > 0)
{
fp->Offset = fp->FileSize;
}
else
{
fp->Offset = 0;
}
}
Rt = NOT_FIND_DISK;
DiskInfo = GetDiskInfo(fp->Drive);
if (DiskInfo != NULL)
{
Rt = RETURN_OK;
i = fp->Offset / (DiskInfo->BytsPerSec * DiskInfo->SecPerClus);
Clus = fp->FstClus;
for (; i != 0; i--)
{
Clus = FATGetNextClus(fp->Drive, Clus);
if (Clus >= BAD_CLUS)
{
Rt = FAT_ERR;
break;
}
}
fp->Clus = Clus;
}
}
}
return Rt;
}
/*********************************************************************************************************
** 函数名称: FS_GetDateTime
** 功能描述: 时间格式转换函数,将DATE_TIME格式的数据转换为SYS_TIME格式的时间数据
**
** 输 入: CurTime 指向保存结果
**
** 输 出: 错误代码,RETURN_OK为正确
**
** 全局变量: 无
** 调用模块: GetDataTime
**
** 作 者: 严寒亮
** 日 期: 2004年11月3日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8 FS_GetDateTime(SYS_TIME *CurTime)
{
uint8 temp8;
uint16 temp16 = 0;
DATE_TIME Time;
temp8 = GetDataTime(&Time); // 获取当前时间
if(temp8 != RETURN_OK)
{
return temp8; // 如果获取失败,就返回错误代码
}
/* 时间格式转换 */
if(Time.da_year > 1980)
{
temp16 = Time.da_year - 1980; // 年,如果当前年小于1980年,设为0
}
temp16 = (temp16 & 0x7F) << 9; // 年:9~15位
temp16 |= (Time.da_mon & 0x0F) << 5; // 月:5~8位
temp16 |= Time.da_day & 0x1F ; // 日:0~4位
CurTime->date = temp16;
temp16 = (Time.ti_hour & 0x1F) << 11; // 时:11~15位
temp16 |= (Time.ti_min & 0x3F) << 5; // 分:5~10位
temp16 |= (Time.ti_sec & 0x3F) >> 1; // 秒,变为2秒的倍数:0~4位
CurTime->time = temp16;
if((Time.ti_sec & 0x01) == 0x01)
{
temp8 = 100; // 如果当前秒为奇数,毫秒戳加上100
}
temp8 += Time.ti_hund; // 加上百分之一秒数
CurTime->msec = temp8;
return RETURN_OK;
}
/*********************************************************************************************************
** End Of File
********************************************************************************************************/