Annotation of coherent/b/lib/libc/ndir/seekdir.c, revision 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.