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

📄 fatfs.c

📁 基于ARM7的直流电机的驱动,还有FLASH驱动,LCD驱动等
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -