/* * Derived from Berkeley source code. Those parts are * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)telldir.c 5.8 (Berkeley) 6/1/90"; #endif /* LIBC_SCCS and not lint */ #include #include #include /* For malloc and free */ #ifdef USE_SYS_DIR_H #include #else #include #endif #if defined(AIX) && defined(__GNUC__) /* lucb */ #define dd_bsize dd_size #endif /* * The option SINGLEUSE may be defined to say that a telldir * cookie may be used only once before it is freed. This option * is used to avoid having memory usage grow without bound. */ #define SINGLEUSE /* * One of these structures is malloced to describe the current directory * position each time telldir is called. It records the current magic * cookie returned by getdirentries and the offset within the buffer * associated with that return value. */ struct ddloc { struct ddloc *loc_next;/* next structure in list */ long loc_index; /* key associated with structure */ long loc_seek; /* magic cookie returned by getdirentries */ long loc_loc; /* offset of entry in buffer */ }; #define NDIRHASH 32 /* Num of hash lists, must be a power of 2 */ #define LOCHASH(i) ((i)&(NDIRHASH-1)) static long dd_loccnt; /* Index of entry for sequential readdir's */ static struct ddloc *dd_hash[NDIRHASH]; /* Hash list heads for ddlocs */ /* * return a pointer into a directory */ long telldir(dirp) DIR *dirp; { register int index; register struct ddloc *lp; if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) return (-1); index = dd_loccnt++; lp->loc_index = index; lp->loc_seek = dirp->dd_bbase; lp->loc_loc = dirp->dd_loc; lp->loc_next = dd_hash[LOCHASH(index)]; dd_hash[LOCHASH(index)] = lp; return (index); } /* * seek to an entry in a directory. * Only values returned by "telldir" should be passed to seekdir. */ void p__seekdir(register DIR *dirp, long loc) { register struct ddloc *lp; register struct ddloc **prevlp; struct dirent *dp; extern long lseek(); prevlp = &dd_hash[LOCHASH(loc)]; lp = *prevlp; while (lp != NULL) { if (lp->loc_index == loc) break; prevlp = &lp->loc_next; lp = lp->loc_next; } if (lp == NULL) return; if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_bbase) goto found; if(dirp->dd_fd < 0) p__seekvdir(dirp->dd_fd,lp->loc_seek); else (void) lseek(dirp->dd_fd, lp->loc_seek, 0); dirp->dd_bbase = lp->loc_seek; dirp->dd_loc = 0; while (dirp->dd_loc < lp->loc_loc) { assert(P_IS_THIS_THREAD_MASTER()); /*SOLARIS: readdir MT-Unsafe */ dp = readdir(dirp); if (dp == NULL) break; } found: #ifdef SINGLEUSE *prevlp = lp->loc_next; free((caddr_t)lp); #endif }