From 76b87c039ba8d20add4f52ba43f3471fd92e210b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 29 May 1997 12:06:58 +0000 Subject: Update. 1997-05-29 12:48 Ulrich Drepper * io/ftw.c: Complete rewrite. Add implementation of `nftw'. * io/ftw.h: Update for new implementation and XPG4.2. * login/Makefile: Update for UTMP daemon implementation. Update resolver code to bind-4.9.6-T1A. * resolv/Banner: Update. * nss/digits_dots.c: Adapt text address matching to T1A. * nss/nss_files/files-hosts.c: Always use inet_pton. * resolv/base64.c (b64_pton): Follow T1A but don't use this code since it would lead to warnings. * resolv/gethnamaddr.c (getanswer): Test host name for maximal length at several places. * resolv/inet_net_pton.c (inet_net_pton_ipv4): Correct typo in comment. * resolv/res_comp.c (dn_expand): Check for overflow. (dn_comp): Likewise. * resolv/res_debug.c (precsize_aton): Better implementation. * resolv/res_init.c (res_init): Make `buf' of size MAXDNAME. * resolv/res_send.c (res_send): Check for overflow in descriptor set. * resolv/nss_dns/dns-host.c (getanswer_r): Test host name for maximal length at several places. 1997-05-29 12:51 Mark Kettenis * login/utmp-private.h (struct utfuncs): Add one more parameter to updwtmp function. Declare all three function jump tables. * login/utmp.h: Declare __utmpname. * login/getutent_r.c: Remove db backend and provide support for utmpd backend. * login/login.c: Use `updwtmp' function insteead of writing the record ourself. * login/logwtmp.c: Move `updwtmp' function to... * login/updwtmp.c: ...here. New file. * login/utmp_db.h: Removed. * login/utmp_file.c: Add updwtmp function to write to file. * login/utmp_daemon.c: New file. Daemon backend. * login/utmpname.c: New file. Implementation of utmpname function. * login/utmpdump.c: New file. Tool to dump utmp-like files. * login/utmpd/connection.c: New file. * login/utmpd/database.c: New file. * login/utmpd/error.c: New file. * login/utmpd/request.c: New file. * login/utmpd/utmpd-private.h: New file. * login/utmpd/utmpd.c: New file. * login/utmpd/utmpd.h: New file. * login/utmpd/xtmp.c: New file. * login/utmpd/xtmp.h: New file. 1997-05-29 12:28 Jim Meyering * time/strftime.c: Correct/normalize indentation in cpp directives. 1997-05-28 20:43 Philip Blundell * nis/nis_error.c: Include to fix warning. * nis/nis_print.c: Likewise. * nis/nss_nisplus/nisplus-hosts.c: Arg 3 of map_v4v6_hostent is int* not size_t*. 1997-05-28 21:56 Andreas Jaeger * math/cmathcalls.h: Correct typo in comment. * inet/netinet/icmp6.h: Include for in6_addr. * sysdeps/unix/sysv/linux/netinet/ip_fw.h: Include for IFNAMSIZ. * sysdeps/unix/sysv/linux/net/ppp_defs.h: Include for time_t. * login/pty.h: Include for definition of struct winsize. * misc/regexp.h (compile): Correct typo. * argp/argp.h: Put extern before __const in defintion of argp_program_bug_address. 1997-05-29 00:20 Ulrich Drepper * sysdeps/wordsize-32/inttypes.h: Correct names of unsigned fast and least types. Correct names of ?INT_FAST*_{MIN,MAX} macros. * sysdeps/wordsize-64/inttypes.h: Likewise. Reported by Andreas Jaeger . 1997-05-28 22:51 Ulrich Drepper * sysdeps/unix/Makefile (make-ioctls-CFLAGS): Use generic ttydefaults.h file instead of non-existing version in termios/sys. Reported by Zack Weinberg . * time/strptime.c (strptime_internal, case 'Y'): Restrict year number to four digits and to representable range for 4 byte time_t values. Patch by H.J. Lu . 1997-05-28 18:19 Philip Blundell * posix/execl.c: Include to avoid warning. 1997-05-27 18:19 Andreas Jaeger * math/libm-test.c: Implement testing of inlined functions, make output nicer, update comments. * math/test-idouble.c: New file. Frontend for double tests of inlined functions. * math/test-ildoubl.c: New file. Frontend for long double tests of inlined functions. * math/test-ifloat.c: New file. Frontend for float tests of inlined functions. * math/test-longdouble.c: Rename to... * math/test-ldouble.c: ...this. * math/Makefile: Add rules for new test programs, change rules for renaming of longdouble test. 1997-05-20 15:50 H.J. Lu * sunrpc/rpc/svc.h (__dispatch_fn_t): New. (svc_register): Use __dispatch_fn_t in prototype. 1997-05-28 17:02 Ulrich Drepper * sysdeps/generic/bzero.c (bzero): Fix typo. Patch by Witek Wnuk . 1997-05-27 12:00 Andreas Jaeger * sysdeps/generic/vtimes.c: Use ISO C declaration style. * sysdeps/unix/bsd/ualarm.c: Include for prototype. * sysdeps/generic/memccpy.c: Include for prototype. * signal/tst-signal.c (handler): Correct function declaration to avoid warning. * stdlib/testsort.c (compare): Likewise. * string/tester.c: Likewise. 1997-05-27 14:16 Miles Bader * argp-help.c (argp_args_usage): Supply correct argp to filter_doc. 1997-05-27 17:51 Andreas Schwab * db/hash/extern.h, db/hash/hash.c, db/hash/hash.h, db/hash/hash_log2.c: Rename __log2 to __hash_log2 to avoid clash with libm. 1997-05-27 14:47 Andreas Schwab * sysdeps/m68k/fpu/e_atan2.c: Fix missing negate. Use __m81_test instead of explicit comparisons. 1997-05-26 18:36 Andreas Schwab * inet/netinet/icmp6.h: Remove use of which has no place in a generic header and is no user include file. --- io/ftw.c | 585 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- io/ftw.h | 81 +++++++-- 2 files changed, 518 insertions(+), 148 deletions(-) (limited to 'io') diff --git a/io/ftw.c b/io/ftw.c index d7ec716936..e20ad231d3 100644 --- a/io/ftw.c +++ b/io/ftw.c @@ -1,6 +1,7 @@ -/* Copyright (C) 1992, 1995, 1996, 1997 Free Software Foundation, Inc. +/* File tree walker functions. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Ian Lance Taylor (ian@airs.com). + Contributed by Ulrich Drepper , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -17,197 +18,507 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include -#include +#include +#include #include #include -#include -#include +#include +#include #include -#include +/* #define NDEBUG 1 */ +#include -#ifndef PATH_MAX -#define PATH_MAX 1024 /* XXX */ -#endif +struct dir_data +{ + DIR *stream; + char *content; +}; -/* Traverse one level of a directory tree. */ - -static int -ftw_dir (DIR **dirs, int level, int descriptors, char *dir, size_t len, - int (*func) (const char *file, const struct stat *status, int flag)) +struct ftw_data { - int got; - struct dirent *entry; + struct dir_data **dirstreams; + size_t actdir; + size_t maxdir; - got = 0; + char *dirbuf; + size_t dirbufsize; + struct FTW ftw; - __set_errno (0); + int flags; - while ((entry = readdir (dirs[level])) != NULL) - { - struct stat s; - int flag, retval, newlev; - size_t namlen; + int *cvt_arr; + __nftw_func_t func; - ++got; + struct stat st; - if (entry->d_name[0] == '.' - && (entry->d_name[1] == '\0' || - (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) - { - __set_errno (0); - continue; - } + dev_t dev; +}; - namlen = _D_EXACT_NAMLEN (entry); - if (namlen + len + 1 > PATH_MAX) - { -#ifdef ENAMETOOLONG - __set_errno (ENAMETOOLONG); -#else - __set_errno (ENOMEM); -#endif - return -1; - } +/* Internally we use the FTW_* constants used for `nftw'. When the + process called `ftw' we must reduce the flag to the known flags + for `ftw'. */ +static int nftw_arr[] = +{ + FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN +}; - dir[len] = '/'; - memcpy ((void *) (dir + len + 1), (void *) entry->d_name, - namlen + 1); +static int ftw_arr[] = +{ + FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS +}; - if (stat (dir, &s) < 0) - { - if (errno != EACCES && errno != ENOENT) - return -1; - flag = FTW_NS; - } - else if (S_ISDIR (s.st_mode)) + +/* Forward declarations of local functions. */ +static int ftw_dir (struct ftw_data *data); + + +static inline int +open_dir_stream (struct ftw_data *data, struct dir_data *dirp) +{ + int result = 0; + + if (data->dirstreams[data->actdir] != NULL) + { + /* Oh, oh. We must close this stream. Get all remaining + entries and store them as a list in the `content' member of + the `struct dir_data' variable. */ + size_t bufsize = 1024; + char *buf = malloc (bufsize); + + if (buf == NULL) + result = -1; + else { - newlev = (level + 1) % descriptors; + DIR *st = data->dirstreams[data->actdir]->stream; + struct dirent *d; + size_t actsize = 0; + + while ((d = readdir (st)) != NULL) + { + size_t this_len = _D_EXACT_NAMLEN (d); + if (actsize + this_len + 2 >= bufsize) + { + char *newp; + bufsize += MAX (1024, 2 * this_len); + newp = realloc (buf, bufsize); + if (newp == NULL) + { + /* No more memory. */ + int save_err = errno; + free (buf); + __set_errno (save_err); + result = -1; + break; + } + buf = newp; + } + + memcpy (buf + actsize, d->d_name, this_len); + actsize += this_len; + buf[actsize++] = '\0'; + } - if (dirs[newlev] != NULL) - closedir (dirs[newlev]); + /* Terminate the list with an additional NUL byte. */ + buf[actsize++] = '\0'; - dirs[newlev] = opendir (dir); - if (dirs[newlev] != NULL) - flag = FTW_D; + /* Shrink the buffer to what we actually need. */ + data->dirstreams[data->actdir]->content = realloc (buf, actsize); + if (data->dirstreams[data->actdir]->content == NULL) + { + int save_err = errno; + free (buf); + __set_errno (save_err); + result = -1; + } else { - if (errno != EACCES) - return -1; - flag = FTW_DNR; + closedir (st); + data->dirstreams[data->actdir]->stream = NULL; + data->dirstreams[data->actdir] = NULL; } } + } + + /* Open the new stream. */ + if (result == 0) + { + assert (data->dirstreams[data->actdir] == NULL); + + dirp->stream = opendir (data->dirbuf); + if (dirp->stream == NULL) + result = -1; else - flag = FTW_F; + { + dirp->content = NULL; + data->dirstreams[data->actdir] = dirp; + + if (++data->actdir == data->maxdir) + data->actdir = 0; + } + } + + return result; +} + + +static inline int +process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, + size_t namlen) +{ + int result = 0; + int flag; + + if (name[0] == '.' && (name[1] == '\0' + || (name[1] == '.' && name[2] == '\0'))) + /* Don't process the "." and ".." entries. */ + return 0; + + if (data->dirbufsize < data->ftw.base + namlen + 2) + { + /* Enlarge the buffer. */ + char *newp; + + data->dirbufsize *= 2; + newp = realloc (data->dirbuf, data->dirbufsize); + if (newp == NULL) + return -1; + data->dirbuf = newp; + } - retval = (*func) (dir, &s, flag); + memcpy (data->dirbuf + data->ftw.base, name, namlen); + data->dirbuf[data->ftw.base + namlen] = '\0'; + if (((data->flags & FTW_PHYS) ? lstat : stat) (data->dirbuf, &data->st) < 0) + { + if (errno != EACCES && errno != ENOENT) + result = -1; + else if (!(data->flags & FTW_PHYS) + && lstat (data->dirbuf, &data->st) == 0 + && S_ISLNK (data->st.st_mode)) + flag = FTW_SLN; + else + flag = FTW_NS; + } + else + { + if (S_ISDIR (data->st.st_mode)) + flag = FTW_D; + else if (S_ISLNK (data->st.st_mode)) + flag = FTW_SL; + else + flag = FTW_F; + } + + if (result == 0 + && (!(data->flags & FTW_MOUNT) || data->st.st_dev == data->dev)) + { if (flag == FTW_D) { - if (retval == 0) - retval = ftw_dir (dirs, newlev, descriptors, dir, - namlen + len + 1, func); - if (dirs[newlev] != NULL) - { - int save; + result = ftw_dir (data); - save = errno; - closedir (dirs[newlev]); - __set_errno (save); - dirs[newlev] = NULL; + if (result == 0 && (data->flags & FTW_CHDIR)) + { + /* Change back to current directory. */ + int done = 0; + if (dir->stream != NULL) + if (fchdir (dirfd (dir->stream)) == 0) + done = 1; + + if (!done) + { + if (data->ftw.base == 1) + { + if (chdir ("/") < 0) + result = -1; + } + else + { + /* Please note that we overwrite a slash. */ + data->dirbuf[data->ftw.base - 1] = '\0'; + + if (chdir (data->dirbuf) < 0) + result = -1; + else + data->dirbuf[data->ftw.base - 1] = '/'; + } + } } } + else + result = (*data->func) (data->dirbuf, &data->st, data->cvt_arr[flag], + &data->ftw); + } + + return result; +} + + +static int +ftw_dir (struct ftw_data *data) +{ + struct dir_data dir; + struct dirent *d; + int previous_base = data->ftw.base; + int result = 0; + char *startp; + + /* First, report the directory (if not depth-first). */ + if (!(data->flags & FTW_DEPTH)) + { + result = (*data->func) (data->dirbuf, &data->st, FTW_D, &data->ftw); + if (result != 0) + return result; + } - if (retval != 0) - return retval; + /* Open the stream for this directory. This might require that + another stream has to be closed. */ + result = open_dir_stream (data, &dir); + if (result != 0) + return result; - if (dirs[level] == NULL) + /* If necessary, change to this directory. */ + if (data->flags & FTW_CHDIR) + { + if (fchdir (dirfd (dir.stream)) < 0) { - int skip; - - dir[len] = '\0'; - dirs[level] = opendir (dir); - if (dirs[level] == NULL) - return -1; - skip = got; - while (skip-- != 0) + if (errno == ENOSYS) { - __set_errno (0); - if (readdir (dirs[level]) == NULL) - return errno == 0 ? 0 : -1; + if (chdir (data->dirbuf) < 0) + result = -1; } + else + result = -1; } - __set_errno (0); + if (result != 0) + { + int save_err = errno; + closedir (dir.stream); + __set_errno (save_err); + + if (data->actdir-- == 0) + data->actdir = data->maxdir - 1; + data->dirstreams[data->actdir] = NULL; + + return result; + } } - return errno == 0 ? 0 : -1; -} + /* Next, update the `struct FTW' information. */ + ++data->ftw.level; + startp = strchr (data->dirbuf, '\0'); + *startp++ = '/'; + data->ftw.base = startp - data->dirbuf; -/* Call a function on every element in a directory tree. */ + while (dir.stream != NULL && (d = readdir (dir.stream)) != NULL) + { + result = process_entry (data, &dir, d->d_name, _D_EXACT_NAMLEN (d)); + if (result != 0) + break; + } -int -ftw (const char *dir, - int (*func) (const char *file, const struct stat *status, int flag), - int descriptors) -{ - DIR **dirs; - size_t len; - char buf[PATH_MAX + 1]; - struct stat s; - int flag, retval; - int i; - - if (descriptors <= 0) - descriptors = 1; - - dirs = (DIR **) __alloca (descriptors * sizeof (DIR *)); - i = descriptors; - while (i-- > 0) - dirs[i] = NULL; - - if (stat (dir, &s) < 0) + if (dir.stream != NULL) { - if (errno != EACCES && errno != ENOENT) - return -1; - flag = FTW_NS; + /* The stream is still open. I.e., we did not need more + descriptors. Simply close the stream now. */ + int save_err = errno; + + assert (dir.content == NULL); + + closedir (dir.stream); + __set_errno (save_err); + + if (data->actdir-- == 0) + data->actdir = data->maxdir - 1; + data->dirstreams[data->actdir] = NULL; } - else if (S_ISDIR (s.st_mode)) + else { - dirs[0] = opendir (dir); - if (dirs[0] != NULL) - flag = FTW_D; - else + int save_err; + char *runp = dir.content; + + assert (result == 0); + + while (*runp != '\0') { - if (errno != EACCES) - return -1; - flag = FTW_DNR; + char *endp = strchr (runp, '\0'); + + result = process_entry (data, &dir, runp, endp - runp); + if (result != 0) + break; + + runp = endp + 1; } + + save_err = errno; + free (dir.content); + __set_errno (save_err); } - else - flag = FTW_F; - len = strlen (dir); - memcpy ((void *) buf, (void *) dir, len + 1); + /* Prepare the return, revert the `struct FTW' information. */ + --data->ftw.level; + data->ftw.base = previous_base; + + /* Finally, if we process depth-first report the directory. */ + if (result == 0 && (data->flags & FTW_DEPTH)) + result = (*data->func) (data->dirbuf, &data->st, FTW_DP, &data->ftw); - retval = (*func) (buf, &s, flag); + return result; +} + + +static int +ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, + int flags) +{ + struct ftw_data data; + int result = 0; + int save_err; + char *cwd; + char *cp; + + /* First make sure the parameters are reasonable. */ + if (dir[0] == '\0') + { + __set_errno (ENOTDIR); + return -1; + } - if (flag == FTW_D) + data.maxdir = descriptors < 1 ? 1 : descriptors; + data.actdir = 0; + data.dirstreams = (struct dir_data **) alloca (data.maxdir + * sizeof (struct dir_data *)); + memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *)); + + data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX); + data.dirbuf = (char *) malloc (data.dirbufsize); + if (data.dirbuf == NULL) + return -1; + cp = stpcpy (data.dirbuf, dir); + /* Strip trailing slashes. */ + while (cp > data.dirbuf + 1 && cp[-1] == '/') + --cp; + *cp = '\0'; + + data.ftw.level = 0; + + /* Find basename. */ + while (cp > data.dirbuf && cp[-1] != '/') + --cp; + data.ftw.base = cp - data.dirbuf; + + data.flags = flags; + + /* This assignment might seem to be strange but it is what we want. + The trick is that the first three arguments to the `ftw' and + `nftw' callback functions are equal. Therefore we can call in + every case the callback using the format of the `nftw' version + and get the correct result since the stack layout for a function + call in C allows this. */ + data.func = (__nftw_func_t) func; + + /* Since we internally use the complete set of FTW_* values we need + to reduce the value range before calling a `ftw' callback. */ + data.cvt_arr = is_nftw ? nftw_arr : ftw_arr; + + /* Now go to the directory containing the initial file/directory. */ + if ((flags & FTW_CHDIR) && data.ftw.base > 0) { - if (retval == 0) - retval = ftw_dir (dirs, 0, descriptors, buf, len, func); - if (dirs[0] != NULL) + /* GNU extension ahead. */ + cwd = getcwd (NULL, 0); + if (cwd == NULL) + result = -1; + else { - int save; - - save = errno; - closedir (dirs[0]); - __set_errno (save); + /* Change to the directory the file is in. In data.dirbuf + we have a writable copy of the file name. Just NUL + terminate it for now and change the directory. */ + if (data.ftw.base == 1) + /* I.e., the file is in the root directory. */ + result = chdir ("/"); + else + { + char ch = data.dirbuf[data.ftw.base - 1]; + data.dirbuf[data.ftw.base - 1] = '\0'; + result = chdir (data.dirbuf); + data.dirbuf[data.ftw.base - 1] = ch; + } } } - return retval; + /* Get stat info for start directory. */ + if (result == 0) + if (((flags & FTW_PHYS) ? lstat : stat) (data.dirbuf, &data.st) < 0) + { + if (errno == EACCES) + result = (*data.func) (data.dirbuf, &data.st, FTW_NS, &data.ftw); + else if (!(flags & FTW_PHYS) + && errno == ENOENT + && lstat (dir, &data.st) == 0 && S_ISLNK (data.st.st_mode)) + result = (*data.func) (data.dirbuf, &data.st, data.cvt_arr[FTW_SLN], + &data.ftw); + else + /* No need to call the callback since we cannot say anything + about the object. */ + result = -1; + } + else + { + if (S_ISDIR (data.st.st_mode)) + { + data.dev = data.st.st_dev; + result = ftw_dir (&data); + } + else + { + int flag = S_ISLNK (data.st.st_mode) ? FTW_SL : FTW_F; + + result = (*data.func) (data.dirbuf, &data.st, data.cvt_arr[flag], + &data.ftw); + } + } + + /* Return to the start directory (if necessary). */ + if (cwd != NULL) + { + int save_err = errno; + chdir (cwd); + free (cwd); + __set_errno (save_err); + } + + /* Free all memory. */ + save_err = errno; + free (data.dirbuf); + __set_errno (save_err); + + return result; +} + + + +/* Entry points. */ + +int +ftw (path, func, descriptors) + const char *path; + __ftw_func_t func; + int descriptors; +{ + return ftw_startup (path, 0, func, descriptors, 0); +} + +int +nftw (path, func, descriptors, flags) + const char *path; + __nftw_func_t func; + int descriptors; + int flags; +{ + return ftw_startup (path, 1, func, descriptors, flags); } diff --git a/io/ftw.h b/io/ftw.h index e6d0b63626..70fb9e22fd 100644 --- a/io/ftw.h +++ b/io/ftw.h @@ -1,6 +1,5 @@ /* Copyright (C) 1992, 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Ian Lance Taylor (ian@airs.com). The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -26,22 +25,82 @@ #define _FTW_H 1 #include +#include #include -/* The FLAG argument to the user function passed to ftw. */ -#define FTW_F 0 /* Regular file. */ -#define FTW_D 1 /* Directory. */ -#define FTW_DNR 2 /* Unreadable directory. */ -#define FTW_NS 3 /* Unstatable file. */ __BEGIN_DECLS +/* Values for the FLAG argument to the user function passed to `ftw' + and 'nftw'. */ +enum +{ + FTW_F, /* Regular file. */ +#define FTW_F FTW_F + FTW_D, /* Directory. */ +#define FTW_D FTW_D + FTW_DNR, /* Unreadable directory. */ +#define FTW_DNR FTW_DNR + FTW_NS, /* Unstatable file. */ +#define FTW_NS FTW_NS + +#ifdef __USE_XOPEN_EXTENDED + + FTW_SL, /* Symbolic link. */ +# define FTW_SL FTW_SL + +/* These flags are only passed from the `nftw' function. */ + FTW_DP, /* Directory, all subdirs have been visited. */ +# define FTW_DP FTW_DP + FTW_SLN /* Symbolic link naming non-existing file. */ +# define FTW_SLN FTW_SLN + +#endif /* extended X/Open */ +}; + + +#ifdef __USE_XOPEN_EXTENDED +/* Flags for fourth argument of `nftw'. */ +enum +{ + FTW_PHYS = 1, /* Perform physical walk, ignore symlinks. */ +# define FTW_PHYS FTW_PHYS + FTW_MOUNT = 2, /* Report only files on same file system as the + argument. */ +# define FTW_MOUNT FTW_MOUNT + FTW_CHDIR = 4, /* Change to current directory while processing it. */ +# define FTW_CHDIR FTW_CHDIR + FTW_DEPTH = 8 /* Report files in directory before directory itself.*/ +# define FTW_DEPTH FTW_DEPTH +}; + +/* Structure used for fourth argument to callback function for `nftw'. */ +struct FTW + { + int base; + int level; + }; +#endif /* extended X/Open */ + + +/* Convenient types for callback functions. */ +typedef int (*__ftw_func_t) __P ((__const char *filename, + __const struct stat *status, int flag)); +#ifdef __USE_XOPEN_EXTENDED +typedef int (*__nftw_func_t) __P ((__const char *filename, + __const struct stat *status, int flag, + struct FTW *)); +#endif + /* Call a function on every element in a directory tree. */ -extern int ftw __P ((__const char *__dir, - int (*__func) (__const char *__file, - __const struct stat *__status, - int __flag), - int __descriptors)); +extern int ftw __P ((__const char *dir, __ftw_func_t func, int descriptors)); + +#ifdef __USE_XOPEN_EXTENDED +/* Call a function on every element in a directory tree. FLAG allows + to specify the behaviour more detailed. */ +extern int nftw __P ((__const char *dir, __nftw_func_t func, + int descriptors, int flag)); +#endif __END_DECLS -- cgit v1.2.3