22 |
* is so stinking huge. |
* is so stinking huge. |
23 |
*/ |
*/ |
24 |
|
|
25 |
static int true_action(const char *fileName, struct stat *statbuf, void* userData, int depth) |
static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, |
26 |
|
struct stat *statbuf UNUSED_PARAM, |
27 |
|
void* userData UNUSED_PARAM, |
28 |
|
int depth UNUSED_PARAM) |
29 |
{ |
{ |
30 |
return TRUE; |
return TRUE; |
31 |
} |
} |
34 |
* recursive_action() return 0, but it doesn't stop directory traversal |
* recursive_action() return 0, but it doesn't stop directory traversal |
35 |
* (fileAction/dirAction will be called on each file). |
* (fileAction/dirAction will be called on each file). |
36 |
* |
* |
37 |
* if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP) |
* If !ACTION_RECURSE, dirAction is called on the directory and its |
38 |
* prevents recursion into that directory, instead |
* return value is returned from recursive_action(). No recursion. |
39 |
* recursive_action() returns 0 (if FALSE) or 1 (if SKIP). |
* |
40 |
|
* If ACTION_RECURSE, recursive_action() is called on each directory. |
41 |
|
* If any one of these calls returns 0, current recursive_action() returns 0. |
42 |
|
* |
43 |
|
* If ACTION_DEPTHFIRST, dirAction is called after recurse. |
44 |
|
* If it returns 0, the warning is printed and recursive_action() returns 0. |
45 |
|
* |
46 |
|
* If !ACTION_DEPTHFIRST, dirAction is called before we recurse. |
47 |
|
* Return value of 0 (FALSE) or 2 (SKIP) prevents recursion |
48 |
|
* into that directory, instead recursive_action() returns 0 (if FALSE) |
49 |
|
* or 1 (if SKIP) |
50 |
* |
* |
51 |
* followLinks=0/1 differs mainly in handling of links to dirs. |
* followLinks=0/1 differs mainly in handling of links to dirs. |
52 |
* 0: lstat(statbuf). Calls fileAction on link name even if points to dir. |
* 0: lstat(statbuf). Calls fileAction on link name even if points to dir. |
53 |
* 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. |
* 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. |
54 |
*/ |
*/ |
55 |
|
|
56 |
int recursive_action(const char *fileName, |
int FAST_FUNC recursive_action(const char *fileName, |
57 |
int recurse, int followLinks, int depthFirst, |
unsigned flags, |
58 |
int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), |
int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), |
59 |
int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), |
int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), |
60 |
void* userData, |
void* userData, |
61 |
int depth) |
unsigned depth) |
62 |
{ |
{ |
63 |
struct stat statbuf; |
struct stat statbuf; |
64 |
int status; |
int status; |
68 |
if (!fileAction) fileAction = true_action; |
if (!fileAction) fileAction = true_action; |
69 |
if (!dirAction) dirAction = true_action; |
if (!dirAction) dirAction = true_action; |
70 |
|
|
71 |
status = (followLinks ? stat : lstat)(fileName, &statbuf); |
status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ |
72 |
|
if (!depth) |
73 |
|
status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; |
74 |
|
status = ((flags & status) ? stat : lstat)(fileName, &statbuf); |
75 |
if (status < 0) { |
if (status < 0) { |
76 |
#ifdef DEBUG_RECURS_ACTION |
#ifdef DEBUG_RECURS_ACTION |
77 |
bb_error_msg("status=%d followLinks=%d TRUE=%d", |
bb_error_msg("status=%d flags=%x", status, flags); |
|
status, followLinks, TRUE); |
|
78 |
#endif |
#endif |
79 |
bb_perror_msg("%s", fileName); |
goto done_nak_warn; |
|
return FALSE; |
|
80 |
} |
} |
81 |
|
|
82 |
/* If S_ISLNK(m), then we know that !S_ISDIR(m). |
/* If S_ISLNK(m), then we know that !S_ISDIR(m). |
83 |
* Then we can skip checking first part: if it is true, then |
* Then we can skip checking first part: if it is true, then |
84 |
* (!dir) is also true! */ |
* (!dir) is also true! */ |
85 |
if ( /* (!followLinks && S_ISLNK(statbuf.st_mode)) || */ |
if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ |
86 |
!S_ISDIR(statbuf.st_mode) |
!S_ISDIR(statbuf.st_mode) |
87 |
) { |
) { |
88 |
return fileAction(fileName, &statbuf, userData, depth); |
return fileAction(fileName, &statbuf, userData, depth); |
90 |
|
|
91 |
/* It's a directory (or a link to one, and followLinks is set) */ |
/* It's a directory (or a link to one, and followLinks is set) */ |
92 |
|
|
93 |
if (!recurse) { |
if (!(flags & ACTION_RECURSE)) { |
94 |
return dirAction(fileName, &statbuf, userData, depth); |
return dirAction(fileName, &statbuf, userData, depth); |
95 |
} |
} |
96 |
|
|
97 |
if (!depthFirst) { |
if (!(flags & ACTION_DEPTHFIRST)) { |
98 |
status = dirAction(fileName, &statbuf, userData, depth); |
status = dirAction(fileName, &statbuf, userData, depth); |
99 |
if (!status) { |
if (!status) |
100 |
bb_perror_msg("%s", fileName); |
goto done_nak_warn; |
|
return FALSE; |
|
|
} |
|
101 |
if (status == SKIP) |
if (status == SKIP) |
102 |
return TRUE; |
return TRUE; |
103 |
} |
} |
107 |
/* findutils-4.1.20 reports this */ |
/* findutils-4.1.20 reports this */ |
108 |
/* (i.e. it doesn't silently return with exit code 1) */ |
/* (i.e. it doesn't silently return with exit code 1) */ |
109 |
/* To trigger: "find -exec rm -rf {} \;" */ |
/* To trigger: "find -exec rm -rf {} \;" */ |
110 |
bb_perror_msg("%s", fileName); |
goto done_nak_warn; |
|
return FALSE; |
|
111 |
} |
} |
112 |
status = TRUE; |
status = TRUE; |
113 |
while ((next = readdir(dir)) != NULL) { |
while ((next = readdir(dir)) != NULL) { |
116 |
nextFile = concat_subpath_file(fileName, next->d_name); |
nextFile = concat_subpath_file(fileName, next->d_name); |
117 |
if (nextFile == NULL) |
if (nextFile == NULL) |
118 |
continue; |
continue; |
119 |
if (!recursive_action(nextFile, TRUE, followLinks, depthFirst, |
/* process every file (NB: ACTION_RECURSE is set in flags) */ |
120 |
fileAction, dirAction, userData, depth+1)) { |
if (!recursive_action(nextFile, flags, fileAction, dirAction, |
121 |
|
userData, depth + 1)) |
122 |
status = FALSE; |
status = FALSE; |
123 |
} |
// s = recursive_action(nextFile, flags, fileAction, dirAction, |
124 |
|
// userData, depth + 1); |
125 |
free(nextFile); |
free(nextFile); |
126 |
|
//#define RECURSE_RESULT_ABORT 3 |
127 |
|
// if (s == RECURSE_RESULT_ABORT) { |
128 |
|
// closedir(dir); |
129 |
|
// return s; |
130 |
|
// } |
131 |
|
// if (s == FALSE) |
132 |
|
// status = FALSE; |
133 |
} |
} |
134 |
closedir(dir); |
closedir(dir); |
135 |
if (depthFirst) { |
|
136 |
if (!dirAction(fileName, &statbuf, userData, depth)) { |
if (flags & ACTION_DEPTHFIRST) { |
137 |
bb_perror_msg("%s", fileName); |
if (!dirAction(fileName, &statbuf, userData, depth)) |
138 |
return FALSE; |
goto done_nak_warn; |
|
} |
|
139 |
} |
} |
140 |
|
|
141 |
if (!status) |
return status; |
142 |
return FALSE; |
|
143 |
return TRUE; |
done_nak_warn: |
144 |
|
if (!(flags & ACTION_QUIET)) |
145 |
|
bb_simple_perror_msg(fileName); |
146 |
|
return FALSE; |
147 |
} |
} |