为什么fseek使用read()系统调用?

Maj*_*Kid 5 c linux libc system-calls

我正在尝试了解的glibc实现fseek。为此,我下载了glibc源代码并尝试了解其功能执行顺序。

我在中找到了fseek实现libio/fseek.c。基本上,它_IO_fseek()使用相同的参数调用函数(或宏)。该宏在中实现libio/iolibio.h

它定义为_IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT)(在中实现libio/ioseekoff.c)。执行它的下一步对我来说很混乱:

_IO_seekoff_unlocked基本上是return _IO_SEEKOFF (fp, offset, dir, mode);,它返回_IO_seekoff_unlocked (fp, offset, dir, mode);,这应该创建一个调用循环。

另外,在strace示例程序(seek.c)上使用时:

#include <stdio.h>

int main(void) {
    printf("[Fseek] Executing fseek\n");
    FILE *f = fopen("./seek.c", "rb");

    fseek(f, 0L, SEEK_END);
}
Run Code Online (Sandbox Code Playgroud)

它表明fseek将调用read系统调用,即使我在glibc实现中找不到它。

...
write(1, "[Fseek] Executing fseek\n", 24[Fseek] Executing fseek
) = 24
openat(AT_FDCWD, "./seek.c", O_RDONLY)  = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "#include <stdio.h>\n\nint main(voi"..., 146) = 146
exit_group(0)                           = ?
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)

我的目标是了解此处如何使用读取系统调用。我有自己的read系统调用实现,该调用在我编写的其他测试中效果很好,但通过via调用由于某种原因会失败fseek

例如,我使用fseek一个函数来获取文件的大小:

long get_file_size(const char *name)
{
    FILE *temp_file = fopen(name, "rb");
    if (temp_file == NULL)
    {
        return -1;
    }

    fseek(temp_file, 0L, SEEK_END);
    long sz =  ftell(temp_file);
    fclose(temp_file);
    return sz;
}
Run Code Online (Sandbox Code Playgroud)

该函数将通过“正常” read实现返回正确的大小,但由于我的失败。因此,如果有人可以告诉我如何理解read内部使用fseek(在源代码中找不到),我将不胜感激。

Kam*_*Cuk 5

_IO_seekoff_unlocked->_IO_SEEKOFF实际上扩展到JUMP3 (__seekoff, FP, OFF, DIR, MODE). JUMP3__seekoffFILE “跳转” table/vtable调用的宏。

fopen默认分配_IO_file_jumps(或类似的东西,因为文件可以被 mmap-ed 等)作为 new FILEs的跳转表。它是 .a 的跳转表/虚拟表的实现FILE

所以_IO_SEEKOFF调用_IO_file_jumps->__seekoff。它指向_IO_new_file_seekoff并最终在该函数内部调用_IO_SYSREAD_IO_SYSREAD电话_read从跳转表,这反过来又调用_IO_file_read,调用__read其最终执行SYSCALL_CANCEL (read)