1 /* apply-changeset.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/machine/types.h"
14 #include "hackerlab/os/errno.h"
15 #include "hackerlab/os/errno-to-string.h"
16 #include "hackerlab/os/limits.h"
17 #include "hackerlab/os/sys/types.h"
18 #include "hackerlab/os/sys/wait.h"
19 #include "hackerlab/os/signal.h"
20 #include "hackerlab/mem/mem.h"
21 #include "hackerlab/arrays/ar.h"
22 #include "hackerlab/char/str.h"
23 #include "hackerlab/fmt/cvt.h"
24 #include "hackerlab/fs/file-names.h"
25 #include "hackerlab/fs/cwd.h"
26 #include "hackerlab/vu/safe.h"
27 #include "hackerlab/char/pika-escaping-utils.h"
28 #include "tla/libfsutils/link-target.h"
29 #include "tla/libfsutils/read-line.h"
30 #include "tla/libfsutils/tmp-files.h"
31 #include "tla/libfsutils/rmrf.h"
32 #include "tla/libfsutils/ensure-dir.h"
33 #include "tla/libfsutils/copy-file.h"
34 #include "tla/libarch/diffs.h"
35 #include "tla/libawk/associative.h"
36 #include "tla/libawk/relassoc.h"
37 #include "tla/libarch/changelogs.h"
38 #include "tla/libarch/project-tree.h"
39 #include "tla/libarch/changeset-utils.h"
40 #include "tla/libarch/exec.h"
41 #include "tla/libarch/apply-changeset.h"
42 
43 
44 
45 struct running_inventory_assocs
46 {
47   assoc_table dir_loc_of;
48   assoc_table dir_id_of;
49   assoc_table file_loc_of;
50   assoc_table file_id_of;
51 };
52 
53 
54 /* __STDC__ prototypes for static functions */
55 
56 
57 
58 
59 static const t_uchar * no_dot (const t_uchar * name);
60 static void invoke_apply_changeset_callback (struct arch_apply_changeset_report * r,
61                                              const t_uchar * fmt, ...);
62 static t_uchar * set_aside_shuffled_dirs (rel_table * file_set_aside_with,
63                                           rel_table * dir_set_aside_with,
64                                           const t_uchar * target_loc,
65                                           const t_uchar * id,
66                                           int seq_n,
67                                           const t_uchar * dest_root,
68                                           struct running_inventory_assocs * running,
69                                           const t_uchar * target,
70                                           struct arch_changeset_inventory * inv);
71 static void preserve_old_patch_spew (const t_uchar * dest_root,
72                                      const t_uchar * target,
73                                      const t_uchar * loc);
74 static int deferred_conflict (rel_table * deferred_conflicts,
75                               const t_uchar * spew_root,
76                               const t_uchar * target,
77                               const t_uchar * loc,
78                               const t_uchar * orig_copy);
79 static int dir_depth_cmp (const t_uchar * a,
80                           const t_uchar * b);
81 static void analyze_install (struct running_inventory_assocs * running,
82                              int is_dir,
83                              t_uchar ** target_has_dir,
84                              t_uchar ** install_dir,
85                              t_uchar ** install_name,
86                              t_uchar ** install_loc,
87                              const t_uchar * target,
88                              const t_uchar * mod_loc,
89                              const t_uchar * id,
90                              assoc_table mod_dir_id_of,
91                              rel_table file_set_aside_with,
92                              rel_table dir_set_aside_with);
93 static void ensure_directory_eliminating_conflicts (rel_table * deferred_conflicts,
94                                                     const t_uchar * spew_root,
95                                                     const t_uchar * target_has_path,
96                                                     const t_uchar * dir,
97                                                     const t_uchar * target);
98 static int run_diff3 (const t_uchar * basename,
99                       const t_uchar * mine_path,
100                       const t_uchar * older_path,
101                       const t_uchar * yours_path);
102 static int run_patch  (int apply_in_reverse,
103                        int forward_opt_to_patch,
104                        const char * patch_path,
105                        const char * tree_file_base,
106                        const char * original_inode_name);
107 static void save_patch_for_missing_file (const t_uchar * missing_patch_dir,
108                                          const t_uchar * patch_path,
109                                          const t_uchar * mod_loc);
110 
111 
112 
113 int
arch_conflicts_occured(struct arch_apply_changeset_report * r)114 arch_conflicts_occured (struct arch_apply_changeset_report * r)
115 {
116   return (rel_n_records (r->conflict_files) || rel_n_records (r->conflict_dirs) || rel_n_records (r->metadata_conflict_files) || rel_n_records (r->metadata_conflict_dirs));
117 }
118 
119 
120 void
arch_free_apply_changeset_report_data(struct arch_apply_changeset_report * r)121 arch_free_apply_changeset_report_data (struct arch_apply_changeset_report * r)
122 {
123   rel_free_table (r->removed_files);
124   rel_free_table (r->removed_dirs);
125 
126   rel_free_table (r->missing_removed_files);
127   rel_free_table (r->missing_removed_dirs);
128 
129   rel_free_table (r->missing_renamed_files);
130   rel_free_table (r->missing_renamed_dirs);
131 
132   rel_free_table (r->new_dirs);
133   rel_free_table (r->renamed_dirs);
134   rel_free_table (r->new_files);
135   rel_free_table (r->renamed_files);
136 
137   rel_free_table (r->modified_files);
138   rel_free_table (r->modified_dirs);
139   rel_free_table (r->missing_file_for_patch);
140   rel_free_table (r->missing_dir_for_patch);
141 
142   rel_free_table (r->meta_modified_files);
143   rel_free_table (r->meta_modified_dirs);
144   rel_free_table (r->missing_file_for_meta_patch);
145   rel_free_table (r->missing_dir_for_meta_patch);
146 
147   rel_free_table (r->conflict_files);
148   rel_free_table (r->conflict_dirs);
149   rel_free_table (r->metadata_conflict_files);
150   rel_free_table (r->metadata_conflict_dirs);
151 }
152 
153 
154 static const t_uchar *
no_dot(const t_uchar * name)155 no_dot (const t_uchar * name)
156 {
157   if (name[0] == '.' && name[1] == '/')
158     return name + 2;
159   else
160     return name;
161 }
162 
163 
164 static int cut_fields_2_4_3_0[] = { 2, 4, 3, 0, -1 };
165 
166 void
arch_apply_changeset(struct arch_apply_changeset_report * r,const t_uchar * changeset_spec,const t_uchar * target_spec,enum arch_id_tagging_method method,enum arch_inventory_category untagged_source_category,int reverse,int forward,int use_diff3,assoc_table older_table,assoc_table yours_table,int escape_classes)167 arch_apply_changeset (struct arch_apply_changeset_report * r,
168                       const t_uchar * changeset_spec,
169                       const t_uchar * target_spec,
170                       enum arch_id_tagging_method method,
171                       enum arch_inventory_category untagged_source_category,
172                       int reverse,
173                       int forward,
174                       int use_diff3,
175                       assoc_table older_table,
176                       assoc_table yours_table,
177                       int escape_classes)
178 {
179   int x;
180   int here_fd;
181 
182   assoc_table mod_dir_id_of = 0;
183   assoc_table new_dir_perms = 0;
184 
185   t_uchar * changeset_path = 0;
186   t_uchar * target = 0;
187   t_uchar * missing_patch_dir = 0;
188   t_uchar * tree_root = 0;
189   int full_meta = 0;
190   struct arch_changeset_report changeset;
191   struct arch_changeset_inventory inventory;
192   struct arch_changeset_inventory inventory_by_name;
193 
194   rel_table removed_files_index = rel_table_nil;
195   t_uchar * tmp_removed_files_root = 0;
196 
197   rel_table renamed_files_index = rel_table_nil;
198   rel_table present_renamed_files_index = rel_table_nil; /* [0] tgtloc [1] origloc [2] modloc [3] id */
199   t_uchar * tmp_renamed_files_root = 0;
200 
201   rel_table renamed_dirs_index = rel_table_nil;
202   rel_table present_renamed_dirs_index = rel_table_nil; /* [0] tgtloc [1] origloc [2] modloc [3] id [4] tmp_name  (sort -r [0])*/
203 
204   rel_table removed_dirs_index = rel_table_nil;
205   rel_table present_removed_dirs_index = rel_table_nil; /* [0] tgtloc [1] id [2] tmp_name (sort -r [0]) */
206 
207   t_uchar * tmp_shuffled_dirs_root = 0;
208 
209   rel_table dir_set_aside_with_dir_id = rel_table_nil; /* [0] shuffled-dir-id [1] rel-loc-in-shuffled-dir [2] id */
210   rel_table file_set_aside_with_dir_id = rel_table_nil; /* [0] shuffled-dir-id [1] rel-loc-in-shuffled-dir [2] id */
211 
212   t_uchar * removed_patch_conflict_files_path = 0;
213 
214   struct running_inventory_assocs running = {0, 0, 0, 0};
215 
216   rel_table install_dirs_plan = rel_table_nil; /* [0] modloc [1] path-or-empty-str [2] id [3] oldtgtloc  */
217   rel_table deferred_conflicts = rel_table_nil; /* [0] final target location */
218 
219   rel_table added_files_and_symlinks = rel_table_nil;
220 
221   rel_table patched_changelogs = rel_table_nil; /* [0] final-loc [1] id [2] target_path */
222 
223   here_fd = safe_open (".", O_RDONLY, 0);
224 
225   safe_chdir (changeset_spec);
226   changeset_path = safe_current_working_directory ();
227   safe_fchdir (here_fd);
228 
229   safe_chdir (target_spec);
230   target = safe_current_working_directory ();
231   tree_root = arch_tree_root (0, ".", 0);
232   safe_fchdir (here_fd);
233 
234   full_meta = arch_tree_has_meta_flag (tree_root);
235 
236   missing_patch_dir = tmp_seq_file (tree_root, "++patches-missing-files");
237 
238   /****************************************************************
239    * Read and study the changeset.
240    */
241   mem_set0 ((t_uchar *)&changeset, sizeof (changeset));
242   arch_evaluate_changeset (&changeset, changeset_path);
243   if (reverse)
244     {
245       arch_reverse_changeset (&changeset);
246     }
247   mod_dir_id_of = rel_to_assoc (changeset.mod_dirs_index, 0, 1);
248   new_dir_perms = rel_to_assoc (changeset.added_dirs, 0, 2);
249 
250 
251   /****************************************************************
252    * Inventory the target tree.
253    */
254   mem_set0 ((t_uchar *)&inventory, sizeof (inventory));
255   arch_changeset_inventory (&inventory, tree_root, target, method,
256                             untagged_source_category, escape_classes);
257 
258   mem_set0 ((t_uchar *)&inventory_by_name, sizeof (inventory_by_name));
259 
260   inventory_by_name.dirs = rel_copy_table (inventory.dirs);
261   rel_sort_table_by_field (0, inventory_by_name.dirs, 0);
262 
263   inventory_by_name.files = rel_copy_table (inventory.files);
264   rel_sort_table_by_field (0, inventory_by_name.files, 0);
265 
266   /****************************************************************
267    * Build assoc tables of the inventory.
268    *
269    * These will be kept up-to-date as files and dirs get
270    * deleted, added, and renamed.
271    */
272   running.dir_loc_of = rel_to_assoc (inventory.dirs, 1, 0);
273   running.dir_id_of = rel_to_assoc (inventory.dirs, 0, 1);
274   running.file_loc_of = rel_to_assoc (inventory.files, 1, 0);
275   running.file_id_of = rel_to_assoc (inventory.files, 0, 1);
276 
277   assoc_set_taking (&running.dir_id_of, rel_make_field_str ("."), rel_make_field_str ("?_."));
278   assoc_set_taking (&running.dir_loc_of, rel_make_field_str ("?_."), rel_make_field_str ("."));
279 
280 
281   /****************************************************************
282    * Set aside and delete removed files.
283    */
284   removed_files_index = rel_copy_table (changeset.removed_files);
285   rel_append_x (&removed_files_index, changeset.removed_symlinks);
286   rel_sort_table_by_field (0, removed_files_index, 1);
287 
288   r->removed_files = rel_join (-1, rel_join_output (2,0, 2,1, -1), 1, 1, removed_files_index, inventory.files);
289   r->missing_removed_files = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, removed_files_index, inventory.files);
290 
291   rel_sort_table_by_field (0, r->removed_files, 0);
292   rel_sort_table_by_field (0, r->missing_removed_files, 0);
293 
294   tmp_removed_files_root = tmp_file_name (target, ",,tmp-removed-files");
295   rmrf_file (tmp_removed_files_root);
296   safe_mkdir (tmp_removed_files_root, 0777);
297 
298   for (x = 0; x < rel_n_records (r->removed_files); ++x)
299     {
300       rel_field target_loc_field;
301       rel_field target_id_field;
302       const t_uchar * target_loc = 0;
303       const t_uchar * target_id = 0;
304       t_uchar * target_path = 0;
305       t_uchar * dest_path = 0;
306       t_uchar * dest_dir = 0;
307       t_uchar * escaped_tmp = 0;
308 
309       target_loc_field = rel_get_field (r->removed_files, x, 0);
310       target_loc = rel_field_str (target_loc_field);
311 
312       target_id_field = rel_get_field (r->removed_files, x, 1);
313       target_id = rel_field_str (target_id_field);
314 
315       target_path = file_name_in_vicinity (0, target, target_loc);
316       dest_path = file_name_in_vicinity (0, tmp_removed_files_root, target_loc);
317       dest_dir = file_name_directory_file (0, dest_path);
318 
319       escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
320       invoke_apply_changeset_callback (r, "D   %s\n", no_dot (escaped_tmp));
321 
322       ensure_directory_exists (dest_dir);
323       safe_rename (target_path, dest_path);
324 
325       assoc_del_taking (running.file_id_of, rel_field_ref (target_loc_field));
326       assoc_del_taking (running.file_loc_of, rel_field_ref (target_id_field));
327 
328       rel_field_unref (target_loc_field);
329       rel_field_unref (target_id_field);
330 
331       lim_free (0, escaped_tmp);
332       lim_free (0, target_path);
333       lim_free (0, dest_path);
334       lim_free (0, dest_dir);
335     }
336 
337 
338   /****************************************************************
339    * Set aside renamed files.
340    */
341 
342   renamed_files_index = rel_copy_table (changeset.renamed_files);
343   rel_sort_table_by_field (0, renamed_files_index, 2);
344 
345   present_renamed_files_index = rel_join (-1, rel_join_output (2,0, 1,0, 1,1, 2,1, -1), 2, 1, renamed_files_index, inventory.files);
346   r->missing_renamed_files = rel_join (1, rel_join_output (1,0, 1,1, 1,2, -1), 2, 1, renamed_files_index, inventory.files);
347   for (x = 0; x < rel_n_records (r->missing_renamed_files); ++x)
348     {
349       t_uchar * escaped_tmp0;
350       t_uchar * escaped_tmp1;
351       escaped_tmp0 = pika_save_escape_iso8859_1 (0, 0, escape_classes, rel_peek_str (r->missing_renamed_files, x, 0));
352       escaped_tmp1 = pika_save_escape_iso8859_1 (0, 0, escape_classes, rel_peek_str (r->missing_renamed_files, x, 1));
353       invoke_apply_changeset_callback (r, "?r  %s\n     => %s\n",
354                                        no_dot (escaped_tmp0),
355                                        no_dot (escaped_tmp1));
356       lim_free (0, escaped_tmp1);
357       lim_free (0, escaped_tmp0);
358     }
359 
360   rel_sort_table_by_field (0, r->missing_removed_files, 0);
361 
362   tmp_renamed_files_root = tmp_file_name (target, ",,tmp-renamed-files");
363   rmrf_file (tmp_renamed_files_root);
364   safe_mkdir (tmp_renamed_files_root, 0777);
365 
366   for (x = 0; x < rel_n_records (present_renamed_files_index); ++x)
367     {
368       rel_field target_loc_field;
369       rel_field target_id_field;
370       const t_uchar * target_loc = 0;
371       const t_uchar * target_id = 0;
372       t_uchar * target_path = 0;
373       t_uchar * dest_path = 0;
374       t_uchar * dest_dir = 0;
375 
376       target_loc_field = rel_get_field (present_renamed_files_index, x, 0);
377       target_loc = rel_field_str (target_loc_field);
378 
379       target_id_field = rel_get_field (present_renamed_files_index, x, 3);
380       target_id = rel_field_str (target_id_field);
381 
382       target_path = file_name_in_vicinity (0, target, target_loc);
383       dest_path = file_name_in_vicinity (0, tmp_renamed_files_root, target_loc);
384       dest_dir = file_name_directory_file (0, dest_path);
385 
386       ensure_directory_exists (dest_dir);
387       safe_rename (target_path, dest_path);
388 
389       assoc_del_taking (running.file_id_of, rel_field_ref (target_loc_field));
390       assoc_del_taking (running.file_loc_of, rel_field_ref (target_id_field));
391 
392       rel_field_unref (target_loc_field);
393       rel_field_unref (target_id_field);
394 
395       lim_free (0, target_path);
396       lim_free (0, dest_path);
397       lim_free (0, dest_dir);
398     }
399 
400   /****************************************************************
401    * Set Aside Renamed and Removed Directories
402    */
403 
404   renamed_dirs_index = rel_copy_table (changeset.renamed_dirs);
405   rel_sort_table_by_field (0, renamed_dirs_index, 2);
406 
407   present_renamed_dirs_index = rel_join (-1, rel_join_output (2,0, 1,0, 1,1, 1,2, -1), 2, 1, renamed_dirs_index, inventory.dirs);
408   rel_sort_table_by_field (1, present_renamed_dirs_index, 0);
409 
410   r->missing_renamed_dirs = rel_join (1, rel_join_output (1,0, 1,1, 1,2, -1), 2, 1, renamed_dirs_index, inventory.dirs);
411   rel_sort_table_by_field (0, r->missing_renamed_dirs, 0);
412   for (x = 0; x < rel_n_records (r->missing_renamed_dirs); ++x)
413     {
414       t_uchar * escaped_tmp0;
415       t_uchar * escaped_tmp1;
416       escaped_tmp0 = pika_save_escape_iso8859_1 (0, 0, escape_classes, rel_peek_str (r->missing_renamed_dirs, x, 0));
417       escaped_tmp1 = pika_save_escape_iso8859_1 (0, 0, escape_classes, rel_peek_str (r->missing_renamed_dirs, x, 1));
418       invoke_apply_changeset_callback (r, "?r/ %s\n     => %s\n",
419                                        no_dot (escaped_tmp0),
420                                        no_dot (escaped_tmp1));
421       lim_free (0, escaped_tmp1);
422       lim_free (0, escaped_tmp0);
423     }
424 
425   removed_dirs_index = rel_copy_table (changeset.removed_dirs);
426   rel_sort_table_by_field (0, removed_dirs_index, 1);
427 
428   present_removed_dirs_index = rel_join (-1, rel_join_output (2,0, 2,1, -1), 1, 1, removed_dirs_index, inventory.dirs);
429   rel_sort_table_by_field (1, present_removed_dirs_index, 0);
430 
431   r->missing_removed_dirs = rel_join (1, rel_join_output (1,0, 1,1, -1), 1, 1, removed_dirs_index, inventory.dirs);
432   rel_sort_table_by_field (0, r->missing_removed_dirs, 0);
433 
434   tmp_shuffled_dirs_root = tmp_file_name (target, ",,tmp-shuffled-dirs");
435   rmrf_file (tmp_shuffled_dirs_root);
436   safe_mkdir (tmp_shuffled_dirs_root, 0777);
437 
438   /* It's important to set aside shuffled dirs from deepest
439    * to shallowest.
440    */
441   {
442     int seq;
443     int ren_pos;
444     int rem_pos;
445 
446     seq = 0;
447     ren_pos = 0;
448     rem_pos = 0;
449 
450     while (1)
451       {
452         int ren_done;
453         int rem_done;
454         int ren_first;
455         rel_field target_loc_field;
456         rel_field id_field;
457         const t_uchar * target_loc;
458         const t_uchar * id;
459         rel_table dest_table;
460         ssize_t dest_row;
461         t_uchar * tmp_name;
462 
463         ren_done = (ren_pos >= rel_n_records (present_renamed_dirs_index));
464         rem_done = (rem_pos >= rel_n_records (present_removed_dirs_index));
465 
466         if (ren_done && rem_done)
467           break;
468 
469         ren_first = (rem_done
470                      || (!ren_done && (0 < str_cmp (rel_peek_str (present_renamed_dirs_index, ren_pos, 0), rel_peek_str (present_removed_dirs_index, rem_pos, 0)))));
471 
472         if (ren_first)
473           {
474             target_loc = rel_peek_str (present_renamed_dirs_index, ren_pos, 0);
475             id = rel_peek_str (present_renamed_dirs_index, ren_pos, 3);
476 
477             dest_table = present_renamed_dirs_index;
478             dest_row = ren_pos;
479             ++ren_pos;
480           }
481         else
482           {
483             t_uchar * escaped_tmp;
484 
485             target_loc_field = rel_get_field (present_removed_dirs_index, rem_pos, 0);
486             target_loc = rel_field_str (target_loc_field);
487 
488             id_field = rel_get_field (present_removed_dirs_index, rem_pos, 1);
489             id = rel_field_str (id_field);
490 
491             dest_table = present_removed_dirs_index;
492             dest_row = rem_pos;
493             ++rem_pos;
494 
495             escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
496             invoke_apply_changeset_callback (r, "D/  %s\n", no_dot (escaped_tmp));
497             lim_free (0, escaped_tmp);
498 
499             rel_add_records (&r->removed_dirs,
500                              rel_make_record_2_taking (target_loc_field,
501                                                        id_field),
502                              rel_record_null);
503           }
504         tmp_name = set_aside_shuffled_dirs (&file_set_aside_with_dir_id, &dir_set_aside_with_dir_id, target_loc, id, seq, tmp_shuffled_dirs_root, &running, target, &inventory);
505         ++seq;
506         rel_add_field_to_row_taking (dest_table, dest_row, rel_make_field_str (tmp_name));
507         lim_free (0, tmp_name);
508       }
509 
510     rel_sort_table_by_field (0, r->removed_dirs, 0);
511     rel_sort_table_by_field (0, dir_set_aside_with_dir_id, 0);
512     rel_sort_table_by_field (0, file_set_aside_with_dir_id, 0);
513   }
514 
515   /****************************************************************
516    * Make a name for a dir in which to stash removed .rej and .orig files
517    */
518   removed_patch_conflict_files_path = tmp_file_name (target, "+removed-conflict-files");
519 
520 
521   /****************************************************************
522    * What we have:
523    *
524    *    We have the target tree, with all renamed/removed dirs and files
525    *    set aside.
526    *
527    *    The removed files are all under $tmp_removed_files_root/$tgtloc.
528    *
529    *    The renamed files are all under $tmp_renamed_files_root/$tgtloc.
530    *
531    *        (in both of the above cases, $tgtloc is the original target loc)
532    *
533    *    Both the renamed and removed directories are set aside
534    *    in $tmp_shuffled_dirs_root under integer filenames.
535    *    The tmp_name fields of present_renamed_dirs_index and
536    *    present_renamed_dirs_index are full paths to these temp
537    *    names.
538    *
539    * Todo:
540    *
541    *    We have to install renamed and new directories, from shallowest to
542    *    deepest, then install renamed and new files (in any order).
543    *
544    *    Each installed item has a destination path that has, in essense,
545    *    three parts:
546    *
547    *            $tgthas / $newrelpath / $basename
548    *
549    *    where $tgthas is the deepest part of the destination path that
550    *    the target tree already has when the item is installed,
551    *    $newrelpath are additional intermediate directories that need to
552    *    be created (possibly causing conflicts) and $basename is the final
553    *    name for the item (possibly causing a conflict).
554    *
555    *    That three part path is derived from the $modloc of the item
556    *    by finding the deepest containing directory in $modloc which
557    *    is present (by id) in $target (that's $tgthas).
558    *
559    *    In the code that follows:
560    *
561    *            tgthas == $tgthas
562    *            install_dir == $tgthas / $newrelpath
563    *            install_name == $tgthas / $newrelpath / $basename
564    *
565    *    Finally, then, we have to apply individual file and dir patches.
566    */
567 
568   /****************************************************************
569    * Compute an install plan for new and renamed directories.
570    *
571    * We have to add or rename containing dirs before contained.
572    *
573    * So, we need a plan for that.
574    */
575 
576   install_dirs_plan = rel_cut (cut_fields_2_4_3_0, present_renamed_dirs_index);
577   for (x = 0; x < rel_n_records (changeset.added_dirs); ++x)
578     {
579       rel_add_records (&install_dirs_plan,
580                        rel_make_record_3_taking (rel_get_field (changeset.added_dirs, x, 0),
581                                                  rel_make_field_str (""),
582                                                  rel_get_field (changeset.added_dirs, x, 1)),
583                        rel_record_null);
584     }
585   rel_sort_table_by_field_fn (0, install_dirs_plan, 0, dir_depth_cmp);
586 
587 
588   /****************************************************************
589    * Install dirs.
590    */
591   for (x = 0; x < rel_n_records (install_dirs_plan); ++x)
592     {
593       rel_field mod_loc_field;
594       rel_field take_from_field;
595       rel_field id_field;
596       const t_uchar * mod_loc;
597       const t_uchar * take_from;
598       const t_uchar * id;
599 
600       t_uchar * target_has_dir = 0;
601       t_uchar * target_has_path = 0;
602       t_uchar * install_dir = 0;
603       t_uchar * install_name = 0;
604       t_uchar * install_loc = 0;
605 
606       mod_loc_field = rel_get_field (install_dirs_plan, x, 0);
607       mod_loc = rel_field_str (mod_loc_field);
608 
609       take_from_field = rel_get_field (install_dirs_plan, x, 1);
610       take_from = rel_field_str (take_from_field);
611 
612       id_field = rel_get_field (install_dirs_plan, x, 2);
613       id = rel_field_str (id_field);
614 
615       if (!*take_from)
616         take_from = 0;
617 
618       analyze_install (&running, 1, &target_has_dir, &install_dir, &install_name, &install_loc,
619                        target, mod_loc, id, mod_dir_id_of,
620                        file_set_aside_with_dir_id, dir_set_aside_with_dir_id);
621 
622       if (!str_cmp (target_has_dir, "."))
623         target_has_path = str_save (0, target);
624       else
625         target_has_path = file_name_in_vicinity (0, target, 2 + target_has_dir); /* over "./" */
626 
627       ensure_directory_eliminating_conflicts (&deferred_conflicts,
628                                               removed_patch_conflict_files_path,
629                                               target_has_path, install_dir, target);
630 
631       if (!take_from)
632         {
633           if (!safe_file_is_directory (install_name))
634             {
635               int trust_umask = 0;
636               const t_uchar * perms_str;
637               unsigned long perms;
638               long uid;
639               long gid;
640               t_uchar * escaped_tmp = 0;
641 
642               perms_str = assoc_get_str_taking (new_dir_perms, rel_field_ref (mod_loc_field));
643 
644               if (!perms_str)
645                 {
646                   perms = 0777;
647                   trust_umask = 1;
648                   uid = -1;
649                   gid = -1;
650                 }
651 
652               perms = arch_parse_permissions_params (&uid, &gid, perms_str);
653               if (full_meta)
654                 {
655                   perms = (perms & 07777);
656                 }
657               else
658                 {
659                   perms = (perms & 0777);
660                 }
661 
662               escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, install_loc);
663 
664               if (!deferred_conflict (&deferred_conflicts, removed_patch_conflict_files_path, target, install_loc, 0))
665                 {
666                   invoke_apply_changeset_callback (r, "A/  %s\n", no_dot (escaped_tmp));
667                   rel_add_records (&r->new_dirs, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
668                 }
669               else
670                 {
671                   invoke_apply_changeset_callback (r, "CA/ %s\n", no_dot (escaped_tmp));
672                   rel_add_records (&r->conflict_dirs, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
673                 }
674 
675               safe_mkdir (install_name, perms);
676               if (!trust_umask)
677                 {
678                   safe_chmod (install_name, perms);
679                   if (full_meta && (uid > 0) && (gid > 0))
680                     safe_chown (install_name, uid, gid);
681                 }
682 
683               lim_free (0, escaped_tmp);
684             }
685         }
686       else
687         {
688           rel_field oldtgtloc_field;
689           const t_uchar * oldtgtloc;
690           t_uchar * escaped_tmp0 = 0;
691           t_uchar * escaped_tmp1 = 0;
692 
693           oldtgtloc_field = rel_get_field (install_dirs_plan, x, 3);
694           oldtgtloc = rel_field_str (oldtgtloc_field);
695 
696           escaped_tmp0 = pika_save_escape_iso8859_1 (0, 0, escape_classes, oldtgtloc);
697           escaped_tmp1 = pika_save_escape_iso8859_1 (0, 0, escape_classes, install_loc);
698 
699           if (!deferred_conflict (&deferred_conflicts, removed_patch_conflict_files_path, target, install_loc, 0))
700             {
701               invoke_apply_changeset_callback (r, "/>  %s\t%s\n", escaped_tmp0, no_dot (escaped_tmp1));
702               rel_add_records (&r->renamed_dirs,
703                                rel_make_record_3_taking (rel_field_ref (oldtgtloc_field),
704                                                          rel_make_field_str (install_loc),
705                                                          id_field),
706                                rel_record_null);
707             }
708           else
709             {
710               invoke_apply_changeset_callback (r, "C/> %s\t%s\n", escaped_tmp0, no_dot (escaped_tmp1));
711               rel_add_records (&r->conflict_dirs, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
712             }
713 
714           rel_field_unref (oldtgtloc_field);
715           safe_rename (take_from, install_name);
716           lim_free (0, escaped_tmp1);
717           lim_free (0, escaped_tmp0);
718         }
719 
720       rel_field_unref (mod_loc_field);
721       rel_field_unref (take_from_field);
722       rel_field_unref (id_field);
723 
724       lim_free (0, target_has_dir);
725       lim_free (0, target_has_path);
726       lim_free (0, install_dir);
727       lim_free (0, install_name);
728       lim_free (0, install_loc);
729     }
730 
731   rel_sort_table_by_field (0, r->new_dirs, 0);
732   rel_sort_table_by_field (0, r->renamed_dirs, 0);
733 
734   /****************************************************************
735    * Install Renamed Files and Symlinks
736    */
737 
738   for (x = 0; x < rel_n_records (present_renamed_files_index); ++x)
739     {
740       rel_field old_target_loc_field;
741       rel_field mod_loc_field;
742       rel_field id_field;
743 
744       const t_uchar * old_target_loc;
745       const t_uchar * mod_loc;
746       const t_uchar * id;
747 
748       t_uchar * take_from = 0;
749 
750       t_uchar * target_has_dir = 0;
751       t_uchar * install_dir = 0;
752       t_uchar * install_name = 0;
753       t_uchar * install_loc = 0;
754 
755       t_uchar * target_has_path = 0;
756 
757       t_uchar * escaped_tmp0 = 0;
758       t_uchar * escaped_tmp1 = 0;
759 
760       old_target_loc_field = rel_get_field (present_renamed_files_index, x, 0);
761       old_target_loc = rel_field_str (old_target_loc_field);
762 
763       mod_loc_field = rel_get_field (present_renamed_files_index, x, 2);
764       mod_loc = rel_field_str (mod_loc_field);
765 
766       id_field = rel_get_field (present_renamed_files_index, x, 3);
767       id = rel_field_str (id_field);
768 
769       take_from = file_name_in_vicinity (0, tmp_renamed_files_root, old_target_loc);
770 
771       analyze_install (&running, 0, &target_has_dir, &install_dir, &install_name, &install_loc,
772                        target, mod_loc, id, mod_dir_id_of, rel_table_nil, rel_table_nil);
773 
774       if (!str_cmp (target_has_dir, "."))
775         target_has_path = str_save (0, target);
776       else
777         target_has_path = file_name_in_vicinity (0, target, 2 + target_has_dir); /* over "./" */
778 
779       ensure_directory_eliminating_conflicts (&deferred_conflicts,
780                                               removed_patch_conflict_files_path,
781                                               target_has_path, install_dir, target);
782 
783       escaped_tmp0 = pika_save_escape_iso8859_1 (0, 0, escape_classes, old_target_loc);
784       escaped_tmp1 = pika_save_escape_iso8859_1 (0, 0, escape_classes, install_loc);
785 
786       if (!deferred_conflict (&deferred_conflicts, removed_patch_conflict_files_path, target, install_loc, 0))
787         {
788           invoke_apply_changeset_callback (r, "=>  %s\t%s\n", escaped_tmp0, no_dot (escaped_tmp1));
789           rel_add_records (&r->renamed_files,
790                            rel_make_record_3_taking (rel_field_ref (old_target_loc_field),
791                                                      rel_make_field_str (install_loc),
792                                                      rel_field_ref (id_field)),
793                            rel_record_null);
794         }
795       else
796         {
797           invoke_apply_changeset_callback (r, "C=> %s\t%s\n", escaped_tmp0, no_dot (escaped_tmp1));
798           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
799         }
800 
801       safe_rename (take_from, install_name);
802 
803       rel_field_unref (old_target_loc_field);
804       rel_field_unref (mod_loc_field);
805       rel_field_unref (id_field);
806 
807       lim_free (0, escaped_tmp1);
808       lim_free (0, escaped_tmp0);
809       lim_free (0, take_from);
810       lim_free (0, target_has_dir);
811       lim_free (0, install_dir);
812       lim_free (0, install_name);
813       lim_free (0, install_loc);
814       lim_free (0, target_has_path);
815     }
816 
817 
818   added_files_and_symlinks = rel_copy_table (changeset.added_files);
819   rel_append_x (&added_files_and_symlinks, changeset.added_symlinks);
820 
821   for (x = 0; x < rel_n_records (added_files_and_symlinks); ++x)
822     {
823       const t_uchar * mod_loc;
824       rel_field id_field;
825       const t_uchar * id;
826       const t_uchar * take_from;
827 
828       t_uchar * target_has_dir = 0;
829       t_uchar * install_dir = 0;
830       t_uchar * install_name = 0;
831       t_uchar * install_loc = 0;
832 
833       t_uchar * target_has_path = 0;
834 
835       t_uchar * escaped_tmp = 0;
836 
837       mod_loc = rel_peek_str (added_files_and_symlinks, x, 0);
838 
839       id_field = rel_get_field (added_files_and_symlinks, x, 1);
840       id = rel_field_str (id_field);
841 
842       take_from = rel_peek_str (added_files_and_symlinks, x, 2);
843 
844       analyze_install (&running, 0, &target_has_dir, &install_dir, &install_name, &install_loc,
845                        target, mod_loc, id, mod_dir_id_of, rel_table_nil, rel_table_nil);
846 
847       if (!str_cmp (target_has_dir, "."))
848         target_has_path = str_save (0, target);
849       else
850         target_has_path = file_name_in_vicinity (0, target, 2 + target_has_dir); /* over "./" */
851 
852       ensure_directory_eliminating_conflicts (&deferred_conflicts,
853                                               removed_patch_conflict_files_path,
854                                               target_has_path, install_dir, target);
855 
856       escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, install_loc);
857 
858       if (!deferred_conflict (&deferred_conflicts, removed_patch_conflict_files_path, target, install_loc, take_from))
859         {
860           invoke_apply_changeset_callback (r, "A   %s\n", no_dot (escaped_tmp));
861           rel_add_records (&r->new_files, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
862         }
863       else
864         {
865           invoke_apply_changeset_callback (r, "CA  %s\n", no_dot (escaped_tmp));
866           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_make_field_str (install_loc), rel_field_ref (id_field)), rel_record_null);
867         }
868 
869       copy_file_or_symlink (take_from, install_name);
870       copy_permissions (take_from, install_name, full_meta);
871 
872       rel_field_unref (id_field);
873 
874       lim_free (0, escaped_tmp);
875       lim_free (0, target_has_dir);
876       lim_free (0, install_dir);
877       lim_free (0, install_name);
878       lim_free (0, install_loc);
879       lim_free (0, target_has_path);
880     }
881 
882   rel_sort_table_by_field (0, r->renamed_files, 0);
883 
884 
885   /****************************************************************
886    * Patch Regular Files
887    */
888 
889   for (x = 0; x < rel_n_records (changeset.patched_regular_files); ++x)
890     {
891       rel_field mod_loc_field;
892       rel_field id_field;
893       rel_field target_loc_field;
894       const t_uchar * mod_loc;
895       const t_uchar * id;
896       const t_uchar * target_loc;
897       t_uchar * patch_path = 0;
898       t_uchar * target_path = 0;
899       t_uchar * escaped_tmp = 0;
900       struct stat target_stat;
901 
902       patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_regular_files, x, 2), ".patch");
903 
904       mod_loc_field = rel_get_field (changeset.patched_regular_files, x, 0);
905       mod_loc = rel_field_str (mod_loc_field);
906 
907       id_field = rel_get_field (changeset.patched_regular_files, x, 1);
908       id = rel_field_str (id_field);
909 
910       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
911       target_loc = rel_field_str (target_loc_field);
912 
913       if (!target_loc)
914         {
915           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
916           invoke_apply_changeset_callback (r, "?M  %s\n", no_dot (escaped_tmp));
917           rel_add_records (&r->missing_file_for_patch, rel_make_record_2_taking (rel_field_ref (mod_loc_field), rel_field_ref (id_field)), rel_record_null);
918           save_patch_for_missing_file (missing_patch_dir, patch_path, mod_loc);
919           lim_free (0, escaped_tmp);
920           continue;
921         }
922 
923       target_path = file_name_in_vicinity (0, target, target_loc);
924 
925       safe_lstat (target_path, &target_stat);
926 
927       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_loc);
928 
929       if (S_ISLNK (target_stat.st_mode))
930         {
931           t_uchar * orig_name;
932           t_uchar * rej_name;
933 
934           orig_name = str_alloc_cat (0, target_path, ".orig");
935           rej_name = str_alloc_cat (0, target_path, ".rej");
936           safe_rename (target_path, orig_name);
937           copy_file (patch_path, rej_name);
938           copy_permissions (patch_path, rej_name, full_meta);
939 
940           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
941           invoke_apply_changeset_callback (r, "C-> %s\n", no_dot (escaped_tmp));
942           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
943           lim_free (0, escaped_tmp);
944         }
945       else if (arch_id_indicates_changelog (id))
946         {
947           rel_add_records (&patched_changelogs,
948                            rel_make_record_3_taking (rel_field_ref (target_loc_field),
949                                                      rel_field_ref (id_field),
950                                                      rel_make_field_str (target_path)),
951                            rel_record_null);
952         }
953       else
954         {
955           struct stat patch_file_stat;
956 
957           safe_stat (patch_path, &patch_file_stat);
958 
959           if (patch_file_stat.st_size)
960             {
961               int errn;
962               t_uchar * target_dir = 0;
963               t_uchar * basename = 0;
964               t_uchar * original_inode_basename = 0;
965               t_uchar * original_inode_tmpname = 0;
966               int patch_stat = -1;
967 
968               target_dir = file_name_directory_file (0, target_path);
969               basename = file_name_tail (0, target_path);
970               original_inode_basename = str_alloc_cat_many (0, ",,dopatch.", basename, ".", str_end);
971 
972               safe_chdir (target_dir);
973 
974               original_inode_tmpname = tmp_file_name (".", original_inode_basename);
975               safe_rename (basename, original_inode_tmpname);
976 
977               if (vu_unlink (&errn, ",,patch-output") && (errn != ENOENT))
978                 {
979                   safe_printfmt (2, "arch_apply_changeset: unable to unlink file\n");
980                   safe_printfmt (2, "  file: %s/,,patch-output\n", target_dir);
981                   safe_printfmt (2, "  error: %s\n", errno_to_string (errn));
982                   exit (2);
983                 }
984 
985               if (!use_diff3)
986                 {
987                 run_patch_anyway:
988                   patch_stat = run_patch (reverse, forward, patch_path, basename, original_inode_tmpname);
989                 }
990               else
991                 {
992                   const t_uchar * older_path;
993                   const t_uchar * yours_path;
994 
995                   older_path = assoc_get_str_taking (older_table, rel_field_ref (id_field));
996                   yours_path = assoc_get_str_taking (yours_table, rel_field_ref (id_field));
997 
998                   if (!(older_path && yours_path))
999                     goto run_patch_anyway;
1000 
1001                   if (!reverse)
1002                     patch_stat = run_diff3 (basename, original_inode_tmpname, older_path, yours_path);
1003                   else
1004                     patch_stat = run_diff3 (basename, original_inode_tmpname, yours_path, older_path);
1005                 }
1006 
1007               if (patch_stat == 0)
1008                 {
1009                   copy_permissions (original_inode_tmpname, basename, full_meta);
1010                   safe_unlink (original_inode_tmpname);
1011 
1012                   escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1013                   invoke_apply_changeset_callback (r, "M   %s\n",
1014                                                    no_dot (escaped_tmp));
1015                   rel_add_records (&r->modified_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1016                   lim_free (0, escaped_tmp);
1017                 }
1018               else if (patch_stat == 1)
1019                 {
1020                   t_uchar * orig_name;
1021 
1022                   copy_permissions (original_inode_tmpname, basename, full_meta);
1023                   orig_name = str_alloc_cat (0, basename, ".orig");
1024                   safe_rename (original_inode_tmpname, orig_name);
1025 
1026                   escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1027                   invoke_apply_changeset_callback (r, "C   %s\n",
1028                                                    no_dot (escaped_tmp));
1029                   rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1030 
1031                   lim_free (0, escaped_tmp);
1032                   lim_free (0, orig_name);
1033                 }
1034               else
1035                 {
1036                   int in_fd;
1037 
1038                   safe_printfmt (2, "arch_apply_changeset: internal error (patch(1) returned odd status)\n");
1039                   safe_printfmt (2, "   patch(1) exit status: %d\n", patch_stat);
1040                   safe_printfmt (2, "\n");
1041                   in_fd = safe_open (",,patch-output", O_RDONLY, 0);
1042                   copy_fd (in_fd, 2);
1043                   safe_printfmt (2, "\n");
1044                   exit (2);
1045                 }
1046 
1047               if (vu_unlink (&errn, ",,patch-output") && (errn != ENOENT))
1048                 {
1049                   safe_printfmt (2, "arch_apply_changeset: unable to unlink file\n");
1050                   safe_printfmt (2, "  file: %s/,,patch-output\n", target_dir);
1051                   safe_printfmt (2, "  error: %s\n", errno_to_string (errn));
1052                   exit (2);
1053                 }
1054 
1055               safe_fchdir (here_fd);
1056 
1057               lim_free (0, target_dir);
1058               lim_free (0, basename);
1059               lim_free (0, original_inode_basename);
1060               lim_free (0, original_inode_tmpname);
1061             }
1062         }
1063 
1064       rel_field_unref (mod_loc_field);
1065       rel_field_unref (id_field);
1066       rel_field_unref (target_loc_field);
1067 
1068       lim_free (0, patch_path);
1069       lim_free (0, target_path);
1070     }
1071 
1072   /****************************************************************
1073    * Patch Symlinks
1074    */
1075 
1076   for (x = 0; x < rel_n_records (changeset.patched_symlinks); ++x)
1077     {
1078       rel_field mod_loc_field;
1079       rel_field id_field;
1080       rel_field target_loc_field;
1081 
1082       const t_uchar * mod_loc;
1083       const t_uchar * id;
1084       const t_uchar * target_loc;
1085 
1086       t_uchar * orig_patch_path = 0;
1087       t_uchar * mod_patch_path = 0;
1088       t_uchar * target_path = 0;
1089       t_uchar * escaped_tmp = 0;
1090       struct stat target_stat;
1091 
1092       if (!reverse)
1093         {
1094           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_symlinks, x, 2), ".link-orig");
1095           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_symlinks, x, 2), ".link-mod");
1096         }
1097       else
1098         {
1099           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_symlinks, x, 2), ".link-mod");
1100           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_symlinks, x, 2), ".link-orig");
1101         }
1102 
1103       mod_loc_field = rel_get_field (changeset.patched_symlinks, x, 0);
1104       mod_loc = rel_field_str (mod_loc_field);
1105 
1106       id_field = rel_get_field (changeset.patched_symlinks, x, 1);
1107       id = rel_field_str (id_field);
1108 
1109       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
1110       target_loc = rel_field_str (target_loc_field);
1111 
1112       if (!target_loc)
1113         {
1114           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1115           invoke_apply_changeset_callback (r, "?M  %s\n", no_dot (escaped_tmp));
1116           rel_add_records (&r->missing_file_for_patch, rel_make_record_2_taking (rel_field_ref (mod_loc_field), rel_field_ref (id_field)), rel_record_null);
1117           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1118           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1119           lim_free (0, escaped_tmp);
1120           continue;
1121         }
1122 
1123       target_path = file_name_in_vicinity (0, target, target_loc);
1124 
1125       safe_lstat (target_path, &target_stat);
1126 
1127       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_loc);
1128 
1129       if (!S_ISLNK (target_stat.st_mode))
1130         {
1131           t_uchar * orig_name = 0;
1132           t_uchar * rej_name = 0;
1133           int out_fd;
1134           int in_fd;
1135 
1136         symlink_conflict:
1137 
1138           orig_name = str_alloc_cat (0, target_path, ".orig");
1139           rej_name = str_alloc_cat (0, target_path, ".rej");
1140           safe_rename (target_path, orig_name);
1141 
1142           out_fd = safe_open (rej_name, O_WRONLY | O_CREAT | O_EXCL, 0666);
1143           safe_printfmt (out_fd, "Patched wanted to retarget a symbolic link:\n\n");
1144           safe_printfmt (out_fd, "  from: ");
1145           in_fd = safe_open (orig_patch_path, O_RDONLY, 0);
1146           copy_fd (in_fd, out_fd);
1147           safe_close (in_fd);
1148           safe_printfmt (out_fd, "\n to: ");
1149           in_fd = safe_open (mod_patch_path, O_RDONLY, 0);
1150           copy_fd (in_fd, out_fd);
1151           safe_close (in_fd);
1152           safe_printfmt (out_fd, "\n");
1153 
1154           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1155           invoke_apply_changeset_callback (r, "C-> %s\n", no_dot (escaped_tmp));
1156           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1157 
1158           lim_free (0, escaped_tmp);
1159           lim_free (0, orig_name);
1160           lim_free (0, rej_name);
1161         }
1162       else
1163         {
1164           /****************************************************************
1165            * FIX THIS
1166            *
1167            * Strictly speaking:
1168            *
1169            * We should really try to "remap" the orig and mod link targets for
1170            * the current tree layout.
1171            */
1172           t_uchar * orig_link_target = 0;
1173           t_uchar * mod_link_target = 0;
1174           t_uchar * tree_link_target = 0;
1175           int patch_stat;
1176 
1177           orig_link_target = read_line_from_file (orig_patch_path);
1178           mod_link_target = read_line_from_file (mod_patch_path);
1179           tree_link_target = link_target (target_path);
1180 
1181           if (!str_cmp (mod_link_target, tree_link_target))
1182             {
1183               patch_stat = 0;
1184             }
1185           else if (!str_cmp (orig_link_target, tree_link_target))
1186             {
1187               t_uchar * target_path_dir = 0;
1188               t_uchar * target_path_tail = 0;
1189               t_uchar * tmp_file_basename = 0;
1190               t_uchar * tmp_file_path = 0;
1191 
1192               target_path_dir = file_name_directory_file (0, target_path);
1193               target_path_tail = file_name_tail (0, target_path);
1194               tmp_file_basename = str_alloc_cat_many (0, ",,dopatch.", target_path_tail, ".", str_end);
1195               tmp_file_path = tmp_file_name (target_path_dir, tmp_file_basename);
1196 
1197               rmrf_file (tmp_file_path);
1198               safe_rename (target_path, tmp_file_path);
1199               safe_symlink (mod_link_target, target_path);
1200               safe_unlink (tmp_file_path);
1201               patch_stat = 0;
1202 
1203               lim_free (0, target_path_dir);
1204               lim_free (0, target_path_tail);
1205               lim_free (0, tmp_file_basename);
1206               lim_free (0, tmp_file_path);
1207             }
1208           else
1209             {
1210               patch_stat = 1;
1211             }
1212 
1213           if (patch_stat == 0)
1214             {
1215               escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1216               invoke_apply_changeset_callback (r, "M-> %s\n",
1217                                                no_dot (escaped_tmp));
1218               rel_add_records (&r->modified_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1219               lim_free (0, escaped_tmp);
1220             }
1221           else
1222             goto symlink_conflict;
1223 
1224           lim_free (0, orig_link_target);
1225           lim_free (0, mod_link_target);
1226           lim_free (0, tree_link_target);
1227         }
1228 
1229       rel_field_unref (mod_loc_field);
1230       rel_field_unref (id_field);
1231       rel_field_unref (target_loc_field);
1232 
1233       lim_free (0, orig_patch_path);
1234       lim_free (0, mod_patch_path);
1235       lim_free (0, target_path);
1236     }
1237 
1238 
1239   /****************************************************************
1240    * Patch Binaries
1241    */
1242 
1243   for (x = 0; x < rel_n_records (changeset.patched_binaries); ++x)
1244     {
1245       rel_field mod_loc_field;
1246       rel_field id_field;
1247       rel_field target_loc_field;
1248 
1249       const t_uchar * mod_loc;
1250       const t_uchar * id;
1251       const t_uchar * target_loc;
1252 
1253       t_uchar * orig_patch_path = 0;
1254       t_uchar * mod_patch_path = 0;
1255       t_uchar * target_path = 0;
1256       t_uchar * escaped_tmp = 0;
1257       struct stat target_stat;
1258 
1259       if (!reverse)
1260         {
1261           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_binaries, x, 2), ".original");
1262           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_binaries, x, 2), ".modified");
1263         }
1264       else
1265         {
1266           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_binaries, x, 2), ".modified");
1267           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.patched_binaries, x, 2), ".original");
1268         }
1269 
1270       mod_loc_field = rel_get_field (changeset.patched_binaries, x, 0);
1271       mod_loc = rel_field_str (mod_loc_field);
1272 
1273       id_field = rel_get_field (changeset.patched_binaries, x, 1);
1274       id = rel_field_str (id_field);
1275 
1276       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
1277       target_loc = rel_field_str (target_loc_field);
1278 
1279       if (!target_loc)
1280         {
1281           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1282           invoke_apply_changeset_callback (r, "?M  %s\n", no_dot (escaped_tmp));
1283           rel_add_records (&r->missing_file_for_patch, rel_make_record_2_taking (rel_field_ref (mod_loc_field), rel_field_ref (id_field)), rel_record_null);
1284           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1285           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1286           lim_free (0, escaped_tmp);
1287           continue;
1288         }
1289 
1290       target_path = file_name_in_vicinity (0, target, target_loc);
1291 
1292       safe_lstat (target_path, &target_stat);
1293 
1294       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_loc);
1295 
1296       if (S_ISLNK (target_stat.st_mode))
1297         {
1298           t_uchar * orig_name;
1299           t_uchar * rej_name;
1300 
1301         binary_conflict:
1302 
1303           orig_name = str_alloc_cat (0, target_path, ".orig");
1304           rej_name = str_alloc_cat (0, target_path, ".rej");
1305           safe_rename (target_path, orig_name);
1306           copy_file (mod_patch_path, rej_name);
1307           copy_permissions (mod_patch_path, rej_name, full_meta);
1308 
1309           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1310           invoke_apply_changeset_callback (r, "Cb  %s\n", no_dot (escaped_tmp));
1311           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1312 
1313           lim_free (0, escaped_tmp);
1314           lim_free (0, orig_name);
1315           lim_free (0, rej_name);
1316         }
1317       else
1318         {
1319           int patch_stat;
1320 
1321           if (arch_binary_files_differ (orig_patch_path, target_path, 0, 0))
1322             {
1323               patch_stat = 1;
1324             }
1325           else
1326             {
1327               t_uchar * target_path_dir = 0;
1328               t_uchar * target_path_tail = 0;
1329               t_uchar * tmp_file_basename = 0;
1330               t_uchar * tmp_file_path = 0;
1331 
1332               target_path_dir = file_name_directory_file (0, target_path);
1333               target_path_tail = file_name_tail (0, target_path);
1334               tmp_file_basename = str_alloc_cat_many (0, ",,dopatch.", target_path_tail, ".", str_end);
1335               tmp_file_path = tmp_file_name (target_path_dir, tmp_file_basename);
1336 
1337               rmrf_file (tmp_file_path);
1338               safe_rename (target_path, tmp_file_path);
1339               copy_file (mod_patch_path, target_path);
1340               copy_permissions (mod_patch_path, target_path, full_meta);
1341               safe_unlink (tmp_file_path);
1342               patch_stat = 0;
1343 
1344               lim_free (0, target_path_dir);
1345               lim_free (0, target_path_tail);
1346               lim_free (0, tmp_file_basename);
1347               lim_free (0, tmp_file_path);
1348             }
1349 
1350           if (patch_stat == 0)
1351             {
1352               escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1353               invoke_apply_changeset_callback (r, "Mb  %s\n",
1354                                                no_dot (escaped_tmp));
1355               rel_add_records (&r->modified_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1356               lim_free (0, escaped_tmp);
1357             }
1358           else
1359             goto binary_conflict;
1360         }
1361 
1362       rel_field_unref (mod_loc_field);
1363       rel_field_unref (id_field);
1364       rel_field_unref (target_loc_field);
1365 
1366       lim_free (0, orig_patch_path);
1367       lim_free (0, mod_patch_path);
1368       lim_free (0, target_path);
1369     }
1370 
1371 
1372   /****************************************************************
1373    * Symlinks->File Patches
1374    */
1375 
1376   for (x = 0; x < rel_n_records (changeset.symlink_to_file); ++x)
1377     {
1378       rel_field mod_loc_field;
1379       rel_field id_field;
1380       rel_field target_loc_field;
1381 
1382       const t_uchar * mod_loc;
1383       const t_uchar * id;
1384       const t_uchar * target_loc;
1385       t_uchar * orig_patch_path = 0;
1386       t_uchar * mod_patch_path = 0;
1387       t_uchar * target_path = 0;
1388       t_uchar * escaped_tmp = 0;
1389       struct stat target_stat;
1390 
1391       if (!reverse)
1392         {
1393           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.symlink_to_file, x, 2), ".link-orig");
1394           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.symlink_to_file, x, 2), ".modified");
1395         }
1396       else
1397         {
1398           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.symlink_to_file, x, 2), ".modified");
1399           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.symlink_to_file, x, 2), ".link-orig");
1400         }
1401 
1402       mod_loc_field = rel_get_field (changeset.symlink_to_file, x, 0);
1403       mod_loc = rel_field_str (mod_loc_field);
1404 
1405       id_field = rel_get_field (changeset.symlink_to_file, x, 1);
1406       id = rel_field_str (id_field);
1407 
1408       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
1409       target_loc = rel_field_str (target_loc_field);
1410 
1411       if (!target_loc)
1412         {
1413           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1414           invoke_apply_changeset_callback (r, "?M  %s\n", no_dot (escaped_tmp));
1415           rel_add_records (&r->missing_file_for_patch, rel_make_record_2_taking (rel_field_ref (mod_loc_field), rel_field_ref (id_field)), rel_record_null);
1416           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1417           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1418           lim_free (0, escaped_tmp);
1419           continue;
1420         }
1421 
1422       target_path = file_name_in_vicinity (0, target, target_loc);
1423 
1424       safe_lstat (target_path, &target_stat);
1425 
1426       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_loc);
1427 
1428       if (!S_ISLNK (target_stat.st_mode))
1429         {
1430           t_uchar * orig_name;
1431           t_uchar * rej_name;
1432 
1433         symlink_to_file_conflict:
1434 
1435           orig_name = str_alloc_cat (0, target_path, ".orig");
1436           rej_name = str_alloc_cat (0, target_path, ".rej");
1437           safe_rename (target_path, orig_name);
1438           copy_file (mod_patch_path, rej_name);
1439           copy_permissions (mod_patch_path, rej_name, full_meta);
1440 
1441           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1442           invoke_apply_changeset_callback (r, "Cch %s\n", no_dot (escaped_tmp));
1443           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1444 
1445           lim_free (0, escaped_tmp);
1446           lim_free (0, orig_name);
1447           lim_free (0, rej_name);
1448         }
1449       else
1450         {
1451           t_uchar * orig_link_target = 0;
1452           t_uchar * tree_link_target = 0;
1453           int patch_stat;
1454 
1455           orig_link_target = read_line_from_file (orig_patch_path);
1456           tree_link_target = link_target (target_path);
1457 
1458           if (str_cmp (orig_link_target, tree_link_target))
1459             {
1460               patch_stat = 1;
1461             }
1462           else
1463             {
1464               t_uchar * target_path_dir = 0;
1465               t_uchar * target_path_tail = 0;
1466               t_uchar * tmp_file_basename = 0;
1467               t_uchar * tmp_file_path = 0;
1468 
1469               target_path_dir = file_name_directory_file (0, target_path);
1470               target_path_tail = file_name_tail (0, target_path);
1471               tmp_file_basename = str_alloc_cat_many (0, ",,dopatch.", target_path_tail, ".", str_end);
1472               tmp_file_path = tmp_file_name (target_path_dir, tmp_file_basename);
1473 
1474               rmrf_file (tmp_file_path);
1475               safe_rename (target_path, tmp_file_path);
1476               copy_file (mod_patch_path, target_path);
1477               copy_permissions (mod_patch_path, target_path, full_meta);
1478               safe_unlink (tmp_file_path);
1479               patch_stat = 0;
1480 
1481               lim_free (0, target_path_dir);
1482               lim_free (0, target_path_tail);
1483               lim_free (0, tmp_file_basename);
1484               lim_free (0, tmp_file_path);
1485             }
1486 
1487           if (patch_stat == 0)
1488             {
1489               escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1490               invoke_apply_changeset_callback (r, "ch  %s\n",
1491                                                no_dot (escaped_tmp));
1492               rel_add_records (&r->modified_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1493               lim_free (0, escaped_tmp);
1494             }
1495           else
1496             goto symlink_to_file_conflict;
1497 
1498           lim_free (0, orig_link_target);
1499           lim_free (0, tree_link_target);
1500         }
1501 
1502       rel_field_unref (mod_loc_field);
1503       rel_field_unref (id_field);
1504       rel_field_unref (target_loc_field);
1505 
1506       lim_free (0, orig_patch_path);
1507       lim_free (0, mod_patch_path);
1508       lim_free (0, target_path);
1509     }
1510 
1511   /****************************************************************
1512    * File->Symlink Patches
1513    */
1514 
1515   for (x = 0; x < rel_n_records (changeset.file_to_symlink); ++x)
1516     {
1517       rel_field mod_loc_field;
1518       rel_field id_field;
1519       rel_field target_loc_field;
1520 
1521       const t_uchar * mod_loc;
1522       const t_uchar * id;
1523       const t_uchar * target_loc;
1524 
1525       t_uchar * orig_patch_path = 0;
1526       t_uchar * mod_patch_path = 0;
1527       t_uchar * target_path = 0;
1528       t_uchar * escaped_tmp = 0;
1529       struct stat target_stat;
1530 
1531       if (!reverse)
1532         {
1533           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_to_symlink, x, 2), ".original");
1534           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_to_symlink, x, 2), ".link-mod");
1535         }
1536       else
1537         {
1538           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_to_symlink, x, 2), ".link-mod");
1539           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_to_symlink, x, 2), ".original");
1540         }
1541 
1542       mod_loc_field = rel_get_field (changeset.file_to_symlink, x, 0);
1543       mod_loc = rel_field_str (mod_loc_field);
1544 
1545       id_field = rel_get_field (changeset.file_to_symlink, x, 1);
1546       id = rel_field_str (id_field);
1547 
1548       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
1549       target_loc = rel_field_str (target_loc_field);
1550 
1551       if (!target_loc)
1552         {
1553           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1554           invoke_apply_changeset_callback (r, "?M  %s\n", no_dot (escaped_tmp));
1555           rel_add_records (&r->missing_file_for_patch, rel_make_record_2_taking (rel_field_ref (mod_loc_field), rel_field_ref (id_field)), rel_record_null);
1556           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1557           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1558           lim_free (0, escaped_tmp);
1559           continue;
1560         }
1561 
1562       target_path = file_name_in_vicinity (0, target, target_loc);
1563 
1564       safe_lstat (target_path, &target_stat);
1565 
1566       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_loc);
1567 
1568       if (S_ISLNK (target_stat.st_mode))
1569         {
1570           t_uchar * orig_name;
1571           t_uchar * rej_name;
1572           int out_fd;
1573           int in_fd;
1574 
1575         file_to_symlink_conflict:
1576 
1577           orig_name = str_alloc_cat (0, target_path, ".orig");
1578           rej_name = str_alloc_cat (0, target_path, ".rej");
1579           safe_rename (target_path, orig_name);
1580 
1581           out_fd = safe_open (rej_name, O_WRONLY | O_CREAT | O_EXCL, 0666);
1582           safe_printfmt (out_fd, "MOD had a symlink to: ");
1583           in_fd = safe_open (mod_patch_path, O_RDONLY, 0);
1584           copy_fd (in_fd, out_fd);
1585           safe_close (in_fd);
1586           safe_close (out_fd);
1587 
1588           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1589           invoke_apply_changeset_callback (r, "Cch %s\n", no_dot (escaped_tmp));
1590           rel_add_records (&r->conflict_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1591 
1592           lim_free (0, escaped_tmp);
1593           lim_free (0, orig_name);
1594           lim_free (0, rej_name);
1595         }
1596       else
1597         {
1598           t_uchar * mod_link_target = 0;
1599           t_uchar * tree_link_target = 0;
1600           int patch_stat;
1601 
1602           mod_link_target = read_line_from_file (mod_patch_path);
1603 
1604           if (arch_binary_files_differ (orig_patch_path, target_path, 0, 0))
1605             {
1606               patch_stat = 1;
1607             }
1608           else
1609             {
1610               t_uchar * target_path_dir = 0;
1611               t_uchar * target_path_tail = 0;
1612               t_uchar * tmp_file_basename = 0;
1613               t_uchar * tmp_file_path = 0;
1614 
1615               target_path_dir = file_name_directory_file (0, target_path);
1616               target_path_tail = file_name_tail (0, target_path);
1617               tmp_file_basename = str_alloc_cat_many (0, ",,dopatch.", target_path_tail, ".", str_end);
1618               tmp_file_path = tmp_file_name (target_path_dir, tmp_file_basename);
1619 
1620               rmrf_file (tmp_file_path);
1621               safe_rename (target_path, tmp_file_path);
1622               safe_symlink (mod_link_target, target_path);
1623               safe_unlink (tmp_file_path);
1624               patch_stat = 0;
1625 
1626               lim_free (0, target_path_dir);
1627               lim_free (0, target_path_tail);
1628               lim_free (0, tmp_file_basename);
1629               lim_free (0, tmp_file_path);
1630             }
1631 
1632           if (patch_stat == 0)
1633             {
1634               escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1635               invoke_apply_changeset_callback (r, "ch  %s\n",
1636                                                no_dot (escaped_tmp));
1637               rel_add_records (&r->modified_files, rel_make_record_2_taking (rel_field_ref (target_loc_field), rel_field_ref (id_field)), rel_record_null);
1638               lim_free (0, escaped_tmp);
1639             }
1640           else
1641             goto file_to_symlink_conflict;
1642 
1643           lim_free (0, mod_link_target);
1644           lim_free (0, tree_link_target);
1645         }
1646 
1647       rel_field_unref (mod_loc_field);
1648       rel_field_unref (id_field);
1649       rel_field_unref (target_loc_field);
1650 
1651       lim_free (0, orig_patch_path);
1652       lim_free (0, mod_patch_path);
1653       lim_free (0, target_path);
1654     }
1655 
1656 
1657   /****************************************************************
1658    * Patch File Metadata
1659    */
1660   for (x = 0; x < rel_n_records (changeset.file_metadata_changed); ++x)
1661     {
1662       rel_field mod_loc_field;
1663       rel_field id_field;
1664       rel_field target_loc_field;
1665 
1666       const t_uchar * mod_loc;
1667       const t_uchar * id;
1668       const t_uchar * target_loc;
1669 
1670       t_uchar * orig_patch_path = 0;
1671       t_uchar * mod_patch_path = 0;
1672       t_uchar * target_path = 0;
1673       t_uchar * target_spew_loc = 0;
1674       t_uchar * target_spew_path = 0;
1675       t_uchar * escaped_tmp = 0;
1676       struct stat target_stat;
1677 
1678       if (!reverse)
1679         {
1680           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_metadata_changed, x, 2), ".meta-orig");
1681           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_metadata_changed, x, 2), ".meta-mod");
1682         }
1683       else
1684         {
1685           orig_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_metadata_changed, x, 2), ".meta-mod");
1686           mod_patch_path = str_alloc_cat (0, rel_peek_str (changeset.file_metadata_changed, x, 2), ".meta-orig");
1687         }
1688 
1689       mod_loc_field = rel_get_field (changeset.file_metadata_changed, x, 0);
1690       mod_loc = rel_field_str (mod_loc_field);
1691 
1692       id_field = rel_get_field (changeset.file_metadata_changed, x, 1);
1693       id = rel_field_str (id_field);
1694 
1695       target_loc_field = assoc_get_taking (running.file_loc_of, rel_field_ref (id_field));
1696       target_loc = rel_field_str (target_loc_field);
1697 
1698       if (!target_loc)
1699         {
1700           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1701           invoke_apply_changeset_callback (r, "?-- %s\n", no_dot (escaped_tmp));
1702           rel_field_ref (mod_loc_field);
1703           rel_field_ref (id_field);
1704           rel_add_records (&r->missing_file_for_meta_patch, rel_make_record_2_taking (mod_loc_field, id_field), rel_record_null);
1705           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1706           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1707           lim_free (0, escaped_tmp);
1708           continue;
1709         }
1710 
1711       target_path = file_name_in_vicinity (0, target, target_loc);
1712       target_spew_loc = str_alloc_cat (0, target_loc, ".meta");
1713       target_spew_path = file_name_in_vicinity (0, target, target_spew_loc);
1714 
1715       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_spew_loc);
1716 
1717       safe_lstat (target_path, &target_stat);
1718 
1719       if (S_ISLNK (target_stat.st_mode))
1720         {
1721           t_uchar * rej_name;
1722           int out_fd;
1723           int in_fd;
1724 
1725           rej_name = str_alloc_cat (0, target_spew_path, ".rej");
1726 
1727           out_fd = safe_open (rej_name, O_WRONLY | O_CREAT | O_EXCL, 0666);
1728           safe_printfmt (out_fd, "MOD had a metadata change: ");
1729           in_fd = safe_open (mod_patch_path, O_RDONLY, 0);
1730           copy_fd (in_fd, out_fd);
1731           safe_close (in_fd);
1732           safe_close (out_fd);
1733 
1734           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1735           invoke_apply_changeset_callback (r, "C-- %s\n", no_dot (escaped_tmp));
1736           rel_field_ref (target_loc_field);
1737           rel_field_ref (id_field);
1738           rel_add_records (&r->metadata_conflict_files, rel_make_record_2_taking (target_loc_field, id_field), rel_record_null);
1739 
1740           lim_free (0, escaped_tmp);
1741           lim_free (0, rej_name);
1742         }
1743       else
1744         {
1745           mode_t orig_perms;
1746           mode_t mod_perms;
1747           int mode_matches;
1748           long orig_uid;
1749           long mod_uid;
1750           long orig_gid;
1751           long mod_gid;
1752 
1753           mod_perms = arch_read_permissions_patch (&mod_uid, &mod_gid, mod_patch_path);
1754           orig_perms = arch_read_permissions_patch (&orig_uid, &orig_gid, orig_patch_path);
1755 
1756           if (full_meta)
1757             {
1758               mod_perms = (mod_perms & 07777);
1759               orig_perms = (orig_perms & 07777);
1760               mode_matches = (mod_perms == (target_stat.st_mode & 07777));
1761             }
1762           else
1763             {
1764               mod_perms = (mod_perms & 0777);
1765               orig_perms = (orig_perms & 0777);
1766               mode_matches = (mod_perms == (target_stat.st_mode & 0777));
1767             }
1768 
1769           if (!mode_matches)
1770             {
1771               t_uchar * target_path_dir = 0;
1772               t_uchar * target_path_tmp = 0;
1773 
1774               target_path_dir = file_name_directory_file (0, target_path);
1775               target_path_tmp = tmp_file_name (target_path_dir, ",,meta-tmp");
1776               rmrf_file (target_path_tmp);
1777               copy_file (target_path, target_path_tmp);
1778               copy_permissions (target_path, target_path_tmp, full_meta);
1779               safe_chmod (target_path_tmp, mod_perms);
1780               safe_rename (target_path_tmp, target_path);
1781 
1782               lim_free (0, target_path_dir);
1783               lim_free (0, target_path_tmp);
1784             }
1785 
1786           if (full_meta
1787               && (((mod_uid != target_stat.st_uid) && (mod_uid >= 0))
1788                   || ((mod_gid != target_stat.st_gid) && (mod_gid >= 0))))
1789             {
1790               t_uchar * target_path_dir = 0;
1791               t_uchar * target_path_tmp = 0;
1792 
1793               target_path_dir = file_name_directory_file (0, target_path);
1794               target_path_tmp = tmp_file_name (target_path_dir, ",,meta-tmp");
1795               rmrf_file (target_path_tmp);
1796               copy_file (target_path, target_path_tmp);
1797               copy_permissions (target_path, target_path_tmp, full_meta);
1798               safe_chown (target_path_tmp, mod_uid, mod_gid);
1799               safe_rename (target_path_tmp, target_path);
1800 
1801               lim_free (0, target_path_dir);
1802               lim_free (0, target_path_tmp);
1803             }
1804 
1805 
1806 
1807           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1808           invoke_apply_changeset_callback (r, "--  %s\n", no_dot (escaped_tmp));
1809           rel_field_ref (target_loc_field);
1810           rel_field_ref (id_field);
1811           rel_add_records (&r->meta_modified_files, rel_make_record_2_taking (target_loc_field, id_field), rel_record_null);
1812           lim_free (0, escaped_tmp);
1813         }
1814 
1815       rel_field_unref (mod_loc_field);
1816       rel_field_unref (id_field);
1817       rel_field_unref (target_loc_field);
1818 
1819       lim_free (0, orig_patch_path);
1820       lim_free (0, mod_patch_path);
1821       lim_free (0, target_path);
1822       lim_free (0, target_spew_loc);
1823       lim_free (0, target_spew_path);
1824     }
1825 
1826 
1827 
1828 
1829   /****************************************************************
1830    * Patch Dir Metadata
1831    */
1832 
1833   for (x = 0; x < rel_n_records (changeset.dir_metadata_changed); ++x)
1834     {
1835       rel_field mod_loc_field;
1836       rel_field id_field;
1837       rel_field target_loc_field;
1838 
1839       const t_uchar * mod_loc;
1840       const t_uchar * id;
1841       const t_uchar * target_loc;
1842 
1843       t_uchar * orig_patch_path = 0;
1844       t_uchar * mod_patch_path = 0;
1845       t_uchar * target_path = 0;
1846       t_uchar * target_spew_loc = 0;
1847       t_uchar * target_spew_path = 0;
1848       t_uchar * escaped_tmp = 0;
1849       struct stat target_stat;
1850 
1851       if (!reverse)
1852         {
1853           orig_patch_path = file_name_in_vicinity (0, rel_peek_str (changeset.dir_metadata_changed, x, 2), "=dir-meta-orig");
1854           mod_patch_path = file_name_in_vicinity (0, rel_peek_str (changeset.dir_metadata_changed, x, 2), "=dir-meta-mod");
1855         }
1856       else
1857         {
1858           orig_patch_path = file_name_in_vicinity (0, rel_peek_str (changeset.dir_metadata_changed, x, 2), "=dir-meta-mod");
1859           mod_patch_path = file_name_in_vicinity (0, rel_peek_str (changeset.dir_metadata_changed, x, 2), "=dir-meta-orig");
1860         }
1861 
1862       mod_loc_field = rel_get_field (changeset.dir_metadata_changed, x, 0);
1863       mod_loc = rel_field_str (mod_loc_field);
1864 
1865       id_field = rel_get_field (changeset.dir_metadata_changed, x, 1);
1866       id = rel_field_str (id_field);
1867 
1868       target_loc_field = assoc_get_taking (running.dir_loc_of, rel_field_ref (id_field));
1869       target_loc = rel_field_str (target_loc_field);
1870 
1871       if (!target_loc)
1872         {
1873           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, mod_loc);
1874           invoke_apply_changeset_callback (r, "?-/ %s\n", no_dot (escaped_tmp));
1875           rel_field_ref (mod_loc_field);
1876           rel_field_ref (id_field);
1877           rel_add_records (&r->missing_dir_for_meta_patch, rel_make_record_2_taking (mod_loc_field, id_field), rel_record_null);
1878           save_patch_for_missing_file (missing_patch_dir, orig_patch_path, mod_loc);
1879           save_patch_for_missing_file (missing_patch_dir, mod_patch_path, mod_loc);
1880           lim_free (0, escaped_tmp);
1881           continue;
1882         }
1883 
1884       target_path = file_name_in_vicinity (0, target, target_loc);
1885       target_spew_loc = str_alloc_cat (0, target_loc, ".meta");
1886       target_spew_path = file_name_in_vicinity (0, target, target_spew_loc);
1887 
1888       preserve_old_patch_spew (removed_patch_conflict_files_path, target, target_spew_loc);
1889 
1890       safe_stat (target_path, &target_stat);
1891 
1892       {
1893         mode_t orig_perms;
1894         mode_t mod_perms;
1895         int mode_matches;
1896         long orig_uid;
1897         long mod_uid;
1898         long orig_gid;
1899         long mod_gid;
1900 
1901         mod_perms = arch_read_permissions_patch (&mod_uid, &mod_gid, mod_patch_path);
1902         orig_perms = arch_read_permissions_patch (&orig_uid, &orig_gid, orig_patch_path);
1903 
1904         if (full_meta)
1905           {
1906             mod_perms = (mod_perms & 07777);
1907             orig_perms = (orig_perms & 07777);
1908             mode_matches = (mod_perms == (target_stat.st_mode & 07777));
1909           }
1910         else
1911           {
1912             mod_perms = (mod_perms & 0777);
1913             orig_perms = (orig_perms & 0777);
1914             mode_matches = (mod_perms == (target_stat.st_mode & 0777));
1915           }
1916 
1917         if (!mode_matches)
1918           {
1919             safe_chmod (target_path, mod_perms);
1920           }
1921 
1922         if (full_meta
1923             && (((mod_uid != target_stat.st_uid) && (mod_uid >= 0))
1924                 || ((mod_gid != target_stat.st_gid) && (mod_gid >= 0))))
1925           {
1926             safe_chown (target_path, mod_uid, mod_gid);
1927           }
1928 
1929         escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
1930         invoke_apply_changeset_callback (r, "--/ %s\n", no_dot (escaped_tmp));
1931         rel_field_ref (target_loc_field);
1932         rel_field_ref (id_field);
1933         rel_add_records (&r->meta_modified_dirs, rel_make_record_2_taking (target_loc_field, id_field), rel_record_null);
1934         lim_free (0, escaped_tmp);
1935       }
1936 
1937       rel_field_unref (mod_loc_field);
1938       rel_field_unref (id_field);
1939       rel_field_unref (target_loc_field);
1940 
1941       lim_free (0, orig_patch_path);
1942       lim_free (0, mod_patch_path);
1943       lim_free (0, target_path);
1944       lim_free (0, target_spew_loc);
1945       lim_free (0, target_spew_path);
1946     }
1947 
1948 
1949 
1950   /****************************************************************
1951    * Update Changelogs
1952    */
1953   for (x = 0; x < rel_n_records (patched_changelogs); ++x)
1954     {
1955       rel_field target_loc_field;
1956       rel_field id_field;
1957       rel_field target_path_field;
1958 
1959       const t_uchar * target_loc;
1960       const t_uchar * id;
1961       const t_uchar * target_path;
1962 
1963       t_uchar * target_dir = 0;
1964       t_uchar * target_tmp = 0;
1965       t_uchar * archive = 0;
1966       t_uchar * version = 0;
1967       t_uchar * escaped_tmp = 0;
1968       int out_fd;
1969       struct stat stat_was;
1970       mode_t mode;
1971 
1972       target_loc_field = rel_get_field (patched_changelogs, x, 0);
1973       target_loc = rel_field_str (target_loc_field);
1974 
1975       id_field = rel_get_field (patched_changelogs, x, 1);
1976       id = rel_field_str (id_field);
1977 
1978       target_path_field = rel_get_field (patched_changelogs, x, 2);
1979       target_path = rel_field_str (target_path_field);
1980 
1981       target_dir = file_name_directory_file (0, target_path);
1982       target_tmp = tmp_file_name (target_dir, ",,new-changeset");
1983 
1984       safe_stat (target_path, &stat_was);
1985 
1986       if (full_meta)
1987         {
1988           mode = (stat_was.st_mode & 07777);
1989         }
1990       else
1991         {
1992           mode = (stat_was.st_mode & 0777);
1993         }
1994 
1995       arch_parse_changelog_id (&archive, &version, id);
1996 
1997       rmrf_file (target_tmp);
1998       out_fd = safe_open (target_tmp, O_WRONLY | O_EXCL | O_CREAT, mode);
1999       safe_fchmod (out_fd, mode);
2000       if (full_meta)
2001         safe_fchown (out_fd, stat_was.st_uid, stat_was.st_gid);
2002       safe_buffer_fd (out_fd, 0, O_WRONLY, 0);
2003       arch_generate_changelog (out_fd, tree_root, 0, 0, 0, 0, archive, version);
2004       safe_close (out_fd);
2005       safe_rename (target_tmp, target_path);
2006 
2007       escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, target_loc);
2008       invoke_apply_changeset_callback (r, "cl  %s\n", no_dot (escaped_tmp));
2009       rel_field_ref (target_loc_field);
2010       rel_field_ref (id_field);
2011       rel_add_records (&r->modified_files, rel_make_record_2_taking (target_loc_field, id_field), rel_record_null);
2012 
2013       rel_field_unref (target_loc_field);
2014       rel_field_unref (id_field);
2015       rel_field_unref (target_path_field);
2016 
2017       lim_free (0, escaped_tmp);
2018       lim_free (0, target_dir);
2019       lim_free (0, target_tmp);
2020       lim_free (0, archive);
2021       lim_free (0, version);
2022     }
2023 
2024 
2025   /****************************************************************
2026    * Finish Up Deferred Conflicts
2027    */
2028 
2029   rel_sort_table_by_field (1, deferred_conflicts, 0);
2030   for (x = 0; x < rel_n_records (deferred_conflicts); ++x)
2031     {
2032       t_uchar * target_path = 0;
2033       t_uchar * rej_path = 0;
2034 
2035       target_path = file_name_in_vicinity (0, target, rel_peek_str (deferred_conflicts, x, 0));
2036       rej_path = str_alloc_cat (0, target_path, ".rej");
2037       safe_rename (target_path, rej_path);
2038 
2039       lim_free (0, target_path);
2040       lim_free (0, rej_path);
2041     }
2042 
2043   /****************************************************************
2044    * Sort and Uniq Report Fields
2045    */
2046 
2047   rel_sort_table_by_field (0, r->removed_files, 0);
2048   rel_uniq_by_field (&r->removed_files, 0);
2049   rel_sort_table_by_field (0, r->removed_dirs, 0);
2050   rel_uniq_by_field (&r->removed_dirs, 0);
2051 
2052   rel_sort_table_by_field (0, r->missing_removed_files, 0);
2053   rel_uniq_by_field (&r->missing_removed_files, 0);
2054   rel_sort_table_by_field (0, r->missing_removed_dirs, 0);
2055   rel_uniq_by_field (&r->missing_removed_dirs, 0);
2056 
2057   rel_sort_table_by_field (0, r->missing_renamed_files, 0);
2058   rel_uniq_by_field (&r->missing_renamed_files, 0);
2059   rel_sort_table_by_field (0, r->missing_renamed_dirs, 0);
2060   rel_uniq_by_field (&r->missing_renamed_dirs, 0);
2061 
2062   rel_sort_table_by_field (0, r->new_dirs, 0);
2063   rel_uniq_by_field (&r->new_dirs, 0);
2064   rel_sort_table_by_field (0, r->renamed_dirs, 0);
2065   rel_uniq_by_field (&r->renamed_dirs, 0);
2066   rel_sort_table_by_field (0, r->new_files, 0);
2067   rel_uniq_by_field (&r->new_files, 0);
2068   rel_sort_table_by_field (0, r->renamed_files, 0);
2069   rel_uniq_by_field (&r->renamed_files, 0);
2070 
2071   rel_sort_table_by_field (0, r->modified_files, 0);
2072   rel_uniq_by_field (&r->modified_files, 0);
2073   rel_sort_table_by_field (0, r->modified_dirs, 0);
2074   rel_uniq_by_field (&r->modified_dirs, 0);
2075   rel_sort_table_by_field (0, r->missing_file_for_patch, 0);
2076   rel_uniq_by_field (&r->missing_file_for_patch, 0);
2077   rel_sort_table_by_field (0, r->missing_dir_for_patch, 0);
2078   rel_uniq_by_field (&r->missing_dir_for_patch, 0);
2079 
2080   rel_sort_table_by_field (0, r->meta_modified_files, 0);
2081   rel_uniq_by_field (&r->meta_modified_files, 0);
2082   rel_sort_table_by_field (0, r->meta_modified_dirs, 0);
2083   rel_uniq_by_field (&r->meta_modified_dirs, 0);
2084   rel_sort_table_by_field (0, r->missing_file_for_meta_patch, 0);
2085   rel_uniq_by_field (&r->missing_file_for_meta_patch, 0);
2086   rel_sort_table_by_field (0, r->missing_dir_for_meta_patch, 0);
2087   rel_uniq_by_field (&r->missing_dir_for_meta_patch, 0);
2088 
2089   rel_sort_table_by_field (0, r->conflict_files, 0);
2090   rel_uniq_by_field (&r->conflict_files, 0);
2091   rel_sort_table_by_field (0, r->conflict_dirs, 0);
2092   rel_uniq_by_field (&r->conflict_dirs, 0);
2093   rel_sort_table_by_field (0, r->metadata_conflict_files, 0);
2094   rel_uniq_by_field (&r->metadata_conflict_files, 0);
2095   rel_sort_table_by_field (0, r->metadata_conflict_dirs, 0);
2096   rel_uniq_by_field (&r->metadata_conflict_dirs, 0);
2097 
2098 
2099   /****************************************************************
2100    * cleanup
2101    */
2102 
2103   free_assoc_table (mod_dir_id_of);
2104   free_assoc_table (new_dir_perms);
2105   safe_close (here_fd);
2106   lim_free (0, changeset_path);
2107   arch_free_changeset_report_data (&changeset);
2108   lim_free (0, target);
2109   lim_free (0, missing_patch_dir);
2110   lim_free (0, tree_root);
2111   arch_free_changeset_inventory_data (&inventory);
2112   arch_free_changeset_inventory_data (&inventory_by_name);
2113   rel_free_table (removed_files_index);
2114   rmrf_file (tmp_removed_files_root);
2115   lim_free (0, tmp_removed_files_root);
2116   rel_free_table (renamed_files_index);
2117   rel_free_table (present_renamed_files_index);
2118   rmrf_file (tmp_renamed_files_root);
2119   lim_free (0, tmp_renamed_files_root);
2120   rel_free_table (renamed_dirs_index);
2121   rel_free_table (present_renamed_dirs_index);
2122   rel_free_table (removed_dirs_index);
2123   rel_free_table (present_removed_dirs_index);
2124   rmrf_file (tmp_shuffled_dirs_root);
2125   lim_free (0, tmp_shuffled_dirs_root);
2126   rel_free_table (file_set_aside_with_dir_id);
2127   rel_free_table (dir_set_aside_with_dir_id);
2128   lim_free (0, removed_patch_conflict_files_path);
2129   free_assoc_table (running.dir_loc_of);
2130   free_assoc_table (running.dir_id_of);
2131   free_assoc_table (running.file_loc_of);
2132   free_assoc_table (running.file_id_of);
2133   rel_free_table (install_dirs_plan);
2134   rel_free_table (deferred_conflicts);
2135   rel_free_table (added_files_and_symlinks);
2136   rel_free_table (patched_changelogs);
2137 }
2138 
2139 
2140 
2141 
2142 static void
invoke_apply_changeset_callback(struct arch_apply_changeset_report * r,const t_uchar * fmt,...)2143 invoke_apply_changeset_callback (struct arch_apply_changeset_report * r,
2144                                  const t_uchar * fmt, ...)
2145 {
2146   va_list ap;
2147 
2148   if (r->callback)
2149     {
2150       va_start (ap, fmt);
2151       r->callback (r->thunk, fmt, ap);
2152       va_end (ap);
2153     }
2154 }
2155 
2156 
2157 static t_uchar *
set_aside_shuffled_dirs(rel_table * file_set_aside_with,rel_table * dir_set_aside_with,const t_uchar * target_loc,const t_uchar * id,int seq_n,const t_uchar * dest_root,struct running_inventory_assocs * running,const t_uchar * target,struct arch_changeset_inventory * inv)2158 set_aside_shuffled_dirs (rel_table * file_set_aside_with,
2159                          rel_table * dir_set_aside_with,
2160                          const t_uchar * target_loc,
2161                          const t_uchar * id,
2162                          int seq_n,
2163                          const t_uchar * dest_root,
2164                          struct running_inventory_assocs * running,
2165                          const t_uchar * target,
2166                          struct arch_changeset_inventory * inv)
2167 {
2168 #define SEQ_STR_BUF_SIZE 128
2169   t_uchar seq_str[SEQ_STR_BUF_SIZE];
2170   int cvt_status;
2171   t_uchar * target_path = 0;
2172   t_uchar * dest_path = 0;
2173   t_uchar * target_loc_as_dir = 0;
2174   size_t target_loc_as_dir_len;
2175   int y;
2176 
2177   /* Is `seq_str' a large enough buffer to hold the decimal
2178    * form of `seq_n' plus a terminating 0?
2179    */
2180 #if (4 * (SEQ_STR_BUF_SIZE - 1)) < (CHAR_BIT * MACHINE_SIZEOF_LONG)
2181 #error "an unexpected buffer overlow might occur!"
2182 #endif
2183 
2184   cvt_status = cvt_ulong_to_decimal_n (seq_str, sizeof (seq_str), (unsigned long)seq_n, 0);
2185   invariant (!cvt_status);	/* the compile-time check above justifies this `invariant' */
2186 
2187   target_path = file_name_in_vicinity (0, target, target_loc);
2188   dest_path = file_name_in_vicinity (0, dest_root, seq_str);
2189 
2190   ensure_directory_exists (dest_root);
2191   safe_rename (target_path, dest_path);
2192 
2193   target_loc_as_dir = file_name_as_directory (0, target_loc);
2194   target_loc_as_dir_len = str_length (target_loc_as_dir);
2195 
2196   for (y = 0; y < rel_n_records (inv->files); ++y)
2197     {
2198       if (!str_cmp_prefix (target_loc_as_dir, rel_peek_str (inv->files, y, 0)))
2199         {
2200           if (assoc_get_str_taking (running->file_id_of, rel_get_field (inv->files, y, 0)))
2201             {
2202               assoc_del_taking (running->file_id_of, rel_get_field (inv->files, y, 0));
2203               assoc_del_taking (running->file_loc_of, rel_get_field (inv->files, y, 1));
2204 
2205               rel_add_records (file_set_aside_with,
2206                                rel_make_record_3_taking (rel_make_field_str (id),
2207                                                          rel_make_field_str (rel_peek_str (inv->files, y, 0) + target_loc_as_dir_len),
2208                                                          rel_get_field (inv->files, y, 1)),
2209                                rel_record_null);
2210             }
2211         }
2212     }
2213   for (y = 0; y < rel_n_records (inv->dirs); ++y)
2214     {
2215       if (!str_cmp_prefix (target_loc_as_dir, rel_peek_str (inv->dirs, y, 0)))
2216         {
2217           if (assoc_get_str_taking (running->dir_id_of, rel_get_field (inv->dirs, y, 0)))
2218             {
2219               assoc_del_taking (running->dir_id_of, rel_get_field (inv->dirs, y, 0));
2220               assoc_del_taking (running->dir_loc_of, rel_get_field (inv->dirs, y, 1));
2221 
2222               rel_add_records (dir_set_aside_with,
2223                                rel_make_record_3_taking (rel_make_field_str (id),
2224                                                          rel_make_field_str (rel_peek_str (inv->dirs, y, 0) + target_loc_as_dir_len),
2225                                                          rel_get_field (inv->dirs, y, 1)),
2226                                rel_record_null);
2227             }
2228         }
2229     }
2230   assoc_del_taking (running->dir_id_of, rel_make_field_str (target_loc));
2231   assoc_del_taking (running->dir_loc_of, rel_make_field_str (id));
2232 
2233   lim_free (0, target_path);
2234   lim_free (0, target_loc_as_dir);
2235 
2236   return dest_path;
2237 }
2238 
2239 
2240 static void
preserve_old_patch_spew(const t_uchar * dest_root,const t_uchar * target,const t_uchar * loc)2241 preserve_old_patch_spew (const t_uchar * dest_root,
2242                          const t_uchar * target,
2243                          const t_uchar * loc)
2244 {
2245   t_uchar * target_path = 0;
2246   t_uchar * orig_path = 0;
2247   t_uchar * rej_path = 0;
2248   t_uchar * dest_path = 0;
2249   t_uchar * dest_dir;
2250   t_uchar * orig_dest = 0;
2251   t_uchar * rej_dest = 0;
2252 
2253   target_path = file_name_in_vicinity (0, target, loc);
2254   orig_path = str_alloc_cat (0, target_path, ".orig");
2255   rej_path = str_alloc_cat (0, target_path, ".rej");
2256 
2257   dest_path = file_name_in_vicinity (0, dest_root, loc);
2258   dest_dir = file_name_directory_file (0, dest_path);
2259   orig_dest = str_alloc_cat (0, dest_path, ".orig");
2260   rej_dest = str_alloc_cat (0, dest_path, ".rej");
2261 
2262   if (!safe_access (orig_path, F_OK))
2263     {
2264       ensure_directory_exists (dest_dir);
2265       safe_rename (orig_path, orig_dest);
2266     }
2267 
2268   if (!safe_access (rej_path, F_OK))
2269     {
2270       ensure_directory_exists (dest_dir);
2271       safe_rename (rej_path, rej_dest);
2272     }
2273 
2274   lim_free (0, target_path);
2275   lim_free (0, orig_path);
2276   lim_free (0, rej_path);
2277   lim_free (0, dest_path);
2278   lim_free (0, dest_dir);
2279   lim_free (0, orig_dest);
2280   lim_free (0, rej_dest);
2281 }
2282 
2283 static int
deferred_conflict(rel_table * deferred_conflicts,const t_uchar * spew_root,const t_uchar * target,const t_uchar * loc,const t_uchar * orig_copy)2284 deferred_conflict (rel_table * deferred_conflicts,
2285                    const t_uchar * spew_root,
2286                    const t_uchar * target,
2287                    const t_uchar * loc,
2288                    const t_uchar * orig_copy)
2289 {
2290   t_uchar * path = 0;
2291   t_uchar * orig_path = 0;
2292   int conflict_detected;
2293 
2294   path = file_name_in_vicinity (0, target, loc);
2295   orig_path = str_alloc_cat (0, path, ".orig");
2296   conflict_detected = 0;
2297 
2298   if (!safe_access (path, F_OK))
2299     {
2300       struct stat orig_stat;
2301       struct stat target_stat;
2302 
2303       if (orig_copy)
2304         {
2305           safe_stat (orig_copy, &orig_stat);
2306           safe_stat (path, &target_stat);
2307 
2308           if (S_ISREG (orig_stat.st_mode) && S_ISREG (target_stat.st_mode) && !arch_binary_files_differ (orig_copy, path, 0, 0))
2309             {
2310               safe_unlink (path);
2311             }
2312           else
2313             goto conflict;
2314         }
2315       else
2316         {
2317         conflict:
2318           preserve_old_patch_spew (spew_root, target, loc);
2319           rel_add_records (deferred_conflicts, rel_singleton_record_taking (rel_make_field_str (loc)), rel_record_null);
2320 
2321           safe_rename (path, orig_path);
2322           conflict_detected = 1;
2323         }
2324     }
2325 
2326   lim_free (0, path);
2327   lim_free (0, orig_path);
2328 
2329   return conflict_detected;
2330 }
2331 
2332 
2333 static int
dir_depth_cmp(const t_uchar * a,const t_uchar * b)2334 dir_depth_cmp (const t_uchar * a,
2335                const t_uchar * b)
2336 {
2337   return str_cmp (a, b);
2338 }
2339 
2340 
2341 static void
analyze_install(struct running_inventory_assocs * running,int is_dir,t_uchar ** target_has_dir,t_uchar ** install_dir,t_uchar ** install_name,t_uchar ** install_loc,const t_uchar * target,const t_uchar * mod_loc,const t_uchar * id,assoc_table mod_dir_id_of,rel_table file_set_aside_with,rel_table dir_set_aside_with)2342 analyze_install (struct running_inventory_assocs * running,
2343                  int is_dir,
2344                  t_uchar ** target_has_dir,
2345                  t_uchar ** install_dir,
2346                  t_uchar ** install_name,
2347                  t_uchar ** install_loc,
2348                  const t_uchar * target,
2349                  const t_uchar * mod_loc,
2350                  const t_uchar * id,
2351                  assoc_table mod_dir_id_of,
2352                  rel_table file_set_aside_with,
2353                  rel_table dir_set_aside_with)
2354 {
2355   t_uchar * basename = 0;
2356   t_uchar * loc_dir = 0;
2357 
2358   basename = file_name_tail (0, mod_loc);
2359   loc_dir = file_name_directory_file (0, mod_loc);
2360 
2361   if (!str_cmp (loc_dir, "."))
2362     {
2363       *target_has_dir = str_save (0, ".");
2364       *install_dir = str_save (0, target);
2365       *install_name = file_name_in_vicinity (0, *install_dir, basename);
2366       *install_loc = file_name_in_vicinity (0, ".", basename);
2367     }
2368   else
2369     {
2370       t_uchar * relpath = 0;
2371       t_uchar * install_loc_dir = 0;
2372 
2373       while (str_cmp (loc_dir, "."))
2374         {
2375           const t_uchar * dir_id;
2376           const t_uchar * loc_dir_in_tgt;
2377           t_uchar * dir_tail = 0;
2378           t_uchar * s;
2379 
2380           dir_id = assoc_get_str_taking (mod_dir_id_of, rel_make_field_str (loc_dir));
2381 
2382           if (!dir_id)
2383             {
2384               /* A degenerate changeset -- it should include that dir-id but
2385                * doesn't.   Let's try a guess.
2386                */
2387               dir_id = assoc_get_str_taking (running->dir_id_of, rel_make_field_str (loc_dir));
2388             }
2389 
2390           loc_dir_in_tgt = assoc_get_str_taking (running->dir_loc_of, rel_make_field_str (dir_id));
2391 
2392           if (loc_dir_in_tgt)
2393             break;
2394 
2395           dir_tail = file_name_tail (0, loc_dir);
2396           if (!relpath)
2397             relpath = str_save (0, dir_tail);
2398           else
2399             {
2400               t_uchar * t = relpath;
2401               relpath = file_name_in_vicinity (0, dir_tail, relpath);
2402               lim_free (0, t);
2403             }
2404 
2405 
2406           s = file_name_directory_file (0, loc_dir);
2407           lim_free (0, loc_dir);
2408           loc_dir = s;
2409 
2410           lim_free (0, dir_tail);
2411         }
2412 
2413       *target_has_dir = str_save (0, loc_dir);
2414       install_loc_dir = file_name_in_vicinity (0, loc_dir, relpath);
2415       if (!str_cmp (install_loc_dir, "./"))
2416         *install_dir = str_save (0, target);
2417       else
2418         *install_dir = file_name_in_vicinity (0, target, 2 + install_loc_dir);
2419       *install_name = file_name_in_vicinity (0, *install_dir, basename);
2420       *install_loc = file_name_in_vicinity (0, install_loc_dir, basename);
2421 
2422       lim_free (0, relpath);
2423       lim_free (0, install_loc_dir);
2424     }
2425 
2426 
2427   if (is_dir)
2428     {
2429       int x;
2430 
2431       assoc_set_taking (&running->dir_loc_of, rel_make_field_str (id), rel_make_field_str (*install_loc));
2432       assoc_set_taking (&running->dir_id_of, rel_make_field_str (*install_loc), rel_make_field_str (id));
2433 
2434       for (x = 0; x < rel_n_records (file_set_aside_with); ++x)
2435         {
2436           int cmp;
2437           t_uchar * new_loc = 0;
2438           const t_uchar * sub_id;
2439 
2440           cmp = str_cmp (rel_peek_str (file_set_aside_with, x, 0), id);
2441 
2442           if (cmp < 0)
2443             continue;
2444           else if (cmp > 0)
2445             break;
2446 
2447           new_loc = file_name_in_vicinity (0, *install_loc, rel_peek_str (file_set_aside_with, x, 1));
2448           sub_id = rel_peek_str (file_set_aside_with, x, 2);
2449 
2450           assoc_set_taking (&running->file_loc_of, rel_make_field_str (sub_id), rel_make_field_str (new_loc));
2451           assoc_set_taking (&running->file_id_of, rel_make_field_str (new_loc), rel_make_field_str (sub_id));
2452 
2453           lim_free (0, new_loc);
2454         }
2455 
2456       for (x = 0; x < rel_n_records (dir_set_aside_with); ++x)
2457         {
2458           int cmp;
2459           t_uchar * new_loc = 0;
2460           const t_uchar * sub_id;
2461 
2462           cmp = str_cmp (rel_peek_str (dir_set_aside_with, x, 0), id);
2463 
2464           if (cmp < 0)
2465             continue;
2466           else if (cmp > 0)
2467             break;
2468 
2469           new_loc = file_name_in_vicinity (0, *install_loc, rel_peek_str (dir_set_aside_with, x, 1));
2470           sub_id = rel_peek_str (dir_set_aside_with, x, 2);
2471 
2472           assoc_set_taking (&running->dir_loc_of, rel_make_field_str (sub_id), rel_make_field_str (new_loc));
2473           assoc_set_taking (&running->dir_id_of, rel_make_field_str (new_loc), rel_make_field_str (sub_id));
2474 
2475           lim_free (0, new_loc);
2476         }
2477     }
2478   else
2479     {
2480       assoc_set_taking (&running->file_loc_of, rel_make_field_str (id), rel_make_field_str (*install_loc));
2481       assoc_set_taking (&running->file_id_of, rel_make_field_str (*install_loc), rel_make_field_str (id));
2482     }
2483 
2484   lim_free (0, basename);
2485   lim_free (0, loc_dir);
2486 }
2487 
2488 
2489 static void
ensure_directory_eliminating_conflicts(rel_table * deferred_conflicts,const t_uchar * spew_root,const t_uchar * target_has_path,const t_uchar * dir,const t_uchar * target)2490 ensure_directory_eliminating_conflicts (rel_table * deferred_conflicts,
2491                                         const t_uchar * spew_root,
2492                                         const t_uchar * target_has_path,
2493                                         const t_uchar * dir,
2494                                         const t_uchar * target)
2495 {
2496   t_uchar * dir_of_dir = 0;
2497 
2498   if (!str_cmp (target_has_path, dir))
2499     return;
2500 
2501   dir_of_dir = file_name_directory_file (0, dir);
2502   ensure_directory_eliminating_conflicts (deferred_conflicts, spew_root, target_has_path, dir_of_dir, target);
2503 
2504   if (safe_file_is_directory (dir))
2505     return;
2506 
2507   if (!safe_access (dir, F_OK))
2508     {
2509       t_uchar * loc;
2510       t_uchar * orig;
2511 
2512       loc = str_alloc_cat (0, "./", dir + str_length (target) + 1);
2513       orig = str_alloc_cat (0, dir, ".orig");
2514 
2515       deferred_conflict (deferred_conflicts, spew_root, target, loc, 0);
2516       safe_rename (dir, orig);
2517 
2518       lim_free (0, loc);
2519       lim_free (0, orig);
2520     }
2521 
2522   safe_mkdir (dir, 0777);
2523 
2524   lim_free (0, dir_of_dir);
2525 }
2526 
2527 
2528 static int
run_diff3(const t_uchar * basename,const t_uchar * mine_path,const t_uchar * older_path,const t_uchar * yours_path)2529 run_diff3 (const t_uchar * basename,
2530            const t_uchar * mine_path,
2531            const t_uchar * older_path,
2532            const t_uchar * yours_path)
2533 {
2534   int pid;
2535 
2536   pid = fork ();
2537 
2538   if (pid == -1)
2539     panic ("unable to fork for diff3");
2540 
2541   if (pid)
2542     {
2543       int status;
2544       int wait_pid;
2545 
2546       wait_pid = waitpid (pid, &status, 0);
2547       if (wait_pid < 0)
2548         {
2549           panic_msg ("error waiting for patch subprocess");
2550           kill (0, SIGKILL);
2551           panic ("error waiting for subprocess");
2552         }
2553       if (WIFSIGNALED (status))
2554         {
2555           safe_printfmt (2, "\n");
2556           safe_printfmt (2, "arch_apply_changeset: diff3 subprocess killed by signal %d\n", WTERMSIG (status));
2557           safe_printfmt (2, "\n");
2558           exit (2);
2559         }
2560       else if (!WIFEXITED (status))
2561         {
2562           panic_msg ("waitpid returned for a non-exited process");
2563           kill (0, SIGKILL);
2564           panic ("waitpid returned for a non-exited process");
2565         }
2566       else
2567         {
2568           int exit_status;
2569 
2570           exit_status = WEXITSTATUS (status);
2571 
2572           if (exit_status == 1)
2573             {
2574               t_uchar * rej_name = str_alloc_cat (0, basename, ".rej");
2575               int fd;
2576 
2577               if (!safe_access (rej_name, F_OK))
2578                 {
2579                   t_uchar * setaside_base_name = str_alloc_cat (0, ",,saved-", rej_name);
2580 
2581                   safe_rename (rej_name, setaside_base_name);
2582 
2583                   lim_free (0, setaside_base_name);
2584                 }
2585 
2586               fd = safe_open (rej_name, O_WRONLY | O_CREAT | O_EXCL, 0444);
2587               safe_printfmt (fd, "Conflicts occured, diff3 conflict markers left in file.\n");
2588               safe_close (fd);
2589 
2590               lim_free (0, rej_name);
2591             }
2592           return exit_status;
2593         }
2594     }
2595   else
2596     {
2597       int output_redir_fd;
2598       int input_redir_fd;
2599       t_uchar ** argv;
2600 
2601       argv = 0;
2602 
2603       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = cfg__gnu_diff3;
2604 
2605       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-E";
2606       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--merge";
2607 
2608       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-L";
2609       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "TREE";
2610 
2611       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-L";
2612       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "ANCESTOR";
2613 
2614       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-L";
2615       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "MERGE-SOURCE";
2616 
2617       /* The cast rvalues discard `const' --- reasonable here since we are
2618        * about to call `exec'.
2619        */
2620 
2621       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)mine_path;
2622       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)older_path;
2623       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)yours_path;
2624 
2625       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = 0;
2626 
2627       input_redir_fd = safe_open ("/dev/null", O_RDONLY, 0);
2628       output_redir_fd = safe_open (basename, O_WRONLY | O_CREAT | O_EXCL, 0666);
2629 
2630       safe_move_fd (input_redir_fd, 0);
2631       safe_move_fd (output_redir_fd, 1);
2632       output_redir_fd = safe_dup (1);
2633       safe_move_fd (output_redir_fd, 2);
2634 
2635       arch_util_execvp (cfg__gnu_diff3, argv);
2636       panic ("arch_apply_changeset: execvp for diff3 returned to caller");
2637       exit (2);
2638     }
2639   panic ("dopatch: not reached (run_diff3)");
2640   return 2;
2641 }
2642 
2643 
2644 static int
run_patch(int apply_in_reverse,int forward_opt_to_patch,const char * patch_path,const char * tree_file_base,const char * original_inode_name)2645 run_patch  (int apply_in_reverse,
2646             int forward_opt_to_patch,
2647             const char * patch_path,
2648             const char * tree_file_base,
2649             const char * original_inode_name)
2650 {
2651   int pid;
2652 
2653   pid = fork ();
2654 
2655   if (pid == -1)
2656     panic ("unable to fork for patch");
2657 
2658   if (pid)
2659     {
2660       int status;
2661       int wait_pid;
2662 
2663       wait_pid = waitpid (pid, &status, 0);
2664       if (wait_pid < 0)
2665         {
2666           panic_msg ("error waiting for patch subprocess");
2667           kill (0, SIGKILL);
2668           panic ("error waiting for subprocess");
2669         }
2670       if (WIFSIGNALED (status))
2671         {
2672           safe_printfmt (2, "\n");
2673           safe_printfmt (2, "arch_apply_changeset: patch subprocess killed by signal %d\n", WTERMSIG (status));
2674           safe_printfmt (2, "\n");
2675           exit (2);
2676         }
2677       else if (!WIFEXITED (status))
2678         {
2679           panic_msg ("waitpid returned for a non-exited process");
2680           kill (0, SIGKILL);
2681           panic ("waitpid returned for a non-exited process");
2682         }
2683       else
2684         {
2685           int exit_status;
2686 
2687           exit_status = WEXITSTATUS (status);
2688           return exit_status;
2689         }
2690     }
2691   else
2692     {
2693       int output_redir_fd;
2694       int input_redir_fd;
2695       t_uchar ** argv;
2696 
2697       argv = 0;
2698 
2699       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = cfg__gnu_patch;
2700 
2701       if (forward_opt_to_patch)
2702         *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--forward";
2703 
2704       if (apply_in_reverse)
2705         *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--reverse";
2706 
2707       /* `const' is discarded here -- we are about to reach `exec'
2708        */
2709 
2710       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-f";
2711       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-s";
2712       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--posix";
2713       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-i";
2714       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)patch_path;
2715       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-o";
2716       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)tree_file_base;
2717       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = (t_uchar *)original_inode_name;
2718       *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (char *)) = 0;
2719 
2720       input_redir_fd = safe_open ("/dev/null", O_RDONLY, 0);
2721       output_redir_fd = safe_open (",,patch-output", O_WRONLY | O_CREAT | O_EXCL, 0666);
2722 
2723       safe_move_fd (input_redir_fd, 0);
2724       safe_move_fd (output_redir_fd, 1);
2725       output_redir_fd = safe_dup (1);
2726       safe_move_fd (output_redir_fd, 2);
2727 
2728       arch_util_execvp (cfg__gnu_patch, argv);
2729       panic ("arch_apply_changeset: execvp for patch returned to caller");
2730       exit (2);
2731     }
2732   panic ("dopatch: not reached (run_patch)");
2733   return 2;
2734 }
2735 
2736 
2737 static void
save_patch_for_missing_file(const t_uchar * missing_patch_dir,const t_uchar * patch_path,const t_uchar * mod_loc)2738 save_patch_for_missing_file (const t_uchar * missing_patch_dir,
2739                              const t_uchar * patch_path,
2740                              const t_uchar * mod_loc)
2741 {
2742   t_uchar * mod_loc_dir = 0;
2743   t_uchar * dest_dir = 0;
2744   t_uchar * patch_tail = 0;
2745   t_uchar * dest_path = 0;
2746 
2747   mod_loc_dir = file_name_directory_file (0, mod_loc);
2748   dest_dir = file_name_in_vicinity (0, missing_patch_dir, mod_loc_dir);
2749   ensure_directory_exists (dest_dir);
2750   patch_tail = file_name_tail (0, patch_path);
2751   dest_path = file_name_in_vicinity (0, dest_dir, patch_tail);
2752   copy_file (patch_path, dest_path);
2753 
2754   lim_free (0, mod_loc_dir);
2755   lim_free (0, dest_dir);
2756   lim_free (0, patch_tail);
2757   lim_free (0, dest_path);
2758 }
2759 
2760 
2761 
2762 
2763 /* tag: Tom Lord Thu May 15 17:19:28 2003 (apply-changeset.c)
2764  */
2765