cposixtaillseek

C lseek misbehaving


Im trying to write a program that emulates the tail behavior in C. When searching the file for '/n' chars, im getting a strange behavior from lseek. Here is the relevant piece of code:

   FILE *myfile = fopen(argv[i], "r");
    if (myfile == NULL) {
        printf("File not valid. Skipping.\n");
        continue;
    }
    //Go to the end of the file - You have to find the pos of the n lines.
    off_t pos = lseek(fileno(myfile), 0, SEEK_END);

    
    if (pos == -1) {
        perror("Lseek");
    }
    int l = 0;
    int temp = 10; //ofc there is a lines variable not hardcoded, this is just for testing purposes
    pos--;
    off_t pos2 = lseek(fileno(myfile), pos, SEEK_SET);
    printf("pos2: %ld\n", pos2);
    
    off_t curpos = 0;
     
    while ((l = fgetc(myfile)) != EOF && temp >= 0) {
        curpos = lseek(fileno(myfile), 0, SEEK_CUR);
        printf("Curpos: %ld; pos: %ld\n", curpos, pos);

        if (l == '\n') {
            temp--;
        }
        pos--;
        lseek(fileno(myfile), pos, SEEK_SET);
    }

Running this piece of code gave me those printf statements:

pos2: 25699
CurPos: 25700; pos: 25699 //EOF
CurPos: 25700; pos: 25698 //EOF
CurPos: 25697; pos: 25697
CurPos: 25700; pos: 25696 //EOF
CurPos: 25695; pos: 25695
CurPos: 25694; pos: 25694
CurPos: 25693; pos: 25693
CurPos: 25700; pos: 25692 //EOF
CurPos: 25691; pos: 25691
CurPos: 25690; pos: 25690
CurPos: 25689; pos: 25689
CurPos: 25688; pos: 25688
CurPos: 25687; pos: 25687
CurPos: 25686; pos: 25686
CurPos: 25685; pos: 25685
and so on but it never goes to EOF again

So it goes to EOF for four times and reads again a final '\n' before EOF, giving me the wrong results.

Switching the while body with:

while (pread(fileno(myfile), &l, 1, pos) != 0 && temp >= 0) {

        if (l == '\n') {
            temp--;
        }
        pos--;
    }
    

Gives me the expected behavior.

So, i would like to know, why my first while body was broken?

EDITS: Fixed formattings and things that didnt matter


Solution

  • You should not mix operations on the FILE * with operations on the underlying file descriptor. If you lseek on the file descriptor, then subsequent calls to fgetc will be ... wrong. Instead of lseek, use fseek.