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