Update applet define from BB_CP_MV to BB_CP and BB_MV.
[oweals/busybox.git] / libbb / recursive_action.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) tons of folks.  Tracking down who wrote what
6  * isn't something I'm going to worry about...  If you wrote something
7  * here, please feel free to acknowledge your work.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
24  * Permission has been granted to redistribute this code under the GPL.
25  *
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <stdlib.h>     /* free() */
33 #include "libbb.h"
34
35
36 /* same conditions as recursive_action */
37 #define bb_need_name_too_long
38 #define BB_DECLARE_EXTERN
39 #include "../messages.c"
40
41 #undef DEBUG_RECURS_ACTION
42
43
44 /*
45  * Walk down all the directories under the specified 
46  * location, and do something (something specified
47  * by the fileAction and dirAction function pointers).
48  *
49  * Unfortunately, while nftw(3) could replace this and reduce 
50  * code size a bit, nftw() wasn't supported before GNU libc 2.1, 
51  * and so isn't sufficiently portable to take over since glibc2.1
52  * is so stinking huge.
53  */
54 int recursive_action(const char *fileName,
55                                         int recurse, int followLinks, int depthFirst,
56                                         int (*fileAction) (const char *fileName,
57                                                                            struct stat * statbuf,
58                                                                            void* userData),
59                                         int (*dirAction) (const char *fileName,
60                                                                           struct stat * statbuf,
61                                                                           void* userData),
62                                         void* userData)
63 {
64         int status;
65         struct stat statbuf;
66         struct dirent *next;
67
68         if (followLinks == TRUE)
69                 status = stat(fileName, &statbuf);
70         else
71                 status = lstat(fileName, &statbuf);
72
73         if (status < 0) {
74 #ifdef DEBUG_RECURS_ACTION
75                 fprintf(stderr,
76                                 "status=%d followLinks=%d TRUE=%d\n",
77                                 status, followLinks, TRUE);
78 #endif
79                 perror_msg("%s", fileName);
80                 return FALSE;
81         }
82
83         if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
84                 if (fileAction == NULL)
85                         return TRUE;
86                 else
87                         return fileAction(fileName, &statbuf, userData);
88         }
89
90         if (recurse == FALSE) {
91                 if (S_ISDIR(statbuf.st_mode)) {
92                         if (dirAction != NULL)
93                                 return (dirAction(fileName, &statbuf, userData));
94                         else
95                                 return TRUE;
96                 }
97         }
98
99         if (S_ISDIR(statbuf.st_mode)) {
100                 DIR *dir;
101
102                 if (dirAction != NULL && depthFirst == FALSE) {
103                         status = dirAction(fileName, &statbuf, userData);
104                         if (status == FALSE) {
105                                 perror_msg("%s", fileName);
106                                 return FALSE;
107                         } else if (status == SKIP)
108                                 return TRUE;
109                 }
110                 dir = opendir(fileName);
111                 if (!dir) {
112                         perror_msg("%s", fileName);
113                         return FALSE;
114                 }
115                 status = TRUE;
116                 while ((next = readdir(dir)) != NULL) {
117                         char *nextFile;
118
119                         if ((strcmp(next->d_name, "..") == 0)
120                                         || (strcmp(next->d_name, ".") == 0)) {
121                                 continue;
122                         }
123                         nextFile = concat_path_file(fileName, next->d_name);
124                         if (recursive_action(nextFile, TRUE, followLinks, depthFirst,
125                                                 fileAction, dirAction, userData) == FALSE) {
126                                 status = FALSE;
127                         }
128                         free(nextFile);
129                 }
130                 closedir(dir);
131                 if (dirAction != NULL && depthFirst == TRUE) {
132                         if (dirAction(fileName, &statbuf, userData) == FALSE) {
133                                 perror_msg("%s", fileName);
134                                 return FALSE;
135                         }
136                 }
137                 if (status == FALSE)
138                         return FALSE;
139         } else {
140                 if (fileAction == NULL)
141                         return TRUE;
142                 else
143                         return fileAction(fileName, &statbuf, userData);
144         }
145         return TRUE;
146 }
147
148
149 /* END CODE */
150 /*
151 Local Variables:
152 c-file-style: "linux"
153 c-basic-offset: 4
154 tab-width: 4
155 End:
156 */