Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does fseek use read() system call?

I'm trying to understand the glibc implementation of fseek. To do so, I downloaded the glibc source code and tried to understand its function execution order.

I found the fseek implementation in libio/fseek.c. Basically, it calls the function (or rather the macro) _IO_fseek() using the same parameters. This macro is implemented in libio/iolibio.h.

It is defined as _IO_seekoff_unlocked (__fp, __offset, __whence, _IOS_INPUT|_IOS_OUTPUT) (implemented in libio/ioseekoff.c). The next step in its execution is rather confusing for me:

_IO_seekoff_unlocked basically returns _IO_SEEKOFF (fp, offset, dir, mode);, which returns _IO_seekoff_unlocked (fp, offset, dir, mode);, which should create a call loop.

Also, when using strace on an example program (seek.c):

#include <stdio.h>

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

    fseek(f, 0L, SEEK_END);
}

it shows that fseek will call the read system call, even though I could not find it in the glibc implementation.

...
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 +++

My goal is to understand how the read system call is used here. I have my own implementation of the read system call, which works well for other tests I wrote but will fail for some reason when it is called via fseek.

As an example, I use fseek in a function to get the size of a file:

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;
}

This function will return the correct size with the "normal" read implementation but will fail with mine. So, if anybody can tell me how I can understand the use of read within fseek (which I could not find in the source), I would highly appreciate it.

like image 927
MajorasKid Avatar asked Nov 20 '19 11:11

MajorasKid


People also ask

Is Fseek a system call?

it shows that fseek will call the read system call, even though I could not find it in the glibc implementation. My goal is to understand how the read system call is used here.

What does fseek() do?

fseek() is used to move file pointer associated with a given file to a specific position. position defines the point with respect to which the file pointer needs to be moved.

What does Fseek return in C?

The fseek function returns zero if successful. If an error occurs, the fseek function will return a nonzero value.


1 Answers

_IO_seekoff_unlocked->_IO_SEEKOFF actually expands to JUMP3 (__seekoff, FP, OFF, DIR, MODE). JUMP3 is a macro that calls __seekoff from the FILE "jump" table/vtable.

fopen by default assigns _IO_file_jumps (or something like that, because the file can be mmap-ed etc. etc.) as the jump table for new FILEs. It is the implementation of the jump table/virtual table for a FILE.

So _IO_SEEKOFF calls _IO_file_jumps->__seekoff. It points to _IO_new_file_seekoff and finally inside that function a call is made to _IO_SYSREAD. _IO_SYSREAD calls _read from the jump table, which in turn calls _IO_file_read, which calls __read which finally executes SYSCALL_CANCEL (read).

like image 191
KamilCuk Avatar answered Oct 29 '22 18:10

KamilCuk