Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
2 | /* |
||
3 | * Recursively descent the directory hierarchy rooted in DIR, |
||
4 | * calling FUNC for each object in the hierarchy. We cannot |
||
5 | * use ftw(), because it uses some non-ANSI functions which |
||
6 | * will pollute ANSI namespace, while we need this function |
||
7 | * in some ANSI functions (e.g., rename()). Thus, this function |
||
8 | * is closely modeled on ftw(), but uses DOS directory search |
||
9 | * functions and structures instead of opendir()/readdir()/stat(). |
||
10 | * |
||
11 | * Copyright (c) 1995 Eli Zaretskii |
||
12 | * |
||
13 | * This software may be used freely as long as this copyright notice is |
||
14 | * left intact. There is no warranty on this software. |
||
15 | * |
||
16 | */ |
||
17 | |||
18 | #include |
||
19 | #include |
||
20 | #include |
||
21 | #include |
||
22 | #include |
||
23 | #include |
||
24 | |||
25 | #define FA_ALL (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_LABEL|FA_DIREC|FA_ARCH) |
||
26 | |||
27 | int |
||
28 | __file_tree_walk(const char *dir, |
||
29 | int (*func)(const char *, const struct ffblk *)) |
||
30 | { |
||
31 | struct ffblk ff; |
||
32 | unsigned char searchspec[FILENAME_MAX]; |
||
33 | unsigned char found[FILENAME_MAX], *dir_end; |
||
34 | int e = errno; |
||
35 | |||
36 | if (dir == 0 || func == 0) |
||
37 | { |
||
38 | errno = EFAULT; |
||
39 | return -1; |
||
40 | } |
||
41 | |||
42 | if (*dir == '\0') |
||
43 | { |
||
44 | errno = ENOENT; |
||
45 | return -1; |
||
46 | } |
||
47 | |||
48 | /* Construct the search spec for findfirst(). Treat ``d:'' as ``d:.''. */ |
||
49 | strcpy(searchspec, dir); |
||
50 | dir_end = searchspec + strlen(searchspec) - 1; |
||
51 | if (*dir_end == ':') |
||
52 | { |
||
53 | *++dir_end = '.'; |
||
54 | *++dir_end = '\0'; |
||
55 | } |
||
56 | else if (*dir_end == '/' || *dir_end == '\\') |
||
57 | *dir_end = '\0'; |
||
58 | else |
||
59 | ++dir_end; |
||
60 | strcpy(dir_end, "/*.*"); |
||
61 | |||
62 | /* Prepare the buffer where the full pathname of the found files |
||
63 | will be placed. */ |
||
64 | strcpy(found, dir); |
||
65 | dir_end = found + strlen(found) - 1; |
||
66 | if (*dir_end == ':') |
||
67 | { |
||
68 | *++dir_end = '.'; |
||
69 | dir_end[1] = '\0'; |
||
70 | } |
||
71 | if (*dir_end != '/' && *dir_end != '\\') |
||
72 | { |
||
73 | /* Try to preserve user's forward/backward slash style. */ |
||
74 | *++dir_end = strchr(found, '\\') == 0 ? '/': '\\'; |
||
75 | *++dir_end = '\0'; |
||
76 | } |
||
77 | else |
||
78 | ++dir_end; |
||
79 | |||
80 | if (findfirst(searchspec, &ff, FA_ALL)) |
||
81 | return -1; |
||
82 | |||
83 | do |
||
84 | { |
||
85 | int func_result; |
||
86 | unsigned char *p = dir_end; |
||
87 | |||
88 | /* Skip `.' and `..' entries. */ |
||
89 | if (ff.ff_name[0] == '.' && |
||
90 | (ff.ff_name[1] == '\0' || ff.ff_name[1] == '.')) |
||
91 | continue; |
||
92 | |||
93 | /* Construct full pathname in FOUND[]. */ |
||
94 | strcpy(dir_end, ff.ff_name); |
||
95 | |||
96 | /* Convert name of found file to lower-case. Cannot use |
||
97 | strlwr() because it's non-ANSI. Sigh... */ |
||
98 | while (*p) |
||
99 | *p++ = tolower(*p); |
||
100 | |||
101 | /* Invoke FUNC() on this file. */ |
||
102 | if ((func_result = (*func)(found, &ff)) != 0) |
||
103 | return func_result; |
||
104 | |||
105 | /* If this is a directory, walk its siblings. */ |
||
106 | if (ff.ff_attrib & 0x10) |
||
107 | { |
||
108 | int subwalk_result; |
||
109 | |||
110 | if ((subwalk_result = __file_tree_walk(found, func)) != 0) |
||
111 | return subwalk_result; |
||
112 | } |
||
113 | } while (findnext(&ff) == 0); |
||
114 | |||
115 | if (errno == ENMFILE) /* normal case: tree exhausted */ |
||
116 | { |
||
117 | errno = e; /* restore errno from previous syscall */ |
||
118 | return 0; |
||
119 | } |
||
120 | |||
121 | return -1; /* error; errno set by findnext() */ |
||
122 | } |
||
123 | |||
124 | #ifdef TEST |
||
125 | |||
126 | #include |
||
127 | |||
128 | int |
||
129 | ff_walker(const char *path, const struct ffblk *ff) |
||
130 | { |
||
131 | printf("%s:\t%lu\t", path, ff->ff_fsize); |
||
132 | if (ff->ff_attrib & 1) |
||
133 | printf("R"); |
||
134 | if (ff->ff_attrib & 2) |
||
135 | printf("H"); |
||
136 | if (ff->ff_attrib & 4) |
||
137 | printf("S"); |
||
138 | if (ff->ff_attrib & 8) |
||
139 | printf("V"); |
||
140 | if (ff->ff_attrib & 0x10) |
||
141 | printf("D"); |
||
142 | if (ff->ff_attrib & 0x20) |
||
143 | printf("A"); |
||
144 | printf("\n"); |
||
145 | |||
146 | if (strcmp(ff->ff_name, "XXXXX") == 0) |
||
147 | return 8; |
||
148 | return 0; |
||
149 | } |
||
150 | |||
151 | int |
||
152 | main(int argc, char *argv[]) |
||
153 | { |
||
154 | if (argc > 1) |
||
155 | { |
||
156 | char msg[80]; |
||
157 | |||
158 | sprintf(msg, "file_tree_walk: %d", |
||
159 | file_tree_walk(argv[1], ff_walker)); |
||
160 | if (errno) |
||
161 | perror(msg); |
||
162 | else |
||
163 | puts(msg); |
||
164 | } |
||
165 | else |
||
166 | printf("Usage: %s dir\n", argv[0]); |
||
167 | |||
168 | return 0; |
||
169 | } |
||
170 | |||
171 | #endif |