我正在使用保险丝实现虚拟文件系统,需要对readdir中的偏移参数有所了解。
之前我们忽略了偏移并在填充函数中传递了0,在这种情况下内核应该小心。
我们的文件系统数据库存储:目录名,文件长度,索引节点号和父索引号。
我如何计算得到偏移量?
然后是每个组件的偏移量,等于它们的大小以其inode编号的增量形式排序?会发生什么事情是目录中有一个目录,在这种情况下偏移是否等于里面文件的总和?
Example: in case the dir listing is - a.txt b.txt c.txt
And inode number of a.txt=3, b.txt=5, c.txt=7
Offset of a.txt= directory offset
Offset of b.txt=dir offset + size of a.txt
Offset of c.txt=dir offset + size of b.txt
上述假设是否正确?
答案 0 :(得分:4)
传递给填充函数的偏移量是目录中下一个项目的偏移量。您可以按照所需的任何顺序在目录中输入条目。如果您不想一次返回整个目录,则需要使用偏移量来确定要求和存储的内容。目录中的项目顺序取决于您,并且名称或inode或其他任何内容的顺序并不重要。
具体来说,在readdir调用中,您将传递一个偏移量。您希望开始使用将在此回调或稍后的条目调用填充函数。在最简单的情况下,每个条目的长度为24个字节+ strlen(条目名称),向上舍入到最接近的8个字节的倍数。但是,请参阅http://sourceforge.net/projects/fuse/处的保险丝源代码,了解情况可能并非如此。
我有一个简单的例子,我的readdir函数中有一个循环(伪c代码):
int my_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
(a bunch of prep work has been omitted)
struct stat st;
int off, nextoff=0, lenentry, i;
char namebuf[(long enough for any one name)];
for (i=0; i<NumDirectoryEntries; i++)
{
(fill st with the stat information, including inode, etc.)
(fill namebuf with the name of the directory entry)
lenentry = ((24+strlen(namebuf)+7)&~7);
off = nextoff; /* offset of this entry */
nextoff += lenentry;
/* Skip this entry if we weren't asked for it */
if (off<offset)
continue;
/* Add this to our response until we are asked to stop */
if (filler(buf, namebuf, &st, nextoff))
break;
}
/* All done because we were asked to stop or because we finished */
return 0;
}
我在自己的代码中测试了这个(之前从未使用过偏移量),并且它工作正常。
答案 1 :(得分:0)
所选答案不正确
填充函数似乎未使用offset
值填充其不透明缓冲区buf
。如果offset
值不能一次读入所有文件名,则对客户端代码有意义。上一次传递给填充符的值是在下次调用时传递回客户端的readdir()
回调的值。 filler()
只关心该值是否为0或0。
'net上的任何来源似乎都缺少有关整个过程的最基本信息: 如何向Fuse系统发送信号,告知您readdir()
回调已完成文件名。 。这可能就是您最喜欢的搜索引擎将您引到这里的原因。
下面的代码可能使您了解如何完成此操作。这是我发现的效果:
列出文件的各个部分
int readdir_callback( char *path,
void *buf, // Its format is not your concern.
fuse_fill_dir_t *filler, // filler takes care of buf.
off_t off, // Last value given to filler.
struct fuse_file_info *fi )
{
name_list *list = get_some_dir_member_names(path, off);
for (int i = 0; i < list->length; i++)
{
filler(buf, list->names[i], NULL, off + i + 1);
}
if (list->dir_is_fully_listed)
{
return 1; // Tell Fuse we're done.
}
return 0;
}
通过一些猜测和实验,我发现当名称列表的最后一个被赋予filler()
时返回1似乎可以解决问题。以上内容有效地向Fuse表示上市已完成; ,它不需要任何轨迹来计算偏移量值,也不需要任何关于inode的计算(我正在安装的文件系统甚至都无法实现)。
off
(偏移量)参数应为非0才能执行部分列表。就filler()
而言,这是唯一的要求。在上述情况下,我使用文件列表中下一项的索引作为其值-这很有用,对get_some_dir_member_names()
有意义。但是关于off
的价值,filler
就像众所周知的蜜badge一样,不在乎。
一次列出所有文件
int readdir_callback( char *path,
void *buf,
fuse_fill_dir_t *filler,
off_t off,
struct fuse_file_info *fi )
{
name_list *list = get_all_dir_member_names(path);
for (int i = 0; i < list->length; i++)
{
filler(buf, list->names[i], NULL, 0);
}
return 0;
}
一次列出所有文件比较简单。请注意,这不需要了解buf
的结构,并且Fuse填充器在内部无需任何外部帮助即可知道如何填充它(其他方法也是如此)。
您可能希望与部分列出文件的其他方法在性能上有一些好处。例如,文件浏览器可能在读取文件和文件夹之前就开始显示它们。但是我还没有看到这种情况。我有一个安装FTP URL的模块,两种方法都需要很长时间才能开始在Nemo文件浏览器中看到任何操作。
那么,为什么还要烦恼首先读取部分文件夹内容的方法呢?
部分分配策略非常有用,它可以分配一定数量的文件名缓冲区,并且文件夹中的文件数可能会超过该数目。例如,{{1的实现}}以上可能仅分配了8个缓冲区(name_list
)。同样,如果一次给出太多名称,char names[8][256]
可能会填满,并且buf
开始返回1。第一种方法可以避免这种情况。
这里有一些常识。将filler()
参数声明为buf
是有原因的,并且该原因并不是要强迫您选择void*
源代码来确定其格式。知道这一点后,您就省去了邓布利多的麻烦,他们可以通过libfuse
伍兹去寻找神奇的咒语,以破解Libfuse
的缓冲器。但是,如果您无法抵制这种冲动,可能会有一些线索可能会有所帮助:咒语以数字24开头,包括狮riff羽毛。