From bf96705ac465877e175c3e1ac47a0fbe34637801edb135e89fac00d46f9ca8f3 Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Fri, 26 Oct 2007 18:07:50 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/acl?expand=0&rev=2 --- acl-2.2.34.src.tar.bz2 | 3 - acl-2.2.45.src.tar.bz2 | 3 + acl.changes | 6 + acl.spec | 24 +- builddefs.in.diff | 10 +- walk-acl.diff | 602 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 631 insertions(+), 17 deletions(-) delete mode 100644 acl-2.2.34.src.tar.bz2 create mode 100644 acl-2.2.45.src.tar.bz2 create mode 100644 walk-acl.diff diff --git a/acl-2.2.34.src.tar.bz2 b/acl-2.2.34.src.tar.bz2 deleted file mode 100644 index 9b6190b..0000000 --- a/acl-2.2.34.src.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c5a8bfd1ffd1322f701a95cf9cba3c26b45ad2f3e20e4cd53f9a847c5612456d -size 121754 diff --git a/acl-2.2.45.src.tar.bz2 b/acl-2.2.45.src.tar.bz2 new file mode 100644 index 0000000..5a6eda3 --- /dev/null +++ b/acl-2.2.45.src.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a46338bedea261eda948549509f60d1351d8b73440a1fa18e4bfd200702ff26 +size 131042 diff --git a/acl.changes b/acl.changes index 0be49c4..615f1d9 100644 --- a/acl.changes +++ b/acl.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Oct 26 02:34:02 CEST 2007 - agruen@suse.de + +- A large jump to the current upstream version 2.2.45. +- Fix the upstream path walking code. + ------------------------------------------------------------------- Sat Mar 18 10:04:15 CET 2006 - agruen@suse.de diff --git a/acl.spec b/acl.spec index ae089e0..1f32172 100644 --- a/acl.spec +++ b/acl.spec @@ -1,7 +1,7 @@ # -# spec file for package acl (Version 2.2.34) +# spec file for package acl (Version 2.2.45) # -# Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2007 SUSE LINUX Products GmbH, Nuernberg, Germany. # This file and all modifications and additions to the pristine # package are under the same license as the package itself. # @@ -13,14 +13,15 @@ Name: acl BuildRequires: libattr-devel Group: System/Filesystems -Autoreqprov: on +AutoReqProv: on Summary: Commands for Manipulating POSIX Access Control Lists -Version: 2.2.34 -Release: 7 +Version: 2.2.45 +Release: 1 Source: %name-%version.src.tar.bz2 Patch0: builddefs.in.diff -URL: ftp://oss.sgi.com/projects/xfs/cmd_tars -License: GPL, Other License(s), see package +Patch1: walk-acl.diff +Url: ftp://oss.sgi.com/projects/xfs/cmd_tars +License: GPL v2 or later BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -52,7 +53,7 @@ Authors: %package -n libacl-devel Summary: Include Files and Libraries mandatory for Development -Autoreqprov: on +AutoReqProv: on Group: Development/Libraries/C and C++ Requires: libacl = %{version} libattr-devel Provides: acl-devel @@ -71,6 +72,7 @@ Authors: %prep %setup -n acl-%version %patch0 -p1 +%patch1 -p1 %build export OPTIMIZER="$RPM_OPT_FLAGS -fPIC" @@ -176,8 +178,10 @@ rm -f $RPM_BUILD_ROOT/%{_lib}/libacl.{a,la,so} %files -n libacl %defattr(755,root,root,755) /%{_lib}/libacl.so.1* - -%changelog -n acl +%changelog +* Fri Oct 26 2007 - agruen@suse.de +- A large jump to the current upstream version 2.2.45. +- Fix the upstream path walking code. * Sat Mar 18 2006 - agruen@suse.de - Remove broken file /usr/lib[64]/libacl.la. * Fri Mar 17 2006 - agruen@suse.de diff --git a/builddefs.in.diff b/builddefs.in.diff index 85dd9ef..6635284 100644 --- a/builddefs.in.diff +++ b/builddefs.in.diff @@ -1,7 +1,9 @@ ---- acl-2.2.34/include/builddefs.in -+++ acl-2.2.34/include/builddefs.in -@@ -31,7 +31,7 @@ - PKG_DEVLIB_DIR = @libexecdir@ +Index: acl-2.2.45/include/builddefs.in +=================================================================== +--- acl-2.2.45.orig/include/builddefs.in ++++ acl-2.2.45/include/builddefs.in +@@ -33,7 +33,7 @@ PKG_LIB_DIR = @libdir@@libdirsuffix@ + PKG_DEVLIB_DIR = @libexecdir@@libdirsuffix@ PKG_INC_DIR = @includedir@ PKG_MAN_DIR = @mandir@ -PKG_DOC_DIR = @datadir@/doc/@pkg_name@ diff --git a/walk-acl.diff b/walk-acl.diff new file mode 100644 index 0000000..055c07e --- /dev/null +++ b/walk-acl.diff @@ -0,0 +1,602 @@ +Index: acl-2.2.45/doc/CHANGES +=================================================================== +--- acl-2.2.45.orig/doc/CHANGES ++++ acl-2.2.45/doc/CHANGES +@@ -2,6 +2,12 @@ + * Update acl.5 man page to clarify the relationship between + the file permissions and the *OBJ ACL entries thanks + to Andreas Gruenbacher. ++* In some cases, gcc does not link in functions from libmisc.a ++ unless libmisc is specifief before the dynamic libraries on ++ the command line. ++* Rip out nftw tree walking, it is broken and hopeless to fix. ++ The replacement walk_tree() function does exactly what we ++ want, and is much simpler to use. + + 2.2.45 (11 September 2007) + * Fix symlink handling with getfacl and setfacl, thanks to Utako Usaka. +Index: acl-2.2.45/getfacl/Makefile +=================================================================== +--- acl-2.2.45.orig/getfacl/Makefile ++++ acl-2.2.45/getfacl/Makefile +@@ -9,8 +9,8 @@ LTCOMMAND = getfacl + CFILES = getfacl.c user_group.c + HFILES = user_group.h + +-LLDLIBS = $(LIBACL) $(LIBATTR) $(LIBMISC) +-LTDEPENDENCIES = $(LIBACL) $(LIBMISC) ++LLDLIBS = $(LIBMISC) $(LIBACL) $(LIBATTR) ++LTDEPENDENCIES = $(LIBMISC) $(LIBACL) + + default: $(LTCOMMAND) + +Index: acl-2.2.45/getfacl/getfacl.c +=================================================================== +--- acl-2.2.45.orig/getfacl/getfacl.c ++++ acl-2.2.45/getfacl/getfacl.c +@@ -34,10 +34,10 @@ + #include + #include + #include +-#include + #include + #include "config.h" + #include "user_group.h" ++#include "walk_tree.h" + #include "misc.h" + + #define POSIXLY_CORRECT_STR "POSIXLY_CORRECT" +@@ -70,24 +70,22 @@ struct option long_options[] = { + const char *progname; + const char *cmd_line_options; + +-int opt_recursive; /* recurse into sub-directories? */ +-int opt_walk_logical; /* always follow symbolic links */ +-int opt_walk_physical; /* never follow symbolic links */ +-int opt_print_acl = 0; +-int opt_print_default_acl = 0; ++int walk_flags = WALK_TREE_DEREFERENCE; ++int opt_print_acl; ++int opt_print_default_acl; + int opt_strip_leading_slash = 1; + int opt_comments = 1; /* include comments */ +-int opt_skip_base = 0; /* skip files that only have the base entries */ +-int opt_tabular = 0; /* tabular output format (alias `showacl') */ ++int opt_skip_base; /* skip files that only have the base entries */ ++int opt_tabular; /* tabular output format (alias `showacl') */ + #if POSIXLY_CORRECT + const int posixly_correct = 1; /* Posix compatible behavior! */ + #else +-int posixly_correct = 0; /* Posix compatible behavior? */ ++int posixly_correct; /* Posix compatible behavior? */ + #endif +-int had_errors = 0; +-int absolute_warning = 0; /* Absolute path warning was issued */ ++int had_errors; ++int absolute_warning; /* Absolute path warning was issued */ + int print_options = TEXT_SOME_EFFECTIVE; +-int opt_numeric = 0; /* don't convert id's to symbolic names */ ++int opt_numeric; /* don't convert id's to symbolic names */ + + + static const char *xquote(const char *str) +@@ -425,12 +423,18 @@ acl_get_file_mode(const char *path_p) + return acl_from_mode(st.st_mode); + } + +-int do_print(const char *path_p, const struct stat *st) ++int do_print(const char *path_p, const struct stat *st, int walk_flags, void *unused) + { + const char *default_prefix = NULL; + acl_t acl = NULL, default_acl = NULL; + int error = 0; + ++ if (walk_flags & WALK_TREE_FAILED) { ++ fprintf(stderr, "%s: %s: %s\n", progname, xquote(path_p), ++ strerror(errno)); ++ return 1; ++ } ++ + if (opt_print_acl) { + acl = acl_get_file(path_p, ACL_TYPE_ACCESS); + if (acl == NULL && (errno == ENOSYS || errno == ENOTSUP)) +@@ -549,7 +553,7 @@ void help(void) + " --skip-base skip files that only have the base entries\n" + " -R, --recursive recurse into subdirectories\n" + " -L, --logical logical walk, follow symbolic links\n" +-" -P --physical physical walk, do not follow symbolic links\n" ++" -P, --physical physical walk, do not follow symbolic links\n" + " --tabular use tabular output format\n" + " --numeric print numeric user/group identifiers\n" + " --absolute-names don't strip leading '/' in pathnames\n")); +@@ -560,75 +564,6 @@ void help(void) + " --help this help text\n")); + } + +- +-static int __errors; +-int __do_print(const char *file, const struct stat *stat, +- int flag, struct FTW *ftw) +-{ +- int saved_errno = errno; +- +- /* Process the target of a symbolic link, and traverse the link, +- only if doing a logical walk, or if the symbolic link was +- specified on the command line. Always skip symbolic links if +- doing a physical walk. */ +- +- if (S_ISLNK(stat->st_mode) && +- (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical))) +- return 0; +- +- if (do_print(file, stat)) +- __errors++; +- +- if (flag == FTW_DNR && opt_recursive) { +- /* Item is a directory which can't be read. */ +- fprintf(stderr, "%s: %s: %s\n", +- progname, file, strerror(saved_errno)); +- return 0; +- } +- +- /* We also get here in non-recursive mode. In that case, +- return something != 0 to abort nftw. */ +- +- if (!opt_recursive) +- return 1; +- +- return 0; +-} +- +-char *resolve_symlinks(const char *file) +-{ +- static char buffer[4096]; +- struct stat stat; +- char *path = NULL; +- +- if (lstat(file, &stat) == -1) +- return path; +- +- if (S_ISLNK(stat.st_mode) && !opt_walk_physical) +- path = realpath(file, buffer); +- else +- path = (char *)file; /* not a symlink, use given path */ +- +- return path; +-} +- +-int walk_tree(const char *file) +-{ +- const char *p; +- +- __errors = 0; +- if ((p = resolve_symlinks(file)) == NULL) { +- fprintf(stderr, "%s: %s: %s\n", progname, +- xquote(file), strerror(errno)); +- __errors++; +- } else if (nftw(p, __do_print, 0, opt_walk_logical? 0 : FTW_PHYS) < 0) { +- fprintf(stderr, "%s: %s: %s\n", progname, xquote(file), +- strerror(errno)); +- __errors++; +- } +- return __errors; +-} +- + int main(int argc, char *argv[]) + { + int opt; +@@ -691,21 +626,21 @@ int main(int argc, char *argv[]) + case 'R': /* recursive */ + if (posixly_correct) + goto synopsis; +- opt_recursive = 1; ++ walk_flags |= WALK_TREE_RECURSIVE; + break; + + case 'L': /* follow all symlinks */ + if (posixly_correct) + goto synopsis; +- opt_walk_logical = 1; +- opt_walk_physical = 0; ++ walk_flags |= WALK_TREE_LOGICAL; ++ walk_flags &= ~WALK_TREE_PHYSICAL; + break; + + case 'P': /* skip all symlinks */ + if (posixly_correct) + goto synopsis; +- opt_walk_logical = 0; +- opt_walk_physical = 1; ++ walk_flags |= WALK_TREE_PHYSICAL; ++ walk_flags &= ~WALK_TREE_LOGICAL; + break; + + case 's': /* skip files with only base entries */ +@@ -762,7 +697,7 @@ int main(int argc, char *argv[]) + if (*line == '\0') + continue; + +- had_errors += walk_tree(line); ++ had_errors += walk_tree(line, walk_flags, do_print, NULL); + } + if (!feof(stdin)) { + fprintf(stderr, _("%s: Standard input: %s\n"), +@@ -770,7 +705,7 @@ int main(int argc, char *argv[]) + had_errors++; + } + } else +- had_errors += walk_tree(argv[optind]); ++ had_errors += walk_tree(argv[optind], walk_flags, do_print, NULL); + optind++; + } while (optind < argc); + +Index: acl-2.2.45/libmisc/Makefile +=================================================================== +--- acl-2.2.45.orig/libmisc/Makefile ++++ acl-2.2.45/libmisc/Makefile +@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs + LTLIBRARY = libmisc.la + LTLDFLAGS = + +-CFILES = quote.c unquote.c high_water_alloc.c next_line.c ++CFILES = quote.c unquote.c high_water_alloc.c next_line.c walk_tree.c + + default: $(LTLIBRARY) + install install-dev install-lib: +Index: acl-2.2.45/setfacl/Makefile +=================================================================== +--- acl-2.2.45.orig/setfacl/Makefile ++++ acl-2.2.45/setfacl/Makefile +@@ -9,8 +9,8 @@ LTCOMMAND = setfacl + CFILES = setfacl.c do_set.c sequence.c parse.c + HFILES = sequence.h parse.h + +-LLDLIBS = $(LIBACL) $(LIBATTR) $(LIBMISC) +-LTDEPENDENCIES = $(LIBACL) $(LIBMISC) ++LLDLIBS = $(LIBMISC) $(LIBACL) $(LIBATTR) ++LTDEPENDENCIES = $(LIBMISC) $(LIBACL) + + default: $(LTCOMMAND) + +Index: acl-2.2.45/setfacl/do_set.c +=================================================================== +--- acl-2.2.45.orig/setfacl/do_set.c ++++ acl-2.2.45/setfacl/do_set.c +@@ -36,10 +36,10 @@ + #include "sequence.h" + #include "parse.h" + #include "config.h" ++#include "walk_tree.h" + + + extern const char *progname; +-extern int opt_recursive; + extern int opt_recalculate; + extern int opt_test; + extern int print_options; +@@ -259,8 +259,10 @@ int + do_set( + const char *path_p, + const struct stat *st, +- const seq_t seq) ++ int walk_flags, ++ void *arg) + { ++ const seq_t seq = (const seq_t)arg; + acl_t old_acl = NULL, old_default_acl = NULL; + acl_t acl = NULL, default_acl = NULL; + acl_t *xacl, *old_xacl; +@@ -272,6 +274,11 @@ do_set( + int acl_modified = 0, default_acl_modified = 0; + int acl_mask_provided = 0, default_acl_mask_provided = 0; + ++ if (walk_flags & WALK_TREE_FAILED) { ++ fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno)); ++ return 1; ++ } ++ + /* Execute the commands in seq (read ACLs on demand) */ + error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); + if (error == 0) +@@ -426,7 +433,7 @@ do_set( + } + + /* Only directores can have default ACLs */ +- if (default_acl && !S_ISDIR(st->st_mode) && opt_recursive) { ++ if (default_acl && !S_ISDIR(st->st_mode) && (walk_flags & WALK_TREE_RECURSIVE)) { + /* In recursive mode, ignore default ACLs for files */ + acl_free(default_acl); + default_acl = NULL; +Index: acl-2.2.45/setfacl/setfacl.c +=================================================================== +--- acl-2.2.45.orig/setfacl/setfacl.c ++++ acl-2.2.45/setfacl/setfacl.c +@@ -28,20 +28,15 @@ + #include + #include + #include +-#include + #include + #include + #include "config.h" + #include "sequence.h" + #include "parse.h" ++#include "walk_tree.h" + #include "misc.h" + +-extern int +-do_set( +- const char *path_p, +- const struct stat *stat_p, +- const seq_t seq); +- ++extern int do_set(const char *path_p, const struct stat *stat_p, int flags, void *arg); + + #define POSIXLY_CORRECT_STR "POSIXLY_CORRECT" + +@@ -82,9 +77,7 @@ struct option long_options[] = { + const char *progname; + const char *cmd_line_options, *cmd_line_spec; + +-int opt_recursive; /* recurse into sub-directories? */ +-int opt_walk_logical; /* always follow symbolic links */ +-int opt_walk_physical; /* never follow symbolic links */ ++int walk_flags = WALK_TREE_DEREFERENCE; + int opt_recalculate; /* recalculate mask entry (0=default, 1=yes, -1=no) */ + int opt_promote; /* promote access ACL to default ACL */ + int opt_test; /* do not write to the file system. +@@ -188,7 +181,7 @@ restore( + stat.st_uid = uid; + stat.st_gid = gid; + +- error = do_set(path_p, &stat, seq); ++ error = do_set(path_p, &stat, 0, seq); + if (error != 0) { + status = 1; + goto resume; +@@ -275,77 +268,6 @@ void help(void) + } + + +-static int __errors; +-static seq_t __seq; +- +-int __do_set(const char *file, const struct stat *stat, +- int flag, struct FTW *ftw) +-{ +- int saved_errno = errno; +- +- /* Process the target of a symbolic link, and traverse the link, +- only if doing a logical walk, or if the symbolic link was +- specified on the command line. Always skip symbolic links if +- doing a physical walk. */ +- +- if (S_ISLNK(stat->st_mode) && +- (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical))) +- return 0; +- +- if (do_set(file, stat, __seq)) +- __errors++; +- +- if (flag == FTW_DNR && opt_recursive) { +- /* Item is a directory which can't be read. */ +- fprintf(stderr, "%s: %s: %s\n", +- progname, file, strerror(saved_errno)); +- return 0; +- } +- +- /* We also get here in non-recursive mode. In that case, +- return something != 0 to abort nftw. */ +- +- if (!opt_recursive) +- return 1; +- +- return 0; +-} +- +-char *resolve_symlinks(const char *file) +-{ +- static char buffer[4096]; +- struct stat stat; +- char *path = NULL; +- +- if (lstat(file, &stat) == -1) +- return path; +- +- if (S_ISLNK(stat.st_mode) && !opt_walk_physical) +- path = realpath(file, buffer); +- else +- path = (char *)file; /* not a symlink, use given path */ +- +- return path; +-} +- +-int walk_tree(const char *file, seq_t seq) +-{ +- const char *p; +- +- __errors = 0; +- __seq = seq; +- if ((p = resolve_symlinks(file)) == NULL) { +- fprintf(stderr, "%s: %s: %s\n", progname, +- xquote(file), strerror(errno)); +- __errors++; +- } else if (nftw(p, __do_set, 0, opt_walk_logical ? 0 : FTW_PHYS) < 0) { +- fprintf(stderr, "%s: %s: %s\n", progname, +- xquote(file), strerror(errno)); +- __errors++; +- } +- return __errors; +-} +- + int next_file(const char *arg, seq_t seq) + { + char *line; +@@ -353,14 +275,14 @@ int next_file(const char *arg, seq_t seq + + if (strcmp(arg, "-") == 0) { + while ((line = next_line(stdin))) +- errors = walk_tree(line, seq); ++ errors = walk_tree(line, walk_flags, do_set, seq); + if (!feof(stdin)) { + fprintf(stderr, _("%s: Standard input: %s\n"), + progname, strerror(errno)); + errors = 1; + } + } else { +- errors = walk_tree(arg, seq); ++ errors = walk_tree(arg, walk_flags, do_set, seq); + } + return errors ? 1 : 0; + } +@@ -627,17 +549,17 @@ int main(int argc, char *argv[]) + break; + + case 'R': /* recursive */ +- opt_recursive = 1; ++ walk_flags |= WALK_TREE_RECURSIVE; + break; + + case 'L': /* follow symlinks */ +- opt_walk_logical = 1; +- opt_walk_physical = 0; ++ walk_flags |= WALK_TREE_LOGICAL; ++ walk_flags &= ~WALK_TREE_PHYSICAL; + break; + + case 'P': /* do not follow symlinks */ +- opt_walk_logical = 0; +- opt_walk_physical = 1; ++ walk_flags |= WALK_TREE_PHYSICAL; ++ walk_flags &= ~WALK_TREE_LOGICAL; + break; + + case 't': /* test mode */ +Index: acl-2.2.45/include/walk_tree.h +=================================================================== +--- /dev/null ++++ acl-2.2.45/include/walk_tree.h +@@ -0,0 +1,18 @@ ++#ifndef __WALK_TREE_H ++#define __WALK_TREE_H ++ ++#define WALK_TREE_RECURSIVE 0x1 ++#define WALK_TREE_PHYSICAL 0x2 ++#define WALK_TREE_LOGICAL 0x4 ++#define WALK_TREE_DEREFERENCE 0x8 ++ ++#define WALK_TREE_SYMLINK 0x10 ++#define WALK_TREE_FAILED 0x20 ++ ++struct stat; ++ ++extern int walk_tree(const char *path, int walk_flags, ++ int (*func)(const char *, const struct stat *, int, void *), ++ void *arg); ++ ++#endif +Index: acl-2.2.45/libmisc/walk_tree.c +=================================================================== +--- /dev/null ++++ acl-2.2.45/libmisc/walk_tree.c +@@ -0,0 +1,100 @@ ++/* ++ File: walk_tree.c ++ ++ Copyright (C) 2007 Andreas Gruenbacher ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public ++ License as published by the Free Software Foundation; either ++ version 2 of the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with this library; if not, 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 "walk_tree.h" ++ ++static int walk_tree_rec(const char *path, int walk_flags, ++ int (*func)(const char *, const struct stat *, int, void *), ++ void *arg, int depth) ++{ ++ int (*xstat)(const char *, struct stat *) = lstat; ++ struct stat st; ++ int local_walk_flags = walk_flags, err; ++ ++ /* Default to traversing symlinks on the command line, traverse all symlinks ++ * with -L, and do not traverse symlinks with -P. (This is similar to chown.) ++ */ ++ ++follow_symlink: ++ if (xstat(path, &st) != 0) ++ return func(path, NULL, local_walk_flags | WALK_TREE_FAILED, arg); ++ if (S_ISLNK(st.st_mode)) { ++ if ((local_walk_flags & WALK_TREE_PHYSICAL) || ++ (!(local_walk_flags & WALK_TREE_LOGICAL) && depth > 1)) ++ return 0; ++ local_walk_flags |= WALK_TREE_SYMLINK; ++ xstat = stat; ++ if (local_walk_flags & WALK_TREE_DEREFERENCE) ++ goto follow_symlink; ++ } ++ err = func(path, &st, local_walk_flags, arg); ++ if ((local_walk_flags & WALK_TREE_RECURSIVE) && ++ (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))) { ++ char path2[FILENAME_MAX]; ++ DIR *dir; ++ struct dirent *entry; ++ int err2; ++ ++ dir = opendir(path); ++ if (!dir) { ++ /* PATH may be a symlink to a regular file or a dead symlink ++ * which we didn't follow above. ++ */ ++ if (errno != ENOTDIR && errno != ENOENT) ++ err += func(path, &st, ++ local_walk_flags | WALK_TREE_FAILED, arg); ++ return err; ++ } ++ while ((entry = readdir(dir)) != NULL) { ++ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) ++ continue; ++ err2 = snprintf(path2, sizeof(path2), "%s/%s", path, ++ entry->d_name); ++ if (err2 < 0 || err2 > FILENAME_MAX) { ++ errno = ENAMETOOLONG; ++ err += func(path, NULL, ++ local_walk_flags | WALK_TREE_FAILED, arg); ++ continue; ++ } ++ err += walk_tree_rec(path2, walk_flags, func, arg, depth + 1); ++ } ++ if (closedir(dir) != 0) ++ err += func(path, &st, local_walk_flags | WALK_TREE_FAILED, arg); ++ } ++ return err; ++} ++ ++int walk_tree(const char *path, int walk_flags, ++ int (*func)(const char *, const struct stat *, int, void *), void *arg) ++{ ++ if (strlen(path) >= FILENAME_MAX) { ++ errno = ENAMETOOLONG; ++ return func(path, NULL, WALK_TREE_FAILED, arg); ++ } ++ return walk_tree_rec(path, walk_flags, func, arg, 1); ++}