[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
readdir and readdir64 see different files (linux)
From: |
Leon Bottou |
Subject: |
readdir and readdir64 see different files (linux) |
Date: |
Sat, 10 Mar 2001 20:47:49 -0500 |
Lots of programs still use readdir instead of readdir64.
But I got a case where they return different results.
The following runs on my machine running
linux-2.4.2 on with glibc-2.2.2 (x86)
The relevant directory is NFS mounted
from a SGI server (nfs2)
----------------------- junk.c
#include <stdio.h>
#include <dirent.h>
int
main(int argc, char **argv)
{
struct DIRENT *ent = 0;
DIR *dir = opendir(argv[1]);
while ((ent = READDIR(dir)))
puts(ent->d_name);
closedir(dir);
}
--------------------------
Let's compare the 32 and 64 bit versions:
% gcc -D_GNU_SOURCE -DDIRENT=dirent -DREADDIR=readdir -o junk32 junk.c
% junk32 mimelnk/
.
..
audio
video
application
% gcc -D_GNU_SOURCE -DDIRENT=dirent64 -DREADDIR=readdir64 -o junk64
junk.c
% junk64 mimelnk/
.
..
audio
video
application
image <--------- This file was missing!
----------------------------
In glibc-2.2.2, both readdir and readdir64 use
syscall __NR_getdents64. Here is a capture of what
__NR_getdents64 returns:
0x62, 0xce, 0xbe, 0x02, 0x00, 0x00, 0x00, 0x00, // d_ino
0x2e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // d_off
0x18, 0x00, 0x00, /* . */ // d_reclen d_type
0x2e, 0x00, 0x00, 0x00, 0x00, // d_name
0xe0, 0x05, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe9, 0x34, 0xb9, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, /* .. */
0x2e, 0x2e, 0x00, 0x00, 0x00,
0x1d, 0xd0, 0x69, 0x03, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x32, 0x39, 0x6d, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, /* audio */
0x61, 0x75, 0x64, 0x69, 0x6f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xcf, 0x69, 0x03, 0x00, 0x00, 0x00, 0x00,
0x88, 0xc8, 0x43, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, /* video */
0x76, 0x69, 0x64, 0x65, 0x6f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc5, 0x62, 0xe5, 0x02, 0x00, 0x00, 0x00, 0x00,
0xe3, 0x73, 0xb8, 0x9d, 0xff, 0xff, 0xff, 0xff,
0x20, 0x00, 0x00, /* application */
0x61, 0x70, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
0xa8, 0xa1, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, // last d_ino
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // last d_off
0x20, 0x00, 0x00, /* image */
0x69, 0x6d, 0x61, 0x67, 0x65,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Note the strange numbers in the d_off fields.
These are in fact cookies used internally by nfs.
Under nfs2, these are 32 bit unsigned number.
The linux kernel (2.4.2) sign extend these to 64 bits
except for the last one wich is filled separately
by the vfs and is not sign extended.
The glibc-2.2.2 source code for readdir() eventually arrives
in function getdents
<http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/linux/getdents.c?rev=1.16&content-type=text/x-cvsweb-markup&cvsroot=glibc>
and notices that the last d_off cannot fit into a signed 32 bit number.
This behavior is commented :
<< Overflow. If there was at least one entry
before this one, return them without error,
otherwise signal overflow. >>
Note that this could be considered a linux problem.
NFS2 should properly sign extend the last d_off.
I patched my linux kernel, posted a message (no reply).
On the other hand, NFS3 already uses 64 bit cookies
and newer disk file systems use 64 bits inodes.
Most applications using readdir() just care about
the filenames and do not even access the d_ino and d_off
fields. These applications should be allowed to work
with newer file systems as well. Otherwise we would
have a show stopper there.
Instead of returning EOVERFLOW or simply bailing out
with the filenames returned so far, wouldn't it be better
to set these fields to some error value such as -1 ?
Thanks for the good work.
- Leon Bottou
<address@hidden>
- readdir and readdir64 see different files (linux),
Leon Bottou <=