1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
/*
* Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
*
* TODO: should this be replaced by using nftw(3)?
*/
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "walk_tree.h"
int walk_recurse = 0;
int walk_postorder = 0;
int walk_symlinks = WALK_HALF_LOGICAL;
int walk_tree(const char *path_p, int (*call)(const char *, struct stat *,
void *), void *arg)
{
static struct stat st;
static int level = 0;
int follow;
int errors = 0;
level++;
if (lstat(path_p, &st) != 0)
goto fail;
if (S_ISLNK(st.st_mode)) {
if (walk_symlinks == WALK_PHYSICAL)
follow = 0;
else {
if (stat(path_p, &st) != 0)
goto fail;
follow = ((walk_symlinks == WALK_HALF_LOGICAL &&
level == 1) ||
walk_symlinks == WALK_FULL_LOGICAL);
}
} else
follow = 1;
if (!follow)
goto cleanup;
if (!walk_postorder)
errors += call(path_p, &st, arg);
if (walk_recurse && S_ISDIR(st.st_mode)) {
struct dirent *dirent;
DIR *dir;
char *ipath_p = (char *)path_p;
int ipath_length = strlen(ipath_p);
if (ipath_p[ipath_length-1] != '/') {
ipath_p = (char*)alloca(ipath_length +
_POSIX_PATH_MAX + 2);
if (ipath_p == NULL)
goto fail;
strcpy(ipath_p, path_p);
strcpy(ipath_p + ipath_length, "/");
ipath_length++;
}
dir = opendir(path_p);
if (dir == NULL)
goto fail;
while ((dirent = readdir(dir)) != NULL) {
if (!strcmp(dirent->d_name, ".") ||
!strcmp(dirent->d_name, ".."))
continue;
strncpy(ipath_p + ipath_length,
dirent->d_name, _POSIX_PATH_MAX);
ipath_p[ipath_length + _POSIX_PATH_MAX] = '\0';
walk_tree(ipath_p, call, arg); /* recurse */
}
ipath_p[ipath_length] = '\0';
closedir(dir);
}
if (walk_postorder)
errors += call(path_p, &st, arg);
cleanup:
level--;
return errors;
fail:
fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno));
errors++;
goto cleanup;
}
|