|
|
1.1 ! root 1: /* ! 2: getdents -- get directory entries in a file system independent format ! 3: (SVR3 system call emulation) ! 4: ! 5: last edit: 25-Apr-1987 D A Gwyn ! 6: ! 7: This single source file supports several different methods of ! 8: getting directory entries from the operating system. Define ! 9: whichever one of the following describes your system: ! 10: ! 11: UFS original UNIX filesystem (14-character name limit) ! 12: BFS 4.2BSD (also 4.3BSD) native filesystem (long names) ! 13: NFS getdirentries() system call ! 14: ! 15: Also define any of the following that are pertinent: ! 16: ! 17: BRL BRL UNIX System V emulation environment on 4.nBSD ! 18: UNK have _getdents() system call, but kernel may not support it ! 19: ! 20: If your C library has a getdents() system call interface, but you ! 21: can't count on all kernels on which your application binaries may ! 22: run to support it, change the system call interface name to ! 23: _getdents() and define "UNK" to enable the system-call validity ! 24: test in this "wrapper" around _getdents(). ! 25: ! 26: If your system has a getdents() system call that is guaranteed ! 27: to always work, you shouldn't be using this source file at all. ! 28: */ ! 29: ! 30: ! 31: #if DBG ! 32: #include <stdio.h> ! 33: #endif ! 34: ! 35: #include <sys/types.h> ! 36: ! 37: #ifdef COHERENT ! 38: # include <errno.h> ! 39: #else ! 40: # include <sys/errno.h> ! 41: #endif /*Coherent*/ ! 42: ! 43: #ifdef BRL ! 44: # include <sys/_dir.h> /* BSD flavor, not System V */ ! 45: #else ! 46: # ifndef COHERENT ! 47: # include <sys/dir.h> ! 48: # endif ! 49: /* Good thing we don't need to use the DIRSIZ() macro! */ ! 50: # ifdef d_ino /* 4.3BSD/NFS using d_fileno */ ! 51: # undef d_ino /* (not absolutely necessary) */ ! 52: # else ! 53: # define d_fileno d_ino /* (struct direct) member */ ! 54: # endif ! 55: #endif ! 56: ! 57: /* sys.dirent.h no longer needed for 4.2 */ ! 58: #if 0 ! 59: #if DBG ! 60: #include "sys.dirent.h" ! 61: #else ! 62: #include "sys.dirent.h" ! 63: #endif /*DBG*/ ! 64: #endif ! 65: ! 66: #include <dirent.h> ! 67: ! 68: #include <sys/stat.h> ! 69: #ifdef UNK ! 70: # ifndef UFS ! 71: # include "***** ERROR ***** UNK applies only to UFS" ! 72: /* One could do something similar for getdirentries(), but I didn't bother. */ ! 73: # endif ! 74: # include <signal.h> ! 75: #endif ! 76: ! 77: ! 78: ! 79: #if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */ ! 80: #include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined" ! 81: #endif ! 82: ! 83: ! 84: #define max(a,b) ( ((a)>(b)) ? (a) : (b) ) ! 85: ! 86: #ifdef UFS ! 87: #define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */ ! 88: #else /* BFS || NFS */ ! 89: #define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */ ! 90: #endif ! 91: ! 92: #ifdef NFS ! 93: # ifdef BRL ! 94: # define getdirentries _getdirentries /* package hides this system call */ ! 95: # endif ! 96: extern int getdirentries(); ! 97: static long dummy; /* getdirentries() needs basep */ ! 98: # define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy ) ! 99: #else /* UFS || BFS */ ! 100: # ifdef BRL ! 101: # define read _read /* avoid emulation overhead */ ! 102: # endif ! 103: extern int read(); ! 104: # define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n ) ! 105: #endif ! 106: ! 107: #ifdef UNK ! 108: extern int _getdents(); /* actual system call */ ! 109: #endif ! 110: ! 111: extern char *strncpy(); ! 112: extern int fstat(), strlen(); ! 113: ! 114: off_t lseek(); ! 115: ! 116: extern int errno; ! 117: ! 118: #ifndef DIRBLKSIZ ! 119: #define DIRBLKSIZ 4096 /* directory file read buffer size */ ! 120: #endif ! 121: ! 122: #ifndef NULL ! 123: #define NULL 0 ! 124: #endif ! 125: ! 126: #ifndef SEEK_CUR ! 127: #define SEEK_CUR 1 ! 128: #endif ! 129: ! 130: #ifndef S_ISDIR /* macro to test for directory file */ ! 131: #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) ! 132: #endif ! 133: ! 134: #ifdef UNK ! 135: static enum { maybe, no, yes } state = maybe; ! 136: /* does _getdents() work? */ ! 137: ! 138: /*ARGSUSED*/ ! 139: static void ! 140: sig_catch( sig ) ! 141: int sig; /* must be SIGSYS */ ! 142: { ! 143: state = no; /* attempted _getdents() faulted */ ! 144: } ! 145: #endif ! 146: ! 147: int ! 148: getdents( fildes, buf, nbyte ) /* returns # bytes read; ! 149: 0 on EOF, -1 on error */ ! 150: int fildes; /* directory file descriptor */ ! 151: char *buf; /* where to put the (struct dirent)s */ ! 152: unsigned nbyte; /* size of buf[] */ ! 153: { ! 154: int serrno; /* entry errno */ ! 155: off_t offset; /* initial directory file offset */ ! 156: struct stat statb; /* fstat() info */ ! 157: union { ! 158: char dblk[DIRBLKSIZ]; ! 159: /* directory file block buffer */ ! 160: struct direct dummy; /* just for alignment */ ! 161: } u; /* (avoids having to malloc()) */ ! 162: register struct direct *dp; /* -> u.dblk[.] */ ! 163: register struct dirent *bp; /* -> buf[.] */ ! 164: ! 165: #ifdef UNK ! 166: switch ( state ) ! 167: { ! 168: void (*shdlr)(); /* entry SIGSYS handler */ ! 169: register int retval; /* return from _getdents() if any */ ! 170: ! 171: case yes: /* _getdents() is known to work */ ! 172: return _getdents( fildes, buf, nbyte ); ! 173: ! 174: case maybe: /* first time only */ ! 175: shdlr = signal( SIGSYS, sig_catch ); ! 176: retval = _getdents( fildes, buf, nbyte ); /* try it */ ! 177: (void)signal( SIGSYS, shdlr ); ! 178: ! 179: if ( state == maybe ) /* SIGSYS did not occur */ ! 180: { ! 181: state = yes; /* so _getdents() must have worked */ ! 182: return retval; ! 183: } ! 184: /* else fall through into emulation */ ! 185: ! 186: case no: /* fall through into emulation */ ! 187: } ! 188: #endif ! 189: ! 190: #if DBG ! 191: printf("\ngetdents: fd= %d; buf=%x; nbytes=%d\n",fildes,buf,nbyte); ! 192: #endif ! 193: ! 194: if ( buf == NULL ! 195: #ifndef BIT_16 ! 196: || (unsigned long)buf % sizeof(long) != 0 ) /* ugh */ ! 197: #else ! 198: ) ! 199: #endif /*16bit*/ ! 200: { ! 201: errno = EFAULT; /* invalid pointer */ ! 202: return -1; ! 203: } ! 204: ! 205: #if DBG ! 206: printf("fstat says: %d\n",fstat(fildes, &statb)); ! 207: #endif ! 208: if ( fstat( fildes, &statb ) != 0 ) ! 209: return -1; /* errno set by fstat() */ ! 210: #if DBG ! 211: printf("fstat OK\n"); ! 212: #endif ! 213: if ( !S_ISDIR( statb.st_mode ) ) ! 214: { ! 215: errno = ENOTDIR; /* not a directory */ ! 216: return -1; ! 217: } ! 218: #ifdef DBG ! 219: printf("fd is a dir.\n"); ! 220: #endif ! 221: if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 ) ! 222: return -1; /* errno set by lseek() */ ! 223: ! 224: ! 225: #ifdef BFS /* no telling what remote hosts do */ ! 226: if ( (unsigned long)offset % DIRBLKSIZ != 0 ) ! 227: { ! 228: errno = ENOENT; /* file pointer probably misaligned */ ! 229: return -1; ! 230: } ! 231: #endif ! 232: ! 233: serrno = errno; /* save entry errno */ ! 234: ! 235: #if DBG ! 236: printf(stderr,"\nIn getdents: \n"); ! 237: #endif ! 238: for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; ) ! 239: { /* convert next directory block */ ! 240: int size; ! 241: ! 242: do size = GetBlock( fildes, u.dblk, DIRBLKSIZ ); ! 243: while ( size == -1 && errno == EINTR ); ! 244: ! 245: if ( size <= 0 ) ! 246: return size; /* EOF or error (EBADF) */ ! 247: ! 248: for ( dp = (struct direct *)u.dblk; ! 249: (char *)dp < &u.dblk[size]; ! 250: dp = (struct direct *)((char *)dp + RecLen( dp )) ! 251: ) { ! 252: #ifndef UFS ! 253: if ( dp->d_reclen <= 0 ) ! 254: { ! 255: errno = EIO; /* corrupted directory */ ! 256: return -1; ! 257: } ! 258: #endif ! 259: ! 260: if ( dp->d_fileno != 0 ) ! 261: { /* non-empty; copy to user buffer */ ! 262: register int reclen, namlen = ! 263: strlen ( dp ->d_name ); ! 264: #if DBG ! 265: printf("name (%s) is %d long, ",dp->d_name, namlen); ! 266: #endif /*DBG*/ ! 267: namlen = (namlen > MAXNAMLEN) ? MAXNAMLEN ! 268: : namlen; ! 269: #ifdef DBG ! 270: printf("(ultimately %d long) MAXNAMLEN=%d\n", namlen,MAXNAMLEN); ! 271: #endif ! 272: reclen = DIRENTSIZ(namlen); ! 273: ! 274: if ( (char *)bp + reclen > &buf[nbyte] ) ! 275: { ! 276: errno = EINVAL; ! 277: return -1; /* buf too small */ ! 278: } ! 279: ! 280: bp->d_ino = (long) dp->d_fileno; ! 281: bp->d_off = offset + ((char *)dp - u.dblk); ! 282: bp->d_reclen = reclen; ! 283: ! 284: (void)strncpy( bp->d_name, dp->d_name, ! 285: namlen); ! 286: (void)memset (bp->d_name + namlen, (char *)0, ! 287: reclen - DIRENTBASESIZ - namlen ! 288: ); /* adds NUL padding */ ! 289: ! 290: #if DBG ! 291: printf("getdents: Name=%s; inode = %D; offset = %D; len=%d\n",bp->d_name, ! 292: bp->d_ino, bp->d_off, bp->d_reclen ); ! 293: #endif ! 294: bp = (struct dirent *)((char *)bp + reclen); ! 295: } ! 296: } ! 297: ! 298: if ( (char *)dp > &u.dblk[size] ) ! 299: { ! 300: errno = EIO; /* corrupted directory */ ! 301: return -1; ! 302: } ! 303: } ! 304: ! 305: errno = serrno; /* restore entry errno */ ! 306: return (char *)bp - buf; /* return # bytes read */ ! 307: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.