1 /* diffs.c:
2 *
3 ****************************************************************
4 * Copyright (C) 2003 Tom Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11 #include "config-options.h"
12 #include "hackerlab/bugs/panic.h"
13 #include "hackerlab/os/sys/wait.h"
14 #include "hackerlab/os/signal.h"
15 #include "hackerlab/mem/mem.h"
16 #include "hackerlab/char/str.h"
17 #include "hackerlab/arrays/ar.h"
18 #include "hackerlab/vu/safe.h"
19 #include "hackerlab/fs/file-names.h"
20 #include "tla/libarch/exec.h"
21 #include "tla/libarch/inode-sig.h"
22 #include "tla/libarch/diffs.h"
23
24
25
26 int
arch_binary_files_differ(const t_uchar * a,const t_uchar * b,const t_uchar * id,assoc_table inode_sig_shortcuts_of_b)27 arch_binary_files_differ (const t_uchar * a, const t_uchar * b, const t_uchar * id, assoc_table inode_sig_shortcuts_of_b)
28 {
29 struct stat a_stat;
30 struct stat b_stat;
31
32 int answer;
33
34 safe_stat (a, &a_stat);
35 safe_stat (b, &b_stat);
36
37 answer = arch_file_stats_differ (&a_stat, &b_stat);
38 if (answer == 0)
39 return answer;
40 answer = arch_inode_sigs_differ (&b_stat, id, inode_sig_shortcuts_of_b);
41 if (answer == 0)
42 return answer;
43
44 return arch_filename_contents_differ (a, b);
45 }
46
47
48 int
arch_file_stats_differ(struct stat * a_stat,struct stat * b_stat)49 arch_file_stats_differ (struct stat *a_stat, struct stat *b_stat)
50 {
51 if (a_stat->st_size != b_stat->st_size)
52 return 1;
53
54 if (a_stat->st_ino == b_stat->st_ino && a_stat->st_dev == b_stat->st_dev )
55 return 0;
56 return -1;
57 }
58
59 int
arch_inode_sigs_differ(struct stat * b_stat,const t_uchar * id,assoc_table inode_sig_shortcuts_of_b)60 arch_inode_sigs_differ (struct stat *b_stat, const t_uchar * id, assoc_table inode_sig_shortcuts_of_b)
61 {
62 if (id && inode_sig_shortcuts_of_b)
63 {
64 t_uchar * b_sig = arch_statb_inode_sig (b_stat);
65 const t_uchar * b_goal = assoc_get_str_taking (inode_sig_shortcuts_of_b, rel_make_field_str (id));
66 int shortcut_applies = !str_cmp (b_sig, b_goal);
67
68 lim_free (0, b_sig);
69 if (shortcut_applies)
70 return 0;
71 }
72
73 return -1;
74 }
75
76 int
arch_filename_contents_differ(const t_uchar * a,const t_uchar * b)77 arch_filename_contents_differ (const t_uchar * a, const t_uchar * b)
78 {
79 int a_fd;
80 int b_fd;
81 int answer;
82
83 a_fd = safe_open (a, O_RDONLY, 0);
84 b_fd = safe_open (b, O_RDONLY, 0);
85 answer = arch_file_contents_differ (a_fd, b_fd);
86
87 safe_close (a_fd);
88 safe_close (b_fd);
89
90 return answer;
91 }
92
93 int
arch_file_contents_differ(int a_fd,int b_fd)94 arch_file_contents_differ (int a_fd, int b_fd)
95 {
96 static t_uchar a_buf[65536];
97 static t_uchar b_buf[sizeof (a_buf)];
98 long a_amt;
99 long b_amt;
100 int answer = 0;
101
102 while (1)
103 {
104 a_amt = safe_read_retry (a_fd, a_buf, sizeof (a_buf));
105 b_amt = safe_read_retry (b_fd, b_buf, sizeof (b_buf));
106
107 if ((a_amt != b_amt) || mem_cmp (a_buf, b_buf, a_amt))
108 {
109 answer = 1;
110 break;
111 }
112
113 if (!a_amt)
114 break;
115 }
116
117 return answer;
118 }
119
120
121 int
arch_invoke_diff(int output_fd,const char * orig_path,const char * orig_loc,const char * mod_path,const char * mod_loc,t_uchar * id,assoc_table inode_sig_shortcuts_of_mod)122 arch_invoke_diff (int output_fd,
123 const char * orig_path, const char * orig_loc,
124 const char * mod_path, const char * mod_loc,
125 t_uchar * id,
126 assoc_table inode_sig_shortcuts_of_mod)
127 {
128 if (!arch_binary_files_differ (orig_path, mod_path, id, inode_sig_shortcuts_of_mod))
129 return 0;
130 return arch_really_invoke_diff (output_fd, orig_path, orig_loc, mod_path, mod_loc, NULL);
131 }
132
133 int
arch_really_invoke_diff(int output_fd,const char * orig_path,const char * orig_loc,const char * mod_path,const char * mod_loc,const char ** extraopts)134 arch_really_invoke_diff (int output_fd,
135 const char * orig_path, const char * orig_loc,
136 const char * mod_path, const char * mod_loc, const char **extraopts)
137 {
138 char * orig_label = 0;
139 char * mod_label = 0;
140 int pid;
141
142 if (orig_loc)
143 {
144 orig_label = file_name_in_vicinity (0, "orig", orig_loc + 2);
145 }
146 if (mod_loc)
147 {
148 mod_label = file_name_in_vicinity (0, "mod", mod_loc + 2);
149 }
150
151 safe_flush (output_fd);
152
153 pid = fork ();
154 if (pid == -1)
155 panic ("unable to fork for diff");
156
157 if (pid)
158 {
159 int status;
160 int wait_pid;
161
162 wait_pid = waitpid (pid, &status, 0);
163 if (wait_pid < 0)
164 {
165 panic_msg ("error waiting for subprocess");
166 kill (0, SIGKILL);
167 panic ("error waiting for subprocess");
168 }
169 if (WIFSIGNALED (status))
170 {
171 safe_printfmt (2, "\n");
172 safe_printfmt (2, "diff subprocess killed by signal %d\n", WTERMSIG (status));
173 safe_printfmt (2, "\n");
174 exit (2);
175 }
176 else if (!WIFEXITED (status))
177 {
178 panic_msg ("waitpid returned for a non-exited process");
179 kill (0, SIGKILL);
180 panic ("waitpid returned for a non-exited process");
181 }
182 else
183 {
184 int exit_status;
185
186 exit_status = WEXITSTATUS (status);
187
188 if (exit_status && (exit_status != 1) && (exit_status != 2))
189 {
190 safe_printfmt (2, "\n");
191 safe_printfmt (2, "encountered error diffing files\n");
192 safe_printfmt (2, " orig: %s\n", orig_path);
193 safe_printfmt (2, " mod: %s\n", mod_path);
194 safe_printfmt (2, " diff exit status: %d\n", exit_status);
195 safe_printfmt (2, "\n");
196 exit (2);
197 }
198 if (orig_label)
199 {
200 lim_free (0, orig_label);
201 }
202 if (mod_label)
203 {
204 lim_free (0, mod_label);
205 }
206 return exit_status;
207 }
208 }
209 else
210 {
211 int errn;
212 t_uchar ** argv = 0;
213
214 if (0 > vu_move_fd (&errn, output_fd, 1))
215 panic ("unable to redirect stdout for diff");
216
217
218 /* `const' discarded before `exec'
219 */
220
221 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = cfg__gnu_diff;
222 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "--binary";
223 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-u";
224 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-L";
225 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = orig_label ? (char *)orig_label : (char *)orig_path;
226 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = "-L";
227 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = mod_label ? (char *)mod_label : (char *)mod_path;
228 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = (char *)orig_path;
229 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = (char *)mod_path;
230 if (extraopts != NULL)
231 {
232 t_uchar ** opt;
233 for (opt = extraopts; *opt != NULL; ++opt)
234 {
235 *(t_uchar **) ar_push ((void*) &argv, 0, sizeof(t_uchar*)) = *opt;
236
237 }
238 }
239
240 *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = 0;
241
242 arch_util_execvp (cfg__gnu_diff, argv);
243
244 panic ("execvp for diff returned to caller");
245
246 exit (2);
247 }
248 panic ("arch_invoke_diff: not reached");
249 return 1;
250 }
251
252
253
254
255 /* tag: Tom Lord Mon May 19 18:00:23 2003 (diffs.c)
256 */
257