fuse:在readdir中设置填充功能的偏移量

时间:2014-05-09 12:52:22

标签: linux filesystems fuse

我正在使用保险丝实现虚拟文件系统,需要对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

上述假设是否正确?

P.S:Here are the callbacks of fuse

2 个答案:

答案 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羽毛。