1 /* changeset-report.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 "hackerlab/bugs/panic.h"
12 #include "hackerlab/char/str.h"
13 #include "hackerlab/fs/file-names.h"
14 #include "hackerlab/vu/safe.h"
15 #include "hackerlab/arrays/ar.h"
16 #include "hackerlab/char/pika-escaping-utils.h"
17 #include "tla/libfsutils/read-line.h"
18 #include "tla/libawk/relassoc.h"
19 #include "tla/libfsutils/find-utils.h"
20 #include "tla/libfsutils/ensure-dir.h"
21 #include "tla/libfsutils/copy-file.h"
22 #include "tla/libarch/diffs.h"
23 #include "tla/libarch/changeset-utils.h"
24 #include "tla/libarch/changeset-report.h"
25 
26 
27 /* __STDC__ prototypes for static functions */
28 static void fix_mod_locs (assoc_table loc_of, rel_table table);
29 static void arch_print_file_metadata_diffs (int out_fd,
30                                             struct arch_changeset_report * report,
31                                             int escape_classes);
32 static void arch_print_dir_metadata_diffs (int out_fd,
33                                            struct arch_changeset_report * report,
34                                            int escape_classes);
35 static void print_custom_diffs(int fd, struct arch_changeset_report * report,
36                                t_uchar * orig_dir, t_uchar * mod_dir,
37                                t_uchar ** opts);
38 
39 static void arch_print_file_diffs (int out_fd,
40                                    struct arch_changeset_report * report,
41                                    int escape_classes);
42 static void arch_print_added_file_diffs (int out_fd,
43                                          struct arch_changeset_report * report,
44                                          int escape_classes);
45 static void
46 print_removed_file_diffs (int fd, struct arch_changeset_report * report,
47                           t_uchar ** opts);
48 static void print_file_metadata (int out_fd,
49                                  struct arch_changeset_report * report,
50                                  int escape_classes);
51 static void print_dir_metadata (int out_fd,
52                                 struct arch_changeset_report * report,
53                                 int escape_classes);
54 static void print_diffs_new(int fd, struct arch_changeset_report * report);
55 
56 static char * no_dot (char *name);
57 static void report_unique_files_and_symlinks (rel_table * files, rel_table * symlinks,
58                                               rel_table index,
59                                               t_uchar * archive_dir, t_uchar * archive_basename);
60 static void find_renames (rel_table * out, rel_table common, assoc_table orig_dir_id_of, assoc_table mod_dir_id_of);
61 
62 
63 
64 
65 int
arch_any_changes(struct arch_changeset_report * report)66 arch_any_changes (struct arch_changeset_report * report)
67 {
68   return (rel_n_records (report->removed_dirs)
69           || rel_n_records (report->added_dirs)
70 
71           || rel_n_records (report->removed_files)
72           || rel_n_records (report->added_files)
73 
74           || rel_n_records (report->removed_symlinks)
75           || rel_n_records (report->added_symlinks)
76 
77           || rel_n_records (report->renamed_files)
78           || rel_n_records (report->renamed_dirs)
79 
80           || rel_n_records (report->patched_regular_files)
81           || rel_n_records (report->patched_symlinks)
82           || rel_n_records (report->patched_binaries)
83           || rel_n_records (report->file_metadata_changed)
84           || rel_n_records (report->dir_metadata_changed)
85           || rel_n_records (report->symlink_to_file)
86           || rel_n_records (report->file_to_symlink));
87 }
88 
89 void
arch_evaluate_changeset(struct arch_changeset_report * report,t_uchar * path)90 arch_evaluate_changeset (struct arch_changeset_report * report, t_uchar * path)
91 {
92   t_uchar * orig_files_index_path = 0;
93   t_uchar * orig_dirs_index_path = 0;
94   t_uchar * mod_files_index_path = 0;
95   t_uchar * mod_dirs_index_path = 0;
96 
97   rel_table removed_dirs_index = rel_table_nil;
98   rel_table added_dirs_index = rel_table_nil;
99 
100   rel_table removed_files_and_symlinks_index = rel_table_nil;
101   rel_table added_files_and_symlinks_index = rel_table_nil;
102 
103   rel_table common_files_index = rel_table_nil; /* [0] origloc [1] modloc [2] id */
104   rel_table common_dirs_index = rel_table_nil; /* [0] origloc [1] modloc [2] id */
105 
106   assoc_table orig_dir_loc_of = 0;
107   assoc_table orig_dir_id_of = 0;
108   assoc_table orig_file_loc_of = 0;
109   assoc_table orig_file_id_of = 0;
110   assoc_table mod_dir_loc_of = 0;
111   assoc_table mod_dir_id_of = 0;
112   assoc_table mod_file_loc_of = 0;
113   assoc_table mod_file_id_of = 0;
114 
115 
116   orig_files_index_path = file_name_in_vicinity (0, path, "orig-files-index");
117   orig_dirs_index_path = file_name_in_vicinity (0, path, "orig-dirs-index");
118   mod_files_index_path = file_name_in_vicinity (0, path, "mod-files-index");
119   mod_dirs_index_path = file_name_in_vicinity (0, path, "mod-dirs-index");
120 
121   report->orig_files_index = arch_read_changeset_index (orig_files_index_path);
122   report->orig_dirs_index = arch_read_changeset_index (orig_dirs_index_path);
123   report->mod_files_index = arch_read_changeset_index (mod_files_index_path);
124   report->mod_dirs_index = arch_read_changeset_index (mod_dirs_index_path);
125 
126   /* just to be sure:
127    */
128   rel_sort_table_by_field (0, report->orig_files_index, 1);
129   rel_sort_table_by_field (0, report->orig_dirs_index, 1);
130   rel_sort_table_by_field (0, report->mod_files_index, 1);
131   rel_sort_table_by_field (0, report->mod_dirs_index, 1);
132 
133   orig_dir_id_of = rel_to_assoc (report->orig_dirs_index, 0, 1);
134   orig_dir_loc_of = rel_to_assoc (report->orig_dirs_index, 1, 0);
135   orig_file_id_of = rel_to_assoc (report->orig_files_index, 0, 1);
136   orig_file_loc_of = rel_to_assoc (report->orig_files_index, 1, 0);
137   mod_dir_id_of = rel_to_assoc (report->mod_dirs_index, 0, 1);
138   mod_dir_loc_of = rel_to_assoc (report->mod_dirs_index, 1, 0);
139   mod_file_id_of = rel_to_assoc (report->mod_files_index, 0, 1);
140   mod_file_loc_of = rel_to_assoc (report->mod_files_index, 1, 0);
141 
142 
143   /****************************************************************
144    * Removed and added directories
145    */
146 
147   {
148     t_uchar * original_only_dir_metadata_file = 0;
149     t_uchar * modified_only_dir_metadata_file = 0;
150     rel_table original_only_dir_metadata = rel_table_nil;
151     rel_table modified_only_dir_metadata = rel_table_nil;
152     rel_table orig_dirs_by_name = rel_table_nil;
153     rel_table mod_dirs_by_name = rel_table_nil;
154     rel_table t;        /* [0] name [1] id  -- sort 0*/
155     rel_table t2;       /* [0] name [1] id [2] name -- sort 0 -- of dirs sans perms */
156 
157     original_only_dir_metadata_file = file_name_in_vicinity (0, path, "original-only-dir-metadata");
158     modified_only_dir_metadata_file = file_name_in_vicinity (0, path, "modified-only-dir-metadata");
159 
160     original_only_dir_metadata = arch_read_changeset_dir_metadata (original_only_dir_metadata_file);
161     modified_only_dir_metadata = arch_read_changeset_dir_metadata (modified_only_dir_metadata_file);
162 
163     orig_dirs_by_name = rel_copy_table (report->orig_dirs_index);
164     rel_sort_table_by_field (0, orig_dirs_by_name, 0);
165 
166     mod_dirs_by_name = rel_copy_table (report->mod_dirs_index);
167     rel_sort_table_by_field (0, mod_dirs_by_name, 0);
168 
169     removed_dirs_index = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
170     added_dirs_index = rel_join (2, rel_join_output (2,0, 2,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
171 
172     t = rel_copy_table (removed_dirs_index);
173     rel_sort_table_by_field (0, t, 0);
174     report->removed_dirs = rel_join (-1, rel_join_output (1,0, 1,1, 2,1, -1), 0, 0, t, original_only_dir_metadata);
175     t2 = rel_join (1, rel_join_output (1,0, 1,1, 1,0, -1), 0, 0, t, original_only_dir_metadata);
176     rel_append_x (&report->removed_dirs, t2);
177     rel_sort_table_by_field (0, report->removed_dirs, 0);
178     rel_free_table (t);
179     rel_free_table (t2);
180     invariant (rel_n_records (report->removed_dirs) == rel_n_records (removed_dirs_index));
181 
182     t = rel_copy_table (added_dirs_index);
183     rel_sort_table_by_field (0, t, 0);
184     report->added_dirs = rel_join (-1, rel_join_output (1,0, 1,1, 2,1, -1), 0, 0, t, modified_only_dir_metadata);
185     t2 = rel_join (1, rel_join_output (1,0, 1,1, 1,0, -1), 0, 0, t, modified_only_dir_metadata);
186     rel_append_x (&report->added_dirs, t2);
187     rel_sort_table_by_field (0, report->added_dirs, 0);
188     rel_free_table (t);
189     rel_free_table (t2);
190     invariant (rel_n_records (report->added_dirs) == rel_n_records (added_dirs_index));
191 
192     lim_free (0, original_only_dir_metadata_file);
193     lim_free (0, modified_only_dir_metadata_file);
194     rel_free_table (original_only_dir_metadata);
195     rel_free_table (modified_only_dir_metadata);
196     rel_free_table (orig_dirs_by_name);
197     rel_free_table (mod_dirs_by_name);
198   }
199 
200   /****************************************************************
201    * Removed and added filenames and symlinks
202    */
203 
204   removed_files_and_symlinks_index = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
205   added_files_and_symlinks_index = rel_join (2, rel_join_output (2,0, 2,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
206 
207   report_unique_files_and_symlinks (&report->removed_files, &report->removed_symlinks,
208                                     removed_files_and_symlinks_index,
209                                     path, "removed-files-archive");
210 
211   report_unique_files_and_symlinks (&report->added_files, &report->added_symlinks,
212                                     added_files_and_symlinks_index,
213                                     path, "new-files-archive");
214 
215   /****************************************************************
216    * renamed files and dirs
217    */
218   common_dirs_index = rel_join (-1, rel_join_output (1,0, 2,0, 1,1, -1), 1, 1, report->orig_dirs_index, report->mod_dirs_index);
219   common_files_index = rel_join (-1, rel_join_output (1,0, 2,0, 1,1, -1), 1, 1, report->orig_files_index, report->mod_files_index);
220 
221   find_renames (&report->renamed_dirs, common_dirs_index, orig_dir_id_of, mod_dir_id_of);
222   find_renames (&report->renamed_files, common_files_index, orig_dir_id_of, mod_dir_id_of);
223 
224   /****************************************************************
225    * Identify patches
226    */
227   {
228     int lim;
229     int x;
230     int here_fd;
231     t_uchar * patches_root;
232     rel_table patches_files = rel_table_nil;
233     assoc_table saw_patches_file = 0;
234 
235     patches_root = file_name_in_vicinity (0, path, "patches");
236 
237     here_fd = safe_open (".", O_RDONLY, 0);
238     safe_chdir (patches_root);
239     find_files (&patches_files, ".");
240     safe_fchdir (here_fd);
241     safe_close (here_fd);
242 
243     saw_patches_file = rel_to_assoc (patches_files, 0, 0);
244 
245     lim = rel_n_records (patches_files);
246     for (x = 0; x < lim; ++x)
247       {
248         const t_uchar * patch_file;
249         t_uchar * patch_file_tail = 0;
250         t_uchar * patch_file_suffix = 0;
251 
252         t_uchar * patch_file_loc = 0;
253         rel_table * dest = 0;
254         t_uchar * complement_patch = 0;
255 
256         t_uchar * patch_file_path = 0;
257 
258         rel_field id_field = rel_field_nil;
259 
260         patch_file = rel_peek_str (patches_files, x, 0);
261         patch_file_suffix = str_chr_rindex (patch_file, '.');
262         patch_file_tail = file_name_tail (0, patch_file);
263 
264         /* Compute the loc and the appropriate table for this
265          * this patch.  (patch_file_loc and dest)
266          */
267         if (!str_cmp (patch_file_tail, "=dir-meta-orig"))
268           {
269             patch_file_loc = file_name_directory_file (0, patch_file);
270             dest = &report->dir_metadata_changed;
271             id_field = assoc_get_taking (mod_dir_id_of, rel_make_field_str (patch_file_loc));
272           }
273         else if (!str_cmp (patch_file_suffix, ".link-orig"))
274           {
275             patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
276             complement_patch = str_alloc_cat (0, patch_file_loc, ".link-mod");
277             if (assoc_get_str_taking (saw_patches_file, rel_make_field_str (complement_patch)))
278               dest = &report->patched_symlinks;
279             else
280               dest = &report->symlink_to_file;
281             id_field = assoc_get_taking (mod_file_id_of, rel_make_field_str (patch_file_loc));
282           }
283         else if (!str_cmp (patch_file_suffix, ".original"))
284           {
285             patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
286             complement_patch = str_alloc_cat (0, patch_file_loc, ".modified");
287             if (assoc_get_str_taking (saw_patches_file, rel_make_field_str (complement_patch)))
288               dest = &report->patched_binaries;
289             else
290               dest = &report->file_to_symlink;
291             id_field = assoc_get_taking (mod_file_id_of, rel_make_field_str (patch_file_loc));
292           }
293         else if (!str_cmp (patch_file_suffix, ".patch"))
294           {
295             patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
296             dest = &report->patched_regular_files;
297             id_field = assoc_get_taking (mod_file_id_of, rel_make_field_str (patch_file_loc));
298           }
299         else if (!str_cmp (patch_file_suffix, ".meta-orig"))
300           {
301             patch_file_loc = str_save_n (0, patch_file, patch_file_suffix - patch_file);
302             dest = &report->file_metadata_changed;
303             id_field = assoc_get_taking (mod_file_id_of, rel_make_field_str (patch_file_loc));
304           }
305         else
306           {
307             id_field = rel_field_nil;
308           }
309 
310         if (dest && patch_file_loc)
311           {
312             patch_file_path = file_name_in_vicinity (0, patches_root, patch_file_loc);
313             rel_add_records (dest,
314                              rel_make_record_3_taking (rel_make_field_str (patch_file_loc),
315                                                        rel_field_ref (id_field),
316                                                        rel_make_field_str (patch_file_path)),
317                              rel_record_null);
318           }
319 
320         rel_field_unref (id_field);
321         lim_free (0, patch_file_tail);
322         lim_free (0, patch_file_loc);
323         lim_free (0, complement_patch);
324         lim_free (0, patch_file_path);
325       }
326 
327 
328     lim_free (0, patches_root);
329     rel_free_table (patches_files);
330     free_assoc_table (saw_patches_file);
331   }
332 
333   rel_sort_table_by_field (0, report->removed_dirs, 0);
334   rel_sort_table_by_field (0, report->added_dirs, 0);
335 
336   rel_sort_table_by_field (0, report->removed_files, 0);
337   rel_sort_table_by_field (0, report->added_files, 0);
338 
339   rel_sort_table_by_field (0, report->removed_symlinks, 0);
340   rel_sort_table_by_field (0, report->added_symlinks, 0);
341 
342   rel_sort_table_by_field (0, report->renamed_files, 0);
343   rel_sort_table_by_field (0, report->renamed_dirs, 0);
344 
345   rel_sort_table_by_field (0, report->patched_regular_files, 0);
346   rel_sort_table_by_field (0, report->patched_symlinks, 0);
347   rel_sort_table_by_field (0, report->patched_binaries, 0);
348   rel_sort_table_by_field (0, report->file_metadata_changed, 0);
349   rel_sort_table_by_field (0, report->dir_metadata_changed, 0);
350   rel_sort_table_by_field (0, report->symlink_to_file, 0);
351   rel_sort_table_by_field (0, report->file_to_symlink, 0);
352 
353   lim_free (0, orig_files_index_path);
354   lim_free (0, orig_dirs_index_path);
355   lim_free (0, mod_files_index_path);
356   lim_free (0, mod_dirs_index_path);
357   rel_free_table (removed_dirs_index);
358   rel_free_table (added_dirs_index);
359   rel_free_table (removed_files_and_symlinks_index);
360   rel_free_table (added_files_and_symlinks_index);
361   free_assoc_table (orig_dir_loc_of);
362   free_assoc_table (orig_dir_id_of);
363   free_assoc_table (orig_file_loc_of);
364   free_assoc_table (orig_file_id_of);
365   free_assoc_table (mod_dir_loc_of);
366   free_assoc_table (mod_dir_id_of);
367   free_assoc_table (mod_file_loc_of);
368   free_assoc_table (mod_file_id_of);
369   rel_free_table (common_files_index);
370   rel_free_table (common_dirs_index);
371 
372 }
373 
374 
375 void
arch_reverse_changeset(struct arch_changeset_report * report)376 arch_reverse_changeset (struct arch_changeset_report * report)
377 {
378   rel_table t;
379   int x;
380   assoc_table new_mod_file_loc_of = 0;
381   assoc_table new_mod_dir_loc_of = 0;
382 
383   t = report->orig_files_index;
384   report->orig_files_index = report->mod_files_index;
385   report->mod_files_index = t;
386 
387   t = report->orig_dirs_index;
388   report->orig_dirs_index = report->mod_dirs_index;
389   report->mod_dirs_index = t;
390 
391   t = report->removed_dirs;
392   report->removed_dirs = report->added_dirs;
393   report->added_dirs = t;
394 
395   t = report->removed_files;
396   report->removed_files = report->added_files;
397   report->added_files = t;
398 
399   t = report->removed_symlinks;
400   report->removed_symlinks = report->added_symlinks;
401   report->added_symlinks = t;
402 
403   for (x = 0; x < rel_n_records (report->renamed_files); ++x)
404     {
405       t_uchar * s;
406 
407       s = str_save (0, rel_peek_str (report->renamed_files, x, 0));
408       rel_set_taking (report->renamed_files, x, 0, rel_get_field (report->renamed_files, x, 1));
409       rel_set_taking (report->renamed_files, x, 1, rel_make_field_str (s));
410       lim_free (0, s);
411     }
412   for (x = 0; x < rel_n_records (report->renamed_dirs); ++x)
413     {
414       t_uchar * s;
415 
416       s = str_save (0, rel_peek_str (report->renamed_dirs, x, 0));
417       rel_set_taking (report->renamed_dirs, x, 0, rel_get_field (report->renamed_dirs, x, 1));
418       rel_set_taking (report->renamed_dirs, x, 1, rel_make_field_str (s));
419       lim_free (0, s);
420     }
421 
422   new_mod_file_loc_of = rel_to_assoc (report->mod_files_index, 1, 0);
423   new_mod_dir_loc_of = rel_to_assoc (report->mod_dirs_index, 1, 0);
424 
425   fix_mod_locs (new_mod_file_loc_of, report->patched_regular_files);
426   fix_mod_locs (new_mod_file_loc_of, report->patched_symlinks);
427   fix_mod_locs (new_mod_file_loc_of, report->patched_binaries);
428   fix_mod_locs (new_mod_file_loc_of, report->file_metadata_changed);
429   fix_mod_locs (new_mod_dir_loc_of, report->dir_metadata_changed);
430   fix_mod_locs (new_mod_file_loc_of, report->symlink_to_file);
431   fix_mod_locs (new_mod_file_loc_of, report->file_to_symlink);
432 }
433 
434 static void
fix_mod_locs(assoc_table loc_of,rel_table table)435 fix_mod_locs (assoc_table loc_of, rel_table table)
436 {
437   int x;
438 
439   for (x = 0; x < rel_n_records (table); ++x)
440     {
441       rel_field id_field;
442       rel_field new_loc_field;
443 
444       id_field = rel_get_field (table, x, 1);
445       new_loc_field = assoc_get_taking (loc_of, id_field);
446       rel_set_taking (table, x, 0, new_loc_field);
447     }
448 }
449 
450 static void
arch_print_file_metadata_diffs(int out_fd,struct arch_changeset_report * report,int escape_classes)451 arch_print_file_metadata_diffs (int out_fd,
452                                 struct arch_changeset_report * report,
453                                 int escape_classes)
454 {
455   int x;
456 
457   for (x = 0; x < rel_n_records (report->file_metadata_changed); ++x)
458     {
459       t_uchar * orig_meta_path = 0;
460       t_uchar * mod_meta_path = 0;
461       t_uchar * orig_meta = 0;
462       t_uchar * mod_meta = 0;
463       t_uchar * file_metadata_changed = 0;
464 
465       file_metadata_changed = pika_save_escape_iso8859_1 (0, 0, escape_classes,
466                                                           rel_peek_str (report->file_metadata_changed, x, 0));
467       safe_printfmt (out_fd, "    %s\n", file_metadata_changed);
468 
469       orig_meta_path = str_alloc_cat (0, rel_peek_str (report->file_metadata_changed, x, 2), ".meta-orig");
470       mod_meta_path = str_alloc_cat (0, rel_peek_str (report->file_metadata_changed, x, 2), ".meta-mod");
471       orig_meta = read_line_from_file (orig_meta_path);
472       mod_meta = read_line_from_file (mod_meta_path);
473 
474       safe_printfmt (out_fd, "        %s\n        => %s\n", orig_meta, mod_meta);
475 
476       lim_free (0, file_metadata_changed);
477       lim_free (0, orig_meta_path);
478       lim_free (0, mod_meta_path);
479       lim_free (0, orig_meta);
480       lim_free (0, mod_meta);
481     }
482 }
483 
484 static void
arch_print_dir_metadata_diffs(int out_fd,struct arch_changeset_report * report,int escape_classes)485 arch_print_dir_metadata_diffs (int out_fd,
486                                struct arch_changeset_report * report,
487                                int escape_classes)
488 {
489   int x;
490 
491   for (x = 0; x < rel_n_records (report->dir_metadata_changed); ++x)
492     {
493       t_uchar * orig_meta_path = 0;
494       t_uchar * mod_meta_path = 0;
495       t_uchar * orig_meta = 0;
496       t_uchar * mod_meta = 0;
497       t_uchar * dir_metadata_changed = 0;
498 
499       dir_metadata_changed = pika_save_escape_iso8859_1 (0, 0, escape_classes,
500                                                          rel_peek_str (report->dir_metadata_changed, x, 0));
501       safe_printfmt (out_fd, "    %s\n", dir_metadata_changed);
502 
503       orig_meta_path = file_name_in_vicinity (0, rel_peek_str (report->dir_metadata_changed, x, 2), "=dir-meta-orig");
504       mod_meta_path = file_name_in_vicinity (0, rel_peek_str (report->dir_metadata_changed, x, 2), "=dir-meta-mod");
505       orig_meta = read_line_from_file (orig_meta_path);
506       mod_meta = read_line_from_file (mod_meta_path);
507 
508       safe_printfmt (out_fd, "        %s\n        => %s\n", orig_meta, mod_meta);
509 
510       lim_free (0, dir_metadata_changed);
511       lim_free (0, orig_meta_path);
512       lim_free (0, mod_meta_path);
513       lim_free (0, orig_meta);
514       lim_free (0, mod_meta);
515     }
516 }
517 
518 static void
arch_print_file_diffs(int out_fd,struct arch_changeset_report * report,int escape_classes)519 arch_print_file_diffs (int out_fd,
520                        struct arch_changeset_report * report,
521                        int escape_classes)
522 {
523   int x;
524 
525   for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
526     {
527       t_uchar * patch_file;
528       int in_fd;
529 
530       patch_file = str_alloc_cat (0, rel_peek_str (report->patched_regular_files, x, 2), ".patch");
531       in_fd = safe_open (patch_file, O_RDONLY, 0);
532       copy_fd (in_fd, out_fd);
533       safe_printfmt (out_fd, "\n\n");
534       safe_close (in_fd);
535       lim_free (0, patch_file);
536     }
537 }
538 
539 static void
arch_print_added_file_diffs(int out_fd,struct arch_changeset_report * report,int escape_classes)540 arch_print_added_file_diffs (int out_fd,
541                              struct arch_changeset_report * report,
542                              int escape_classes)
543 {
544   int x;
545 
546   for (x = 0; x < rel_n_records (report->added_files); ++x)
547     {
548       arch_really_invoke_diff (1, "/dev/null", NULL, rel_peek_str (report->added_files, x, 2), NULL, NULL);
549     }
550 }
551 
552 
print_file_metadata(int out_fd,struct arch_changeset_report * report,int escape_classes)553 static void print_file_metadata (int out_fd, struct arch_changeset_report *
554                                  report, int escape_classes)
555 {
556   if (rel_n_records(report->file_metadata_changed) > 0)
557     {
558       safe_printfmt (out_fd, "* file metadata changed\n\n");
559       arch_print_file_metadata_diffs (out_fd, report, escape_classes);
560       safe_printfmt (out_fd, "\n");
561     }
562 }
563 
564 
print_dir_metadata(int out_fd,struct arch_changeset_report * report,int escape_classes)565 static void print_dir_metadata (int out_fd,
566                                 struct arch_changeset_report * report,
567                                 int escape_classes)
568 {
569   if (rel_n_records(report->dir_metadata_changed) > 0)
570     {
571       safe_printfmt (out_fd, "* dir metadata changed\n\n");
572       arch_print_dir_metadata_diffs (out_fd, report, escape_classes);
573       safe_printfmt (out_fd, "\n");
574     }
575 }
576 
print_diffs_new(int out_fd,struct arch_changeset_report * report)577 static void print_diffs_new(int out_fd, struct arch_changeset_report * report)
578 {
579   if (rel_n_records(report->patched_regular_files))
580     {
581       safe_printfmt (out_fd, "* modified files\n\n");
582       arch_print_file_diffs (out_fd, report, 0);
583       safe_printfmt (out_fd, "\n");
584     }
585   if (rel_n_records(report->added_files))
586     {
587       safe_printfmt (out_fd, "* added files\n\n");
588       arch_print_added_file_diffs (out_fd, report, 0);
589       safe_printfmt (out_fd, "\n");
590     }
591   print_removed_file_diffs(out_fd, report, NULL);
592 }
593 
594 
595 /**
596  * \brief Write custom diffs for to a file descriptor
597  *
598  * The changeset report is used to determine which files to diff, and the
599  * partial file paths.  The orig_dir and mod_dir are used to produce full
600  * paths.  diff is invoked to produce the output.
601  *
602  * \param report The report to use for output
603  * \param orig_dir The path to a copy of the ORIG tree
604  * \param mod_dir The path to a copy of the MOD tree
605  */
606 static void
print_custom_diffs(int out_fd,struct arch_changeset_report * report,t_uchar * orig_dir,t_uchar * mod_dir,t_uchar ** opts)607 print_custom_diffs (int out_fd, struct arch_changeset_report * report, t_uchar * orig_dir, t_uchar * mod_dir, t_uchar ** opts)
608 {
609   if (rel_n_records(report->patched_regular_files))
610     {
611       int x;
612       rel_field key;
613       assoc_table orig_paths = rel_to_assoc (report->orig_files_index,  out_fd, 0);
614 
615       safe_printfmt ( out_fd, "* modified files\n\n");
616       for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
617         {
618           t_uchar *id = str_save(0, rel_peek_str(report->patched_regular_files, x, 1)) /*report->patched_regular_files[x][1]*/;
619           t_uchar *id2 = str_save(0, rel_peek_str(report->patched_regular_files, x, 0)) /*report->patched_regular_files[x][1]*/;
620 
621           t_uchar *orig_part_path;
622           t_uchar *orig_path;
623           t_uchar *mod_path;
624 
625           key = rel_make_field_str(id);
626 
627           rel_field_ref(key);
628 
629           orig_part_path = assoc_get_str_taking(orig_paths, key) /*assoc_ref(orig_paths, id)*/;
630           orig_path = file_name_in_vicinity(0, orig_dir, orig_part_path);
631           mod_path = file_name_in_vicinity(0, mod_dir, id2 /*report->patched_regular_files[x][0]*/);
632 
633 	  arch_really_invoke_diff ( out_fd, orig_path,  orig_part_path, mod_path, id2 /*report->patched_regular_files[x][0]*/, (char **)opts);
634 
635           rel_field_unref(key);
636           lim_free(0, mod_path);
637           lim_free(0, orig_path);
638           lim_free(0, id);
639           lim_free(0, id2);
640         }
641       safe_printfmt ( out_fd, "\n");
642       free_assoc_table (orig_paths);
643     }
644   if (rel_n_records(report->added_files))
645     {
646       int x;
647       safe_printfmt (1, "* added files\n\n");
648 
649       for (x = 0; x < rel_n_records (report->added_files); ++x)
650         {
651           t_uchar *id = str_save(0, rel_peek_str(report->added_files, x, 2));
652           t_uchar *id2 = str_save(0, rel_peek_str(report->added_files, x, 0));
653           arch_really_invoke_diff ( out_fd, "/dev/null", NULL, id /*report->added_files[x][2]*/, id2 /*report->added_files[x][0]*/, (char**)opts);
654           lim_free(0, id);
655           lim_free(0, id2);
656         }
657       safe_printfmt ( out_fd, "\n");
658     }
659   print_removed_file_diffs ( out_fd, report, opts);
660 }
661 
662 
663 
664 /**
665  * \brief Print the diffs for any removed files to output.
666  *
667  * If no files were removed, no output is produced
668  * \param report The changeset report to generate results for
669  * \param opts Additional parameters to pass to diff, or NULL
670  */
671 static void
print_removed_file_diffs(int out_fd,struct arch_changeset_report * report,t_uchar ** opts)672 print_removed_file_diffs (int out_fd, struct arch_changeset_report * report, t_uchar ** opts)
673 {
674   if (rel_n_records(report->removed_files))
675     {
676       int x;
677       safe_printfmt ( out_fd, "* removed files\n\n");
678 
679       for (x = 0; x < rel_n_records (report->removed_files); ++x)
680         {
681           t_uchar *id = str_save(0, rel_peek_str(report->removed_files, x, 2));
682           t_uchar *id2 = str_save(0, rel_peek_str(report->removed_files, x, 0));
683           arch_really_invoke_diff ( out_fd, id /*report->removed_files[x][2]*/, id2 /*report->removed_files[x][0]*/, "/dev/null", NULL, (char**)opts);
684           lim_free(0, id);
685           lim_free(0, id2);
686         }
687       safe_printfmt ( out_fd, "\n");
688     }
689 }
690 
691 
692 /**
693  * \brief Write a changeset report with custom diffs to a file descriptor
694  *
695  * \param report The report to use for output
696  * \param orig_dir The path to a copy of the ORIG tree
697  * \param mod_dir The path to a copy of the MOD tree
698  * \param escape_classes The types of characters that should be escaped
699  * \todo Consider reimplementing so that a custom changeset is generated, not
700  * custom diffs.
701  */
702 void
arch_print_changeset_custom_diffs(int out_fd,struct arch_changeset_report * report,t_uchar * orig_dir,t_uchar * mod_dir,t_uchar ** opts,int escape_classes)703 arch_print_changeset_custom_diffs (int  out_fd, struct arch_changeset_report * report, t_uchar * orig_dir, t_uchar * mod_dir, t_uchar ** opts, int escape_classes)
704 {
705   print_file_metadata ( out_fd, report, escape_classes);
706   print_dir_metadata ( out_fd, report, escape_classes);
707   if (opts == NULL)
708     print_diffs_new ( out_fd, report);
709   else
710     print_custom_diffs ( out_fd, report, orig_dir, mod_dir, opts);
711 }
712 
713 
714 
715 
716 
717 void
arch_print_changeset_diffs(int out_fd,struct arch_changeset_report * report,int escape_classes)718 arch_print_changeset_diffs (int out_fd, struct arch_changeset_report * report, int escape_classes)
719 {
720   if (rel_n_records (report->file_metadata_changed))
721     {
722       safe_printfmt (out_fd, "* file metadata changed\n\n");
723       arch_print_file_metadata_diffs (out_fd, report, escape_classes);
724       safe_printfmt (out_fd, "\n");
725     }
726 
727   if (rel_n_records (report->dir_metadata_changed))
728     {
729       safe_printfmt (out_fd, "* dir metadata changed\n\n");
730       arch_print_dir_metadata_diffs (out_fd, report, escape_classes);
731       safe_printfmt (out_fd, "\n");
732     }
733 
734   if (rel_n_records (report->patched_regular_files))
735     {
736       safe_printfmt (out_fd, "* modified files\n\n");
737       arch_print_file_diffs (out_fd, report, escape_classes);
738       safe_printfmt (out_fd, "\n");
739     }
740   if (rel_n_records (report->added_files))
741     {
742       safe_printfmt (out_fd, "* added files\n\n");
743       arch_print_added_file_diffs (out_fd, report, escape_classes);
744       safe_printfmt (out_fd, "\n");
745     }
746 }
747 
748 
749 static char *
no_dot(char * name)750 no_dot (char *name)
751 {
752   if (name[0] == '.' && name[1] == '/')
753     return name + 2;
754   else
755     return name;
756 }
757 
758 void
arch_print_changeset(int out_fd,struct arch_changeset_report * report,int diffs,int escape_classes)759 arch_print_changeset  (int out_fd, struct arch_changeset_report * report, int diffs, int escape_classes)
760 {
761   int x;
762 
763   if (rel_n_records (report->removed_dirs))
764     {
765       safe_printfmt (out_fd, "* removed directories\n\n");
766       for (x = 0; x < rel_n_records (report->removed_dirs); ++x)
767         {
768           t_uchar * item;
769           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
770                                              rel_peek_str (report->removed_dirs, x, 0));
771           safe_printfmt (out_fd, "    %s\n", no_dot (item));
772           lim_free (0, item);
773         }
774       safe_printfmt (out_fd, "\n");
775     }
776   if (rel_n_records (report->added_dirs))
777     {
778       safe_printfmt (out_fd, "* added directories\n\n");
779       for (x = 0; x < rel_n_records (report->added_dirs); ++x)
780         {
781           t_uchar * item;
782           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
783                                              rel_peek_str (report->added_dirs, x, 0));
784           safe_printfmt (out_fd, "    %s\n", no_dot (item));
785           lim_free (0, item);
786         }
787       safe_printfmt (out_fd, "\n");
788     }
789 
790   if (rel_n_records (report->removed_files))
791     {
792       safe_printfmt (out_fd, "* removed files\n\n");
793       for (x = 0; x < rel_n_records (report->removed_files); ++x)
794         {
795           t_uchar * item;
796           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
797                                              rel_peek_str (report->removed_files, x, 0));
798           safe_printfmt (out_fd, "    %s\n", no_dot (item));
799           lim_free (0, item);
800         }
801       safe_printfmt (out_fd, "\n");
802     }
803 
804   if (rel_n_records (report->added_files))
805     {
806       safe_printfmt (out_fd, "* added files\n\n");
807       for (x = 0; x < rel_n_records (report->added_files); ++x)
808         {
809           t_uchar * item;
810           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
811                                              rel_peek_str (report->added_files, x, 0));
812           safe_printfmt (out_fd, "    %s\n", no_dot (item));
813           lim_free (0, item);
814         }
815       safe_printfmt (out_fd, "\n");
816     }
817 
818   if (rel_n_records (report->removed_symlinks))
819     {
820       safe_printfmt (out_fd, "* removed symlinks\n\n");
821       for (x = 0; x < rel_n_records (report->removed_symlinks); ++x)
822         {
823           t_uchar * item;
824           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
825                                              rel_peek_str (report->removed_symlinks, x, 0));
826           safe_printfmt (out_fd, "    %s\n", no_dot (item));
827           lim_free (0, item);
828         }
829       safe_printfmt (out_fd, "\n");
830     }
831 
832   if (rel_n_records (report->added_symlinks))
833     {
834       safe_printfmt (out_fd, "* added symlinks\n\n");
835       for (x = 0; x < rel_n_records (report->added_symlinks); ++x)
836         {
837           t_uchar * item;
838           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
839                                              rel_peek_str (report->added_symlinks, x, 0));
840           safe_printfmt (out_fd, "    %s\n", no_dot (item));
841           lim_free (0, item);
842         }
843       safe_printfmt (out_fd, "\n");
844     }
845 
846   if (rel_n_records (report->renamed_files))
847     {
848       safe_printfmt (out_fd, "* renamed files and symlinks\n\n");
849       for (x = 0; x < rel_n_records (report->renamed_files); ++x)
850         {
851           t_uchar * item1;
852           t_uchar * item2;
853           item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
854                                               rel_peek_str (report->renamed_files, x, 0));
855           item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
856                                               rel_peek_str (report->renamed_files, x, 1));
857           safe_printfmt (out_fd, "    %s\n     => %s\n\n", no_dot (item1), no_dot (item2));
858           lim_free (0, item2);
859           lim_free (0, item1);
860         }
861     }
862 
863   if (rel_n_records (report->renamed_dirs))
864     {
865       safe_printfmt (out_fd, "* renamed directories\n\n");
866       for (x = 0; x < rel_n_records (report->renamed_dirs); ++x)
867         {
868           t_uchar * item1;
869           t_uchar * item2;
870           item1 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
871                                               rel_peek_str (report->renamed_dirs, x, 0));
872           item2 = pika_save_escape_iso8859_1 (0, 0, escape_classes,
873                                               rel_peek_str (report->renamed_dirs, x, 1));
874           safe_printfmt (out_fd, "    %s\n     => %s\n\n", no_dot (item1), no_dot (item2));
875           lim_free (0, item2);
876           lim_free (0, item1);
877         }
878     }
879 
880   if (rel_n_records (report->file_to_symlink))
881     {
882       safe_printfmt (out_fd, "* files replaced by symlinks \n\n");
883       for (x = 0; x < rel_n_records (report->file_to_symlink); ++x)
884         {
885           t_uchar * item;
886           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
887                                              rel_peek_str (report->file_to_symlink, x, 0));
888           safe_printfmt (out_fd, "    %s\n", no_dot (item));
889           lim_free (0, item);
890         }
891       safe_printfmt (out_fd, "\n");
892     }
893 
894   if (rel_n_records (report->symlink_to_file))
895     {
896       safe_printfmt (out_fd, "* symlinks replaced by files\n\n");
897       for (x = 0; x < rel_n_records (report->symlink_to_file); ++x)
898         {
899           t_uchar * item;
900           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
901                                              rel_peek_str (report->symlink_to_file, x, 0));
902           safe_printfmt (out_fd, "    %s\n", no_dot (item));
903           lim_free (0, item);
904         }
905       safe_printfmt (out_fd, "\n");
906     }
907 
908   if (rel_n_records (report->file_metadata_changed))
909     {
910       safe_printfmt (out_fd, "* file metadata changed\n\n");
911 
912       if (diffs)
913         {
914           arch_print_file_metadata_diffs (out_fd, report, escape_classes);
915         }
916       else
917         {
918           for (x = 0; x < rel_n_records (report->file_metadata_changed); ++x)
919             {
920               t_uchar * item;
921               item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
922                                                  rel_peek_str (report->file_metadata_changed, x, 0));
923               safe_printfmt (out_fd, "    %s\n", no_dot (item));
924               lim_free (0, item);
925             }
926         }
927       safe_printfmt (out_fd, "\n");
928     }
929 
930   if (rel_n_records (report->dir_metadata_changed))
931     {
932       safe_printfmt (out_fd, "* dir metadata changed\n\n");
933 
934       if (diffs)
935         {
936           arch_print_dir_metadata_diffs (out_fd, report, escape_classes);
937         }
938       else
939         {
940           for (x = 0; x < rel_n_records (report->dir_metadata_changed); ++x)
941             {
942               t_uchar * item;
943               item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
944                                                  rel_peek_str (report->dir_metadata_changed, x, 0));
945               safe_printfmt (out_fd, "    %s\n", no_dot (item));
946               lim_free (0, item);
947             }
948         }
949       safe_printfmt (out_fd, "\n");
950     }
951 
952   if (rel_n_records (report->patched_symlinks))
953     {
954       safe_printfmt (out_fd, "* retargeted symlinks\n\n");
955       for (x = 0; x < rel_n_records (report->patched_symlinks); ++x)
956         {
957           t_uchar * item;
958           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
959                                              rel_peek_str (report->patched_symlinks, x, 0));
960           safe_printfmt (out_fd, "    %s\n", no_dot (item));
961           lim_free (0, item);
962         }
963       safe_printfmt (out_fd, "\n");
964     }
965 
966   if (rel_n_records (report->patched_binaries))
967     {
968       safe_printfmt (out_fd, "* modified binary files\n\n");
969       for (x = 0; x < rel_n_records (report->patched_binaries); ++x)
970         {
971           t_uchar * item;
972           item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
973                                              rel_peek_str (report->patched_binaries, x, 0));
974           safe_printfmt (out_fd, "    %s\n", no_dot (item));
975           lim_free (0, item);
976         }
977       safe_printfmt (out_fd, "\n");
978     }
979 
980   if (rel_n_records (report->patched_regular_files))
981     {
982       safe_printfmt (out_fd, "* modified files\n\n");
983 
984       if (diffs)
985         {
986           arch_print_file_diffs (out_fd, report, escape_classes);
987         }
988       else
989         {
990           for (x = 0; x < rel_n_records (report->patched_regular_files); ++x)
991             {
992               t_uchar * item;
993               item = pika_save_escape_iso8859_1 (0, 0, escape_classes,
994                                                  rel_peek_str (report->patched_regular_files, x, 0));
995               safe_printfmt (out_fd, "    %s\n", no_dot (item));
996               lim_free (0, item);
997             }
998         }
999       safe_printfmt (out_fd, "\n");
1000     }
1001 }
1002 
1003 void
arch_free_changeset_report_data(struct arch_changeset_report * r)1004 arch_free_changeset_report_data (struct arch_changeset_report * r)
1005 {
1006   rel_free_table (r->orig_files_index);                 r->orig_files_index = rel_table_nil;
1007   rel_free_table (r->orig_dirs_index);                  r->orig_dirs_index = rel_table_nil;
1008   rel_free_table (r->mod_files_index);                  r->mod_files_index = rel_table_nil;
1009   rel_free_table (r->mod_dirs_index);                   r->mod_dirs_index = rel_table_nil;
1010 
1011   rel_free_table (r->removed_dirs);                     r->removed_dirs = rel_table_nil;
1012   rel_free_table (r->added_dirs);                       r->added_dirs = rel_table_nil;
1013 
1014   rel_free_table (r->removed_files);                    r->removed_files = rel_table_nil;
1015   rel_free_table (r->added_files);                      r->added_files = rel_table_nil;
1016 
1017   rel_free_table (r->removed_symlinks);                 r->removed_symlinks = rel_table_nil;
1018   rel_free_table (r->added_symlinks);                   r->added_symlinks = rel_table_nil;
1019 
1020   rel_free_table (r->renamed_files);                    r->renamed_files = rel_table_nil;
1021   rel_free_table (r->renamed_dirs);                     r->renamed_dirs = rel_table_nil;
1022 
1023   rel_free_table (r->patched_regular_files);            r->patched_regular_files = rel_table_nil;
1024   rel_free_table (r->patched_symlinks);                 r->patched_symlinks = rel_table_nil;
1025   rel_free_table (r->patched_binaries);                 r->patched_binaries = rel_table_nil;
1026   rel_free_table (r->file_metadata_changed);            r->file_metadata_changed = rel_table_nil;
1027   rel_free_table (r->dir_metadata_changed);             r->dir_metadata_changed = rel_table_nil;
1028   rel_free_table (r->symlink_to_file);                  r->symlink_to_file = rel_table_nil;
1029   rel_free_table (r->file_to_symlink);                  r->file_to_symlink = rel_table_nil;
1030 }
1031 
1032 
1033 
1034 
1035 static void
report_unique_files_and_symlinks(rel_table * files,rel_table * symlinks,rel_table index,t_uchar * archive_dir,t_uchar * archive_basename)1036 report_unique_files_and_symlinks (rel_table * files, rel_table * symlinks,
1037                                   rel_table index,
1038                                   t_uchar * archive_dir, t_uchar * archive_basename)
1039 {
1040   t_uchar * archive = 0;
1041   int lim;
1042   int x;
1043 
1044   archive = file_name_in_vicinity (0, archive_dir, archive_basename);
1045 
1046   lim = rel_n_records (index);
1047   for (x = 0; x < lim; ++x)
1048     {
1049       t_uchar * archive_path;
1050       struct stat stat_buf;
1051 
1052       archive_path = file_name_in_vicinity (0, archive, rel_peek_str (index, x, 0));
1053 
1054       safe_lstat (archive_path, &stat_buf);
1055 
1056       if (S_ISLNK (stat_buf.st_mode))
1057         {
1058           rel_add_records (symlinks,
1059                            rel_make_record_3_taking (rel_get_field (index, x, 0),
1060                                                      rel_get_field (index, x, 1),
1061                                                      rel_make_field_str (archive_path)),
1062                            rel_record_null);
1063         }
1064       else
1065         {
1066           rel_add_records (files,
1067                            rel_make_record_3_taking (rel_get_field (index, x, 0),
1068                                                      rel_get_field (index, x, 1),
1069                                                      rel_make_field_str (archive_path)),
1070                            rel_record_null);
1071         }
1072 
1073       lim_free (0, archive_path);
1074     }
1075 
1076   rel_sort_table_by_field (0, *files, 0);
1077   rel_sort_table_by_field (0, *symlinks, 0);
1078 
1079   lim_free (0, archive);
1080 }
1081 
1082 static void
find_renames(rel_table * out,rel_table common,assoc_table orig_dir_id_of,assoc_table mod_dir_id_of)1083 find_renames (rel_table * out, rel_table common, assoc_table orig_dir_id_of, assoc_table mod_dir_id_of)
1084 {
1085   int lim;
1086   int x;
1087 
1088   lim = rel_n_records (common);
1089   for (x = 0; x < lim; ++x)
1090     {
1091       rel_field orig_loc_field;
1092       rel_field mod_loc_field;
1093       rel_field id_field;
1094 
1095       const t_uchar * orig_loc;
1096       const t_uchar * mod_loc;
1097       const t_uchar * id;
1098 
1099       t_uchar * orig_basename = 0;
1100       t_uchar * mod_basename = 0;
1101       t_uchar * orig_dir = 0;
1102       t_uchar * mod_dir = 0;
1103       const t_uchar * orig_dir_id;
1104       const t_uchar * mod_dir_id;
1105 
1106       orig_loc_field = rel_get_field (common, x, 0);
1107       orig_loc = rel_field_str (orig_loc_field);
1108 
1109       mod_loc_field = rel_get_field (common, x, 1);
1110       mod_loc = rel_field_str (mod_loc_field);
1111 
1112       id_field = rel_get_field (common, x, 2);
1113       id = rel_field_str (id_field);
1114 
1115       orig_basename = file_name_tail (0, orig_loc);
1116       mod_basename = file_name_tail (0, mod_loc);
1117 
1118       orig_dir = file_name_directory_file (0, orig_loc);
1119       mod_dir = file_name_directory_file (0, mod_loc);
1120 
1121       orig_dir_id = assoc_get_str_taking (orig_dir_id_of, rel_make_field_str (orig_dir));
1122       mod_dir_id = assoc_get_str_taking (mod_dir_id_of, rel_make_field_str (mod_dir));
1123 
1124       /* The conditional subexpression here attempts to identify renames
1125        * even when the the changeset is missing locs and ids for
1126        * one or both of the containing dirs of the object under consideration.
1127        *
1128        */
1129 
1130       if (str_cmp (orig_basename, mod_basename)
1131           || ((orig_dir_id && mod_dir_id)
1132               ? str_cmp (orig_dir_id, mod_dir_id)
1133               : str_cmp (orig_dir, mod_dir)))
1134         {
1135           rel_field_ref (orig_loc_field);
1136           rel_field_ref (mod_loc_field);
1137           rel_field_ref (id_field);
1138           rel_add_records (out, rel_make_record_3_taking (orig_loc_field,
1139                                                           mod_loc_field,
1140                                                           id_field),
1141                            rel_record_null);
1142         }
1143 
1144 
1145       rel_field_unref (orig_loc_field);
1146       rel_field_unref (mod_loc_field);
1147       rel_field_unref (id_field);
1148 
1149       lim_free (0, orig_basename);
1150       lim_free (0, mod_basename);
1151       lim_free (0, orig_dir);
1152       lim_free (0, mod_dir);
1153     }
1154 }
1155 
1156 
1157 
1158 
1159 
1160 /* tag: Tom Lord Thu May 15 13:07:24 2003 (changeset-report.c)
1161  */
1162