/* make-changeset-files.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2003 Tom Lord * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/mem/mem.h" #include "hackerlab/char/str.h" #include "hackerlab/char/pika-escaping-utils.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/vu/safe.h" #include "libarch/diffs.h" #include "libawk/relassoc.h" #include "libarch/invent.h" #include "libarch/make-changeset-files.h" /* __STDC__ prototypes for static functions */ static int find_id_in_inventory (rel_table invent, t_uchar * id); static void double_check_file_identity (t_uchar * from_here_path, t_uchar * tree_root, t_uchar * loc); #if !defined(__GNUC__) # undef __attribute__ # define __attribute__(X) #endif static void __attribute__((format (printf, 2, 3))) invoke_report_callback (struct arch_make_changeset_report * report, char * fmt, ...) { va_list ap; if (report->callback) { va_start (ap, fmt); report->callback (report->thunk, fmt, ap); va_end (ap); } } /** * \brief make a changeset with limits * * fixing up the method and unttaged source here * requires fixing up inventory. * \param file_list a list of paths in the orig tree */ void arch_make_files_changeset (struct arch_make_changeset_report * report, t_uchar * dest, rel_table file_list, arch_project_tree_t * orig, arch_project_tree_t * mod, enum arch_id_tagging_method method, enum arch_inventory_category untagged_source_category, int escape_classes) { int x; struct arch_changeset_report csr = {0,}; int overide_untagged_source = 0; int overide_method = 0; int prior_untagged_source = 0; enum arch_id_tagging_method prior_method = arch_unspecified_id_tagging; if (method == arch_unspecified_id_tagging) { /* sets untagged source in mod */ method = arch_tree_id_tagging_method (mod, &untagged_source_category, 0); } else { overide_untagged_source = 1; overide_method = 1; } /* sets untagged source in orig */ arch_tree_id_tagging_method (orig, &untagged_source_category, 0); mem_set0 ((t_uchar *)&report->orig_index, sizeof (report->orig_index)); mem_set0 ((t_uchar *)&report->mod_index, sizeof (report->mod_index)); arch_changeset_inventory (&report->orig_index, orig, method, untagged_source_category, escape_classes); report->mod_index.dirs = rel_copy_table (report->orig_index.dirs); report->mod_index.files = rel_copy_table (report->orig_index.files); /**************************************************************** * build associative tables too and from ids and locs */ report->orig_dir_id_of = rel_to_assoc (report->orig_index.dirs, 0, 1); report->orig_dir_loc_of = rel_to_assoc (report->orig_index.dirs, 1, 0); report->orig_file_id_of = rel_to_assoc (report->orig_index.files, 0, 1); report->orig_file_loc_of = rel_to_assoc (report->orig_index.files, 1, 0); report->mod_dir_id_of = rel_to_assoc (report->mod_index.dirs, 0, 1); report->mod_dir_loc_of = rel_to_assoc (report->mod_index.dirs, 1, 0); report->mod_file_id_of = rel_to_assoc (report->mod_index.files, 0, 1); report->mod_file_loc_of = rel_to_assoc (report->mod_index.files, 1, 0); assoc_set (&report->orig_dir_id_of, ".", "?_."); assoc_set (&report->mod_dir_id_of, ".", "?_."); assoc_set (&report->orig_dir_loc_of, "?_.", "."); assoc_set (&report->mod_dir_loc_of, "?_.", "."); arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_dir_id, report->orig_dir_id_of, report->orig_index.dirs); arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_file_id, report->orig_dir_id_of, report->orig_index.files); arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_dir_id, report->mod_dir_id_of, report->mod_index.dirs); arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_file_id, report->mod_dir_id_of, report->mod_index.files); arch_make_empty_changeset (report, &csr, dest); for (x = 0; x < rel_n_records (file_list); ++x) { t_uchar * id = 0; int orig_index; int mod_index; t_uchar * orig_path = 0; t_uchar * mod_path = 0; int diff_fd; if (overide_untagged_source) { prior_untagged_source = orig->untagged_is_source; orig->untagged_is_source = untagged_source_category == arch_inventory_source; } if (overide_method) { prior_method = orig->tag_method; orig->tag_method = method; } id = arch_inventory_id (orig, file_list[x][0], 0); if (overide_untagged_source) orig->untagged_is_source = prior_untagged_source; if (overide_method) orig->tag_method = prior_method; orig_index = find_id_in_inventory (report->orig_index.files, id); mod_index = find_id_in_inventory (report->mod_index.files, id); if (orig_index < 0) { safe_printfmt (2, "make-changeset-files: file missing from ORIG tree (%s)\n", file_list[x][0]); exit (1); } if (mod_index < 0) { safe_printfmt (2, "make-changeset-files: file missing from MOD tree (%s)\n", file_list[x][0]); exit (1); } double_check_file_identity (file_list[x][0], mod->root, report->mod_index.files[mod_index][0]); orig_path = file_name_in_vicinity (0, orig->root, report->orig_index.files[orig_index][0]); mod_path = file_name_in_vicinity (0, mod->root, report->mod_index.files[mod_index][0]); if (arch_binary_files_differ (orig_path, mod_path, 0, 0)) { int diff_stat; t_uchar * escaped_tmp; escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, file_list[x][0]); invoke_report_callback (report, "M %s\n", escaped_tmp); diff_fd = arch_changeset_add_diffs (&csr, report, dest, report->orig_index.files[orig_index][0], report->mod_index.files[mod_index][0], id); diff_stat = arch_invoke_diff (diff_fd, orig_path, report->orig_index.files[orig_index][0], mod_path, report->orig_index.files[orig_index][0], 0, 0); safe_close (diff_fd); lim_free (0, escaped_tmp); if (diff_stat == 1) { t_uchar diff_pseudo_magic[sizeof ("binary files ")]; t_uchar * patches_path = 0; t_uchar * patch_path = 0; int diff_in_fd; long amt; patches_path = file_name_in_vicinity (0, dest, "patches"); patch_path = file_name_in_vicinity (0, patches_path, report->mod_index.files[mod_index][0]); patch_path = str_realloc_cat (0, patch_path, ".patch"); diff_in_fd = safe_open (patch_path, O_RDONLY, 0); /* diff might have just said "binary files differ" or something * similar. */ amt = safe_read (diff_in_fd, diff_pseudo_magic, sizeof (diff_pseudo_magic) - 1); if (amt > 0) { diff_pseudo_magic[amt] = 0; if (!str_casecmp (diff_pseudo_magic, "binary files ")) diff_stat = 2; } safe_close (diff_in_fd); lim_free (0, patch_path); lim_free (0, patches_path); } if (diff_stat == 2) { safe_printfmt (2, "binary files not yet supported with --files or --file-list\n"); exit (2); } } lim_free (0, id); lim_free (0, orig_path); lim_free (0, mod_path); } arch_changeset_rewrite_indexes (dest, &csr); arch_free_changeset_report_data (&csr); } static int find_id_in_inventory (rel_table invent, t_uchar * id) { int x; for (x = 0; x < rel_n_records (invent); ++x) { if (!str_cmp (id, invent[x][1])) return x; } return -1; } static void double_check_file_identity (t_uchar * from_here_path, t_uchar * tree_root, t_uchar * loc) { struct stat users_stat; t_uchar * computed_path = 0; struct stat computed_stat; safe_stat (from_here_path, &users_stat); computed_path = file_name_in_vicinity (0, tree_root, loc); safe_stat (computed_path, &computed_stat); lim_free (0, computed_path); if ((users_stat.st_dev != computed_stat.st_dev) || (users_stat.st_ino != computed_stat.st_ino)) { safe_printfmt (2, "make-changeset --files: the file specified as %s\n is not the same as the one in the project tree (%s)\n", from_here_path, computed_path); exit (1); } } /* tag: Tom Lord Tue Jun 17 21:39:34 2003 (make-changeset-files.c) */