七、支持长文件名(二)。
4、先在0:/doc下建立好目录:这是一个very long的目录.它里面是空的.txt文档
这次再调用命令flist 0:/doc/这是一个very long的目录.它里面是空的.txt文档。
从串口follow_path(dj, path)输入是,都是以ascii码和GB2312码的形式发过去的。程序仍然是调用调用先函数 chk_mounted(),然后调用follow_path(dj, path)。在follow_path(dj, path)里,又分别调用create_name()函数和dir_find()函数。这次的关键是:对于这么一个长目录名,这两个函数分别是怎么处理的。
追踪进入create_name()函数。
if (IsDBCS1(w)) { b = p[si++]; w = (w << 8) + b; }
w = ff_convert(w, 1);
lfn[di++] = w;
它的主要动作使将接收到的 DBCS双字节 和 ASCII码单字节 都转换为unicode码存入dj->lfn长文件名缓冲区。再跟踪短文件名的创建,我发现这次创建的短文件名明显不符合要求。明明是一个目录,也创建了这样的短文件名“这是一个txt”这样的短文件名。再进入dir_find()函数看怎么处理。
追踪进入,这一次它的搜索是在0:/bin目录对应的簇里面,找到长目录项的过程跟dir_read()函数完全一样,只是每次不是pick_lfn(dj->lfn, dir),而是采用cmp_lfn(dj->lfn, dir)了,它的作用是对比当前长目录项里的unicode和dj->lfn存储区的unicode字符,如果一直到ord=0,对比都返回TRUE,则找到相应的长目录项。追踪进入,函数比较简单,逐个比较13个字节。
定位到短文件名目录项后,if (!ord && sum == sum_sfn(dir)) break,根本不对比短文件名,直接跳出搜索循环,这样实际上已经定位到所要找的目录。
回到,取得长目录的起始簇号。再调用f_readdir()函数获得各个目录项的属性就很方便了,上一篇文章已经分析过,这里就不再赘述了。
5、调用fwrite命令在0:/doc下建立文件:这是一个very long的文件.它里面是空的.txt文档
上一篇分析时用到的长文件名,再来分析一下这样的长文件名目录项是如何在文件系统那个里面建立起来的?
输入命令 fwrite 0:/doc/这是一个very long的文件.它里面是空的.txt文档
程序会调用f_open()函数,以创建新文件的方式打开该文档。在调用follow_path进行文件搜索的时候,最后一次在DIR结构里建立了长文件名缓冲和短文件名缓冲:
res = create_name(dj, &path); /* Get a segment */
res = dir_find(dj); 但是在执行这一句是找不到对应的文件(因为还没有建立,现在就是要建立这个文件)。结果follow_path()函数返回FR_NO_FILE。
执行流程回到f_open()函数,函数在FA_CREATE_NEW模式下调用dir_register(&dj)函数进行新目录项的添加。(这里要记住,在create_name()函数里面产生的短目录项名是不符合规定的,那么在dir_register()函数里应该进行新的处理。)追踪进入dir_register(&dj)函数。
进入dir_register(&dj)函数,果然先进行标准短文件名的创建:
gen_numname(fn, sn, lfn, n); /* 按数字规则产生这是一~1.txt或者这是一~2.txt这样的短文件名 */
res = dir_find(dj);//如果对应的n(1、2、3等)没用被使用就跳出循环,如果已被使用,则n+1再次循环。进入 gen_numname(fn, sn, lfn, n)看短文件名是如何产生的。
i=7;
do {
ns[i--] = (num % 10) + '0';
num /= 10;
} while (num);
ns = '~';
这里可以简单看出文件名后缀产生的过程。
回到dir_register(&dj)函数,调用dir_seek(dj, 0),回到0:/bin目录所在簇的开始,接下来要搜寻几个连续的空目录项,这里应该是4个,用于三个长文件目录项和一个短文件目录项,其搜寻方法如下:
ne = (ne + 25) / 13;共需要ne个目录项。29+25/13=3个。
循环搜索目录项:
if (c == 0xE5 || c == 0) { /* 搜索到一个空的 */
if (n == 0) is = dj->index; 长目录项进行定位,继续搜索
if (++n == ne) break; 如果连续碰到ne个,则跳出循环
} else {
n = 0; /* 在没有到ne+1个之前,碰到一个非空,立即清0 */
}
找到ne+1个空的目录项以后,首先res = dir_seek(dj, is)定位到空目录项的第一个。然后调用以下代码:
sum = sum_sfn(dj->fn); /* 计算短文件名的校验和 */
ne--;
do { /* Store LFN entries in bottom first */
res = move_window(dj->fs, dj->sect);
fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum); //调用这个函数将dj->lfn缓冲区的unicode依次写入目录项。
dj->fs->wflag = 1;
res = dir_next(dj, FALSE); /* Next entry */
} while (res == FR_OK && --ne);
长目录项写好以后,再写对应的短目录项:
mem_set(dir, 0, 32); /* Clean the entry */
mem_cpy(dir, dj->fn, 11); /* Put SFN */
dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);
这里实际上只写入了标准文件名和属性,其它的创建时间等信息等待f_open()函数完成。
文件的创建就算是完成了。
6、调用fdel命令在0:/doc下删除文件:这是一个very long的文件.它里面是空的.txt文档
这里主要是要观测长目录项的删除过程。
删除文件由f_unlink()函数调用dir_remove(&dj)函数完成。追踪进入dir_remove(&dj)。
i = dj->index; /* SFN index */
res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));
i保存当前短目录项的索引,然后dj->index定位到长目录项的起始索引,将这些目录的首个字母全部写入0xE5,目录项就算全部删除了。
再回到f_unlink()删除该文件的簇链,文件删除完成。
八、FatFS的其它特性和新进展
1、支持重入功能
在多任务操作系统中,各个任务是并发的。当它们要同时访问文件系统时,先要获得同步对象。比如在ucos中,可以采用互斥信号量来同步。在f_mount()时,创建同步对象,在check_mount()和validate()函数调用时,先申请同步对象,若是其它任务在使用文件系统,则在同步对象上等待。任务完成后,再释放同步对象。
这个功能与操作系统的任务同步特性相关,以后如果要使用这个特性的话在详细分析。
2、支持文件的共享打开(主要是多次以读的方式打开)
这是FatFs作者在3月份新上传的R008 Rev1版本里新增加的功能:
在ffconf.h中增加了_FS_SHARE共享数目定义。
在ff.h增加了:文件共享信息结构体定义,并在文件系统结构体中使用。
typedef struct _FILESEM_ {
DWORD clu; /* File ID 1, directory */
WORD idx; /* File ID 2, index in the directory */
WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:in write open */
} FILESEM;
在ff.c中增加了四个函数:
FRESULT chk_lock ( /* 检查文件是否可以被访问 */
DIR* dj, /* Directory object pointing the file to be checked */
int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
)
BOOL enq_lock ( /* 为一个新文件找到可用的文件共享结构体 */
FATFS* fs /* File system object */
)
UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
DIR* dj, /* Directory object pointing the file to increment */
int acc /* Desired access mode (0:Read, !0:Write) */
)
FRESULT dec_lock ( /* Decrement file open counter */
FATFS* fs, /* File system object */
UINT i /* Semaphore index */
)
主要调用的地方是f_open()和f_close()函数。
3、支持文件的快速定位。
这是FatFs作者在3月份新上传的R008 Rev1版本里新增加的功能:
在ffconf.h 定义了_USE_FASTSEEK,用于支持文件的快速定位。
FRESULT f_lseek (
FIL *fp, /* Pointer to the file object */
DWORD ofs, /* File pointer from top of file */
DWORD *tbl /* Pointer to cluster link map table */
)
说明是这样描述的:
The f_lseek function has been changed to implement fast seek feature. But the additional 3rd argument is ignored unless fast seek feature is enabled (_USE_FASTSEEK == 1). To use this feature, give a pointer to the working buffer to store the cluster link map to the 3rd argument.
主要意思是在内存中划一块缓冲区用于存储 文件的簇链映射图,以方便查找簇链。稍微阅读了以下源代码,其实现方法是这样的:当给出参数ofs == CREATE_LINKMAP的时候,在tbl所指向的内存区域建立新的簇链映射。
表的第一项是整个映射表的长度,以后每两项为一对:前者存储相邻簇的数目,后者存储相邻簇的起始簇号。举个例子,某个文件占据5、6、7、8、15、16、17共7个簇,则需要两对表项。分别是(4,5)和(3,15)两项。
以后就可以利用该簇链映射图实现文件的快速定位了,不用沿着簇链一项一项找下去,最后实现定位。
4、支持长文件名缓冲区的动态分配。
这是FatFs作者在3月份新上传的R008 Rev1版本里新增加的功能:
这个主要靠运行时系统动态内存分配,这里就不再详细叙述了。
以上的功能实现和使用,我都会一直关注。如果以后学习过程中需要用到或者我的开发板满足使用要求了,再去实验这些功能。
文章评论(0条评论)
登录后参与讨论