tar: fix "xopen with O_CREAT" warning, improve zero padding write
[platform/upstream/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 int recursive_action(const char *fileName,
26                 int recurse, int followLinks, int depthFirst,
27                 int (*fileAction) (const char *fileName, struct stat * statbuf, void* userData),
28                 int (*dirAction) (const char *fileName, struct stat * statbuf, void* userData),
29                 void* userData)
30 {
31         int status;
32         struct stat statbuf;
33         struct dirent *next;
34
35         if (followLinks)
36                 status = stat(fileName, &statbuf);
37         else
38                 status = lstat(fileName, &statbuf);
39
40         if (status < 0) {
41 #ifdef DEBUG_RECURS_ACTION
42                 bb_error_msg("status=%d followLinks=%d TRUE=%d",
43                                 status, followLinks, TRUE);
44 #endif
45                 bb_perror_msg("%s", fileName);
46                 return FALSE;
47         }
48
49         if (! followLinks && (S_ISLNK(statbuf.st_mode))) {
50                 if (fileAction == NULL)
51                         return TRUE;
52                 else
53                         return fileAction(fileName, &statbuf, userData);
54         }
55
56         if (! recurse) {
57                 if (S_ISDIR(statbuf.st_mode)) {
58                         if (dirAction != NULL)
59                                 return (dirAction(fileName, &statbuf, userData));
60                         else
61                                 return TRUE;
62                 }
63         }
64
65         if (S_ISDIR(statbuf.st_mode)) {
66                 DIR *dir;
67
68                 if (dirAction != NULL && ! depthFirst) {
69                         status = dirAction(fileName, &statbuf, userData);
70                         if (! status) {
71                                 bb_perror_msg("%s", fileName);
72                                 return FALSE;
73                         } else if (status == SKIP)
74                                 return TRUE;
75                 }
76                 dir = opendir(fileName);
77                 if (!dir) {
78                         return FALSE;
79                 }
80                 status = TRUE;
81                 while ((next = readdir(dir)) != NULL) {
82                         char *nextFile;
83
84                         nextFile = concat_subpath_file(fileName, next->d_name);
85                         if(nextFile == NULL)
86                                 continue;
87                         if (! recursive_action(nextFile, TRUE, followLinks, depthFirst,
88                                                 fileAction, dirAction, userData)) {
89                                 status = FALSE;
90                         }
91                         free(nextFile);
92                 }
93                 closedir(dir);
94                 if (dirAction != NULL && depthFirst) {
95                         if (! dirAction(fileName, &statbuf, userData)) {
96                                 bb_perror_msg("%s", fileName);
97                                 return FALSE;
98                         }
99                 }
100                 if (! status)
101                         return FALSE;
102         } else {
103                 if (fileAction == NULL)
104                         return TRUE;
105                 else
106                         return fileAction(fileName, &statbuf, userData);
107         }
108         return TRUE;
109 }