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