diff options
Diffstat (limited to 'descend.c')
-rw-r--r-- | descend.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/descend.c b/descend.c new file mode 100644 index 000000000..9ada7b4fc --- /dev/null +++ b/descend.c | |||
@@ -0,0 +1,124 @@ | |||
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 | } | ||