home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / std_unix / pax / 5 / paxdir.c < prev   
C/C++ Source or Header  |  1989-01-07  |  17KB  |  694 lines

  1. /*
  2.     opendir -- open a directory stream
  3.   
  4.     last edit:    16-Jun-1987    D A Gwyn
  5. */
  6.  
  7. #include    <sys/errno.h>
  8. #include    <sys/types.h>
  9. #include    <sys/stat.h>
  10. #include    "paxdir.h"
  11.  
  12. #ifdef BSD_SYSV
  13. /*
  14.     <sys/_dir.h> -- definitions for 4.2,4.3BSD directories
  15.   
  16.     last edit:    25-Apr-1987    D A Gwyn
  17.   
  18.     A directory consists of some number of blocks of DIRBLKSIZ bytes each,
  19.     where DIRBLKSIZ is chosen such that it can be transferred to disk in a
  20.     single atomic operation (e.g., 512 bytes on most machines).
  21.   
  22.     Each DIRBLKSIZ-byte block contains some number of directory entry
  23.     structures, which are of variable length.  Each directory entry has the
  24.     beginning of a (struct direct) at the front of it, containing its
  25.     filesystem-unique ident number, the length of the entry, and the length
  26.     of the name contained in the entry.  These are followed by the NUL-
  27.     terminated name padded to a (long) boundary with 0 bytes.  The maximum
  28.     length of a name in a directory is MAXNAMELEN.
  29.   
  30.     The macro DIRSIZ(dp) gives the amount of space required to represent a
  31.     directory entry.  Free space in a directory is represented by entries
  32.     that have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes in a
  33.     directory block are claimed by the directory entries; this usually
  34.     results in the last entry in a directory having a large dp->d_reclen.
  35.     When entries are deleted from a directory, the space is returned to the
  36.     previous entry in the same directory block by increasing its
  37.     dp->d_reclen.  If the first entry of a directory block is free, then
  38.     its dp->d_fileno is set to 0; entries other than the first in a
  39.     directory do not normally have     dp->d_fileno set to 0.
  40.   
  41.     prerequisite:    <sys/types.h>
  42. */
  43.  
  44. #if defined(accel) || defined(sun) || defined(vax)
  45. #define    DIRBLKSIZ    512    /* size of directory block */
  46. #else
  47. #ifdef alliant
  48. #define    DIRBLKSIZ    4096    /* size of directory block */
  49. #else
  50. #ifdef gould
  51. #define    DIRBLKSIZ    1024    /* size of directory block */
  52. #else
  53. #ifdef ns32000            /* Dynix System V */
  54. #define    DIRBLKSIZ    2600    /* size of directory block */
  55. #else                /* be conservative; multiple blocks are okay
  56.                  * but fractions are not */
  57. #define    DIRBLKSIZ    4096    /* size of directory block */
  58. #endif
  59. #endif
  60. #endif
  61. #endif
  62.  
  63. #define    MAXNAMELEN    255    /* maximum filename length */
  64. /* NOTE:  not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
  65.  
  66. struct direct {            /* data from read()/_getdirentries() */
  67.     unsigned long   d_fileno;    /* unique ident of entry */
  68.     unsigned short  d_reclen;    /* length of this record */
  69.     unsigned short  d_namlen;    /* length of string in d_name */
  70.     char            d_name[MAXNAMELEN + 1];    /* NUL-terminated filename */
  71. };
  72.  
  73. /*
  74.     The DIRSIZ macro gives the minimum record length which will hold the
  75.     directory entry.  This requires the amount of space in a (struct
  76.     direct) without the d_name field, plus enough space for the name with a
  77.     terminating NUL character, rounded up to a (long) boundary.
  78.   
  79.     (Note that Berkeley didn't properly compensate for struct padding,
  80.     but we nevertheless have to use the same size as the actual system.)
  81. */
  82.  
  83. #define    DIRSIZ( dp )    ((sizeof(struct direct) - (MAXNAMELEN+1) \
  84.             + sizeof(long) + (dp)->d_namlen) \
  85.             / sizeof(long) * sizeof(long))
  86.  
  87. #else
  88. #include    <sys/dir.h>
  89. #ifdef SYSV3
  90. #undef    MAXNAMLEN        /* avoid conflict with SVR3 */
  91. #endif
  92.  /* Good thing we don't need to use the DIRSIZ() macro! */
  93. #ifdef d_ino            /* 4.3BSD/NFS using d_fileno */
  94. #undef    d_ino            /* (not absolutely necessary) */
  95. #else
  96. #define    d_fileno    d_ino    /* (struct direct) member */
  97. #endif
  98. #endif
  99. #ifdef UNK
  100. #ifndef UFS
  101. #include "***** ERROR ***** UNK applies only to UFS"
  102. /* One could do something similar for getdirentries(), but I didn't bother. */
  103. #endif
  104. #include    <signal.h>
  105. #endif
  106.  
  107. #if defined(UFS) + defined(BFS) + defined(NFS) != 1    /* sanity check */
  108. #include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
  109. #endif
  110.  
  111. #ifdef UFS
  112. #define    RecLen( dp )    (sizeof(struct direct))    /* fixed-length entries */
  113. #else                /* BFS || NFS */
  114. #define    RecLen( dp )    ((dp)->d_reclen)    /* variable-length entries */
  115. #endif
  116.  
  117. #ifdef NFS
  118. #ifdef BSD_SYSV
  119. #define    getdirentries    _getdirentries    /* package hides this system call */
  120. #endif
  121. extern int      getdirentries();
  122. static long     dummy;        /* getdirentries() needs basep */
  123. #define    GetBlock( fd, buf, n )    getdirentries( fd, buf, (unsigned)n, &dummy )
  124. #else                /* UFS || BFS */
  125. #ifdef BSD_SYSV
  126. #define read    _read        /* avoid emulation overhead */
  127. #endif
  128. extern int      read();
  129. #define    GetBlock( fd, buf, n )    read( fd, buf, (unsigned)n )
  130. #endif
  131.  
  132. #ifdef UNK
  133. extern int      _getdents();    /* actual system call */
  134. #endif
  135.  
  136. extern char    *strncpy();
  137. extern int      fstat();
  138. extern OFFSET   lseek();
  139.  
  140. extern int      errno;
  141.  
  142. #ifndef DIRBLKSIZ
  143. #define    DIRBLKSIZ    4096    /* directory file read buffer size */
  144. #endif
  145.  
  146. #ifndef NULL
  147. #define    NULL    0
  148. #endif
  149.  
  150. #ifndef SEEK_CUR
  151. #define    SEEK_CUR    1
  152. #endif
  153.  
  154. #ifndef S_ISDIR            /* macro to test for directory file */
  155. #define    S_ISDIR( mode )        (((mode) & S_IFMT) == S_IFDIR)
  156. #endif
  157.  
  158.  
  159. #ifndef SEEK_CUR
  160. #define    SEEK_CUR    1
  161. #endif
  162.  
  163. #ifdef BSD_SYSV
  164. #define open    _open        /* avoid emulation overhead */
  165. #endif
  166.  
  167. extern int      getdents();    /* SVR3 system call, or emulation */
  168.  
  169. typedef char   *pointer;    /* (void *) if you have it */
  170.  
  171. extern void     free();
  172. extern pointer  malloc();
  173. extern int
  174. open(), close(), fstat();
  175.  
  176. extern int      errno;
  177. extern OFFSET   lseek();
  178.  
  179. #ifndef SEEK_SET
  180. #define    SEEK_SET    0
  181. #endif
  182.  
  183. typedef int     bool;        /* Boolean data type */
  184. #define    false    0
  185. #define    true    1
  186.  
  187.  
  188. #ifndef NULL
  189. #define    NULL    0
  190. #endif
  191.  
  192. #ifndef O_RDONLY
  193. #define    O_RDONLY    0
  194. #endif
  195.  
  196. #ifndef S_ISDIR            /* macro to test for directory file */
  197. #define    S_ISDIR( mode )        (((mode) & S_IFMT) == S_IFDIR)
  198. #endif
  199.  
  200. #ifdef __STDC__
  201.  
  202. DIR *opendir(char *dirname)
  203.  
  204. #else
  205.     
  206. DIR *opendir(dirname)
  207. char           *dirname;    /* name of directory */
  208.  
  209. #endif
  210. {
  211.     register DIR   *dirp;    /* -> malloc'ed storage */
  212.     register int    fd;        /* file descriptor for read */
  213.     struct stat     sbuf;    /* result of fstat() */
  214.  
  215.     if ((fd = open(dirname, O_RDONLY)) < 0)
  216.     return NULL;        /* errno set by open() */
  217.  
  218.     if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
  219.     close(fd);
  220.     errno = ENOTDIR;
  221.     return NULL;        /* not a directory */
  222.     }
  223.     if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL
  224.     || (dirp->dd_buf = (char *) malloc((unsigned) DIRBUF)) == NULL
  225.     ) {
  226.     register int    serrno = errno;
  227.     /* errno set to ENOMEM by sbrk() */
  228.  
  229.     if (dirp != NULL)
  230.         free((pointer) dirp);
  231.  
  232.     close(fd);
  233.     errno = serrno;
  234.     return NULL;        /* not enough memory */
  235.     }
  236.     dirp->dd_fd = fd;
  237.     dirp->dd_loc = dirp->dd_size = 0;    /* refill needed */
  238.  
  239.     return dirp;
  240. }
  241.  
  242.  
  243. /*
  244.  *    closedir -- close a directory stream
  245.  *
  246.  *    last edit:    11-Nov-1988    D A Gwyn
  247.  */
  248.  
  249. #ifdef __STDC__
  250.  
  251. int closedir(register DIR *dirp)
  252.  
  253. #else
  254.     
  255. int closedir(dirp)
  256. register DIR    *dirp;        /* stream from opendir() */
  257.  
  258. #endif
  259. {
  260.     register int    fd;
  261.  
  262.     if ( dirp == NULL || dirp->dd_buf == NULL ) {
  263.     errno = EFAULT;
  264.     return -1;            /* invalid pointer */
  265.     }
  266.  
  267.     fd = dirp->dd_fd;            /* bug fix thanks to R. Salz */
  268.     free( (pointer)dirp->dd_buf );
  269.     free( (pointer)dirp );
  270.     return close( fd );
  271. }
  272.  
  273.  
  274. /*
  275.     readdir -- read next entry from a directory stream
  276.   
  277.     last edit:    25-Apr-1987    D A Gwyn
  278. */
  279.  
  280. #ifdef __STDC__
  281.  
  282. struct dirent  *readdir(register DIR *dirp)
  283.  
  284. #else
  285.     
  286. struct dirent  *readdir(dirp)
  287. register DIR   *dirp;        /* stream from opendir() */
  288.  
  289. #endif
  290. {
  291.     register struct dirent *dp;    /* -> directory data */
  292.  
  293.     if (dirp == NULL || dirp->dd_buf == NULL) {
  294.     errno = EFAULT;
  295.     return NULL;        /* invalid pointer */
  296.     }
  297.     do {
  298.     if (dirp->dd_loc >= dirp->dd_size)    /* empty or obsolete */
  299.         dirp->dd_loc = dirp->dd_size = 0;
  300.  
  301.     if (dirp->dd_size == 0    /* need to refill buffer */
  302.         && (dirp->dd_size =
  303.         getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) DIRBUF)
  304.         ) <= 0
  305.         )
  306.         return NULL;    /* EOF or error */
  307.  
  308.     dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc];
  309.     dirp->dd_loc += dp->d_reclen;
  310.     }
  311.     while (dp->d_ino == 0L);    /* don't rely on getdents() */
  312.  
  313.     return dp;
  314. }
  315.  
  316.  
  317. /*
  318.     seekdir -- reposition a directory stream
  319.   
  320.     last edit:    24-May-1987    D A Gwyn
  321.   
  322.     An unsuccessful seekdir() will in general alter the current
  323.     directory position; beware.
  324.   
  325.     NOTE:    4.nBSD directory compaction makes seekdir() & telldir()
  326.         practically impossible to do right.  Avoid using them!
  327. */
  328.  
  329. #ifdef __STDC__
  330.  
  331. void seekdir(register DIR *dirp, register OFFSET loc)
  332.  
  333. #else
  334.     
  335. void seekdir(dirp, loc)
  336. register DIR   *dirp;        /* stream from opendir() */
  337. register OFFSET  loc;        /* position from telldir() */
  338.  
  339. #endif
  340. {
  341.     register bool   rewind;    /* "start over when stymied" flag */
  342.  
  343.     if (dirp == NULL || dirp->dd_buf == NULL) {
  344.     errno = EFAULT;
  345.     return;            /* invalid pointer */
  346.     }
  347.     /*
  348.      * A (struct dirent)'s d_off is an invented quantity on 4.nBSD
  349.      * NFS-supporting systems, so it is not safe to lseek() to it. 
  350.      */
  351.  
  352.     /* Monotonicity of d_off is heavily exploited in the following. */
  353.  
  354.     /*
  355.      * This algorithm is tuned for modest directory sizes.  For huge
  356.      * directories, it might be more efficient to read blocks until the first
  357.      * d_off is too large, then back up one block, or even to use binary
  358.      * search on the directory blocks.  I doubt that the extra code for that
  359.      * would be worthwhile. 
  360.      */
  361.  
  362.     if (dirp->dd_loc >= dirp->dd_size    /* invalid index */
  363.     || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc
  364.     /* too far along in buffer */
  365.     )
  366.     dirp->dd_loc = 0;    /* reset to beginning of buffer */
  367.     /* else save time by starting at current dirp->dd_loc */
  368.  
  369.     for (rewind = true;;) {
  370.     register struct dirent *dp;
  371.  
  372.     /* See whether the matching entry is in the current buffer. */
  373.  
  374.     if ((dirp->dd_loc < dirp->dd_size    /* valid index */
  375.          || readdir(dirp) != NULL    /* next buffer read */
  376.          && (dirp->dd_loc = 0, true)    /* beginning of buffer set */
  377.          )
  378.         && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off
  379.         <= loc        /* match possible in this buffer */
  380.         ) {
  381.         for ( /* dp initialized above */ ;
  382.          (char *) dp < &dirp->dd_buf[dirp->dd_size];
  383.          dp = (struct dirent *) ((char *) dp + dp->d_reclen)
  384.         )
  385.         if (dp->d_off == loc) {    /* found it! */
  386.             dirp->dd_loc =
  387.             (char *) dp - dirp->dd_buf;
  388.             return;
  389.         }
  390.         rewind = false;    /* no point in backing up later */
  391.         dirp->dd_loc = dirp->dd_size;    /* set end of buffer */
  392.     } else
  393.      /* whole buffer past matching entry */ if (!rewind) {    /* no point in searching
  394.                                  * further */
  395.         errno = EINVAL;
  396.         return;        /* no entry at specified loc */
  397.     } else {        /* rewind directory and start over */
  398.         rewind = false;    /* but only once! */
  399.  
  400.         dirp->dd_loc = dirp->dd_size = 0;
  401.  
  402.         if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET)
  403.         != 0
  404.         )
  405.         return;        /* errno already set (EBADF) */
  406.  
  407.         if (loc == 0)
  408.         return;        /* save time */
  409.     }
  410.     }
  411. }
  412.  
  413.  
  414. /* telldir - report directory stream position
  415.  *
  416.  * DESCRIPTION
  417.  *
  418.  *    Returns the offset of the next directory entry in the
  419.  *    directory associated with dirp.
  420.  *
  421.  *    NOTE:    4.nBSD directory compaction makes seekdir() & telldir()
  422.  *        practically impossible to do right.  Avoid using them!
  423.  *
  424.  * PARAMETERS
  425.  *
  426.  *    DIR    *dirp    - stream from opendir()
  427.  *
  428.  * RETURNS
  429.  *
  430.  *     Return offset of next entry 
  431.  */
  432.  
  433.  
  434. #ifdef __STDC__
  435.  
  436. OFFSET telldir(DIR *dirp)
  437.  
  438. #else
  439.     
  440. OFFSET telldir(dirp)            
  441. DIR            *dirp;        /* stream from opendir() */
  442.  
  443. #endif
  444. {
  445.     if (dirp == NULL || dirp->dd_buf == NULL) {
  446.     errno = EFAULT;
  447.     return -1;        /* invalid pointer */
  448.     }
  449.     if (dirp->dd_loc < dirp->dd_size)    /* valid index */
  450.     return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off;
  451.     else            /* beginning of next directory block */
  452.     return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR);
  453. }
  454.  
  455.  
  456. #ifdef UFS
  457.  
  458. /*
  459.     The following routine is necessary to handle DIRSIZ-long entry names.
  460.     Thanks to Richard Todd for pointing this out.
  461. */
  462.  
  463.  
  464. /* return # chars in embedded name */
  465.  
  466. #ifdef __STDC__
  467.  
  468. static int NameLen(char *name)
  469.  
  470. #else
  471.     
  472. static int NameLen(name)
  473. char            *name;        /* -> name embedded in struct direct */
  474.  
  475. #endif
  476. {
  477.     register char  *s;        /* -> name[.] */
  478.     register char  *stop = &name[DIRSIZ];    /* -> past end of name field */
  479.  
  480.     for (s = &name[1];        /* (empty names are impossible) */
  481.      *s != '\0'        /* not NUL terminator */
  482.      && ++s < stop;        /* < DIRSIZ characters scanned */
  483.     );
  484.  
  485.     return s - name;        /* # valid characters in name */
  486. }
  487.  
  488. #else                /* BFS || NFS */
  489.  
  490. extern int      strlen();
  491.  
  492. #define    NameLen( name )    strlen( name )    /* names are always NUL-terminated */
  493.  
  494. #endif
  495.  
  496. #ifdef UNK
  497. static enum {
  498.     maybe, no, yes
  499. } state = maybe;
  500.  
  501.  
  502. /* sig_catch - used to catch signals
  503.  *
  504.  * DESCRIPTION
  505.  *
  506.  *    Used to catch signals.
  507.  */
  508.  
  509. /*ARGSUSED*/
  510.  
  511. #ifdef __STDC__
  512.  
  513. static void sig_catch(int sig)
  514.  
  515. #else
  516.     
  517. static void sig_catch(sig)
  518. int             sig;        /* must be SIGSYS */
  519.  
  520. #endif
  521. {
  522.     state = no;            /* attempted _getdents() faulted */
  523. }
  524. #endif
  525.  
  526.  
  527. /* getdents - get directory entries
  528.  *
  529.  * DESCRIPTION
  530.  *
  531.  *    Gets directory entries from the filesystem in an implemenation
  532.  *    defined way.
  533.  *
  534.  * PARAMETERS
  535.  *
  536.  *    int             fildes    - directory file descriptor 
  537.  *    char           *buf    - where to put the (struct dirent)s 
  538.  *    unsigned    nbyte    - size of buf[] 
  539.  *
  540.  * RETURNS
  541.  * 
  542.  *    Returns number of bytes read; 0 on EOF, -1 on error 
  543.  */
  544.  
  545. #ifdef __STDC__
  546.  
  547. int getdents(int fildes, char *buf, unsigned nbyte)
  548.  
  549. #else
  550.     
  551. int getdents(fildes, buf, nbyte)    
  552. int             fildes;        /* directory file descriptor */
  553. char           *buf;        /* where to put the (struct dirent)s */
  554. unsigned        nbyte;        /* size of buf[] */
  555.  
  556. #endif
  557. {
  558.     int             serrno;    /* entry errno */
  559.     OFFSET          offset;    /* initial directory file offset */
  560.     struct stat     statb;    /* fstat() info */
  561.     union {
  562.     /* directory file block buffer */
  563. #ifdef UFS
  564.     char        dblk[DIRBLKSIZ + 1];
  565. #else
  566.     char            dblk[DIRBLKSIZ];
  567. #endif
  568.     struct direct   dummy;    /* just for alignment */
  569.     } u;        /* (avoids having to malloc()) */
  570.     register struct direct *dp;    /* -> u.dblk[.] */
  571.     register struct dirent *bp;    /* -> buf[.] */
  572.  
  573. #ifdef UNK
  574.     switch (state) {
  575.     SIG_T         (*shdlr)();    /* entry SIGSYS handler */
  576.     register int    retval;        /* return from _getdents() if any */
  577.  
  578.     case yes:            /* _getdents() is known to work */
  579.     return _getdents(fildes, buf, nbyte);
  580.  
  581.     case maybe:        /* first time only */
  582.     shdlr = signal(SIGSYS, sig_catch);
  583.     retval = _getdents(fildes, buf, nbyte);    /* try it */
  584.     signal(SIGSYS, shdlr);
  585.  
  586.     if (state == maybe) {    /* SIGSYS did not occur */
  587.         state = yes;    /* so _getdents() must have worked */
  588.         return retval;
  589.     }
  590.     /* else fall through into emulation */
  591.  
  592. /*    case no:    /* fall through into emulation */
  593.     }
  594. #endif
  595.  
  596.     if (buf == NULL
  597. #ifdef ATT_SPEC
  598.     || (unsigned long) buf % sizeof(long) != 0    /* ugh */
  599. #endif
  600.     ) {
  601.     errno = EFAULT;        /* invalid pointer */
  602.     return -1;
  603.     }
  604.     if (fstat(fildes, &statb) != 0) {
  605.     return -1;        /* errno set by fstat() */
  606.     }
  607.  
  608.     if (!S_ISDIR(statb.st_mode)) {
  609.     errno = ENOTDIR;    /* not a directory */
  610.     return -1;
  611.     }
  612.     if ((offset = lseek(fildes, (OFFSET) 0, SEEK_CUR)) < 0) {
  613.     return -1;        /* errno set by lseek() */
  614.     }
  615.  
  616. #ifdef BFS            /* no telling what remote hosts do */
  617.     if ((unsigned long) offset % DIRBLKSIZ != 0) {
  618.     errno = ENOENT;        /* file pointer probably misaligned */
  619.     return -1;
  620.     }
  621. #endif
  622.  
  623.     serrno = errno;        /* save entry errno */
  624.  
  625.     for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) {    
  626.  
  627.         /* convert next directory block */
  628.     int             size;
  629.  
  630.     do {
  631.         size = GetBlock(fildes, u.dblk, DIRBLKSIZ);
  632.     } while (size == -1 && errno == EINTR);
  633.  
  634.     if (size <= 0) {
  635.         return size;    /* EOF or error (EBADF) */
  636.     }
  637.  
  638.     for (dp = (struct direct *) u.dblk;
  639.          (char *) dp < &u.dblk[size];
  640.          dp = (struct direct *) ((char *) dp + RecLen(dp))
  641.         ) {
  642. #ifndef UFS
  643.         if (dp->d_reclen <= 0) {
  644.         errno = EIO;    /* corrupted directory */
  645.         return -1;
  646.         }
  647. #endif
  648.  
  649.         if (dp->d_fileno != 0) {    /* non-empty; copy to user buffer */
  650.         register int    reclen =
  651.         DIRENTSIZ(NameLen(dp->d_name));
  652.  
  653.         if ((char *) bp + reclen > &buf[nbyte]) {
  654.             errno = EINVAL;
  655.             return -1;    /* buf too small */
  656.         }
  657.         bp->d_ino = dp->d_fileno;
  658.         bp->d_off = offset + ((char *) dp - u.dblk);
  659.         bp->d_reclen = reclen;
  660.  
  661.         {
  662. #ifdef UFS
  663.             /* Is the following kludge ugly?  You bet. */
  664.  
  665.             register char   save = dp->d_name[DIRSIZ];
  666.             /* save original data */
  667.  
  668.             dp->d_name[DIRSIZ] = '\0';
  669.             /* ensure NUL termination */
  670. #endif
  671.             /* adds NUL padding */
  672.             strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ);
  673. #ifdef UFS
  674.             dp->d_name[DIRSIZ] = save;
  675.             /* restore original data */
  676. #endif
  677.         }
  678.  
  679.         bp = (struct dirent *) ((char *) bp + reclen);
  680.         }
  681.     }
  682.  
  683. #ifndef BFS            /* 4.2BSD screwed up; fixed in 4.3BSD */
  684.     if ((char *) dp > &u.dblk[size]) {
  685.         errno = EIO;    /* corrupted directory */
  686.         return -1;
  687.     }
  688. #endif
  689.     }
  690.  
  691.     errno = serrno;        /* restore entry errno */
  692.     return (char *) bp - buf;    /* return # bytes read */
  693. }
  694.