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