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.
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.
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.
The fseek function returns zero if successful. If an error occurs, the fseek function will return a nonzero value.
_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 FILE
s. 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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With