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

kin*_*er1 4 linux filesystems fuse

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

早些时候我们忽略了偏移量并在填充函数中传递了 0,在这种情况下内核应该注意。

我们的文件系统数据库存储:目录名称、文件长度、inode 编号和父 inode 编号。

我如何计算得到偏移量?

那么每个组件的偏移量是否等于它们的大小以它们的 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
Run Code Online (Sandbox Code Playgroud)

上述假设是否正确?

PS:这里是fuse的回调

Tod*_*odd 6

所选答案不正确

尽管这个答案缺乏赞成票,但这就是正确的答案。应该不鼓励破解缓冲区的格式void,这就是void在 C 代码中声明此类内容的意图 - 您不应该编写假设了解指针后面的数据格式的代码void,而是使用正确提供的任何 API。

下面的代码非常简单明了,正如它应该的那样。无需了解熔丝缓冲区的格式。

虚构的API

这是一些设备的 API 的一个人为示例。这不是 Fuse 的一部分。

// get_some_file_names() - 
// returns a struct with buffers holding the names of files.
// PARAMETERS
// * path   - A path of some sort that the fictitious device groks.
// * offset - Where in the list of file names to start.
// RETURNS
// * A name_list, it has some char buffers holding the file names
//   and a couple other auxiliary vars.
//   
name_list *get_some_file_names(char *path, size_t offset);
Run Code Online (Sandbox Code Playgroud)

分部分列出文件

这是一个 Fuse 回调,可以在 Fuse 系统中注册,以列出get_some_file_names(). 它是任意命名的readdir_callback(),因此其目的很明显。

int readdir_callback(      char  *path, 
                           void  *buf,      // This is meant to be "opaque".
                fuse_fill_dir_t  *filler,   // filler takes care of buf.
                          off_t  off,       // Last value given to filler.
          struct fuse_file_info  *fi        )
{
    // Call the fictitious API to get a list of file names.
    name_list *list = get_some_file_names(path, off);

    for (int i = 0; i < list->length; i++)
    {
        // Feed the file names to filler() one at a time.
        if (filler(buf, list->names[i], NULL, off + i + 1)) 
        { 
            break;   // filler() returned 1, requesting a break.
        }
        incr_num_files_listed(list);
    }

    if (all_files_listed(list))
    {
        return 1;    // Tell Fuse we're done.
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

填充函数不使用off(偏移)值来填充其不透明缓冲区。然而,该值作为偏移基数对于回调来说是有意义的,因为它向. 上次传递的值将在下一次调用时传递回。 它本身只关心该值是否是- 。bufofffiller()filler()readdir_callback() filler()off00

表示“我已完成列表!” 熔断

要向 Fuse 系统发出信号,表明您readdir_callback()已完成按部分列出文件名的操作(当名称列表的最后一个已指定给 时filler()),只需1从中返回即可。

如何off使用

, offset off, 参数应该是非0以执行部分​​列表。就其而言,这是唯一的要求filler()。如果off0,则向 Fuse 表明您将一次性列出完整的列表(见下文)。

尽管filler()不关心该off值是什么0,但该值仍然可以有意义地使用。上面的代码使用其自己的文件列表中下一项的索引作为其值。Fuse 将在每次调用时将其收到的最后一个值继续传递off回 read dir 回调,直到列表完成(当readdir_callback()returns时1)。

一次列出所有文件

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_file_names(path);

    for (int i = 0; i < list->length; i++)
    {
        filler(buf, list->names[i], NULL, 0);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如上所述,一次列出所有文件更简单 - 但也不是很多。请注意,这off0完整列表。人们可能会想,“为什么还要费心使用第一种方法来部分读取文件夹内容呢?”

当分配了一定数量的文件名缓冲区并且文件夹内的文件数量可能超过此数量时,部分策略非常有用。例如,name_list上面的实现可能只有 8 个分配的缓冲区 ( char names[8][256])。此外,如果一次给出太多名字,buf可能会填满并filler()开始返回。1第一种方法避免了这种情况。


gar*_*on4 5

传递给填充函数的偏移量是目录中下一项的偏移量。您可以按照您想要的任何顺序在目录中放置条目。如果您不想一次返回整个目录,则需要使用偏移量来确定请求和存储的内容。目录中项目的顺序由您决定,与名称或 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;
}
Run Code Online (Sandbox Code Playgroud)

我在自己的代码中对此进行了测试(我以前从未使用过偏移量),并且效果很好。