latest and greatest.
[oweals/busybox.git] / descend.c
1 #include "internal.h"
2 #include <stdio.h>
3 #include <dirent.h>
4 #include <string.h>
5 #include <errno.h>
6
7
8 static int 
9 noDots(const struct dirent * e)
10 {
11         if ( e->d_name[0] == '.'
12          && (e->d_name[1] == '\0'
13           || (e->d_name[1] == '.' && e->d_name[2] == '\0')) )
14                 return 0;
15         else
16                 return 1;
17 }
18
19 extern int
20 descend(
21  struct FileInfo *oldInfo
22 ,int            (*function)(const struct FileInfo * i))
23 {
24         char                    pathname[1024];
25         struct dirent * *       names;
26         struct dirent * *       n;
27         int                     length;
28         char *                  filename;
29         int                     status = 0;
30         int                     count;
31
32         if ( *oldInfo->source == '\0' ) {
33                 errno = EINVAL;
34                 return -1;
35         }
36
37         if ( oldInfo->stat.st_dev == 0
38          && oldInfo->stat.st_ino == 0
39          && oldInfo->stat.st_mode == 0 ) {
40                 if ( lstat(oldInfo->source, &oldInfo->stat) != 0 )
41                         return -1;
42                 oldInfo->isSymbolicLink = ((oldInfo->stat.st_mode & S_IFMT) == S_IFLNK);
43
44                 if ( oldInfo->isSymbolicLink )
45                         if ( stat(oldInfo->source, &oldInfo->stat) != 0 )
46                                 memset((void *)&oldInfo->stat, 0, sizeof(oldInfo->stat));
47         }
48
49         if ( !oldInfo->processDirectoriesAfterTheirContents ) {
50                 if ( function )
51                         status = (*function)(oldInfo);
52                 if ( status == 0 )
53                         status = post_process(oldInfo);
54         }
55
56         if ( (count = scandir(oldInfo->source, &names, noDots, alphasort)) < 0 )
57                 return -1;
58
59         length = strlen(oldInfo->source);
60         if ( oldInfo->source[length-1] == '/' )
61                 length--;
62
63         memcpy(pathname, oldInfo->source, length+1);
64         pathname[length] = '/';
65         filename = &pathname[length+1];
66         
67         n = names;
68         while ( count-- > 0 ) {
69                 struct FileInfo         i = *oldInfo;
70
71                 strcpy(filename, (*n)->d_name);
72                 free(*n++);
73
74                 if ( lstat(pathname, &i.stat) != 0 && errno != ENOENT ) {
75                         fprintf(stderr, "Can't stat %s: %s\n", pathname, strerror(errno));
76                         return -1;
77                 }
78                 i.isSymbolicLink = ((i.stat.st_mode & S_IFMT) == S_IFLNK);
79
80                 if ( i.isSymbolicLink )
81                         if ( stat(pathname, &i.stat) != 0 )
82                                 memset((void *)&i.stat, 0, sizeof(i.stat));
83
84                 i.source = pathname;
85
86                 if ( i.dyadic ) {
87                         char    d[1024];
88
89                         i.destination = join_paths(d, i.destination, &i.source[i.directoryLength]);
90                 }
91                 else
92                         i.destination = i.source;
93
94                  if ( !i.isSymbolicLink && (i.stat.st_mode & S_IFMT) == S_IFDIR )
95                         status = descend(&i, function);
96                 else {
97                         if ( function )
98                                 status = (*function)(&i);
99                         if ( status == 0 )
100                                 status = post_process(&i);
101                 }
102
103                 if ( !i.processDirectoriesAfterTheirContents
104                  && status == 0
105                  && (i.stat.st_mode & S_IFMT) == S_IFDIR )
106                         descend(&i, function);
107
108                 if ( status != 0 && !i.force ) {
109                         while ( count-- > 0 )
110                                 free(*n++);
111                         break;
112                 }
113         }
114         free(names);
115
116         if ( oldInfo->processDirectoriesAfterTheirContents ) {
117                 if ( function )
118                         status = (*function)(oldInfo);
119                 if ( status == 0 )
120                         status = post_process(oldInfo);
121         }
122
123         return status;
124 }