1 /* make-changeset-files.c:
2  *
3  ****************************************************************
4  * Copyright (C) 2003 Tom Lord
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 
11 #include "hackerlab/mem/mem.h"
12 #include "hackerlab/char/str.h"
13 #include "hackerlab/char/pika-escaping-utils.h"
14 #include "hackerlab/fs/file-names.h"
15 #include "hackerlab/vu/safe.h"
16 #include "tla/libarch/diffs.h"
17 #include "tla/libawk/relassoc.h"
18 #include "tla/libarch/invent.h"
19 #include "tla/libarch/make-changeset-files.h"
20 
21 
22 /* __STDC__ prototypes for static functions */
23 static void __attribute__((format (printf, 2, 3))) invoke_report_callback (struct arch_make_changeset_report * report,
24                                                                            const char * fmt, ...);
25      static int find_id_in_inventory (rel_table invent,
26                                       const t_uchar * id);
27      static void double_check_file_identity (const t_uchar * from_here_path,
28                                              const t_uchar * tree_root,
29                                              const t_uchar * loc);
30 
31 
32 #if !defined(__GNUC__)
33 #  undef __attribute__
34 #  define __attribute__(X)
35 #endif
36 
37 static void __attribute__((format (printf, 2, 3)))
invoke_report_callback(struct arch_make_changeset_report * report,const char * fmt,...)38 invoke_report_callback (struct arch_make_changeset_report * report,
39                         const char * fmt, ...)
40 {
41   va_list ap;
42 
43   if (report->callback)
44     {
45       va_start (ap, fmt);
46       report->callback (report->thunk, fmt, ap);
47       va_end (ap);
48     }
49 }
50 
51 
52 void
arch_make_files_changeset(struct arch_make_changeset_report * report,const t_uchar * dest,rel_table file_list,const t_uchar * orig,const t_uchar * mod,enum arch_id_tagging_method method,enum arch_inventory_category untagged_source_category,int escape_classes)53 arch_make_files_changeset (struct arch_make_changeset_report * report,
54                            const t_uchar * dest,
55                            rel_table file_list,
56                            const t_uchar * orig,
57                            const t_uchar * mod,
58                            enum arch_id_tagging_method method,
59                            enum arch_inventory_category untagged_source_category,
60                            int escape_classes)
61 {
62   int x;
63 
64   struct arch_changeset_report csr = {rel_table_nil,};
65 
66   if (method == arch_unspecified_id_tagging)
67     {
68       method = arch_tree_id_tagging_method (&untagged_source_category, mod, 0);
69     }
70 
71   mem_set0 ((t_uchar *)&report->orig_index, sizeof (report->orig_index));
72   mem_set0 ((t_uchar *)&report->mod_index, sizeof (report->mod_index));
73 
74   arch_changeset_inventory (&report->orig_index, orig, orig, method, untagged_source_category, escape_classes);
75   report->mod_index.dirs = rel_copy_table (report->orig_index.dirs);
76   report->mod_index.files = rel_copy_table (report->orig_index.files);
77 
78 
79   /****************************************************************
80    * build associative tables too and from ids and locs
81    */
82   report->orig_dir_id_of = rel_to_assoc (report->orig_index.dirs, 0, 1);
83   report->orig_dir_loc_of = rel_to_assoc (report->orig_index.dirs, 1, 0);
84 
85   report->orig_file_id_of = rel_to_assoc (report->orig_index.files, 0, 1);
86   report->orig_file_loc_of = rel_to_assoc (report->orig_index.files, 1, 0);
87 
88   report->mod_dir_id_of = rel_to_assoc (report->mod_index.dirs, 0, 1);
89   report->mod_dir_loc_of = rel_to_assoc (report->mod_index.dirs, 1, 0);
90 
91   report->mod_file_id_of = rel_to_assoc (report->mod_index.files, 0, 1);
92   report->mod_file_loc_of = rel_to_assoc (report->mod_index.files, 1, 0);
93 
94   assoc_set_taking (&report->orig_dir_id_of, rel_make_field_str ("."), rel_make_field_str ("?_."));
95   assoc_set_taking (&report->mod_dir_id_of, rel_make_field_str ("."), rel_make_field_str ("?_."));
96   assoc_set_taking (&report->orig_dir_loc_of, rel_make_field_str ("?_."), rel_make_field_str ("."));
97   assoc_set_taking (&report->mod_dir_loc_of, rel_make_field_str ("?_."), rel_make_field_str ("."));
98 
99   arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_dir_id, report->orig_dir_id_of, report->orig_index.dirs);
100   arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_file_id, report->orig_dir_id_of, report->orig_index.files);
101   arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_dir_id, report->mod_dir_id_of, report->mod_index.dirs);
102   arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_file_id, report->mod_dir_id_of, report->mod_index.files);
103 
104   arch_make_empty_changeset (report, &csr, dest);
105 
106   for (x = 0; x < rel_n_records (file_list); ++x)
107     {
108       t_uchar * id = 0;
109       int orig_index;
110       int mod_index;
111       t_uchar * orig_path = 0;
112       t_uchar * mod_path = 0;
113       int diff_fd;
114 
115       id = arch_inventory_id (method, untagged_source_category, rel_peek_str (file_list, x, 0), 0, 0, 0);
116 
117       orig_index = find_id_in_inventory (report->orig_index.files, id);
118       mod_index = find_id_in_inventory (report->mod_index.files, id);
119 
120       if (orig_index < 0)
121         {
122           safe_printfmt (2, "make-changeset-files: file missing from ORIG tree (%s)\n", rel_peek_str (file_list, x, 0));
123           exit (1);
124         }
125 
126       if (mod_index < 0)
127         {
128           safe_printfmt (2, "make-changeset-files: file missing from MOD tree (%s)\n", rel_peek_str (file_list, x, 0));
129           exit (1);
130         }
131 
132       double_check_file_identity (rel_peek_str (file_list, x, 0), mod, rel_peek_str (report->mod_index.files, mod_index, 0));
133 
134       orig_path = file_name_in_vicinity (0, orig, rel_peek_str (report->orig_index.files, orig_index, 0));
135       mod_path = file_name_in_vicinity (0, mod, rel_peek_str (report->mod_index.files, mod_index, 0));
136 
137       if (arch_binary_files_differ (orig_path, mod_path, 0, 0))
138         {
139           int diff_stat;
140           t_uchar * escaped_tmp;
141 
142           escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, rel_peek_str (file_list, x, 0));
143           invoke_report_callback (report, "M  %s\n", escaped_tmp);
144           diff_fd = arch_changeset_add_diffs (&csr, report, dest, rel_peek_str (report->orig_index.files, orig_index, 0), rel_peek_str (report->mod_index.files, mod_index, 0), id);
145           diff_stat = arch_invoke_diff (diff_fd, orig_path, rel_peek_str (report->orig_index.files, orig_index, 0), mod_path, rel_peek_str (report->orig_index.files, orig_index, 0), 0, 0);
146           safe_close (diff_fd);
147 
148           lim_free (0, escaped_tmp);
149 
150           if (diff_stat == 1)
151             {
152               t_uchar diff_pseudo_magic[sizeof ("binary files ")];
153               t_uchar * patches_path = 0;
154               t_uchar * patch_path = 0;
155               int diff_in_fd;
156               long amt;
157 
158               patches_path = file_name_in_vicinity (0, dest, "patches");
159               patch_path = file_name_in_vicinity (0, patches_path, rel_peek_str (report->mod_index.files, mod_index, 0));
160               patch_path = str_realloc_cat (0, patch_path, ".patch");
161 
162               diff_in_fd = safe_open (patch_path, O_RDONLY, 0);
163 
164               /* diff might have just said "binary files differ" or something
165                * similar.
166                */
167               amt = safe_read (diff_in_fd, diff_pseudo_magic, sizeof (diff_pseudo_magic) - 1);
168 
169               if (amt > 0)
170                 {
171                   diff_pseudo_magic[amt] = 0;
172                   if (!str_casecmp (diff_pseudo_magic, "binary files "))
173                     diff_stat = 2;
174                 }
175               safe_close (diff_in_fd);
176               lim_free (0, patch_path);
177               lim_free (0, patches_path);
178             }
179 
180           if (diff_stat == 2)
181             {
182               safe_printfmt (2, "binary files not yet supported with --files or --file-list\n");
183               exit (2);
184             }
185 
186         }
187 
188       lim_free (0, id);
189       lim_free (0, orig_path);
190       lim_free (0, mod_path);
191     }
192 
193   arch_changeset_rewrite_indexes (dest, &csr);
194   arch_free_changeset_report_data (&csr);
195 }
196 
197 
198 
199 
200 static int
find_id_in_inventory(rel_table invent,const t_uchar * id)201 find_id_in_inventory (rel_table invent,
202                       const t_uchar * id)
203 {
204   int x;
205 
206   for (x = 0; x < rel_n_records (invent); ++x)
207     {
208       if (!str_cmp (id, rel_peek_str (invent, x, 1)))
209         return x;
210     }
211 
212   return -1;
213 }
214 
215 
216 static void
double_check_file_identity(const t_uchar * from_here_path,const t_uchar * tree_root,const t_uchar * loc)217 double_check_file_identity (const t_uchar * from_here_path,
218                             const t_uchar * tree_root,
219                             const t_uchar * loc)
220 {
221   struct stat users_stat;
222   t_uchar * computed_path = 0;
223   struct stat computed_stat;
224 
225   safe_stat (from_here_path, &users_stat);
226   computed_path = file_name_in_vicinity (0, tree_root, loc);
227   safe_stat (computed_path, &computed_stat);
228 
229   lim_free (0, computed_path);
230   if ((users_stat.st_dev != computed_stat.st_dev) || (users_stat.st_ino != computed_stat.st_ino))
231     {
232       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);
233       exit (1);
234     }
235 }
236 
237 
238 
239 
240 /* tag: Tom Lord Tue Jun 17 21:39:34 2003 (make-changeset-files.c)
241  */
242