11573Srgrimes/* 21573Srgrimes * Copyright (c) 1983, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 311573Srgrimesstatic char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3390039Sobrien#include <sys/cdefs.h> 3490039Sobrien__FBSDID("$FreeBSD: releng/10.3/lib/libc/gen/telldir.c 282979 2015-05-15 15:49:24Z julian $"); 351573Srgrimes 3671579Sdeischen#include "namespace.h" 371573Srgrimes#include <sys/param.h> 3869841Sdeischen#include <sys/queue.h> 391573Srgrimes#include <dirent.h> 4071579Sdeischen#include <pthread.h> 411573Srgrimes#include <stdlib.h> 421573Srgrimes#include <unistd.h> 4371579Sdeischen#include "un-namespace.h" 441573Srgrimes 4571579Sdeischen#include "libc_private.h" 46235647Sgleb#include "gen-private.h" 4769841Sdeischen#include "telldir.h" 4869841Sdeischen 491573Srgrimes/* 501573Srgrimes * return a pointer into a directory 511573Srgrimes */ 521573Srgrimeslong 531573Srgrimestelldir(dirp) 5469656Sdeischen DIR *dirp; 551573Srgrimes{ 5669841Sdeischen struct ddloc *lp; 57270002Sjhb long idx; 581573Srgrimes 5971579Sdeischen if (__isthreaded) 60174221Sdes _pthread_mutex_lock(&dirp->dd_lock); 61270002Sjhb LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { 62270002Sjhb if (lp->loc_seek == dirp->dd_seek && 63270002Sjhb lp->loc_loc == dirp->dd_loc) 64270002Sjhb break; 65270002Sjhb } 66270002Sjhb if (lp == NULL) { 67270002Sjhb lp = malloc(sizeof(struct ddloc)); 68270002Sjhb if (lp == NULL) { 69270002Sjhb if (__isthreaded) 70270002Sjhb _pthread_mutex_unlock(&dirp->dd_lock); 71270002Sjhb return (-1); 72270002Sjhb } 73270002Sjhb lp->loc_index = dirp->dd_td->td_loccnt++; 74270002Sjhb lp->loc_seek = dirp->dd_seek; 75270002Sjhb lp->loc_loc = dirp->dd_loc; 76270002Sjhb LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe); 77270002Sjhb } 78270002Sjhb idx = lp->loc_index; 7971579Sdeischen if (__isthreaded) 80174221Sdes _pthread_mutex_unlock(&dirp->dd_lock); 81270002Sjhb return (idx); 821573Srgrimes} 831573Srgrimes 841573Srgrimes/* 851573Srgrimes * seek to an entry in a directory. 861573Srgrimes * Only values returned by "telldir" should be passed to seekdir. 871573Srgrimes */ 881573Srgrimesvoid 891573Srgrimes_seekdir(dirp, loc) 9069656Sdeischen DIR *dirp; 911573Srgrimes long loc; 921573Srgrimes{ 9369841Sdeischen struct ddloc *lp; 941573Srgrimes struct dirent *dp; 951573Srgrimes 9669841Sdeischen LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { 971573Srgrimes if (lp->loc_index == loc) 981573Srgrimes break; 991573Srgrimes } 1001573Srgrimes if (lp == NULL) 1011573Srgrimes return; 1021573Srgrimes if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) 103270002Sjhb return; 104282979Sjulian 105282979Sjulian /* If it's within the same chunk of data, don't bother reloading. */ 106282979Sjulian if (lp->loc_seek == dirp->dd_seek) { 107282979Sjulian /* 108282979Sjulian * If we go back to 0 don't make the next readdir 109282979Sjulian * trigger a call to getdirentries(). 110282979Sjulian */ 111282979Sjulian if (lp->loc_loc == 0) 112282979Sjulian dirp->dd_flags |= __DTF_SKIPREAD; 113282979Sjulian dirp->dd_loc = lp->loc_loc; 114282979Sjulian return; 115282979Sjulian } 1161573Srgrimes (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); 1171573Srgrimes dirp->dd_seek = lp->loc_seek; 1181573Srgrimes dirp->dd_loc = 0; 119282979Sjulian dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */ 1201573Srgrimes while (dirp->dd_loc < lp->loc_loc) { 121178772Skib dp = _readdir_unlocked(dirp, 0); 1221573Srgrimes if (dp == NULL) 1231573Srgrimes break; 1241573Srgrimes } 1251573Srgrimes} 1265958Sdfr 1275958Sdfr/* 128282979Sjulian * After readdir returns the last entry in a block, a call to telldir 129282979Sjulian * returns a location that is after the end of that last entry. 130282979Sjulian * However, that location doesn't refer to a valid directory entry. 131282979Sjulian * Ideally, the call to telldir would return a location that refers to 132282979Sjulian * the first entry in the next block. That location is not known 133282979Sjulian * until the next block is read, so readdir calls this function after 134282979Sjulian * fetching a new block to fix any such telldir locations. 135282979Sjulian */ 136282979Sjulianvoid 137282979Sjulian_fixtelldir(DIR *dirp, long oldseek, long oldloc) 138282979Sjulian{ 139282979Sjulian struct ddloc *lp; 140282979Sjulian 141282979Sjulian lp = LIST_FIRST(&dirp->dd_td->td_locq); 142282979Sjulian if (lp != NULL) { 143282979Sjulian if (lp->loc_loc == oldloc && 144282979Sjulian lp->loc_seek == oldseek) { 145282979Sjulian lp->loc_seek = dirp->dd_seek; 146282979Sjulian lp->loc_loc = dirp->dd_loc; 147282979Sjulian } 148282979Sjulian } 149282979Sjulian} 150282979Sjulian 151282979Sjulian/* 1525958Sdfr * Reclaim memory for telldir cookies which weren't used. 1535958Sdfr */ 1545958Sdfrvoid 1555958Sdfr_reclaim_telldir(dirp) 15669656Sdeischen DIR *dirp; 1575958Sdfr{ 15869841Sdeischen struct ddloc *lp; 15969841Sdeischen struct ddloc *templp; 1605958Sdfr 16169841Sdeischen lp = LIST_FIRST(&dirp->dd_td->td_locq); 16269656Sdeischen while (lp != NULL) { 16369656Sdeischen templp = lp; 16469656Sdeischen lp = LIST_NEXT(lp, loc_lqe); 16569656Sdeischen free(templp); 1665958Sdfr } 16769841Sdeischen LIST_INIT(&dirp->dd_td->td_locq); 1685958Sdfr} 169