1 /* $OpenBSD: seekdir.c,v 1.13 2015/09/12 13:34:22 guenther Exp $ */ 2 /* 3 * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <dirent.h> 19 #include <unistd.h> 20 21 #include "thread_private.h" 22 #include "telldir.h" 23 24 /* 25 * Seek to an entry in a directory. 26 * Only values returned by "telldir" should be passed to seekdir. 27 */ 28 void 29 seekdir(DIR *dirp, long loc) 30 { 31 struct dirent *dp; 32 33 /* 34 * First check whether the directory entry to seek for 35 * is still buffered in the directory structure in memory. 36 */ 37 38 _MUTEX_LOCK(&dirp->dd_lock); 39 if (dirp->dd_size && dirp->dd_bufpos == loc) { 40 dirp->dd_loc = 0; 41 dirp->dd_curpos = loc; 42 _MUTEX_UNLOCK(&dirp->dd_lock); 43 return; 44 } 45 46 for (dirp->dd_loc = 0; 47 dirp->dd_loc < dirp->dd_size; 48 dirp->dd_loc += dp->d_reclen) { 49 dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc); 50 if (dp->d_off != loc) 51 continue; 52 53 /* 54 * Entry found in the buffer, use it. If readdir(3) 55 * follows, this will save us a getdents(2) syscall. 56 * Note that d_off is the offset of the _next_ entry, 57 * so advance dd_loc. 58 */ 59 60 dirp->dd_loc += dp->d_reclen; 61 dirp->dd_curpos = loc; 62 _MUTEX_UNLOCK(&dirp->dd_lock); 63 return; 64 } 65 66 /* 67 * The entry is not in the buffer, prepare a call to getdents(2). 68 * In particular, invalidate dd_loc. 69 */ 70 71 dirp->dd_loc = dirp->dd_size; 72 dirp->dd_bufpos = dirp->dd_curpos = lseek(dirp->dd_fd, loc, SEEK_SET); 73 _MUTEX_UNLOCK(&dirp->dd_lock); 74 } 75 DEF_WEAK(seekdir); 76