121363Sdist /* 221363Sdist * Copyright (c) 1983 Regents of the University of California. 334790Sbostic * All rights reserved. 434790Sbostic * 5*42627Sbostic * %sccs.include.redist.c% 621363Sdist */ 721363Sdist 826604Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*42627Sbostic static char sccsid[] = "@(#)telldir.c 5.8 (Berkeley) 06/01/90"; 1034790Sbostic #endif /* LIBC_SCCS and not lint */ 115929Smckusick 126370Smckusic #include <sys/param.h> 1336545Smckusick #include <dirent.h> 145929Smckusick 155929Smckusick /* 1638442Smckusick * The option SINGLEUSE may be defined to say that a telldir 1738442Smckusick * cookie may be used only once before it is freed. This option 1838442Smckusick * is used to avoid having memory usage grow without bound. 1938442Smckusick */ 2038442Smckusick #define SINGLEUSE 2138442Smckusick 2238442Smckusick /* 2338442Smckusick * One of these structures is malloced to describe the current directory 2438442Smckusick * position each time telldir is called. It records the current magic 2538442Smckusick * cookie returned by getdirentries and the offset within the buffer 2638442Smckusick * associated with that return value. 2738442Smckusick */ 2838442Smckusick struct ddloc { 2938442Smckusick struct ddloc *loc_next;/* next structure in list */ 3038442Smckusick long loc_index; /* key associated with structure */ 3138442Smckusick long loc_seek; /* magic cookie returned by getdirentries */ 3238442Smckusick long loc_loc; /* offset of entry in buffer */ 3338442Smckusick }; 3438442Smckusick 3538442Smckusick #define NDIRHASH 32 /* Num of hash lists, must be a power of 2 */ 3638442Smckusick #define LOCHASH(i) ((i)&(NDIRHASH-1)) 3738442Smckusick 3838442Smckusick static long dd_loccnt; /* Index of entry for sequential readdir's */ 3938442Smckusick static struct ddloc *dd_hash[NDIRHASH]; /* Hash list heads for ddlocs */ 4038442Smckusick 4138442Smckusick /* 425929Smckusick * return a pointer into a directory 435929Smckusick */ 445929Smckusick long 455929Smckusick telldir(dirp) 465929Smckusick DIR *dirp; 475929Smckusick { 4838435Smckusick register int index; 4938435Smckusick register struct ddloc *lp; 5011827Smckusick 5138435Smckusick if ((lp = (struct ddloc *)malloc(sizeof(struct ddloc))) == NULL) 5238435Smckusick return (-1); 5338442Smckusick index = dd_loccnt++; 5438435Smckusick lp->loc_index = index; 5538435Smckusick lp->loc_seek = dirp->dd_seek; 5638435Smckusick lp->loc_loc = dirp->dd_loc; 5738442Smckusick lp->loc_next = dd_hash[LOCHASH(index)]; 5838442Smckusick dd_hash[LOCHASH(index)] = lp; 5938435Smckusick return (index); 605929Smckusick } 6138442Smckusick 6238442Smckusick /* 6338442Smckusick * seek to an entry in a directory. 6438442Smckusick * Only values returned by "telldir" should be passed to seekdir. 6538442Smckusick */ 6638442Smckusick void 6738442Smckusick _seekdir(dirp, loc) 6838442Smckusick register DIR *dirp; 6938442Smckusick long loc; 7038442Smckusick { 7138442Smckusick register struct ddloc *lp; 7238442Smckusick register struct ddloc **prevlp; 7338442Smckusick struct dirent *dp; 7438442Smckusick extern long lseek(); 7538442Smckusick 7638442Smckusick prevlp = &dd_hash[LOCHASH(loc)]; 7738442Smckusick lp = *prevlp; 7838442Smckusick while (lp != NULL) { 7938442Smckusick if (lp->loc_index == loc) 8038442Smckusick break; 8138442Smckusick prevlp = &lp->loc_next; 8238442Smckusick lp = lp->loc_next; 8338442Smckusick } 8438442Smckusick if (lp == NULL) 8538442Smckusick return; 8638442Smckusick if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) 8738442Smckusick goto found; 8838442Smckusick (void) lseek(dirp->dd_fd, lp->loc_seek, 0); 8939959Smckusick dirp->dd_seek = lp->loc_seek; 9038442Smckusick dirp->dd_loc = 0; 9138442Smckusick while (dirp->dd_loc < lp->loc_loc) { 9238442Smckusick dp = readdir(dirp); 9338442Smckusick if (dp == NULL) 9438442Smckusick break; 9538442Smckusick } 9638442Smckusick found: 9738442Smckusick #ifdef SINGLEUSE 9838442Smckusick *prevlp = lp->loc_next; 9938442Smckusick free((caddr_t)lp); 10038442Smckusick #endif 10138442Smckusick } 102