This commit is contained in:
parent
4e0dbb700e
commit
d35fbdb5da
@ -1,3 +1,9 @@
|
||||
-------------------------------------------------------------------
|
||||
Sat Oct 27 18:16:49 CEST 2007 - agruen@suse.de
|
||||
|
||||
- Don't exhaust the number of file descriptors in the path walking
|
||||
code, and make sure each directory is only visited once.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Oct 26 02:10:44 CEST 2007 - agruen@suse.de
|
||||
|
||||
|
@ -15,7 +15,7 @@ Group: System/Filesystems
|
||||
AutoReqProv: on
|
||||
Summary: Commands for Manipulating Extended Attributes
|
||||
Version: 2.4.39
|
||||
Release: 1
|
||||
Release: 3
|
||||
Source: %{name}-%{version}.src.tar.bz2
|
||||
Source1: xattr.conf
|
||||
Patch0: builddefs.in.diff
|
||||
@ -165,6 +165,9 @@ rm -rf $RPM_BUILD_ROOT
|
||||
/%{_lib}/libattr.so.1*
|
||||
%config %{_sysconfdir}/xattr.conf
|
||||
%changelog
|
||||
* Sat Oct 27 2007 - agruen@suse.de
|
||||
- Don't exhaust the number of file descriptors in the path walking
|
||||
code, and make sure each directory is only visited once.
|
||||
* Fri Oct 26 2007 - agruen@suse.de
|
||||
- A large jump to the current upstream version 2.4.39.
|
||||
- Fix the upstream path walking code.
|
||||
|
209
walk-attr.diff
209
walk-attr.diff
@ -78,7 +78,7 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
}
|
||||
|
||||
const char *strerror_ea(int err)
|
||||
@@ -347,22 +346,14 @@ int list_attributes(const char *path, in
|
||||
@@ -347,21 +346,19 @@ int list_attributes(const char *path, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -95,18 +95,21 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
- * 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 (walk_flags & WALK_TREE_FAILED) {
|
||||
+ fprintf(stderr, "%s: %s: %s\n", progname, xquote(path), strerror(errno));
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
- if (S_ISLNK(stat->st_mode) &&
|
||||
- (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical)))
|
||||
+ if ((walk_flags & WALK_TREE_SYMLINK) &&
|
||||
+ (walk_flags & WALK_TREE_DEREFERENCE) &&
|
||||
+ ((walk_flags & WALK_TREE_PHYSICAL) ||
|
||||
+ !(walk_flags & (WALK_TREE_TOPLEVEL | WALK_TREE_LOGICAL))))
|
||||
return 0;
|
||||
|
||||
if (opt_name)
|
||||
print_attribute(path, opt_name, &header_printed);
|
||||
@@ -371,21 +362,6 @@ int do_print(const char *path, const str
|
||||
@@ -371,21 +368,6 @@ int do_print(const char *path, const str
|
||||
|
||||
if (header_printed)
|
||||
puts("");
|
||||
@ -128,7 +131,7 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -410,39 +386,6 @@ void help(void)
|
||||
@@ -410,39 +392,6 @@ void help(void)
|
||||
" --help this help text\n"));
|
||||
}
|
||||
|
||||
@ -168,7 +171,7 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
@@ -478,7 +421,7 @@ int main(int argc, char *argv[])
|
||||
@@ -478,7 +427,7 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
|
||||
case 'h': /* do not dereference symlinks */
|
||||
@ -177,7 +180,7 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
break;
|
||||
|
||||
case 'n': /* get named attribute */
|
||||
@@ -497,17 +440,17 @@ int main(int argc, char *argv[])
|
||||
@@ -497,17 +446,17 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
@ -200,12 +203,13 @@ Index: attr-2.4.39/getfattr/getfattr.c
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
@@ -531,7 +474,7 @@ int main(int argc, char *argv[])
|
||||
@@ -531,7 +480,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while (optind < argc) {
|
||||
- had_errors += walk_tree(argv[optind]);
|
||||
+ had_errors += walk_tree(argv[optind], walk_flags, do_print, NULL);
|
||||
+ had_errors += walk_tree(argv[optind], walk_flags, 0,
|
||||
+ do_print, NULL);
|
||||
optind++;
|
||||
}
|
||||
|
||||
@ -364,7 +368,7 @@ Index: attr-2.4.39/include/walk_tree.h
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ attr-2.4.39/include/walk_tree.h
|
||||
@@ -0,0 +1,18 @@
|
||||
@@ -0,0 +1,19 @@
|
||||
+#ifndef __WALK_TREE_H
|
||||
+#define __WALK_TREE_H
|
||||
+
|
||||
@ -373,21 +377,22 @@ Index: attr-2.4.39/include/walk_tree.h
|
||||
+#define WALK_TREE_LOGICAL 0x4
|
||||
+#define WALK_TREE_DEREFERENCE 0x8
|
||||
+
|
||||
+#define WALK_TREE_SYMLINK 0x10
|
||||
+#define WALK_TREE_FAILED 0x20
|
||||
+#define WALK_TREE_TOPLEVEL 0x100
|
||||
+#define WALK_TREE_SYMLINK 0x200
|
||||
+#define WALK_TREE_FAILED 0x400
|
||||
+
|
||||
+struct stat;
|
||||
+
|
||||
+extern int walk_tree(const char *path, int walk_flags,
|
||||
+ int (*func)(const char *, const struct stat *, int, void *),
|
||||
+ void *arg);
|
||||
+extern int walk_tree(const char *path, int walk_flags, unsigned int num,
|
||||
+ int (*func)(const char *, const struct stat *, int,
|
||||
+ void *), void *arg);
|
||||
+
|
||||
+#endif
|
||||
Index: attr-2.4.39/libmisc/walk_tree.c
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ attr-2.4.39/libmisc/walk_tree.c
|
||||
@@ -0,0 +1,100 @@
|
||||
@@ -0,0 +1,188 @@
|
||||
+/*
|
||||
+ File: walk_tree.c
|
||||
+
|
||||
@ -411,6 +416,8 @@ Index: attr-2.4.39/libmisc/walk_tree.c
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/stat.h>
|
||||
+#include <unistd.h>
|
||||
+#include <sys/time.h>
|
||||
+#include <sys/resource.h>
|
||||
+#include <dirent.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
@ -418,75 +425,161 @@ Index: attr-2.4.39/libmisc/walk_tree.c
|
||||
+
|
||||
+#include "walk_tree.h"
|
||||
+
|
||||
+struct entry_handle {
|
||||
+ struct entry_handle *prev, *next;
|
||||
+ struct stat st;
|
||||
+ DIR *stream;
|
||||
+ off_t pos;
|
||||
+};
|
||||
+
|
||||
+struct entry_handle head = {
|
||||
+ .next = &head,
|
||||
+ .prev = &head,
|
||||
+ /* The other fields are unused. */
|
||||
+};
|
||||
+struct entry_handle *closed = &head;
|
||||
+unsigned int num_dir_handles;
|
||||
+
|
||||
+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 (*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;
|
||||
+ int flags = walk_flags, err;
|
||||
+ struct entry_handle dir;
|
||||
+
|
||||
+ /* 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.)
|
||||
+ /*
|
||||
+ * If (walk_flags & WALK_TREE_PHYSICAL), do not traverse symlinks.
|
||||
+ * If (walk_flags & WALK_TREE_LOGICAL), traverse all symlinks.
|
||||
+ * Otherwise, traverse only top-level symlinks.
|
||||
+ */
|
||||
+ if (depth == 0)
|
||||
+ flags |= WALK_TREE_TOPLEVEL;
|
||||
+
|
||||
+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)
|
||||
+ if (xstat(path, &dir.st) != 0)
|
||||
+ return func(path, NULL, flags | WALK_TREE_FAILED, arg);
|
||||
+ if (S_ISLNK(dir.st.st_mode)) {
|
||||
+ flags |= WALK_TREE_SYMLINK;
|
||||
+ if (flags & WALK_TREE_DEREFERENCE) {
|
||||
+ xstat = stat;
|
||||
+ 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;
|
||||
+ err = func(path, &dir.st, flags, arg);
|
||||
+ if ((flags & WALK_TREE_RECURSIVE) &&
|
||||
+ (S_ISDIR(dir.st.st_mode) || (S_ISLNK(dir.st.st_mode))) &&
|
||||
+ (!(flags & WALK_TREE_PHYSICAL) || !(flags & WALK_TREE_SYMLINK)) &&
|
||||
+ (flags & (WALK_TREE_LOGICAL | WALK_TREE_TOPLEVEL))) {
|
||||
+ struct entry_handle *i;
|
||||
+ 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.
|
||||
+ /* Check if we have already visited this directory. */
|
||||
+ for (i = head.next; i != &head; i = i->next)
|
||||
+ if (i->st.st_dev == dir.st.st_dev &&
|
||||
+ i->st.st_ino == dir.st.st_ino)
|
||||
+ return err;
|
||||
+
|
||||
+ if (num_dir_handles == 0 && closed->prev != &head) {
|
||||
+close_another_dir:
|
||||
+ /* Close the topmost directory handle still open. */
|
||||
+ closed = closed->prev;
|
||||
+ closed->pos = telldir(closed->stream);
|
||||
+ closedir(closed->stream);
|
||||
+ closed->stream = NULL;
|
||||
+ num_dir_handles++;
|
||||
+ }
|
||||
+
|
||||
+ dir.stream = opendir(path);
|
||||
+ if (!dir.stream) {
|
||||
+ if (errno == ENFILE && closed->prev != &head) {
|
||||
+ /* Ran out of file descriptors. */
|
||||
+ num_dir_handles = 0;
|
||||
+ goto close_another_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);
|
||||
+ err += func(path, &dir.st,
|
||||
+ flags | WALK_TREE_FAILED, arg);
|
||||
+ return err;
|
||||
+ }
|
||||
+ while ((entry = readdir(dir)) != NULL) {
|
||||
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
+
|
||||
+ /* Insert into the list of handles. */
|
||||
+ dir.next = head.next;
|
||||
+ dir.prev = &head;
|
||||
+ dir.prev->next = &dir;
|
||||
+ dir.next->prev = &dir;
|
||||
+ num_dir_handles--;
|
||||
+
|
||||
+ while ((entry = readdir(dir.stream)) != NULL) {
|
||||
+ char *path_end;
|
||||
+
|
||||
+ 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) {
|
||||
+ path_end = strchr(path, 0);
|
||||
+ if ((path_end - path) + strlen(entry->d_name) + 1 >=
|
||||
+ FILENAME_MAX) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ err += func(path, NULL,
|
||||
+ local_walk_flags | WALK_TREE_FAILED, arg);
|
||||
+ flags | WALK_TREE_FAILED, arg);
|
||||
+ continue;
|
||||
+ }
|
||||
+ err += walk_tree_rec(path2, walk_flags, func, arg, depth + 1);
|
||||
+ *path_end++ = '/';
|
||||
+ strcpy(path_end, entry->d_name);
|
||||
+ err += walk_tree_rec(path, walk_flags, func, arg,
|
||||
+ depth + 1);
|
||||
+ *--path_end = 0;
|
||||
+ if (!dir.stream) {
|
||||
+ /* Reopen the directory handle. */
|
||||
+ dir.stream = opendir(path);
|
||||
+ if (!dir.stream)
|
||||
+ return err + func(path, &dir.st, flags |
|
||||
+ WALK_TREE_FAILED, arg);
|
||||
+ seekdir(dir.stream, dir.pos);
|
||||
+
|
||||
+ closed = closed->next;
|
||||
+ num_dir_handles--;
|
||||
+ }
|
||||
+ }
|
||||
+ if (closedir(dir) != 0)
|
||||
+ err += func(path, &st, local_walk_flags | WALK_TREE_FAILED, arg);
|
||||
+
|
||||
+ if (closedir(dir.stream) != 0)
|
||||
+ err += func(path, &dir.st, flags | WALK_TREE_FAILED,
|
||||
+ arg);
|
||||
+
|
||||
+ /* Remove from the list of handles. */
|
||||
+ dir.prev->next = dir.next;
|
||||
+ dir.next->prev = dir.prev;
|
||||
+ num_dir_handles++;
|
||||
+ }
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+int walk_tree(const char *path, int walk_flags,
|
||||
+ int (*func)(const char *, const struct stat *, int, void *), void *arg)
|
||||
+int walk_tree(const char *path, int walk_flags, unsigned int num,
|
||||
+ int (*func)(const char *, const struct stat *, int, void *),
|
||||
+ void *arg)
|
||||
+{
|
||||
+ char path_copy[FILENAME_MAX];
|
||||
+
|
||||
+ num_dir_handles = num;
|
||||
+ if (num_dir_handles < 1) {
|
||||
+ struct rlimit rlimit;
|
||||
+
|
||||
+ num_dir_handles = 1;
|
||||
+ if (getrlimit(RLIMIT_NOFILE, &rlimit) == 0 &&
|
||||
+ rlimit.rlim_cur >= 2)
|
||||
+ num_dir_handles = rlimit.rlim_cur / 2;
|
||||
+ }
|
||||
+ 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);
|
||||
+ strcpy(path_copy, path);
|
||||
+ return walk_tree_rec(path_copy, walk_flags, func, arg, 0);
|
||||
+}
|
||||
Index: attr-2.4.39/test/getfattr.test
|
||||
===================================================================
|
||||
|
Loading…
Reference in New Issue
Block a user