Subject: Linux compatibility issue for i386, alpha and m68k
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <p99dreyf@criens.u-psud.fr>
List: tech-kern
Date: 02/10/2001 22:01:13
Hi!

In sys/compat/linux/common/linux_misc.c, line 540, it is said that "the
d_off field should contain the offset of the next valid entry, but in
Linux it has the offset of the entry itself. We emulate that bug here."

I ran the sample program at the end of this post, and it appear that
this bug does not exists in Linux/powerpc-2.2.15pre3. The Linux kernel
has the correct behavior, and we are wrong when we emulate the bug. It's
a bug in our bug emulation ;o)

I think about fixing it to get the correct behaviour. But I wonder if
this problem exists on i386, alpha and m68k too. They might have fixed
the bug, leaving our emulation system broken for getdents.

Anyone could try out my sample program on both Linux and NetBSD, on
i386, m68k and alpha? I need to know which ports will require the bug
emulation, and which one will not. If nobody helps here, I will only be
able to fix it for NetBSD/PowerPC.


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#ifdef __NetBSD__
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#endif /* __NetBSD__ */

#ifdef __linux__
#include <linux/types.h>
#include <linux/dirent.h>
#include <linux/unistd.h>

_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);
#endif /* __linux__ */

#define BUF_SIZE 4096

int main (int argc, char** argv) {
        int j,fd, res;
        struct dirent* entry;
        char buf[BUF_SIZE];
        size_t nbytes;
        off_t cur;
        char* filename = ".";

        if (argc > 1) 
                filename = argv[1];

        fd = open (filename, O_RDONLY, 0);
        if (fd == -1) {
                perror ("open() failed");
                exit (-1);
        }

        nbytes=BUF_SIZE;

        res = getdents (fd, buf, nbytes);
        if (res == -1) {
                perror ("getdents() failed");
                exit (-1);
        }
        
        cur = lseek (fd, 0, SEEK_CUR);
        if (cur==(off_t)-1) {
                perror ("lseek() failed\n");
                exit (-1);
        }

        printf ("fd=%d\n", fd);
        printf ("res=%d\n", res);
        printf ("offset=%d\n", cur);

        entry = (struct dirent *)buf;
   while (entry->d_reclen != 0) {
#ifdef __linux__
                printf ("d_ino=0x%x\n", entry->d_ino);
                printf ("d_off=0x%x\n", entry->d_off);
                printf ("d_reclen=0x%x\n", entry->d_reclen);
                printf ("d_name=%s\n", &entry->d_name);
#endif __linux__
#ifdef __NetBSD__
                printf ("d_fileno=0x%x\n", entry->d_fileno);
                printf ("d_reclen=0x%x\n", entry->d_reclen);
                printf ("d_namlen=0x%x\n", entry->d_namlen);
                printf ("d_name=%s\n", &entry->d_name);
#endif __NetBSD__
                printf ("\n");
                entry = (struct dirent *)((long)entry +
(long)(entry->d_reclen));
        }
}

-- 
Emmanuel Dreyfus.
"Le 80x86 n'est pas si complexe - il n'a simplement pas de sens"
(Mike Johnson, responsable de la conception x86 chez AMD) 
p99dreyf@criens.u-psud.fr