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