telldir()函数的返回值是多少?

时间:2015-09-15 11:14:43

标签: c linux unix

程序:

#include<stdio.h>
#include<dirent.h>
void main()
{
    int i=0;
    DIR *dir=opendir("dir");
    struct dirent *dent;
    while((dent=readdir(dir))!=NULL){
            printf("Filename: %s\t\t Location in Directory Stream: %ld\n",
                    dent->d_name,telldir(dir));
    }
}

输出:

$ ./a.out
Filename: b.txt              Location in Directory Stream: 32
Filename: a.txt              Location in Directory Stream: 64
Filename: d.c                Location in Directory Stream: 96
Filename: .                  Location in Directory Stream: 128
Filename: test               Location in Directory Stream: 160
Filename: ..                 Location in Directory Stream: 192
$

在上面的程序中,telldir()函数的返回值是32的倍数。根据telldir()的手册页的引用 是&#34;返回目录流中的当前位置&#34;。所以,我希望该目录包含5个文件,因此首次调用telldir()会返回1和 在下一个调用它返回2.但这里的输出是32的倍数。为什么输出像这样?为什么telldir()函数会返回这种值?

2 个答案:

答案 0 :(得分:2)

POSIX states唯一关于&#34; location&#34;由telldir()返回的是:

  

seekdir()函数应将dirp指定的目录流上的下一个readdir()操作的位置设置为loc指定的位置。应该从之前调用telldir()返回loc的值。

执行telldir()时,新位置将恢复为与目录流关联的位置。

     

如果未从先前调用telldir()获取loc的值,或者在调用telldir()和调用seekdir()之间发生对rewinddir()的调用,则后续调用的结果为readdir()未指定。

因此,telldir()的返回值是实现定义的。 不是当前文件的数量。

如果你看一下glibc实现,你会看到:

  • for some hoststelldir()根据全局计数器返回一个cookie,每隔telldir()次调用递增一次(对于任何目录);
  • 对于other hosts,包括Linux,telldir()返回&#34;文件偏移量&#34;其中is later passedlseek()

即使telldir()返回&#34;文件偏移量&#34;,此偏移量对于目录也可能具有特殊含义,具体取决于文件系统实现。

例如,对于ext4,请参阅ext4_dir_llseek()

  

ext4_dir_llseek()调用generic_file_llseek_size来处理htree目录,其中&#34;偏移&#34;是文件名哈希值而不是字节偏移量。

在我的系统中,程序的示例输出是(ext4):

Filename: ..         Location in Directory Stream: 3540738803800888240
Filename: foo        Location in Directory Stream: 5674377099084065539
Filename: .          Location in Directory Stream: 9223372036854775807

答案 1 :(得分:0)

telldir()函数返回目录中的位置,代码可能如下:

    long int
    telldir (DIR *dirp)
    {
      return dirp->filepos;
    }

当您致电opendir()时,filepos为0,然后readdir()将致电gentdents(),并添加dirp->filepos。例如,在调用readdir(),然后调用dirp->filepos = dp->d_off后,dp->d_off将由file->f_op->iterate()设置。对于文件系统PFS(由我自己设计的linux文件系统驱动程序),iterate()pfs_readdir()

static int
pfs_readdir(struct file *file, struct dir_context *ctx)
{
        int64_t dno;
        unsigned long off;
        struct buffer_head *bh;
        struct pfs_dir_entry *de;
        struct inode *inode = file_inode(file);

        if(ctx->pos == 0)
                ctx->pos = PFS_DIRHASHSIZ * sizeof(int64_t) + sizeof(int64_t);
        for(off = ctx->pos & (PFS_BLOCKSIZ - 1); ctx->pos < inode->i_size; off = ctx->pos & (PFS_BLOCKSIZ - 1)){
                if(!(dno = pfs_get_block_number(inode, pfs_block_number(ctx->pos), 0)))
                        goto skip;
                if(!(bh = sb_bread(inode->i_sb, dno / PFS_STRS_PER_BLOCK))){
                        pr_err("pfs: device %s: %s: failed to read block %lld of dir %lld\n",
                                inode->i_sb->s_id, "pfs_readdir", pfs_block_number(ctx->pos), PFS_I(inode)->i_ino);
                        goto skip;
                }
                do{
                        de = (struct pfs_dir_entry *)((char *)bh->b_data + off);
                        if(de->d_ino){
                                if(!(dir_emit(ctx, pfs_get_de_name(de), de->d_len, (int32_t)le64_to_cpu(de->d_ino), DT_UNKNOWN))){
                                        brelse(bh);
                                        return 0;
                                }
                        }
                        off += pfs_get_de_size(de);
                        ctx->pos += pfs_get_de_size(de);
                }while(off < PFS_BLOCKSIZ && ctx->pos < inode->i_size);
                brelse(bh);
                continue;
skip:
                ctx->pos += PFS_BLOCKSIZ - off;
        }
        return 0;
}

dp->d_offdir_emit()设置,来源为:

static inline bool dir_emit(struct dir_context *ctx, const char *name, int namelen, u64 ino, unsigned type)
{
         return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0;
}

如您所见,ctx->actor会调用filldir()filldir() will set dp - 之前and call __ put_user(ctx-&gt; pos,&amp; dp-&gt; d_off ), then the DP-&GT; D_OFF is set (as you see, the则将ctx-&GT; POS is the offset of previous entry's end), and telldir()will return the position of the last entry you got via READDIR()`

NB void main()不是一个好方法,您可以使用int main(int argc, char *argv[])。代替。