保险丝:在readdir中设置填充函数的偏移量

问题描述 投票:3回答:2

我正在使用保险丝实现虚拟文件系统,并且需要对readdir中的offset参数有一些了解。

以前我们忽略了偏移量,并在填充函数中传递了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

linux filesystems fuse
2个回答
4
投票

传递给填充函数的偏移量是目录中下一项的偏移量。您可以按任意顺序在目录中输入条目。如果您不想一次返回整个目录,则需要使用偏移量来确定要存储的内容。目录中项目的顺序取决于您,而名称或索引节点或其他任何顺序都无关紧要。

特别是在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;
}

我在自己的代码中进行了测试(我以前从未使用过偏移量,并且可以正常工作。


0
投票

其他答案中的方法显然有问题。填充函数似乎没有使用offset值来填充其opaque buf。如果offset值不能一次读取所有文件名,则对客户端代码有意义。上一次传递给填充符的值是在下次调用时传递回客户端的readdir()回调的值。

[整个过程中最重要的信息似乎在'net上的任何来源都完全缺失:如何向Fuse系统发出信号,表明readdir()回调已完成,列出了文件名的一部分。

下面的代码可能会为我们提供一些启示。在我有时间设置我的IDE以逐步执行fuselib代码之后,我可能会找到一种更好的方法。但是,这就是我发现的效果:

列出文件的各个部分

int readdir_callback(char *path, void *buf, fuse_fill_dir_t *filler, off_t off,
                     struct fuse_file_info *fi)
{
    my_file_list *list = get_some_filenames(path, off);

    if (list->length == 0)
    {
        // If get_some_filenames() returns an empty list, the files have all
        // been listed. Let Fuse know we're done...

        memset(list->filenames[0], 0, 8);        // 8 is based on total guesswork.
                                                 // Just one null byte might be
                                                 // enough.

        ((struct fuse_dh *)buf)->filled = 1;     // I shouldn't have to do this.
                                                 // Need to step through fuselib
                                                 // to see how this should get
                                                 // set.

        filler(buf, list->filenames[0], NULL, 0);
    }
    else 
    {
        for (int i = 0; i < list->length; i++)
        {
            filler(buf, list->filenames[i], NULL, off + i + 1);
        }
    }
    return 0;
}

我不必担心buf的内容,所以我知道有一种更好的方法来表示文件夹的文件名结尾。如果我知道了,我会回来再更新。

但是无论如何,以上内容确实有效地向Fuse表示上市已完成;而且它不需要任何神奇的数学来计算偏移值,也不需要任何关于inode的计算(我正在安装的文件系统甚至都无法实现)。

同时列出所有文件

int readdir_callback(char *path, void *buf, fuse_fill_dir_t *filler, off_t off,
                         struct fuse_file_info *fi)
{
    my_file_list *list = get_all_filenames(path);

    for (int i = 0; i < list->length; i++)
    {
        filler(buf, list->filenames[i], NULL, 0);
    }
    return 0;
}

一键列出所有文件要简单得多。请注意,这不需要了解buf的结构,并且保险丝填充器内部知道如何填充它,而无需任何外部帮助(应该如此)。

您希望以其他方式列出文件的各个部分会有一些好处。例如,文件浏览器可能会在读取文件和文件夹之前就开始显示它们。但是我还没有看到这种情况。我有一个安装ftp URL的模块,并且两种方法都需要很长时间才能开始在Nemo文件浏览器中看到任何操作。

那么,为什么还要烦恼首先读取部分文件夹内容的方法?

© www.soinside.com 2019 - 2024. All rights reserved.