Back to index

glibc  2.9
telldir.c
Go to the documentation of this file.
00001 /* Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <stddef.h>
00021 #include <dirent.h>
00022 #include <unistd.h>
00023 #include <sys/types.h>
00024 #include <stdlib.h>
00025 #include "dirstream.h"
00026 
00027 /* Internal data structure for telldir and seekdir.  */
00028 struct record
00029   {
00030     struct record *next; /* Link in chain.  */
00031     off_t cookie;           /* Value returned by `telldir'.  */
00032     off_t pos;
00033     size_t offset;
00034   };
00035 #define NBUCKETS 32
00036 static struct record *records[32];
00037 static off_t lastpos;
00038 __libc_lock_define_initialized(static, lock) /* Locks above data.  */
00039 
00040 
00041 /* Return the current position of DIRP.  */
00042 long int
00043 telldir (dirp)
00044      DIR *dirp;
00045 {
00046   struct record *new;
00047   long int pos;
00048 
00049   new = malloc (sizeof *new);
00050   if (new == NULL)
00051     return -1l;
00052 
00053   __libc_lock_lock (lock);
00054 
00055   new->pos = dirp->filepos;
00056   new->offset = dirp->offset;
00057   new->cookie = ++lastpos;
00058   new->next = records[new->cookie % NBUCKETS];
00059   records[new->cookie % NBUCKETS] = new;
00060 
00061   pos = new->cookie;
00062 
00063   __libc_lock_unlock (lock);
00064 
00065   return pos;
00066 }
00067 
00068 
00069 
00070 /* Seek to position POS in DIRP.  */
00071 void
00072 seekdir (dirp, pos)
00073      DIR *dirp;
00074      long int pos;
00075 {
00076   struct record *r, **prevr;
00077 
00078   __libc_lock_lock (lock);
00079 
00080   for (prevr = &records[pos % NBUCKETS], r = *prevr;
00081        r != NULL;
00082        prevr = &r->next, r = r->next)
00083     if (r->cookie == pos)
00084       {
00085        __libc_lock_lock (dirp->__lock);
00086        if (dirp->filepos != r->pos || dirp->offset != r->offset)
00087          {
00088            dirp->size = 0;  /* Must read a fresh buffer.  */
00089            /* Move to the saved position.  */
00090            __lseek (dirp->fd, r->pos, SEEK_SET);
00091            dirp->filepos = r->pos;
00092            dirp->offset = 0;
00093            /* Read entries until we reach the saved offset.  */
00094            while (dirp->offset < r->offset)
00095              {
00096               struct dirent *scan;
00097               __libc_lock_unlock (dirp->__lock);
00098               scan = readdir (dirp);
00099               __libc_lock_lock (dirp->__lock);
00100               if (! scan)
00101                 break;
00102              }
00103          }
00104        __libc_lock_unlock (dirp->__lock);
00105 
00106        /* To prevent leaking memory, cookies returned from telldir
00107           can only be used once.  So free this one's record now.  */
00108        *prevr = r->next;
00109        free (r);
00110        break;
00111       }
00112 
00113   __libc_lock_unlock (lock);
00114 
00115   /* If we lost there is no way to indicate it.  Oh well.  */
00116 }