Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
文件系统
文件系统目录操作的严重问题(齐心协力已解决)
发布于 2012-10-30 21:36:28 浏览:6772
订阅该版
测试代码如下: ```c { int fd; DIR* dir; struct dirent* dirp; off_t off[6]; int i; mkdir("/testdir",0777); fd = open("/testdir/file1",O_CREAT|O_RDWR,0777); close(fd); fd = open("/testdir/file2",O_CREAT|O_RDWR,0777); close(fd); fd = open("/testdir/file3",O_CREAT|O_RDWR,0777); close(fd); fd = open("/testdir/file4",O_CREAT|O_RDWR,0777); close(fd); fd = open("/testdir/file5",O_CREAT|O_RDWR,0777); close(fd); fd = open("/testdir/file6",O_CREAT|O_RDWR,0777); close(fd); dir = opendir("/testdir"); for(i=0;i<6;i++) { off* = telldir(dir); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } for(i=0;i<6;i++) { seekdir(dir,off*); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } rt_kprintf("unlink file2 "); unlink("/testdir/file2"); rewinddir(dir); for(i=0;i<6;i++) { off* = telldir(dir); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } for(i=0;i<6;i++) { seekdir(dir,off*); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } rt_kprintf("unlink file4 "); unlink("/testdir/file4"); rewinddir(dir); for(i=0;i<6;i++) { off* = telldir(dir); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } for(i=0;i<6;i++) { seekdir(dir,off*); dirp = readdir(dir); if(dirp) rt_kprintf("#%d NAME:%s ",i,dirp->d_name); else break; } unlink("/testdir/file1"); unlink("/testdir/file3"); unlink("/testdir/file5"); unlink("/testdir/file6"); closedir(dir); } ``` 运行结果: ``` #0 NAME:FILE1 #1 NAME:FILE2 #2 NAME:FILE3 #3 NAME:FILE4 #4 NAME:FILE5 #5 NAME:FILE6 #0 NAME:FILE1 #1 NAME:FILE2 #2 NAME:FILE3 #3 NAME:FILE4 #4 NAME:FILE5 #5 NAME:FILE6 unlink file2 #0 NAME:FILE1 #1 NAME:FILE3 #2 NAME:FILE4 #3 NAME:FILE5 #4 NAME:FILE6 #0 NAME:FILE1 #1 NAME:FILE1 #2 NAME:FILE1 #3 NAME:FILE3 #4 NAME:FILE3 #5 NAME:FILE4 unlink file4 #0 NAME:FILE1 #1 NAME:FILE3 #2 NAME:FILE5 #3 NAME:FILE6 #0 NAME:FILE1 #1 NAME:FILE1 #2 NAME:FILE1 #3 NAME:FILE3 #4 NAME:FILE3 #5 NAME:FILE5 ``` 从运行结果可以看到删除文件对目录操作的影响。 ![psb1.jpg](https://oss-club.rt-thread.org/uploads/3948_d547e0db1dce91018dcbbd53df1f5ef7.jpg) ![psb2.jpg](https://oss-club.rt-thread.org/uploads/3948_c88a66d1050016442ef1231861255a08.jpg) ![psb3.jpg](https://oss-club.rt-thread.org/uploads/3948_f2d8086cb5a535adf8a8b8a5a19524b2.jpg) ![psb5.jpg](https://oss-club.rt-thread.org/uploads/3948_ddffa4155579a867ef54d8b0a7313b16.jpg)
查看更多
18
个回答
默认排序
按发布时间排序
prife
2012-10-31
这家伙很懒,什么也没写!
明天我来看看。的确有问题,我来处理下。
amsl
2012-11-01
这家伙很懒,什么也没写!
在unlink之前是不是要先closedir呢。应该是先closedir,再unlink,如果需要查看文件列表,再opendir。
rtt-fans
2012-11-03
这家伙很懒,什么也没写!
>在unlink之前是不是要先closedir呢。应该是先closedir,再unlink,如果需要查看文件列表,再opendir。 --- 这样做好像也是不行的。
rtt-fans
2012-11-13
这家伙很懒,什么也没写!
我按照fat文件系统分析,一个目录表中的各个表项是一个顺序表,删除文件操作会在表项中做出标记,就留下了空洞,添加文件会补齐前面有空洞的目录表,肯定不会为了删除一个文件把目录表后面的各个项往前移。假设1表示目录表项中存在一个文件或目录,0表示空洞和删除的文件或目录。 如题目中的创建过程,目录表项为:00111111,总共6个文件,前面两个空洞是.和..项,如果用fat文件系统的f_seekdir来定位目录,其中的offset是目录表项的偏移量,偏移到0取出.,偏移到1取出..,偏移到2取出第一个文件,偏移到3取出第二个文件,但是在f_readdir的时候会忽略.和..以及删除的项。 如题目所示,删除file2后,目录表项为:00101111,那么偏移到0会读出file1,偏移到1读出file1,偏移到2读出file1,偏移到3读出file3,偏移到4读出file3,。。。 因此问题就这样出现了。 因此在上层的dfs文件系统中不能假设目录文件是个顺序无空洞的文件。
rtt-fans
2012-11-13
这家伙很懒,什么也没写!
>我按照fat文件系统分析,一个目录表中的各个表项是一个顺序表,删除文件操作会在表项中做出标记,就留下了空洞,添加文件会补齐前面有空洞的目录表,肯定不会为了删除一个文件把目录表后面的各个项往前移。假设1表示目录表项中存在一个文件或目录,0表示空洞和删除的文件或目录。 >如题目中的创建过程,目录表项为:00111111,总共6个文件,前面两个空洞是.和..项,如果用fat文件系统的f_seekdir来定位目录,其中的offset是目录表项的偏移量,偏移到0取出.,偏移到1取出..,偏移到2取出第一个文件,偏移到3取出第二个文件,但是在f_readdir的时候会忽略.和..以及删除的项。 >如题目所示,删除file2后,目录表项为:00101111,那么偏移到0会读出file1,偏移到1读出file1,偏移到2读出file1,偏移到3读出file3,偏移到4读出file3,。。。 >因此问题就这样出现了。 >因此在上层的dfs文件系统中不能假设目录文件是个顺序无空洞的文件。 --- 在dfs文件系统中的elmfat下的目录文件的位置需要稍作修改, dfs_elm_getdents函数中 file->pos = dir->index * sizeof(struct dirent); 应该采用fat文件系统中的DIR的index索引字段来指示目录文件的位置。 这样如果还是00101111这样的表项,第一次读取到file1前,文件位置是0,读取file1后文件位置是3*sizeof(struct dirent),第二次读到file3后,文件位置是5*sizeof(struct dirent),这样就没问题了。
prife
2012-11-14
这家伙很懒,什么也没写!
这问题一晃好几天忘记解决了。罪过罪过 楼主能提供patch么?如果能提供补丁,我直接合并,推送到svn上。
prife
2012-11-14
这家伙很懒,什么也没写!
>>我按照fat文件系统分析,一个目录表中的各个表项是一个顺序表,删除文件操作会在表项中做出标记,就留下了空洞,添加文件会补齐前面有空洞的目录表,肯定不会为了删除一个文件把目录表后面的各个项往前移。假设1表示目录表项中存在一个文件或目录,0表示空洞和删除的文件或目录。 >>如题目中的创建过程,目录表项为:00111111,总共6个文件,前面两个空洞是.和..项,如果用fat文件系统的f_seekdir来定位目录,其中的offset是目录表项的偏移量,偏移到0取出.,偏移到1取出..,偏移到2取出第一个文件,偏移到3取出第二个文件,但是在f_readdir的时候会忽略.和..以及删除的项。 >>如题目所示,删除file2后,目录表项为:00101111,那么偏移到0会读出file1,偏移到1读出file1,偏移到2读出file1,偏移到3读出file3,偏移到4读出file3,。。。 >>因此问题就这样出现了。 >>因此在上层的dfs文件系统中不能假设目录文件是个顺序无空洞的文件。 > >--- > > >在dfs文件系统中的elmfat下的目录文件的位置需要稍作修改, >dfs_elm_getdents函数中 >file->pos = dir->index * sizeof(struct dirent); >应该采用fat文件系统中的DIR的index索引字段来指示目录文件的位置。 >这样如果还是00101111这样的表项,第一次读取到file1前,文件位置是0,读取file1后文件位置是3*sizeof(struct dirent),第二次读到file3后,文件位置是5*sizeof(struct dirent),这样就没问题了。 --- 已fix,感谢rtt-fans提供的修改方法。(如果能提供补丁更好了!:-) ) 不对,上面的修改还是有bug... rtt-fans,你可以使用svn 里的bsp/simulator来做测试,我已经把你的test_fs代码添加到application.c里了。 simulator是使用vs编译的,使用方法参见bsp目录下的readme.txt
prife
2012-11-14
这家伙很懒,什么也没写!
用simulator模拟器测试, 此贴中的测试代码我已经放在application.c里,并导出至finsh中。 test_fs()函数。 原帖中给出的解决方案是不行的。我发现问题出在 dfs_posix.c里 ``` 515 struct dirent *readdir(DIR *d) 516 { 517 int result; 518 struct dfs_fd *fd; 519 520 fd = fd_get(d->fd); 521 if (fd == RT_NULL) 522 { 523 rt_set_errno(-DFS_STATUS_EBADF); 524 525 return RT_NULL; 526 } 527 528 if (!d->num || (d->cur += ((struct dirent*)(d->buf + d->cur))->d_reclen) >= 529 { 530 /* get a new entry */ 531 result = dfs_file_getdents(fd, (struct dirent*)d->buf, sizeof(d->buf) - 532 if (result <= 0) 533 { 534 fd_put(fd); 535 rt_set_errno(result); 536 537 return RT_NULL; 538 } 539 540 d->num = result; //此值一般是 sizeof(struct dirent)=260 字节 541 d->cur = 0; /* current entry index */ 542 } 543 544 fd_put(fd); 545 546 return (struct dirent *)(d->buf+d->cur); 547 } 548 RTM_EXPORT(readdir); ``` 问题就出在540行,d->num = result; d->num这个域的语义不是很明确。 ``` 558 long telldir(DIR *d) 559 { 560 struct dfs_fd *fd; 561 long result; 562 563 fd = fd_get(d->fd); 564 if (fd == RT_NULL) 565 { 566 rt_set_errno(-DFS_STATUS_EBADF); 567 568 return 0; 569 } 570 571 result = fd->pos - d->num + d->cur; 572 fd_put(fd); 573 574 return result; 575 } 576 RTM_EXPORT(telldir); ``` d->num和d->cur这两个域看起来是用于dfs_file_getdents 这个函数。当这个函数可以一次读取多个 struct dirent结构时,num = n*sizeof(struct dirent), n是dfs_file_getdents实际读取到的struct direct结构。 但是当前DFS的实现中, dfs_file_getdents每次都是只读一个 struct dirent结构,即n为1,所以num和cur并没有太用处。 如果要使得dfs_file_getdents可以一次读取多个struct dirent结构,那么上面的readdir还需要仔细修改。至少528行的判断就需要改的。 不知道我对num和cur的理解是否正确啊? PS:简单点的修改办法是把571行修改为 571 result = fd->pos; 这样就似乎就没什么问题了。
rtt-fans
2012-11-14
这家伙很懒,什么也没写!
不修改telldir还是有问题的,我修改的telldir如下: ``` long telldir(DIR *d) { struct dfs_fd *fd; long result; fd = fd_get(d->fd); if (fd == RT_NULL) { rt_set_errno(-RT_ERROR); return 0; } if(d->num) result = fd->pos - d->num + d->cur + ((struct dirent*)(d->buf + d->cur))->d_reclen; else result = fd->pos; fd_put(fd); return result; } ``` 这里判断d->num是第一次未读取任何值的时候,d->num是0; d->num是一次dfs_file_getdents获取的数据总数,d->cur读到的所有数据中当前的一个位置,telldir是返回读取数据后的一个位置,所有加上d_reclen就可以了 都搞定了。
prife
2012-11-14
这家伙很懒,什么也没写!
>不修改telldir还是有问题的,我修改的telldir如下: > > >``` > >long telldir(DIR *d) >{ > struct dfs_fd *fd; > long result; > > fd = fd_get(d->fd); > if (fd == RT_NULL) > { > rt_set_errno(-RT_ERROR); > return 0; > } > if(d->num) > result = fd->pos - d->num + d->cur + ((struct dirent*)(d->buf + d->cur))->d_reclen; > else > result = fd->pos; > fd_put(fd); > > return result; >} > >``` > > >这里判断d->num是第一次未读取任何值的时候,d->num是0; >d->num是一次dfs_file_getdents获取的数据总数,d->cur读到的所有数据中当前的一个位置,telldir是返回读取数据后的一个位置,所有加上d_reclen就可以了 > >都搞定了。 --- 1. dfs_elm.c里不要做任何修改。 2. 把571行修改为 571 result = fd->pos; 其他不要修改。你再试试。另外,把你的联系方式爆一下吧,兄弟。我跟你沟通。我是负责RTT的文件系统的开发者。
撰写答案
登录
注册新账号
关注者
0
被浏览
6.8k
关于作者
rtt-fans
这家伙很懒,什么也没写!
提问
13
回答
37
被采纳
0
关注TA
发私信
相关问题
1
【文件系统】目录查询
2
文件系统Posix 接口 的close API疑问
3
dfs_mount挂载文件系统路径的路径必须为‘/’才能成功
4
SD卡连续读写文件报错
5
文件系统挂载断言机制
6
文件系统是否支持挂载NFS网络文件系统
7
文件系统挂载失败!!!
8
dfs_filesystem_lookup() 返回NULL
9
webnet 是否可以做全动态网页,使用内存池来加快速度
10
“文件系统装在表”报错
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部