1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1997, 1999, 2002-2006, 2008, 2011, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <common/ac/errno.h>
20 #include <common/ac/sys/types.h>
21 #include <common/ac/sys/stat.h>
22
23 #include <common/str_list.h>
24 #include <common/trace.h>
25 #include <libaegis/glue.h>
26 #include <libaegis/os.h>
27 #include <libaegis/sub.h>
28
29 #include <aefind/cmdline.h>
30 #include <aefind/descend.h>
31 #include <aefind/tree.h>
32
33
34 string_ty *
stat_stack(string_ty * path,struct stat * st)35 stat_stack(string_ty *path, struct stat *st)
36 {
37 size_t j;
38 string_ty *dir;
39 string_ty *resolved_path;
40 sub_context_ty *scp;
41
42 for (j = 0; ; ++j)
43 {
44 dir = stack_nth(j);
45 if (!dir)
46 break;
47 resolved_path = os_path_cat(dir, path);
48
49 #ifdef S_IFLNK
50 if (!glue_lstat(resolved_path->str_text, st))
51 return resolved_path;
52
53 if (errno != ENOENT)
54 {
55 int errno_old;
56
57 errno_old = errno;
58 scp = sub_context_new();
59 sub_errno_setx(scp, errno_old);
60 sub_var_set_string(scp, "File_Name", resolved_path);
61 fatal_intl(scp, i18n("lstat $filename: $errno"));
62 // NOTREACHED
63 }
64 #else
65 if (!glue_stat(resolved_path->str_text, st))
66 return resolved_path;
67
68 if (errno != ENOENT)
69 {
70 int errno_old;
71
72 errno_old = errno;
73 scp = sub_context_new();
74 sub_errno_setx(scp, errno_old);
75 sub_var_set_string(scp, "File_Name", resolved_path);
76 fatal_intl(scp, i18n("stat $filename: $errno"));
77 // NOTREACHED
78 }
79 #endif
80 str_free(resolved_path);
81 }
82 scp = sub_context_new();
83 sub_errno_setx(scp, ENOENT);
84 sub_var_set_string(scp, "File_Name", path);
85 fatal_intl(scp, i18n("stat $filename: $errno"));
86 // NOTREACHED
87 return 0;
88 }
89
90
91 static void
readdir_stack(string_ty * path,string_list_ty * result)92 readdir_stack(string_ty *path, string_list_ty *result)
93 {
94 size_t j;
95 string_ty *s;
96 string_ty *dir;
97
98 result->clear();
99 for (j = 0; ; ++j)
100 {
101 dir = stack_nth(j);
102 if (!dir)
103 break;
104 s = os_path_cat(dir, path);
105 if (read_whole_dir__wla(s->str_text, result))
106 {
107 sub_context_ty *scp;
108 int errno_old;
109
110 errno_old = errno;
111 if (errno_old == ENOENT)
112 {
113 str_free(s);
114 continue;
115 }
116 scp = sub_context_new();
117 sub_errno_setx(scp, errno_old);
118 sub_var_set_string(scp, "File_Name", path);
119 fatal_intl(scp, i18n("read $filename: $errno"));
120 // NOTREACHED
121 }
122 str_free(s);
123 }
124 }
125
126
127 void
descend(string_ty * path,int resolve,descend_callback_ty callback,void * arg)128 descend(string_ty *path, int resolve, descend_callback_ty callback, void *arg)
129 {
130 struct stat st;
131 size_t j;
132 string_ty *s;
133 string_ty *resolved_path;
134
135 trace(("descend(path = %08lX, callback = %08lX, arg = %08lX)\n{\n",
136 (long)path, (long)callback, (long)arg));
137 trace_string(path->str_text);
138 resolved_path = stat_stack(path, &st);
139 if ((st.st_mode & S_IFMT) == S_IFDIR)
140 {
141 trace(("mark\n"));
142 callback
143 (
144 arg,
145 descend_message_dir_before,
146 path,
147 (resolve ? resolved_path : path),
148 resolved_path,
149 &st
150 );
151 trace(("mark\n"));
152 string_list_ty wl;
153 readdir_stack(path, &wl);
154 for (j = 0; j < wl.nstrings; ++j)
155 {
156 s = os_path_cat(path, wl.string[j]);
157 if (!stack_eliminate(s))
158 descend(s, resolve, callback, arg);
159 str_free(s);
160 }
161 trace(("mark\n"));
162 callback
163 (
164 arg,
165 descend_message_dir_after,
166 path,
167 (resolve ? resolved_path : path),
168 resolved_path,
169 &st
170 );
171 }
172 else
173 {
174 trace(("mark\n"));
175 callback
176 (
177 arg,
178 descend_message_file,
179 path,
180 (resolve ? resolved_path : path),
181 resolved_path,
182 &st
183 );
184 }
185 str_free(resolved_path);
186 trace(("}\n"));
187 }
188
189
190 // vim: set ts=8 sw=4 et :
191