* [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64}
@ 2003-11-07 17:23 Jakub Jelinek
2003-11-07 19:02 ` Ulrich Drepper
2003-11-07 22:59 ` Ulrich Drepper
0 siblings, 2 replies; 3+ messages in thread
From: Jakub Jelinek @ 2003-11-07 17:23 UTC (permalink / raw)
To: Ulrich Drepper, Roland McGrath; +Cc: Glibc hackers
Hi!
The following patch adds a new flag to nftw*, so that the callback
can have a bigger control over the tree walk.
In prelink, I certainly cannot use fts*, since it is not supported
for _FILE_OFFSET_BITS=64, but standard nftw* doesn't allow e.g.
to skip whole subtrees where I know no interesting files will be present.
This speedes up prelink -avmqR on a fully prelinked system with cold
caches (after cat 3GB > /dev/null) from 37s to 22s.
The patch also adds symbol versioning, because old nftw* was clearly
ignoring any unknown flags which were passed to it (and also
so that programs which are compiled against glibc with FTW_ACTIONRETVAL
can be sure they will not be run against glibc which doesn't support it
yet). nftw@GLIBC_2.3.3 will return -1/EINVAL if any unknown flags
are used. POSIX doesn't explicitely list EINVAL, do I have to silently
ignore it instead?
2003-11-07 Jakub Jelinek <jakub@redhat.com>
* io/ftw.c (NFTW_OLD_NAME, NFTW_NEW_NAME): Define.
(ftw_dir, ftw_startup): Add __attribute ((noinline)).
(NFTW_OLD_NAME, NFTW_NEW_NAME): New functions.
(NFTW_NAME): Only define if !_LIBC, add versioned_symbol
and compat_symbol.
* io/ftw64.c (NFTW_OLD_NAME, NFTW_NEW_NAME): Define.
* io/Versions (libc): Export nftw@@GLIBC_2.3.3
and nftw64@@GLIBC_2.3.3.
* io/ftw.h (FTW_ACTIONRETVAL): New flag.
(FTW_CONTINUE, FTW_STOP, FTW_SKIP_SUBTREE, FTW_SKIP_SIBLINGS):
New.
* io/ftw.c (ftw_dir): Add old_dir argument.
Clear result if it was FTW_SKIP_SIBLINGS after processing all
dir entries. Change cwd back if old_dir != NULL.
(process_entry): Adjust caller. Don't change cwd back here.
Change FTW_SKIP_SUBTREE result to 0.
(ftw_startup): Adjust ftw_dir caller.
Clear result if it was FTW_SKIP_SUBTREE or FTW_SKIP_SIBLINGS.
* io/ftwtest.c (skip_subtree, skip_siblings): New variables.
(options, main): Add --skip-subtree and --skip-siblings options.
(cb): Use return FTW_CONTINUE instead of return 0.
Handle --skip-subtree and --skip-siblings.
* io/ftwtest-sh: Add tests for FTW_ACTIONRETVAL.
* manual/filesys.texi: Document FTW_ACTIONRETVAL.
--- libc/io/ftw.h.jj 2003-04-19 18:48:37.000000000 +0200
+++ libc/io/ftw.h 2003-11-07 09:50:09.000000000 +0100
@@ -74,7 +74,33 @@ enum
# define FTW_CHDIR FTW_CHDIR
FTW_DEPTH = 8 /* Report files in directory before directory itself.*/
# define FTW_DEPTH FTW_DEPTH
+# ifdef __USE_GNU
+ ,
+ FTW_ACTIONRETVAL = 16 /* Assume callback to return FTW_* values instead of
+ zero to continue and non-zero to terminate. */
+# define FTW_ACTIONRETVAL FTW_ACTIONRETVAL
+# endif
+};
+
+#ifdef __USE_GNU
+/* Return values from callback functions. */
+enum
+{
+ FTW_CONTINUE = 0, /* Continue with next sibling or for FTW_D with the
+ first child. */
+# define FTW_CONTINUE FTW_CONTINUE
+ FTW_STOP = 1, /* Return from `ftw' or `nftw' with FTW_STOP as return
+ value. */
+# define FTW_STOP FTW_STOP
+ FTW_SKIP_SUBTREE = 2, /* Only meaningful for FTW_D: Don't walk through the
+ subtree, instead just continue with its next
+ sibling. */
+# define FTW_SKIP_SUBTREE FTW_SKIP_SUBTREE
+ FTW_SKIP_SIBLINGS = 3,/* Continue with FTW_DP callback for current directory
+ (if FTW_DEPTH) and then its siblings. */
+# define FTW_SKIP_SIBLINGS FTW_SKIP_SIBLINGS
};
+#endif
/* Structure used for fourth argument to callback function for `nftw'. */
struct FTW
--- libc/io/ftw.c.jj 2003-11-06 14:31:27.000000000 +0100
+++ libc/io/ftw.c 2003-11-07 17:55:40.000000000 +0100
@@ -135,6 +135,8 @@ int rpl_lstat (const char *, struct stat
#ifndef FTW_NAME
# define FTW_NAME ftw
# define NFTW_NAME nftw
+# define NFTW_OLD_NAME __old_nftw
+# define NFTW_NEW_NAME __new_nftw
# define INO_T ino_t
# define STAT stat
# ifdef _LIBC
@@ -217,7 +219,8 @@ static const int ftw_arr[] =
/* Forward declarations of local functions. */
-static int ftw_dir (struct ftw_data *data, struct STAT *st) internal_function;
+static int ftw_dir (struct ftw_data *data, struct STAT *st,
+ struct dir_data *old_dir) internal_function;
static int
@@ -415,43 +418,24 @@ process_entry (struct ftw_data *data, st
|| (!find_object (data, &st)
/* Remember the object. */
&& (result = add_object (data, &st)) == 0))
- {
- result = ftw_dir (data, &st);
-
- if (result == 0 && (data->flags & FTW_CHDIR))
- {
- /* Change back to the parent 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
- if (__chdir ("..") < 0)
- result = -1;
- }
- }
- }
+ result = ftw_dir (data, &st, dir);
}
else
result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
&data->ftw);
}
+ if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
+ result = 0;
+
return result;
}
static int
+__attribute ((noinline))
internal_function
-ftw_dir (struct ftw_data *data, struct STAT *st)
+ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
{
struct dir_data dir;
struct dirent64 *d;
@@ -550,6 +534,9 @@ fail:
__set_errno (save_err);
}
+ if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
+ result = 0;
+
/* Prepare the return, revert the `struct FTW' information. */
data->dirbuf[data->ftw.base - 1] = '\0';
--data->ftw.level;
@@ -559,11 +546,37 @@ fail:
if (result == 0 && (data->flags & FTW_DEPTH))
result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
+ if (old_dir
+ && (data->flags & FTW_CHDIR)
+ && (result == 0
+ || ((data->flags & FTW_ACTIONRETVAL)
+ && (result != -1 && result != FTW_STOP))))
+ {
+ /* Change back to the parent directory. */
+ int done = 0;
+ if (old_dir->stream != NULL)
+ if (__fchdir (dirfd (old_dir->stream)) == 0)
+ done = 1;
+
+ if (!done)
+ {
+ if (data->ftw.base == 1)
+ {
+ if (__chdir ("/") < 0)
+ result = -1;
+ }
+ else
+ if (__chdir ("..") < 0)
+ result = -1;
+ }
+ }
+
return result;
}
static int
+__attribute ((noinline))
internal_function
ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
int flags)
@@ -683,7 +696,7 @@ ftw_startup (const char *dir, int is_nft
result = add_object (&data, &st);
if (result == 0)
- result = ftw_dir (&data, &st);
+ result = ftw_dir (&data, &st, NULL);
}
else
{
@@ -693,6 +706,10 @@ ftw_startup (const char *dir, int is_nft
&data.ftw);
}
}
+
+ if ((flags & FTW_ACTIONRETVAL)
+ && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
+ result = 0;
}
/* Return to the start directory (if necessary). */
@@ -726,6 +743,7 @@ FTW_NAME (path, func, descriptors)
return ftw_startup (path, 0, func, descriptors, 0);
}
+#ifndef _LIBC
int
NFTW_NAME (path, func, descriptors, flags)
const char *path;
@@ -735,3 +753,43 @@ NFTW_NAME (path, func, descriptors, flag
{
return ftw_startup (path, 1, func, descriptors, flags);
}
+#else
+
+#include <shlib-compat.h>
+
+int
+NFTW_NEW_NAME (path, func, descriptors, flags)
+ const char *path;
+ NFTW_FUNC_T func;
+ int descriptors;
+ int flags;
+{
+ if (flags
+ & ~(FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH | FTW_ACTIONRETVAL))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ return ftw_startup (path, 1, func, descriptors, flags);
+}
+
+versioned_symbol (libc, NFTW_NEW_NAME, NFTW_NAME, GLIBC_2_3_3);
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)
+
+/* Older nftw* version just ignored all unknown flags. */
+
+int
+NFTW_OLD_NAME (path, func, descriptors, flags)
+ const char *path;
+ NFTW_FUNC_T func;
+ int descriptors;
+ int flags;
+{
+ flags &= (FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH);
+ return ftw_startup (path, 1, func, descriptors, flags);
+}
+
+compat_symbol (libc, NFTW_OLD_NAME, NFTW_NAME, GLIBC_2_1);
+#endif
+#endif
--- libc/io/ftwtest.c.jj 2003-02-08 19:28:54.000000000 +0100
+++ libc/io/ftwtest.c 2003-11-07 15:30:35.000000000 +0100
@@ -12,12 +12,16 @@ int do_depth;
int do_chdir;
int do_phys;
int do_exit;
+char *skip_subtree;
+char *skip_siblings;
struct option options[] =
{
{ "depth", no_argument, &do_depth, 1 },
{ "chdir", no_argument, &do_chdir, 1 },
{ "phys", no_argument, &do_phys, 1 },
+ { "skip-subtree", required_argument, NULL, 't' },
+ { "skip-siblings", required_argument, NULL, 's' },
{ "early-exit", no_argument, &do_exit, 1 },
{ NULL, 0, NULL, 0 }
};
@@ -38,7 +42,7 @@ static int
cb (const char *name, const struct stat *st, int flag, struct FTW *f)
{
if (do_exit && strcmp (name + f->base, "file@2"))
- return 0;
+ return FTW_CONTINUE;
printf ("base = \"%.*s\", file = \"%s\", flag = %s",
f->base, name, name + f->base, flag2name[flag]);
@@ -49,7 +53,14 @@ cb (const char *name, const struct stat
free (cwd);
}
printf (", level = %d\n", f->level);
- return do_exit ? 26 : 0;
+
+ if (skip_siblings && strcmp (name + f->base, skip_siblings) == 0)
+ return FTW_SKIP_SIBLINGS;
+
+ if (skip_subtree && strcmp (name + f->base, skip_subtree) == 0)
+ return FTW_SKIP_SUBTREE;
+
+ return do_exit ? 26 : FTW_CONTINUE;
}
int
@@ -61,7 +72,12 @@ main (int argc, char *argv[])
mtrace ();
while ((opt = getopt_long_only (argc, argv, "", options, NULL)) != -1)
- ;
+ {
+ if (opt == 't')
+ skip_subtree = optarg;
+ else if (opt == 's')
+ skip_siblings = optarg;
+ }
if (do_chdir)
flag |= FTW_CHDIR;
@@ -69,6 +85,15 @@ main (int argc, char *argv[])
flag |= FTW_DEPTH;
if (do_phys)
flag |= FTW_PHYS;
+ if (skip_subtree || skip_siblings)
+ {
+ flag |= FTW_ACTIONRETVAL;
+ if (do_exit)
+ {
+ printf ("--early-exit cannot be used together with --skip-{siblings,subtree}");
+ exit (1);
+ }
+ }
char *cw1 = getcwd (NULL, 0);
--- libc/io/ftwtest-sh.jj 2003-01-13 00:42:32.000000000 +0100
+++ libc/io/ftwtest-sh 2003-11-07 16:25:37.000000000 +0100
@@ -202,6 +202,83 @@ succeeded
EOF
rm $testout
+mkdir $tmpdir/foo/lvl1b
+echo > $tmpdir/foo/lvl1b/file@1b
+echo > $tmpdir/foo/lvl1b/file2@1b
+echo > $tmpdir/foo/lvl1b/file3@1b
+
+LD_LIBRARY_PATH=$objpfx $ldso $testprogram --skip-subtree=lvl1 $tmpdir |
+ sort > $testout
+
+cat <<EOF | diff -u $testout - || exit 1
+base = "/tmp/", file = "ftwtest.d", flag = FTW_D, level = 0
+base = "/tmp/ftwtest.d/", file = "bar", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/", file = "baz", flag = FTW_F, level = 1
+base = "/tmp/ftwtest.d/", file = "foo", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/bar/", file = "xo", flag = FTW_F, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1b", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file2@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file3@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file@1b", flag = FTW_F, level = 3
+EOF
+rm $testout
+
+LD_LIBRARY_PATH=$objpfx $ldso $testprogram --skip-siblings=lvl1 $tmpdir |
+ sort > $testout
+
+# The filesystem is not required to put lvl1 before lvl1b.
+# If lvl1b comes after lvl1, it shouldn't be printed, while if it
+# comes before, it should.
+catcmd=cat
+[ -n "`ls -U $tmpdir/foo/ | sed -n '/lvl1$/,${/lvl1b$/p}'`" ] \
+ && catcmd="grep -v lvl1b"
+
+$catcmd <<EOF | diff -u $testout - || exit 1
+base = "/tmp/", file = "ftwtest.d", flag = FTW_D, level = 0
+base = "/tmp/ftwtest.d/", file = "bar", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/", file = "baz", flag = FTW_F, level = 1
+base = "/tmp/ftwtest.d/", file = "foo", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/bar/", file = "xo", flag = FTW_F, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1b", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file2@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file3@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file@1b", flag = FTW_F, level = 3
+EOF
+rm $testout
+
+LD_LIBRARY_PATH=$objpfx $ldso $testprogram --skip-siblings=file@1b $tmpdir |
+ sort > $testout
+
+# The filesystem is not required to put file2@1b and file3@1b after file@1b.
+# If file[23]@1b come after file@1b, it shouldn't be printed, while if they
+# come before, they should.
+regexp=`echo $(ls -U /tmp/ftwtest.d/foo/lvl1b \
+ | sed -n '/file@1b$/,${/file[23]@1b$/p}') | sed 's, ,|,'`
+catcmd=cat
+[ -n "$regexp" ] && catcmd="egrep -v $regexp"
+
+$catcmd <<EOF | diff -u $testout - || exit 1
+base = "/tmp/", file = "ftwtest.d", flag = FTW_D, level = 0
+base = "/tmp/ftwtest.d/", file = "bar", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/", file = "baz", flag = FTW_F, level = 1
+base = "/tmp/ftwtest.d/", file = "foo", flag = FTW_D, level = 1
+base = "/tmp/ftwtest.d/bar/", file = "xo", flag = FTW_F, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/", file = "lvl1b", flag = FTW_D, level = 2
+base = "/tmp/ftwtest.d/foo/lvl1/", file = "file@1", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1/", file = "link@1", flag = FTW_SLN, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1/", file = "lvl2", flag = FTW_D, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1/lvl2/", file = "file@2", flag = FTW_F, level = 4
+base = "/tmp/ftwtest.d/foo/lvl1/lvl2/", file = "lvl3", flag = FTW_D, level = 4
+base = "/tmp/ftwtest.d/foo/lvl1/lvl2/lvl3/", file = "file@3", flag = FTW_F, level = 5
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file2@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file3@1b", flag = FTW_F, level = 3
+base = "/tmp/ftwtest.d/foo/lvl1b/", file = "file@1b", flag = FTW_F, level = 3
+EOF
+rm $testout
+
rm -fr $tmpdir
exit 0
--- libc/io/Versions.jj 2003-08-26 23:07:39.000000000 +0200
+++ libc/io/Versions 2003-11-07 17:30:24.000000000 +0100
@@ -93,6 +93,10 @@ libc {
# l*
lchmod;
}
+ GLIBC_2.3.3 {
+ # n*
+ nftw; nftw64;
+ }
GLIBC_PRIVATE {
# functions which have an additional interface since they are
# cancelable.
--- libc/io/ftw64.c.jj 2001-07-06 06:54:53.000000000 +0200
+++ libc/io/ftw64.c 2003-11-07 17:32:29.000000000 +0100
@@ -20,6 +20,8 @@
#define FTW_NAME ftw64
#define NFTW_NAME nftw64
+#define NFTW_OLD_NAME __old_nftw64
+#define NFTW_NEW_NAME __new_nftw64
#define INO_T ino64_t
#define STAT stat64
#define LXSTAT __lxstat64
--- libc/manual/filesys.texi.jj 2003-09-03 13:10:37.000000000 +0200
+++ libc/manual/filesys.texi 2003-11-07 16:37:59.000000000 +0100
@@ -918,6 +918,17 @@ If this option is specified then all sub
them are processed before processing the top directory itself
(depth-first processing). This also means the type flag given to the
callback function is @code{FTW_DP} and not @code{FTW_D}.
+@item FTW_ACTIONRETVAL
+If this option is specified then return values from callbacks
+are handled differently. If the callback returns @code{FTW_CONTINUE},
+walking continues normally. @code{FTW_STOP} means walking stops
+and @code{FTW_STOP} is returned to the caller. If @code{FTW_SKIP_SUBTREE}
+is returned by the callback with @code{FTW_D} argument, the subtree
+is skipped and walking continues with next sibling of the directory.
+If @code{FTW_SKIP_SIBLINGS} is returned by the callback, all siblings
+of the current entry are skipped and walking continues in its parent.
+No other return values should be returned from the callbacks if
+this option is set. This option is a GNU extension.
@end vtable
The return value is computed in the same way as for @code{ftw}.
Jakub
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64}
2003-11-07 17:23 [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64} Jakub Jelinek
@ 2003-11-07 19:02 ` Ulrich Drepper
2003-11-07 22:59 ` Ulrich Drepper
1 sibling, 0 replies; 3+ messages in thread
From: Ulrich Drepper @ 2003-11-07 19:02 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: Roland McGrath, Glibc hackers
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Jakub Jelinek wrote:
> POSIX doesn't explicitely list EINVAL, do I have to silently
> ignore it instead?
It is perfectly alright to add new error values. Especially since a
non-standard feature (the new falg) has to be used to trigger it.
- --
- --------------. ,-. 444 Castro Street
Ulrich Drepper \ ,-----------------' \ Mountain View, CA 94041 USA
Red Hat `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)
iD8DBQE/q+wV2ijCOnn/RHQRAtoWAKC6YX20Ralupx/Ov7ORWoso/3XjOgCfQahL
+cg5Afwed4tmqgdoCJCQQK4=
=G2Wx
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64}
2003-11-07 17:23 [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64} Jakub Jelinek
2003-11-07 19:02 ` Ulrich Drepper
@ 2003-11-07 22:59 ` Ulrich Drepper
1 sibling, 0 replies; 3+ messages in thread
From: Ulrich Drepper @ 2003-11-07 22:59 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: Roland McGrath, Glibc hackers
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Jakub Jelinek wrote:
> The following patch adds a new flag to nftw*, so that the callback
> can have a bigger control over the tree walk.
Applied, thanks.
- --
- --------------. ,-. 444 Castro Street
Ulrich Drepper \ ,-----------------' \ Mountain View, CA 94041 USA
Red Hat `--' drepper at redhat.com `---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)
iD8DBQE/rCOr2ijCOnn/RHQRAvVBAJ9GvAHrmxpoNfAoOBp/Y25fRE8NCACgocqL
MuuhoVbo55bx9zCzKRMMv2Q=
=djm7
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2003-11-07 22:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-07 17:23 [PATCH] Add FTW_ACTIONRETVAL flag to nftw{,64} Jakub Jelinek
2003-11-07 19:02 ` Ulrich Drepper
2003-11-07 22:59 ` Ulrich Drepper
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).