Annotation of coherent/b/lib/libc/ndir/seekdir.c, revision 1.1.1.1

1.1       root        1: /*
                      2:        seekdir -- reposition a directory stream
                      3: 
                      4:        last edit:      25-Apr-1987     D A Gwyn
                      5: 
                      6:        An unsuccessful seekdir() will in general alter the current
                      7:        directory position; beware.
                      8: 
                      9:        NOTE:   4.nBSD directory compaction makes seekdir() & telldir()
                     10:                practically impossible to do right.  Avoid using them!
                     11: */
                     12: #ifdef COHERENT
                     13: #include       <errno.h>
                     14: #else
                     15: #include       <sys/errno.h>
                     16: #endif
                     17: 
                     18: #include       <sys/types.h>
                     19: #include       "dirent.h"
                     20: 
                     21: extern off_t   lseek();
                     22: 
                     23: extern int     errno;
                     24: 
                     25: #ifndef NULL
                     26: #define        NULL    0
                     27: #endif
                     28: 
                     29: #ifndef SEEK_SET
                     30: #define        SEEK_SET        0
                     31: #endif
                     32: 
                     33: typedef int    bool;                   /* Boolean data type */
                     34: #define        false   0
                     35: #define        true    1
                     36: 
                     37: void
                     38: seekdir( dirp, loc )
                     39:        register DIR            *dirp;  /* stream from opendir() */
                     40:        register off_t          loc;    /* position from telldir() */
                     41:        {
                     42:        register bool           rewind; /* "start over when stymied" flag */
                     43: 
                     44:        if ( dirp == NULL || dirp->dd_buf == NULL )
                     45:                {
                     46:                errno = EFAULT;
                     47:                return;                 /* invalid pointer */
                     48:                }
                     49: 
                     50:        /* A (struct dirent)'s d_off is an invented quantity on 4.nBSD
                     51:           NFS-supporting systems, so it is not safe to lseek() to it. */
                     52: 
                     53:        /* Monotonicity of d_off is heavily exploited in the following. */
                     54: 
                     55:        /* This algorithm is tuned for modest directory sizes.  For
                     56:           huge directories, it might be more efficient to read blocks
                     57:           until the first d_off is too large, then back up one block,
                     58:           or even to use binary search on the directory blocks.  I
                     59:           doubt that the extra code for that would be worthwhile. */
                     60: 
                     61:        if ( dirp->dd_loc >= dirp->dd_size      /* invalid index */
                     62:          || ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off > loc
                     63:                                        /* too far along in buffer */
                     64:           )
                     65:                dirp->dd_loc = 0;       /* reset to beginning of buffer */
                     66:        /* else save time by starting at current dirp->dd_loc */
                     67: 
                     68:        for ( rewind = true; ; )
                     69:                {
                     70:                register struct dirent  *dp;
                     71: 
                     72:                /* See whether the matching entry is in the current buffer. */
                     73: 
                     74:                if ( (dirp->dd_loc < dirp->dd_size      /* valid index */
                     75:                   || readdir( dirp ) != NULL   /* next buffer read */
                     76:                   && (dirp->dd_loc = 0, true)  /* beginning of buffer set */
                     77:                     )
                     78:                  && (dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off
                     79:                        <= loc          /* match possible in this buffer */
                     80:                   )    {
                     81:                        for ( /* dp initialized above */ ;
                     82:                              (char *)dp < &dirp->dd_buf[dirp->dd_size];
                     83:                              dp = (struct dirent *)((char *)dp + dp->d_reclen)
                     84:                            )
                     85:                                if ( dp->d_off == loc )
                     86:                                        {       /* found it! */
                     87:                                        dirp->dd_loc =
                     88:                                                (char *)dp - dirp->dd_buf;
                     89:                                        return;
                     90:                                        }
                     91: 
                     92:                        rewind = false; /* no point in backing up later */
                     93:                        dirp->dd_loc = dirp->dd_size;   /* set end of buffer */
                     94:                        }
                     95:                else                    /* whole buffer past matching entry */
                     96:                        if ( !rewind )
                     97:                                {       /* no point in searching further */
                     98:                                errno = EINVAL;
                     99:                                return; /* no entry at specified loc */
                    100:                                }
                    101:                        else    {       /* rewind directory and start over */
                    102:                                rewind = false; /* but only once! */
                    103: 
                    104:                                dirp->dd_loc = dirp->dd_size = 0;
                    105: 
                    106:                                if ( lseek( dirp->dd_fd, (off_t)0, SEEK_SET )
                    107:                                        != 0
                    108:                                   )
                    109:                                        return; /* errno already set (EBADF) */
                    110: 
                    111:                                if ( loc == 0 )
                    112:                                        return; /* save time for rewinddir() */
                    113:                                }
                    114:                }
                    115:        }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.