bug-glibc
[Top][All Lists]
Advanced

[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>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]