recursive_action: preparatory changes. will introduce "int level".
[oweals/busybox.git] / libbb / recursive_action.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9
10 #include "libbb.h"
11
12 #undef DEBUG_RECURS_ACTION
13
14
15 /*
16  * Walk down all the directories under the specified
17  * location, and do something (something specified
18  * by the fileAction and dirAction function pointers).
19  *
20  * Unfortunately, while nftw(3) could replace this and reduce
21  * code size a bit, nftw() wasn't supported before GNU libc 2.1,
22  * and so isn't sufficiently portable to take over since glibc2.1
23  * is so stinking huge.
24  */
25
26 static int true_action(const char *fileName, struct stat *statbuf, void* userData)
27 {
28         return TRUE;
29 }
30
31 int recursive_action(const char *fileName,
32                 int recurse, int followLinks, int depthFirst,
33                 int (*fileAction) (const char *fileName, struct stat * statbuf, void* userData),
34                 int (*dirAction) (const char *fileName, struct stat * statbuf, void* userData),
35                 void* userData)
36 {
37         struct stat statbuf;
38         int status;
39         DIR *dir;
40         struct dirent *next;
41
42         if (!fileAction) fileAction = true_action;
43         if (!dirAction) dirAction = true_action;
44
45         status = (followLinks ? stat : lstat)(fileName, &statbuf);
46
47         if (status < 0) {
48 #ifdef DEBUG_RECURS_ACTION
49                 bb_error_msg("status=%d followLinks=%d TRUE=%d",
50                                 status, followLinks, TRUE);
51 #endif
52                 bb_perror_msg("%s", fileName);
53                 return FALSE;
54         }
55
56         if (!followLinks && (S_ISLNK(statbuf.st_mode))) {
57                 return fileAction(fileName, &statbuf, userData);
58         }
59
60         if (!recurse) {
61                 if (S_ISDIR(statbuf.st_mode)) {
62                         return dirAction(fileName, &statbuf, userData);
63                 }
64         }
65
66         if (!S_ISDIR(statbuf.st_mode))
67                 return fileAction(fileName, &statbuf, userData);
68
69         if (!depthFirst) {
70                 status = dirAction(fileName, &statbuf, userData);
71                 if (!status) {
72                         bb_perror_msg("%s", fileName);
73                         return FALSE;
74                 }
75                 if (status == SKIP)
76                         return TRUE;
77         }
78
79         dir = opendir(fileName);
80         if (!dir) {
81                 return FALSE;
82         }
83         status = TRUE;
84         while ((next = readdir(dir)) != NULL) {
85                 char *nextFile;
86
87                 nextFile = concat_subpath_file(fileName, next->d_name);
88                 if (nextFile == NULL)
89                         continue;
90                 if (!recursive_action(nextFile, TRUE, followLinks, depthFirst,
91                                         fileAction, dirAction, userData)) {
92                         status = FALSE;
93                 }
94                 free(nextFile);
95         }
96         closedir(dir);
97         if (depthFirst) {
98                 if (!dirAction(fileName, &statbuf, userData)) {
99                         bb_perror_msg("%s", fileName);
100                         return FALSE;
101                 }
102         }
103
104         if (!status)
105                 return FALSE;
106         return TRUE;
107 }