/*- * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Copyright (c) 2000 * Daniel Eischen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: head/lib/libc/gen/telldir.h 268531 2014-07-11 16:16:26Z jhb $ */ #ifndef _TELLDIR_H_ #define _TELLDIR_H_ #include "/usr/src/lib/libc/include/namespace.h" #include #include #include #include #include #include "dir.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "/usr/src/lib/libc/include/un-namespace.h" #include "/usr/src/lib/libc/include/libc_private.h" #include "/usr/src/lib/libc/gen/gen-private.h" #if 0 /* from sys/dirents.h for reference only */ struct dirent { __uint32_t d_fileno; /* file number of entry */ __uint16_t d_reclen; /* length of this record */ __uint8_t d_type; /* file type, see below */ __uint8_t d_namlen; /* length of string in d_name */ #if __BSD_VISIBLE #define MAXNAMLEN 255 char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ #else char d_name[255 + 1]; /* name must be no longer than this */ #endif }; /* from /usr/src/lib/libc/gen/gen-private.h for reference only */ /* * Structure describing an open directory. * * NOTE. Change structure layout with care, at least dd_fd field has to * remain unchanged to guarantee backward compatibility. */ struct _dirdesc { int dd_fd; /* file descriptor associated with directory */ long dd_loc; /* offset in current buffer */ long dd_size; /* amount of data returned by getdirentries */ char *dd_buf; /* data buffer */ int dd_len; /* size of data buffer */ long dd_seek; /* magic cookie returned by getdirentries */ int dd_flags; /* flags for readdir */ struct pthread_mutex *dd_lock; /* lock */ struct _telldir *dd_td; /* telldir position recording */ }; #define _dirfd(dirp) ((dirp)->dd_fd) #endif /* * 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 { LIST_ENTRY(ddloc) loc_lqe; /* entry 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 */ }; /* * One of these structures is malloced for each DIR to record telldir * positions. */ struct _telldir { LIST_HEAD(, ddloc) td_locq; /* list of locations */ long td_loccnt; /* index of entry for sequential readdir's */ }; bool x_filldir(DIR *, bool); struct dirent *x_readdir_unlocked(DIR *, int); void x_reclaim_telldir(DIR *); void x_seekdir(DIR *, long); #endif /* * Copyright (c) 1983, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/closedir.c 254499 2013-08-18 20:11:34Z pjd $"); //#include "/usr/src/lib/libc/include/namespace.h" //#include //#include //#include //#include //#include //#include "/usr/src/lib/libc/include/un-namespace.h" //#include "/usr/src/lib/libc/include/libc_private.h" //#include "/usr/src/lib/libc/include/gen-private.h" /* * close a directory. */ int xfdclosedir(DIR *dirp) { int fd; if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); fd = dirp->dd_fd; dirp->dd_fd = -1; dirp->dd_loc = 0; free((void *)dirp->dd_buf); x_reclaim_telldir(dirp); if (__isthreaded) { _pthread_mutex_unlock(&dirp->dd_lock); _pthread_mutex_destroy(&dirp->dd_lock); } free((void *)dirp); return (fd); } int xclosedir(DIR *dirp) { return (_close(xfdclosedir(dirp))); } /*- * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)opendir.c 8.8 (Berkeley) 5/1/95"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/opendir.c 268531 2014-07-11 16:16:26Z jhb $"); //#include "namespace.h" //#include //#include //#include //#include //#include //#include //#include //#include //#include //#include "un-namespace.h" //#include "gen-private.h" static DIR * __opendir_common(int, int, bool); /* * Open a directory. */ DIR * xopendir(const char *name) { return (__opendir2(name, DTF_HIDEW|DTF_NODUP)); } /* * Open a directory with existing file descriptor. */ DIR * xfdopendir(int fd) { if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) return (NULL); return (__opendir_common(fd, DTF_HIDEW|DTF_NODUP, true)); } DIR * __opendir2(const char *name, int flags) { int fd; DIR *dir; int saved_errno; if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0) return (NULL); if ((fd = _open(name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1) return (NULL); dir = __opendir_common(fd, flags, false); if (dir == NULL) { saved_errno = errno; _close(fd); errno = saved_errno; } return (dir); } static int opendir_compar(const void *p1, const void *p2) { return (strcmp((*(const struct dirent **)p1)->d_name, (*(const struct dirent **)p2)->d_name)); } /* * For a directory at the top of a unionfs stack, the entire directory's * contents are read and cached locally until the next call to rewinddir(). * For the fdopendir() case, the initial seek position must be preserved. * For rewinddir(), the full directory should always be re-read from the * beginning. * * If an error occurs, the existing buffer and state of 'dirp' is left * unchanged. */ bool x_filldir(DIR *dirp, bool use_current_pos) { struct dirent **dpv; char *buf, *ddptr, *ddeptr; off_t pos; int fd2, incr, len, n, saved_errno, space; struct stat sb; len = 0; space = 0; buf = NULL; ddptr = NULL; /* * Use the system page size if that is a multiple of DIRBLKSIZ. * Hopefully this can be a big win someday by allowing page * trades to user space to be done by _getdirentries(). */ if (_fstat(dirp->dd_fd, &sb) < 0) { return false; } incr = getpagesize(); if ((incr % sb.st_blksize) != 0) incr = sb.st_blksize; printf("blksiz is %d, using %d\n", sb.st_blksize, incr); /* * The strategy here is to read all the directory * entries into a buffer, sort the buffer, and * remove duplicate entries by setting the inode * number to zero. * * We reopen the directory because _getdirentries() * on a MNT_UNION mount modifies the open directory, * making it refer to the lower directory after the * upper directory's entries are exhausted. * This would otherwise break software that uses * the directory descriptor for fchdir or *at * functions, such as fts.c. */ if ((fd2 = _openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1) return (false); if (use_current_pos) { pos = lseek(dirp->dd_fd, 0, SEEK_CUR); if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) { saved_errno = errno; _close(fd2); errno = saved_errno; return (false); } } do { /* * Always make at least DIRBLKSIZ bytes * available to _getdirentries */ if (space < sb.st_blksize) { space += incr; len += incr; buf = reallocf(buf, len); if (buf == NULL) { saved_errno = errno; _close(fd2); errno = saved_errno; return (false); } ddptr = buf + (len - space); } n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek); if (n > 0) { ddptr += n; space -= n; } if (n < 0) { saved_errno = errno; _close(fd2); errno = saved_errno; return (false); } } while (n > 0); _close(fd2); ddeptr = ddptr; /* * There is now a buffer full of (possibly) duplicate * names. */ dirp->dd_buf = buf; /* * Go round this loop twice... * * Scan through the buffer, counting entries. * On the second pass, save pointers to each one. * Then sort the pointers and remove duplicate names. */ for (dpv = 0;;) { n = 0; ddptr = buf; while (ddptr < ddeptr) { struct dirent *dp; dp = (struct dirent *) ddptr; if ((long)dp & 03L) break; if ((dp->d_reclen <= 0) || (dp->d_reclen > (ddeptr + 1 - ddptr))) break; ddptr += dp->d_reclen; if (dp->d_fileno) { if (dpv) dpv[n] = dp; n++; } } if (dpv) { struct dirent *xp; /* * This sort must be stable. */ mergesort(dpv, n, sizeof(*dpv), opendir_compar); dpv[n] = NULL; xp = NULL; /* * Scan through the buffer in sort order, * zapping the inode number of any * duplicate names. */ for (n = 0; dpv[n]; n++) { struct dirent *dp = dpv[n]; if ((xp == NULL) || strcmp(dp->d_name, xp->d_name)) { xp = dp; } else { dp->d_fileno = 0; } if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW)) dp->d_fileno = 0; } free(dpv); break; } else { dpv = malloc((n+1) * sizeof(struct dirent *)); if (dpv == NULL) break; } } dirp->dd_len = len; dirp->dd_size = ddptr - dirp->dd_buf; return (true); } /* * Common routine for opendir(3), __opendir2(3) and fdopendir(3). */ static DIR * __opendir_common(int fd, int flags, bool use_current_pos) { DIR *dirp; int incr; int saved_errno; int unionstack; struct stat sb; if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL) return (NULL); dirp->dd_buf = NULL; dirp->dd_fd = fd; dirp->dd_flags = flags; dirp->dd_loc = 0; dirp->dd_lock = NULL; dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR)); LIST_INIT(&dirp->dd_td->td_locq); dirp->dd_td->td_loccnt = 0; /* * Use the system page size if that is a multiple of DIRBLKSIZ. * Hopefully this can be a big win someday by allowing page * trades to user space to be done by _getdirentries(). */ if (_fstat(fd, &sb) < 0) { goto fail; } incr = getpagesize(); if ((incr % sb.st_blksize) != 0) incr = sb.st_blksize; printf("blksiz is %d, using %d\n", sb.st_blksize, incr); /* * Determine whether this directory is the top of a union stack. */ if (flags & DTF_NODUP) { struct statfs sfb; if (_fstatfs(fd, &sfb) < 0) goto fail; unionstack = !strcmp(sfb.f_fstypename, "unionfs") || (sfb.f_flags & MNT_UNION); } else { unionstack = 0; } if (unionstack) { if (!x_filldir(dirp, use_current_pos)) goto fail; dirp->dd_flags |= __DTF_READALL; } else { dirp->dd_len = incr; dirp->dd_buf = malloc(dirp->dd_len); if (dirp->dd_buf == NULL) goto fail; if (use_current_pos) { /* * Read the first batch of directory entries * to prime dd_seek. This also checks if the * fd passed to fdopendir() is a directory. */ dirp->dd_size = _getdirentries(dirp->dd_fd, dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); if (dirp->dd_size < 0) { if (errno == EINVAL) errno = ENOTDIR; goto fail; } dirp->dd_flags |= __DTF_SKIPREAD; } else { dirp->dd_size = 0; dirp->dd_seek = 0; } } return (dirp); fail: saved_errno = errno; free(dirp->dd_buf); free(dirp); errno = saved_errno; return (NULL); } /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/readdir.c 268531 2014-07-11 16:16:26Z jhb $"); //#include "namespace.h" //#include //#include //#include //#include //#include //#include "un-namespace.h" //#include "libc_private.h" //#include "gen-private.h" /* * get next entry in a directory. */ struct dirent * x_readdir_unlocked(dirp, skip) DIR *dirp; int skip; { struct dirent *dp; for (;;) { if (dirp->dd_loc >= dirp->dd_size) { if (dirp->dd_flags & __DTF_READALL) return (NULL); dirp->dd_loc = 0; } if (dirp->dd_loc == 0 && !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) { dirp->dd_size = _getdirentries(dirp->dd_fd, dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); if (dirp->dd_size <= 0) return (NULL); } dirp->dd_flags &= ~__DTF_SKIPREAD; dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc); printf("dd_loc is %ld\n", dirp->dd_loc); if ((long)dp & 03L) /* bogus pointer check */ return (NULL); if (dp->d_reclen <= 0 || dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) return (NULL); printf("d_reclen is %d\n", dp->d_reclen); dirp->dd_loc += dp->d_reclen; if (dp->d_ino == 0 && skip) continue; if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW)) continue; return (dp); } } struct dirent * xreaddir(dirp) DIR *dirp; { struct dirent *dp; if (__isthreaded) { _pthread_mutex_lock(&dirp->dd_lock); dp = x_readdir_unlocked(dirp, 1); _pthread_mutex_unlock(&dirp->dd_lock); } else dp = x_readdir_unlocked(dirp, 1); return (dp); } int xreaddir_r(dirp, entry, result) DIR *dirp; struct dirent *entry; struct dirent **result; { struct dirent *dp; int saved_errno; saved_errno = errno; errno = 0; if (__isthreaded) { _pthread_mutex_lock(&dirp->dd_lock); if ((dp = x_readdir_unlocked(dirp, 1)) != NULL) memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); _pthread_mutex_unlock(&dirp->dd_lock); } else if ((dp = x_readdir_unlocked(dirp, 1)) != NULL) memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); if (errno != 0) { if (dp == NULL) return (errno); } else errno = saved_errno; if (dp != NULL) *result = entry; else *result = NULL; return (0); } /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)rewinddir.c 8.1 (Berkeley) 6/8/93"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/rewinddir.c 271048 2014-09-03 19:01:34Z jhb $"); //#include "namespace.h" //#include //#include //#include //#include //#include "un-namespace.h" //#include "libc_private.h" //#include "gen-private.h" void xrewinddir(dirp) DIR *dirp; { if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); if (dirp->dd_flags & __DTF_READALL) x_filldir(dirp, false); else { (void) lseek(dirp->dd_fd, 0, SEEK_SET); dirp->dd_seek = 0; } dirp->dd_loc = 0; x_reclaim_telldir(dirp); if (__isthreaded) _pthread_mutex_unlock(&dirp->dd_lock); } /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/scandir.c 264042 2014-04-02 16:07:48Z theraven $"); /* * Scan the directory dirname calling select to make a list of selected * directory entries then sort using qsort and compare routine dcomp. * Returns the number of entries and a pointer to a list of pointers to * struct dirent (through namelist). Returns -1 if there were any errors. */ //#include "namespace.h" //#include //#include //#include //#include "un-namespace.h" #ifdef I_AM_SCANDIR_B #include "block_abi.h" #define SELECT(x) CALL_BLOCK(select, x) #ifndef __BLOCKS__ void qsort_b(void *, size_t, size_t, void*); #endif #else #define SELECT(x) select(x) #endif int xalphasort(const struct dirent **d1, const struct dirent **d2); static int xalphasort_thunk(void *thunk, const void *p1, const void *p2); /* * The DIRSIZ macro is the minimum record length which will hold the directory * entry. This requires the amount of space in struct dirent without the * d_name field, plus enough space for the name and a terminating nul byte * (dp->d_namlen + 1), rounded up to a 4 byte boundary. */ #undef DIRSIZ #define DIRSIZ(dp) \ ((sizeof(struct dirent) - sizeof(dp)->d_name) + \ (((dp)->d_namlen + 1 + 3) &~ 3)) int #ifdef I_AM_SCANDIR_B xscandir_b(const char *dirname, struct dirent ***namelist, DECLARE_BLOCK(int, select, const struct dirent *), DECLARE_BLOCK(int, dcomp, const struct dirent **, const struct dirent **)) #else xscandir(const char *dirname, struct dirent ***namelist, int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, const struct dirent **)) #endif { struct dirent *d, *p, **names = NULL; size_t nitems = 0; long arraysz; DIR *dirp; if ((dirp = xopendir(dirname)) == NULL) return(-1); arraysz = 32; /* initial estimate of the array size */ names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); if (names == NULL) goto fail; while ((d = xreaddir(dirp)) != NULL) { if (select != NULL && !SELECT(d)) continue; /* just selected names */ /* * Make a minimum size copy of the data */ p = (struct dirent *)malloc(DIRSIZ(d)); if (p == NULL) goto fail; p->d_fileno = d->d_fileno; p->d_type = d->d_type; p->d_reclen = d->d_reclen; p->d_namlen = d->d_namlen; bcopy(d->d_name, p->d_name, p->d_namlen + 1); /* * Check to make sure the array has space left and * realloc the maximum size. */ if (nitems >= arraysz) { struct dirent **names2; names2 = (struct dirent **)realloc((char *)names, (arraysz * 2) * sizeof(struct dirent *)); if (names2 == NULL) { free(p); goto fail; } names = names2; arraysz *= 2; } names[nitems++] = p; } xclosedir(dirp); if (nitems && dcomp != NULL) #ifdef I_AM_SCANDIR_B qsort_b(names, nitems, sizeof(struct dirent *), (void*)dcomp); #else qsort_r(names, nitems, sizeof(struct dirent *), &dcomp, xalphasort_thunk); #endif *namelist = names; return (nitems); fail: while (nitems > 0) free(names[--nitems]); free(names); xclosedir(dirp); return (-1); } /* * Alphabetic order comparison routine for those who want it. * POSIX 2008 requires that alphasort() uses strcoll(). */ int xalphasort(const struct dirent **d1, const struct dirent **d2) { return (strcoll((*d1)->d_name, (*d2)->d_name)); } static int xalphasort_thunk(void *thunk, const void *p1, const void *p2) { int (*dc)(const struct dirent **, const struct dirent **); dc = *(int (**)(const struct dirent **, const struct dirent **))thunk; return (dc((const struct dirent **)p1, (const struct dirent **)p2)); } /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)seekdir.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/seekdir.c 235647 2012-05-19 12:44:27Z gleb $"); //#include "namespace.h" //#include //#include //#include //#include "un-namespace.h" //#include "libc_private.h" //#include "gen-private.h" /* * Seek to an entry in a directory. * _seekdir is in telldir.c so that it can share opaque data structures. */ void xseekdir(dirp, loc) DIR *dirp; long loc; { if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); x_seekdir(dirp, loc); if (__isthreaded) _pthread_mutex_unlock(&dirp->dd_lock); } /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ //#include __FBSDID("$FreeBSD: head/lib/libc/gen/telldir.c 269204 2014-07-29 00:16:33Z jhb $"); //#include "namespace.h" //#include //#include //#include //#include //#include //#include //#include "un-namespace.h" //#include "libc_private.h" //#include "gen-private.h" //#include "telldir.h" /* * return a pointer into a directory */ long xtelldir(dirp) DIR *dirp; { struct ddloc *lp; long idx; if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { if (lp->loc_seek == dirp->dd_seek && lp->loc_loc == dirp->dd_loc) break; } if (lp == NULL) { lp = malloc(sizeof(struct ddloc)); if (lp == NULL) { if (__isthreaded) _pthread_mutex_unlock(&dirp->dd_lock); return (-1); } lp->loc_index = dirp->dd_td->td_loccnt++; lp->loc_seek = dirp->dd_seek; lp->loc_loc = dirp->dd_loc; LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe); } idx = lp->loc_index; printf("tell: loc is %ld, seek is %ld\n", lp->loc_loc, lp->loc_seek); if (__isthreaded) _pthread_mutex_unlock(&dirp->dd_lock); return (idx); } /* * seek to an entry in a directory. * Only values returned by "telldir" should be passed to seekdir. */ void x_seekdir(dirp, loc) DIR *dirp; long loc; { struct ddloc *lp; struct dirent *dp; LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { if (lp->loc_index == loc) break; } if (lp == NULL) return; if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek) return; if (lp->loc_seek == dirp->dd_seek) { dirp->dd_loc = lp->loc_loc; return; } (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); dirp->dd_seek = lp->loc_seek; dirp->dd_loc = 0; while (dirp->dd_loc < lp->loc_loc) { dp = x_readdir_unlocked(dirp, 0); printf("seek: loc is %ld, seek is %ld\n", dirp->dd_loc, dirp->dd_seek); if (dp == NULL) break; } } /* * Reclaim memory for telldir cookies which weren't used. */ void x_reclaim_telldir(dirp) DIR *dirp; { struct ddloc *lp; struct ddloc *templp; lp = LIST_FIRST(&dirp->dd_td->td_locq); while (lp != NULL) { templp = lp; lp = LIST_NEXT(lp, loc_lqe); free(templp); } LIST_INIT(&dirp->dd_td->td_locq); }