📄 fatfs.c
字号:
return mktime(theTime.tm_year, theTime.tm_mon, theTime.tm_mday, theTime.tm_hour, theTime.tm_min, theTime.tm_sec);
}
// 扫描文件根目录
//
// d: 驱动器
// f: 文件结构
// new: 是否创建新文件
//
static int
Lookup(DRIVE *d, FATFILE *f, int new) {
UINT i, j, prevc;
DIRENTRY *pe;
ULONG st;
int rc = FALSE;
UCHAR fn0;
UCHAR *tmpbuf;
CHECK_PTR(d);
CHECK_PTR(f);
//DBG1("Lookup %s...\n", f->Name);
LockDrive(d);
if(!(d->Flags & DRIVE_MOUNT))
goto ret;
// 计算根目录起始扇区
tmpbuf = d->tmpbuf;
if(d->Fat32) {
prevc = d->RootStart;
st = Clus2Sect(d, prevc);
}
else {
st = d->RootStart;
}
i = 0;
pe = (DIRENTRY *)tmpbuf;
while(1) {
// 读入一个扇区
if(!(*d->ReadSector)(d, st, tmpbuf))
goto ret;
// 每个目录项32字节,所以每扇区16个目录项
for(j = 0; j < 16; j++) {
fn0 = pe[j].FileName[0];
if(new && (!fn0 || fn0 == 0xe5)) {
//
// 新建文件
//
f->Time = GetTm();
f->DEOffst = j * 32;
f->DESt = st;
Memcpy((void*)pe[j].FileName, f->Name, 11);
pe[j].Attr = ATTR_ARCHIVE;
pe[j].TimeInTenths = 0x10;
pe[j].CreateTime = f->Time & 0xFFFF;
pe[j].CreateDate = f->Time >> 16;
pe[j].LastAccessDate = 1000;
pe[j].ClusterHigh = f->Start >> 16;
pe[j].Time = 1000;
pe[j].Date = 1000;
pe[j].ClusterLow = f->Start & 0xffff;
pe[j].Size = f->Size;
rc = (*d->WriteSector)(d, st, tmpbuf);
goto ret;
}
// 结束
if(fn0 == 0)
goto ret;
// 文件名不匹配
if(fn0 != f->Name[0])
continue;
// 文件名匹配,找到文件了
if(!memcmp((char *)pe[j].FileName, f->Name, 11)) {
f->DEOffst = j * 32;
f->DESt = st;
f->Time = pe[j].CreateTime | (pe[j].CreateDate << 16);
f->Size = pe[j].Size;
f->Start = (CLNO)((pe[j].ClusterHigh << 16) | pe[j].ClusterLow);
rc = TRUE;
goto ret;
}
}
// 察看下一个扇区
i++; // sector
if(d->Fat32) {
// 下一个簇
if(i == d->SectorsPerCluster) {
prevc = GetNextCluster(d, prevc);
if(prevc >= d->FatEnd)
break;
st = Clus2Sect(d, prevc);
i = 0;
}
else
st++;
}
else {
// FAT16
//
// 下一个扇区,判断根目录限制
if(i >= ((d->RootEntries * 32) >> d->BytesPerSectorShift))
break;
st++;
}
}
ret:
UnlockDrive(d);
return rc; // Too many files or no found
}
//
// 获取文件长度
//
UINT
FileLength(int fd) {
FATFILE *f;
ASSERT((UINT)fd < FILE_MAX);
ASSERT(Files[fd].Flags & F_OPEN);
f = &Files[fd];
if((UINT)fd >= FILE_MAX || !(f->Flags & F_OPEN))
return MAX_FILE_SIZE;
if(!(f->Drive->Flags & DRIVE_MOUNT))
return MAX_FILE_SIZE;
if(Files[fd].Flags & F_SHARE)
return Files[fd].sf->Size;
return Files[fd].Size;
}
//
// 在根目录下新建一个文件
//
// drv: 驱动器
// fn: 文件名
// sz: 预分配文件长度
//
int
CreateFile(DRIVE *drv, const char *fn, ULONG sz) {
int cls, i, fd, rc;
FATFILE *f;
char smn[4];
if(!(drv->Flags & DRIVE_MOUNT))
return -1;
//if(drv->ms != NULL)
// DBG1("CreateFile(%s)\n", fn);
fd = allocf();
ASSERT(fd != -1);
if(fd == -1)
goto ret;
f = &Files[fd];
f->Drive = drv;
if(*fn == '/' || *fn == '\\')
fn++;
// 格式化文件名
Convert(fn, f->Name);
f->Size = sz;
cls = sz >> drv->ClusterSizeShift;
if(sz & (drv->ClusterSize - 1))
cls++;
if(!cls)
cls = 1;
f->Blks = cls;
f->Clus = (CLNO *)kmalloc(cls * sizeof(CLNO));
// 分配空间
if(!AllocCluster(drv, cls, f->Clus)) {
goto err;
}
// 新建文件
f->Start = f->Clus[0];
if(!Lookup(drv, f, TRUE)) { // Exist or disk full
goto err;
}
f->Ref = 1;
f->sf = NULL;
f->Blk = -1;
f->Pos = 0;
f->Flags = F_EOF | F_OPEN;
f->Buffer = 0;
f->Magic = FILE_MAGIC;
// 将簇连接起来
for(i = 0; i < cls - 1; i++) {
rc = SetNextCluster(drv, f->Clus[i], f->Clus[i+1]);
if(!rc) {
err: kfree(f->Clus);
f->Drive = 0;
f->Flags = 0;
fd = -1;
goto ret;
}
}
// 设置最后一个簇为结束标志
rc = SetNextCluster(drv, f->Clus[i], drv->FatEnd + 1); // FAT_EOF
if(!rc)
goto err;
// 创建信号量
smn[0] = 'S';
smn[1] = 'M';
smn[2] = 'F';
smn[3] = '0' + fd;
sm_create(smn, 1, 0, &f->sm);
// 驱动器引用计数加一
drv->Ref++;
ret:
return fd;
}
//
// 删除文件
//
// drv: 驱动器
// fn: 文件名
//
int
DeleteFile(DRIVE *drv, const char *fn) {
FATFILE f;
CLNO c;
int i, rc = FALSE;
DIRENTRY *pe;
UCHAR *tmpbuf = drv->tmpbuf;
CHECK_PTR(drv);
CHECK_PTR(fn);
if(!(drv->Flags & DRIVE_MOUNT))
return FALSE;
// 查找文件
f.Drive = drv;
Convert(fn, f.Name);
if(!Lookup(drv, &f, FALSE)) // Non-exist
return FALSE;
LockDrive(drv);
// 读出文件目录项所在的扇区
if(!(*drv->ReadSector)(drv, f.DESt, tmpbuf))
goto ret;
// 做删除标记
pe = (DIRENTRY *)(tmpbuf + f.DEOffst);
pe->FileName[0] = (char)0xe5;
if(!(*drv->WriteSector)(drv, f.DESt, tmpbuf))
goto ret;
// 释放簇链
i = 0;
c = f.Start;
while(c < drv->FatEnd) {
CLNO next = GetNextCluster(drv, c);
if(!SetNextCluster(drv, c, FAT_FREE))
break;
c = next;
}
rc = TRUE;
ret:
UnlockDrive(drv);
return rc;
}
//
// 查找文件
//
//
int
FindFile(DRIVE *drv, const char *fn) {
FATFILE f;
CHECK_PTR(drv);
CHECK_PTR(fn);
if(!(drv->Flags & DRIVE_MOUNT))
return FALSE;
f.Drive = drv;
if(*fn == '/' || *fn == '\\')
fn++;
Convert(fn, f.Name);
return Lookup(drv, &f, FALSE);
}
//
// 获取文件时间
//
ULONG
GetFileTime(DRIVE *drv, const char *fn) {
FATFILE f;
CHECK_PTR(drv);
CHECK_PTR(fn);
if(!(drv->Flags & DRIVE_MOUNT))
return 0;
f.Drive = drv;
if(*fn == '/' || *fn == '\\')
fn++;
Convert(fn, f.Name);
if(Lookup(drv, &f, FALSE))
return f.Time;
return 0;
}
//
// 获取文件时间(已经打开的文件)
//
ULONG
FileTime(int fd) {
FATFILE *f;
ASSERT((UINT)fd < FILE_MAX);
ASSERT((Files[fd].Flags & F_OPEN));
f = &Files[fd];
if((UINT)fd >= FILE_MAX || !(f->Flags & F_OPEN))
return 0;
return (f->Flags & F_SHARE) ? f->sf->Time : f->Time;
}
//
// 获取文件读写位置
//
ULONG
FileTell(int fd) {
FATFILE *f;
ASSERT((UINT)fd < FILE_MAX);
ASSERT((Files[fd].Flags & F_OPEN));
f = &Files[fd];
return (f->Flags & F_SHARE) ? f->sf->Pos : f->Pos;
}
//
// 察看文件是否已经打开
//
static FATFILE *
ShareFile(const char *Name) {
int i;
for(i = 0; i < FILE_MAX; i++)
if(Files[i].Drive && !memcmp(Files[i].Name, Name, 11))
return &Files[i];
return NULL;
}
//
// 打开文件
//
int
OpenFile(DRIVE *drv, const char *fn) {
int t, c2, fd;
CLNO c;
FATFILE *f, *sf;
char smn[4];
CHECK_PTR(drv);
CHECK_PTR(fn);
if(!(drv->Flags & DRIVE_MOUNT))
return -1;
fd = allocf();
if(fd == -1)
goto ret;
// 格式化文件名
f = &Files[fd];
if(*fn == '/' || *fn == '\\')
fn++;
Convert(fn, f->Name);
// 查看文件是否已经打开
sf = ShareFile(f->Name);
if(sf != NULL) {
ASSERT(sf->Ref >= 1);
f->Drive = drv;
sf->Ref++;
f->Flags = F_SHARE | F_OPEN;
if(sf->Size == 0)
f->Flags |= F_EOF;
f->sf = sf;
f->Blk = -1;
f->Pos = 0;
f->Buffer = NULL;
f->Magic = FILE_MAGIC;
return fd;
}
// 查找文件
f->Drive = drv;
if(!Lookup(drv, f, FALSE)) { // Non-exist
DBG1("%s not found!\n", fn);
f->Drive = 0;
fd = -1;
goto ret;
}
//DBG1("%s founded!\n", fn);
t = f->Size >> drv->ClusterSizeShift;
if(f->Size & (drv->ClusterSize - 1))
t++;
f->Clus = (CLNO *)kmalloc(t * sizeof(CLNO));
// 取得簇链
c2 = 0;
c = f->Start;
while(c < drv->FatEnd) {
if(c2 == t) {
CLNO *cn = (CLNO *)kmalloc((c2 + 1) * sizeof(CLNO));
Memcpy(cn, f->Clus, c2 * sizeof(CLNO));
kfree(f->Clus);
f->Clus = cn;
}
f->Clus[c2++] = c;
c = GetNextCluster(drv, c);
}
DBG3("%s %u Bytes/%u Blocks\n", fn, f->Size, c2);
f->Ref = 1;
f->sf = NULL;
f->Blk = -1;
f->Blks = c2;
f->Pos = 0;
f->Flags = F_OPEN | (f->Size == 0 ? F_EOF : 0);
f->Buffer = 0;
f->Magic = FILE_MAGIC;
// 创建信号量
smn[0] = 'S';
smn[1] = 'M';
smn[2] = 'F';
smn[3] = '0' + fd;
sm_create(smn, 1, 0, &f->sm);
drv->Ref++;
ret:
return fd;
}
//
// 关闭文件
//
void
CloseFile(int fd) {
FATFILE *f;
ASSERT((UINT)fd < FILE_MAX);
ASSERT(Files[fd].Flags & F_OPEN);
f = &Files[fd];
if((UINT)fd < FILE_MAX && (f->Flags & F_OPEN)) {
ASSERT(f->Magic == FILE_MAGIC);
if(f->Flags & F_SHARE) {
f->Drive = NULL;
f->sf->Ref--;
f->sf->Flags |= (f->Flags & F_MODIF);
if(f->sf->Ref == 0) {
f = f->sf;
goto release;
}
return;
}
f->Ref--;
if(f->Ref != 0)
return;
release: // 如果文件内容被修改,将缓冲区内容回写
if(f->Flags & F_MODIF)
FlushBuffer(f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -