home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / LIBC / LIBC-4.6 / LIBC-4 / libc-linux / sysdeps / linux / i386 / readdir.c.new < prev    next >
Encoding:
Text File  |  1994-11-02  |  2.7 KB  |  97 lines

  1. #include <dirent.h>
  2. #include <errno.h>
  3. #include <sys/syscall.h>
  4.  
  5. #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
  6. #define ROUND_UP(x) (((x)+3) & ~3)
  7.  
  8. /*
  9.  * readdir fills up the buffer with the readdir system call. 
  10.  *
  11.  * The old-style kernel readdir interface accepted, but ignored, a
  12.  * third parameter which was set to one by the library and which was
  13.  * reserved to allow future libraries to read more than one dirent at
  14.  * a time.  The return value in this case was simply the length of the
  15.  * name of the dirent returned.
  16.  *
  17.  * Right now the readdir system call accepts a buffer size as its
  18.  * third argument, and returns the number of bytes written into this
  19.  * buffer.  The dirents returned are of variable length, and the
  20.  * d_reclen member gives the length, in bytes, of each entry in the
  21.  * buffer.  Currently only the ext2fs filesystem ever returns more
  22.  * than one dirent, but all filesystems return the number of bytes
  23.  * written.
  24.  *
  25.  * For compatibility with older kernels, the library must still accept
  26.  * return values less than the length of a dirent.
  27.  */
  28. struct dirent *readdir(DIR * dir)
  29. {
  30.   int result;
  31.   int count;
  32.   struct dirent *de;
  33.   char *p;
  34.  
  35.   if (!dir) {
  36.     errno = EBADF;
  37.     return NULL; 
  38.   }
  39.  
  40. repeat:
  41.   if (dir->dd_max == 1 || dir->dd_size <= dir->dd_loc) {
  42.       count = dir->dd_max;
  43. #if defined(__PIC__) || defined (__pic__)
  44.     __asm__ volatile ("pushl %%ebx\n\t"
  45.               "movl %%esi,%%ebx\n\t"
  46.               "int $0x80\n\t"
  47.               "popl %%ebx"
  48.     :"=a" (result)
  49.     :"0" (SYS_readdir),"S" (dir->dd_fd),
  50.     "c" ((long) dir->dd_buf),"d" (count));
  51. #else
  52.     __asm__("int $0x80"
  53.     :"=a" (result)
  54.     :"0" (SYS_readdir),"b" (dir->dd_fd),
  55.     "c" ((long) dir->dd_buf),"d" (count));
  56. #endif
  57.     if (result <= 0) {
  58.       if (result < 0)
  59.     errno = -result;
  60.       return NULL;
  61.     }
  62.  
  63.     if (result > dir->dd_max) {
  64.     /* This should never happen on modern multi-dirent kernels.
  65.            If it does occur, resort to old-style one-at-a-time dirent
  66.            access, and assume the kernel has returned only one dirent
  67.            this time. */
  68.     result = 1;
  69.     dir->dd_max = 1;
  70.     }
  71.     dir->dd_size = result;
  72.     dir->dd_loc = 0;
  73.   }
  74.  
  75.   de = (struct dirent *) (((char *)dir->dd_buf) + dir->dd_loc);
  76.  
  77.   /* Do some sanity checks to getting confused by old kernels */
  78.   p = (char *) de;
  79.   p += de->d_off;
  80.   if (dir->dd_max > 1 && 
  81.       (p > (((char *) dir->dd_buf) + dir->dd_size) ||
  82.        de->d_reclen < 1 ||
  83.        de->d_off < (NAME_OFFSET(de) + de->d_reclen))) {
  84.     /* If the kernel doesn't appear to adhere to modern readdir()
  85.        semantics, only rely on it to return one dirent at a time. */
  86.     dir->dd_max = 1;
  87.     dir->dd_size = 0;
  88.     if (dir->dd_loc) {
  89.       dir->dd_size = 0;
  90.       goto repeat;
  91.     }
  92.   }
  93.  
  94.   dir->dd_loc += de->d_off;
  95.   return de;
  96. }
  97.