程序:
#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()
函数会返回这种值?
答案 0 :(得分:2)
POSIX states唯一关于&#34; location&#34;由telldir()
返回的是:
seekdir()函数应将dirp指定的目录流上的下一个readdir()操作的位置设置为loc指定的位置。应该从之前调用telldir()返回loc的值。
执行telldir()时,新位置将恢复为与目录流关联的位置。如果未从先前调用telldir()获取loc的值,或者在调用telldir()和调用seekdir()之间发生对rewinddir()的调用,则后续调用的结果为readdir()未指定。
因此,telldir()
的返回值是实现定义的。 不是当前文件的数量。
如果你看一下glibc实现,你会看到:
telldir()
根据全局计数器返回一个cookie,每隔telldir()
次调用递增一次(对于任何目录); telldir()
返回&#34;文件偏移量&#34;其中is later passed至lseek()
。即使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_off
由dir_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[])
。代替。