File: | src/usr.bin/cvs/import.c |
Warning: | line 399, column 6 Access to field 'rf_head' results in a dereference of a null pointer (loaded from field 'file_rcs') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: import.c,v 1.109 2019/06/28 13:35:00 deraadt Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2006 Joris Vink <joris@openbsd.org> | |||
4 | * | |||
5 | * Permission to use, copy, modify, and distribute this software for any | |||
6 | * purpose with or without fee is hereby granted, provided that the above | |||
7 | * copyright notice and this permission notice appear in all copies. | |||
8 | * | |||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
16 | */ | |||
17 | ||||
18 | #include <sys/stat.h> | |||
19 | ||||
20 | #include <errno(*__errno()).h> | |||
21 | #include <fcntl.h> | |||
22 | #include <stdlib.h> | |||
23 | #include <string.h> | |||
24 | #include <unistd.h> | |||
25 | ||||
26 | #include "cvs.h" | |||
27 | #include "diff.h" | |||
28 | #include "remote.h" | |||
29 | ||||
30 | void cvs_import_local(struct cvs_file *); | |||
31 | ||||
32 | static void import_loginfo(char *); | |||
33 | static void import_new(struct cvs_file *); | |||
34 | static void import_printf(const char *, ...) | |||
35 | __attribute__((format(printf, 1, 2))); | |||
36 | static void import_update(struct cvs_file *); | |||
37 | static void import_tag(struct cvs_file *, RCSNUM *, RCSNUM *); | |||
38 | static BUF *import_get_rcsdiff(struct cvs_file *, RCSNUM *); | |||
39 | ||||
40 | #define IMPORT_DEFAULT_BRANCH"1.1.1" "1.1.1" | |||
41 | ||||
42 | extern char *loginfo; | |||
43 | extern char *logmsg; | |||
44 | ||||
45 | static char *import_branch = IMPORT_DEFAULT_BRANCH"1.1.1"; | |||
46 | static char *vendor_tag = NULL((void *)0); | |||
47 | static char **release_tags; | |||
48 | static char *koptstr; | |||
49 | static int dflag = 0; | |||
50 | static int tagcount = 0; | |||
51 | static BUF *logbuf; | |||
52 | ||||
53 | char *import_repository = NULL((void *)0); | |||
54 | int import_conflicts = 0; | |||
55 | ||||
56 | struct cvs_cmd cvs_cmd_import = { | |||
57 | CVS_OP_IMPORT11, CVS_USE_WDIR0x01, "import", | |||
58 | { "im", "imp" }, | |||
59 | "Import sources into CVS, using vendor branches", | |||
60 | "[-b branch] [-d] [-k mode] [-m message] " | |||
61 | "repository vendor-tag release-tags", | |||
62 | "b:dk:m:", | |||
63 | NULL((void *)0), | |||
64 | cvs_import | |||
65 | }; | |||
66 | ||||
67 | int | |||
68 | cvs_import(int argc, char **argv) | |||
69 | { | |||
70 | int i, ch; | |||
71 | char repo[PATH_MAX1024], *arg = "."; | |||
72 | struct cvs_recursion cr; | |||
73 | struct trigger_list *line_list; | |||
74 | ||||
75 | while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) { | |||
76 | switch (ch) { | |||
77 | case 'b': | |||
78 | import_branch = optarg; | |||
79 | break; | |||
80 | case 'd': | |||
81 | dflag = 1; | |||
82 | break; | |||
83 | case 'k': | |||
84 | koptstr = optarg; | |||
85 | kflag = rcs_kflag_get(koptstr); | |||
86 | if (RCS_KWEXP_INVAL(kflag)((kflag & 0x20) || ((kflag & 0x10) && (kflag & ~0x10)))) { | |||
87 | cvs_log(LP_ERR1, | |||
88 | "invalid RCS keyword expansion mode"); | |||
89 | fatal("%s", cvs_cmd_import.cmd_synopsis); | |||
90 | } | |||
91 | break; | |||
92 | case 'm': | |||
93 | logmsg = optarg; | |||
94 | break; | |||
95 | default: | |||
96 | fatal("%s", cvs_cmd_import.cmd_synopsis); | |||
97 | break; | |||
98 | } | |||
99 | } | |||
100 | ||||
101 | argc -= optind; | |||
102 | argv += optind; | |||
103 | ||||
104 | if (argc < 3) | |||
105 | fatal("%s", cvs_cmd_import.cmd_synopsis); | |||
106 | ||||
107 | import_repository = argv[0]; | |||
108 | vendor_tag = argv[1]; | |||
109 | argc -= 2; | |||
110 | argv += 2; | |||
111 | ||||
112 | release_tags = argv; | |||
113 | tagcount = argc; | |||
114 | ||||
115 | if (!rcs_sym_check(vendor_tag)) | |||
116 | fatal("invalid symbol: %s", vendor_tag); | |||
117 | ||||
118 | for (i = 0; i < tagcount; i++) { | |||
119 | if (!rcs_sym_check(release_tags[i])) | |||
120 | fatal("invalid symbol: %s", release_tags[i]); | |||
121 | } | |||
122 | ||||
123 | if (logmsg == NULL((void *)0)) { | |||
124 | if (cvs_server_active) | |||
125 | fatal("no log message specified"); | |||
126 | else | |||
127 | logmsg = cvs_logmsg_create(NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0)); | |||
128 | } | |||
129 | ||||
130 | if (cvsroot_is_remote()) { | |||
131 | cvs_client_connect_to_server(); | |||
132 | ||||
133 | cvs_client_send_request("Argument -b%s", IMPORT_DEFAULT_BRANCH"1.1.1"); | |||
134 | ||||
135 | if (kflag) | |||
136 | cvs_client_send_request("Argument -k%s", koptstr); | |||
137 | ||||
138 | cvs_client_send_logmsg(logmsg); | |||
139 | cvs_client_send_request("Argument %s", import_repository); | |||
140 | cvs_client_send_request("Argument %s", vendor_tag); | |||
141 | for (i = 0; i < tagcount; i++) | |||
142 | cvs_client_send_request("Argument %s", release_tags[i]); | |||
143 | ||||
144 | cr.enterdir = NULL((void *)0); | |||
145 | cr.leavedir = NULL((void *)0); | |||
146 | cr.fileproc = cvs_client_sendfile; | |||
147 | cr.flags = CR_RECURSE_DIRS0x01; | |||
148 | ||||
149 | cvs_file_run(1, &arg, &cr); | |||
150 | cvs_client_senddir("."); | |||
151 | cvs_client_send_request("import"); | |||
152 | ||||
153 | cvs_client_get_responses(); | |||
154 | return (0); | |||
155 | } | |||
156 | ||||
157 | if (cvs_logmsg_verify(logmsg)) | |||
158 | return (0); | |||
159 | ||||
160 | (void)xsnprintf(repo, sizeof(repo), "%s/%s", | |||
161 | current_cvsroot->cr_dir, import_repository); | |||
162 | ||||
163 | import_loginfo(import_repository); | |||
164 | ||||
165 | if (cvs_noexec != 1) | |||
166 | cvs_mkdir(repo, 0755); | |||
167 | ||||
168 | cr.enterdir = NULL((void *)0); | |||
169 | cr.leavedir = NULL((void *)0); | |||
170 | cr.fileproc = cvs_import_local; | |||
171 | cr.flags = CR_RECURSE_DIRS0x01; | |||
172 | cvs_file_run(1, &arg, &cr); | |||
173 | ||||
174 | if (import_conflicts != 0) { | |||
175 | import_printf("\n%d conflicts created by this import.\n\n", | |||
176 | import_conflicts); | |||
177 | import_printf("Use the following command to help the merge:\n"); | |||
178 | import_printf("\topencvs checkout "); | |||
179 | import_printf("-j%s:yesterday -j%s %s\n\n", vendor_tag, | |||
180 | vendor_tag, import_repository); | |||
181 | } else { | |||
182 | import_printf("\nNo conflicts created by this import.\n\n"); | |||
183 | } | |||
184 | ||||
185 | loginfo = buf_release(logbuf); | |||
186 | logbuf = NULL((void *)0); | |||
187 | ||||
188 | line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO"CVSROOT" "/loginfo", import_repository); | |||
189 | if (line_list != NULL((void *)0)) { | |||
190 | cvs_trigger_handle(CVS_TRIGGER_LOGINFO2, import_repository, | |||
191 | loginfo, line_list, NULL((void *)0)); | |||
192 | cvs_trigger_freelist(line_list); | |||
193 | } | |||
194 | ||||
195 | free(loginfo); | |||
196 | return (0); | |||
197 | } | |||
198 | ||||
199 | static void | |||
200 | import_printf(const char *fmt, ...) | |||
201 | { | |||
202 | char *str; | |||
203 | va_list vap; | |||
204 | ||||
205 | va_start(vap, fmt)__builtin_va_start((vap), fmt); | |||
206 | if (vasprintf(&str, fmt, vap) == -1) | |||
207 | fatal("import_printf: could not allocate memory"); | |||
208 | va_end(vap)__builtin_va_end((vap)); | |||
209 | ||||
210 | cvs_printf("%s", str); | |||
211 | buf_puts(logbuf, str); | |||
212 | ||||
213 | free(str); | |||
214 | } | |||
215 | ||||
216 | void | |||
217 | cvs_import_ignored(const char *path) | |||
218 | { | |||
219 | const char *p; | |||
220 | ||||
221 | for (p = path; p[0] == '.' && p[1] == '/';) | |||
222 | p += 2; | |||
223 | ||||
224 | import_printf("I %s/%s\n", import_repository, p); | |||
225 | } | |||
226 | ||||
227 | void | |||
228 | cvs_import_local(struct cvs_file *cf) | |||
229 | { | |||
230 | int isnew; | |||
231 | struct stat st; | |||
232 | char repo[PATH_MAX1024]; | |||
233 | ||||
234 | cvs_log(LP_TRACE4, "cvs_import_local(%s)", cf->file_path); | |||
235 | ||||
236 | cvs_file_classify(cf, cvs_directory_tag); | |||
| ||||
237 | ||||
238 | if (cf->file_type == CVS_DIR1) { | |||
239 | if (!strcmp(cf->file_path, ".")) | |||
240 | return; | |||
241 | ||||
242 | if (verbosity > 1) | |||
243 | cvs_log(LP_NOTICE0, "Importing %s", cf->file_path); | |||
244 | ||||
245 | if (cvs_noexec == 1) | |||
246 | return; | |||
247 | ||||
248 | if (mkdir(cf->file_rpath, 0755) == -1 && errno(*__errno()) != EEXIST17) | |||
249 | fatal("cvs_import_local: %s: %s", cf->file_rpath, | |||
250 | strerror(errno(*__errno()))); | |||
251 | ||||
252 | return; | |||
253 | } | |||
254 | ||||
255 | isnew = 1; | |||
256 | (void)xsnprintf(repo, sizeof(repo), "%s/%s/%s/%s%s", | |||
257 | current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC"Attic", | |||
258 | cf->file_name, RCS_FILE_EXT",v"); | |||
259 | ||||
260 | if (cf->file_rcs != NULL((void *)0) || stat(repo, &st) != -1) | |||
261 | isnew = 0; | |||
262 | ||||
263 | if (isnew
| |||
264 | import_new(cf); | |||
265 | else | |||
266 | import_update(cf); | |||
267 | } | |||
268 | ||||
269 | static void | |||
270 | import_loginfo(char *repo) | |||
271 | { | |||
272 | int i; | |||
273 | char pwd[PATH_MAX1024]; | |||
274 | ||||
275 | if (getcwd(pwd, sizeof(pwd)) == NULL((void *)0)) | |||
276 | fatal("Can't get working directory"); | |||
277 | ||||
278 | logbuf = buf_alloc(1024); | |||
279 | cvs_trigger_loginfo_header(logbuf, repo); | |||
280 | ||||
281 | buf_puts(logbuf, "Log Message:\n"); | |||
282 | buf_puts(logbuf, logmsg); | |||
283 | if (logmsg[0] != '\0' && logmsg[strlen(logmsg) - 1] != '\n') | |||
284 | buf_putc(logbuf, '\n'); | |||
285 | buf_putc(logbuf, '\n'); | |||
286 | ||||
287 | buf_puts(logbuf, "Status:\n\n"); | |||
288 | ||||
289 | buf_puts(logbuf, "Vendor Tag:\t"); | |||
290 | buf_puts(logbuf, vendor_tag); | |||
291 | buf_putc(logbuf, '\n'); | |||
292 | buf_puts(logbuf, "Release Tags:\t"); | |||
293 | ||||
294 | for (i = 0; i < tagcount ; i++) { | |||
295 | buf_puts(logbuf, "\t\t"); | |||
296 | buf_puts(logbuf, release_tags[i]); | |||
297 | buf_putc(logbuf, '\n'); | |||
298 | } | |||
299 | buf_putc(logbuf, '\n'); | |||
300 | buf_putc(logbuf, '\n'); | |||
301 | } | |||
302 | ||||
303 | static void | |||
304 | import_new(struct cvs_file *cf) | |||
305 | { | |||
306 | int i; | |||
307 | BUF *bp; | |||
308 | mode_t mode; | |||
309 | time_t tstamp; | |||
310 | struct stat st; | |||
311 | struct rcs_branch *brp; | |||
312 | struct rcs_delta *rdp; | |||
313 | RCSNUM *branch, *brev; | |||
314 | ||||
315 | tstamp = -1; | |||
316 | ||||
317 | cvs_log(LP_TRACE4, "import_new(%s)", cf->file_name); | |||
318 | ||||
319 | if (cvs_noexec == 1) { | |||
320 | import_printf("N %s/%s\n", import_repository, cf->file_path); | |||
321 | return; | |||
322 | } | |||
323 | ||||
324 | if (fstat(cf->fd, &st) == -1) | |||
325 | fatal("import_new: %s", strerror(errno(*__errno()))); | |||
326 | ||||
327 | mode = st.st_mode; | |||
328 | ||||
329 | if (dflag == 1) | |||
330 | tstamp = st.st_mtimest_mtim.tv_sec; | |||
331 | ||||
332 | if ((branch = rcsnum_parse(import_branch)) == NULL((void *)0)) | |||
333 | fatal("import_new: failed to parse branch"); | |||
334 | ||||
335 | bp = buf_load_fd(cf->fd); | |||
336 | ||||
337 | if ((brev = rcsnum_brtorev(branch)) == NULL((void *)0)) | |||
338 | fatal("import_new: failed to get first branch revision"); | |||
339 | ||||
340 | cf->repo_fd = open(cf->file_rpath, O_CREAT0x0200 | O_RDONLY0x0000); | |||
341 | if (cf->repo_fd == -1) | |||
342 | fatal("import_new: %s: %s", cf->file_rpath, strerror(errno(*__errno()))); | |||
343 | ||||
344 | cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE(1<<2), | |||
345 | (mode & ~(S_IWUSR0000200 | S_IWGRP0000020 | S_IWOTH0000002))); | |||
346 | if (cf->file_rcs == NULL((void *)0)) | |||
347 | fatal("import_new: failed to create RCS file for %s", | |||
348 | cf->file_path); | |||
349 | ||||
350 | rcs_branch_set(cf->file_rcs, branch); | |||
351 | ||||
352 | if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1) | |||
353 | fatal("import_new: failed to add vendor tag"); | |||
354 | ||||
355 | for (i = 0; i < tagcount; i++) { | |||
356 | if (rcs_sym_add(cf->file_rcs, release_tags[i], brev) == -1) | |||
357 | fatal("import_new: failed to add release tag"); | |||
358 | } | |||
359 | ||||
360 | if (rcs_rev_add(cf->file_rcs, brev, logmsg, tstamp, NULL((void *)0)) == -1) | |||
361 | fatal("import_new: failed to create first branch revision"); | |||
362 | ||||
363 | if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV((RCSNUM *)(-1)), "Initial revision", | |||
364 | tstamp, NULL((void *)0)) == -1) | |||
365 | fatal("import_new: failed to create first revision"); | |||
366 | ||||
367 | if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL((void *)0)) | |||
368 | fatal("import_new: cannot find newly added revision"); | |||
369 | ||||
370 | brp = xmalloc(sizeof(*brp)); | |||
371 | brp->rb_num = rcsnum_alloc(); | |||
372 | rcsnum_cpy(brev, brp->rb_num, 0); | |||
373 | TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list)do { (brp)->rb_list.tqe_next = ((void *)0); (brp)->rb_list .tqe_prev = (&(rdp->rd_branches))->tqh_last; *(& (rdp->rd_branches))->tqh_last = (brp); (&(rdp->rd_branches ))->tqh_last = &(brp)->rb_list.tqe_next; } while (0 ); | |||
374 | ||||
375 | if (rcs_deltatext_set(cf->file_rcs, | |||
376 | cf->file_rcs->rf_head, bp) == -1) | |||
377 | fatal("import_new: failed to set deltatext"); | |||
378 | ||||
379 | if (kflag) | |||
380 | rcs_kwexp_set(cf->file_rcs, kflag); | |||
381 | ||||
382 | rcs_write(cf->file_rcs); | |||
383 | import_printf("N %s/%s\n", import_repository, cf->file_path); | |||
384 | ||||
385 | free(branch); | |||
386 | free(brev); | |||
387 | } | |||
388 | ||||
389 | static void | |||
390 | import_update(struct cvs_file *cf) | |||
391 | { | |||
392 | int ret; | |||
393 | BUF *b1, *b2, *d; | |||
394 | char branch[CVS_REV_BUFSZ32]; | |||
395 | RCSNUM *newrev, *rev, *brev; | |||
396 | ||||
397 | cvs_log(LP_TRACE4, "import_update(%s)", cf->file_path); | |||
398 | ||||
399 | if (cf->file_rcs->rf_head == NULL((void *)0)) | |||
| ||||
400 | fatal("no head revision in RCS file for `%s'", cf->file_path); | |||
401 | ||||
402 | if ((rev = rcs_translate_tag(import_branch, cf->file_rcs)) == NULL((void *)0)) | |||
403 | fatal("import_update: could not translate tag `%s'", | |||
404 | import_branch); | |||
405 | ||||
406 | if ((brev = rcsnum_parse(import_branch)) == NULL((void *)0)) | |||
407 | fatal("import_update: rcsnum_parse failed"); | |||
408 | ||||
409 | b1 = rcs_rev_getbuf(cf->file_rcs, rev, RCS_KWEXP_NONE0x01); | |||
410 | b2 = buf_load_fd(cf->fd); | |||
411 | ||||
412 | ret = buf_differ(b1, b2); | |||
413 | buf_free(b1); | |||
414 | buf_free(b2); | |||
415 | if (ret == 0) { | |||
416 | import_tag(cf, brev, rev); | |||
417 | free(brev); | |||
418 | if (cvs_noexec != 1) | |||
419 | rcs_write(cf->file_rcs); | |||
420 | import_printf("U %s/%s\n", import_repository, cf->file_path); | |||
421 | return; | |||
422 | } | |||
423 | ||||
424 | if (cf->file_rcs->rf_branch != NULL((void *)0)) | |||
425 | rcsnum_tostr(cf->file_rcs->rf_branch, branch, sizeof(branch)); | |||
426 | ||||
427 | if (cf->file_rcs->rf_branch == NULL((void *)0) || cf->in_attic == 1 || | |||
428 | strcmp(branch, import_branch)) { | |||
429 | import_conflicts++; | |||
430 | import_printf("C %s/%s\n", import_repository, cf->file_path); | |||
431 | } else { | |||
432 | import_printf("U %s/%s\n", import_repository, cf->file_path); | |||
433 | } | |||
434 | ||||
435 | if (cvs_noexec == 1) | |||
436 | return; | |||
437 | ||||
438 | d = import_get_rcsdiff(cf, rev); | |||
439 | newrev = rcsnum_inc(rev); | |||
440 | ||||
441 | if (rcs_rev_add(cf->file_rcs, newrev, logmsg, -1, NULL((void *)0)) == -1) | |||
442 | fatal("import_update: failed to add new revision"); | |||
443 | ||||
444 | if (rcs_deltatext_set(cf->file_rcs, newrev, d) == -1) | |||
445 | fatal("import_update: failed to set deltatext"); | |||
446 | ||||
447 | import_tag(cf, brev, newrev); | |||
448 | ||||
449 | if (kflag) | |||
450 | rcs_kwexp_set(cf->file_rcs, kflag); | |||
451 | ||||
452 | free(brev); | |||
453 | rcs_write(cf->file_rcs); | |||
454 | } | |||
455 | ||||
456 | static void | |||
457 | import_tag(struct cvs_file *cf, RCSNUM *branch, RCSNUM *newrev) | |||
458 | { | |||
459 | int i; | |||
460 | ||||
461 | if (cvs_noexec != 1) { | |||
462 | rcs_sym_add(cf->file_rcs, vendor_tag, branch); | |||
463 | ||||
464 | for (i = 0; i < tagcount; i++) | |||
465 | rcs_sym_add(cf->file_rcs, release_tags[i], newrev); | |||
466 | } | |||
467 | } | |||
468 | ||||
469 | static BUF * | |||
470 | import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) | |||
471 | { | |||
472 | char *p1, *p2; | |||
473 | BUF *b1, *b2; | |||
474 | int fd1, fd2; | |||
475 | ||||
476 | b2 = buf_alloc(128); | |||
477 | ||||
478 | b1 = buf_load_fd(cf->fd); | |||
479 | ||||
480 | (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); | |||
481 | fd1 = buf_write_stmp(b1, p1, NULL((void *)0)); | |||
482 | buf_free(b1); | |||
483 | ||||
484 | (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); | |||
485 | fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE0x01); | |||
486 | ||||
487 | diff_format = D_RCSDIFF5; | |||
488 | if (diffreg(p2, p1, fd2, fd1, b2, D_FORCEASCII0x01) == D_ERROR7) | |||
489 | fatal("import_get_rcsdiff: failed to get RCS patch"); | |||
490 | ||||
491 | close(fd1); | |||
492 | close(fd2); | |||
493 | ||||
494 | (void)unlink(p1); | |||
495 | (void)unlink(p2); | |||
496 | ||||
497 | free(p1); | |||
498 | free(p2); | |||
499 | ||||
500 | return (b2); | |||
501 | } |