GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/commit.c Lines: 212 394 53.8 %
Date: 2017-11-07 Branches: 117 245 47.8 %

Line Branch Exec Source
1
/*	$OpenBSD: commit.c,v 1.158 2017/06/01 08:08:24 joris Exp $	*/
2
/*
3
 * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4
 * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/stat.h>
20
21
#include <errno.h>
22
#include <fcntl.h>
23
#include <libgen.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <unistd.h>
27
28
#include "cvs.h"
29
#include "diff.h"
30
#include "remote.h"
31
32
void			 cvs_commit_local(struct cvs_file *);
33
void			 cvs_commit_check_files(struct cvs_file *);
34
void			 cvs_commit_loginfo(char *);
35
void			 cvs_commit_lock_dirs(struct cvs_file *);
36
37
static BUF *commit_diff(struct cvs_file *, RCSNUM *, int);
38
static void commit_desc_set(struct cvs_file *);
39
40
struct	file_info_list	 files_info;
41
struct	trigger_list	*line_list;
42
43
struct cvs_flisthead	files_affected;
44
struct cvs_flisthead	files_added;
45
struct cvs_flisthead	files_removed;
46
struct cvs_flisthead	files_modified;
47
48
char	*logmsg = NULL;
49
char	*loginfo = NULL;
50
51
static int	conflicts_found;
52
53
struct cvs_cmd cvs_cmd_commit = {
54
	CVS_OP_COMMIT, CVS_USE_WDIR, "commit",
55
	{ "ci", "com" },
56
	"Check files into the repository",
57
	"[-flR] [-F logfile | -m msg] [-r rev] ...",
58
	"F:flm:Rr:",
59
	NULL,
60
	cvs_commit
61
};
62
63
int
64
cvs_commit(int argc, char **argv)
65
{
66
	int flags;
67
	int ch, Fflag, mflag;
68
	struct module_checkout *mc;
69
6
	struct cvs_recursion cr;
70
	struct cvs_filelist *l;
71
	struct file_info *fi;
72
3
	char *arg = ".", repo[PATH_MAX];
73
74
	flags = CR_RECURSE_DIRS;
75
	Fflag = mflag = 0;
76
77
9
	while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) {
78

6
		switch (ch) {
79
		case 'F':
80
			/* free previously assigned value */
81
1
			free(logmsg);
82
1
			logmsg = cvs_logmsg_read(optarg);
83
			Fflag = 1;
84
1
			break;
85
		case 'f':
86
			break;
87
		case 'l':
88
			flags &= ~CR_RECURSE_DIRS;
89
			break;
90
		case 'm':
91
			/* free previously assigned value */
92
2
			free(logmsg);
93
2
			logmsg = xstrdup(optarg);
94
			mflag = 1;
95
2
			break;
96
		case 'R':
97
			flags |= CR_RECURSE_DIRS;
98
			break;
99
		case 'r':
100
			break;
101
		default:
102
			fatal("%s", cvs_cmd_commit.cmd_synopsis);
103
		}
104
	}
105
106
3
	argc -= optind;
107
3
	argv += optind;
108
109
	/* -F and -m are mutually exclusive */
110
3
	if (Fflag && mflag)
111
		fatal("cannot specify both a log file and a message");
112
113
3
	RB_INIT(&files_affected);
114
3
	RB_INIT(&files_added);
115
3
	RB_INIT(&files_removed);
116
3
	RB_INIT(&files_modified);
117
118
3
	TAILQ_INIT(&files_info);
119
3
	conflicts_found = 0;
120
121
3
	cr.enterdir = NULL;
122
3
	cr.leavedir = NULL;
123
3
	cr.fileproc = cvs_commit_check_files;
124
3
	cr.flags = flags;
125
126
3
	if (argc > 0)
127
		cvs_file_run(argc, argv, &cr);
128
	else
129
3
		cvs_file_run(1, &arg, &cr);
130
131
3
	if (conflicts_found != 0)
132
		fatal("%d conflicts found, please correct these first",
133
		    conflicts_found);
134
135
3
	if (RB_EMPTY(&files_affected))
136
		return (0);
137
138
3
	if (cvsroot_is_remote()) {
139
		if (logmsg == NULL) {
140
			logmsg = cvs_logmsg_create(NULL, &files_added,
141
			    &files_removed, &files_modified);
142
			if (logmsg == NULL)
143
				fatal("This shouldnt happen, honestly!");
144
		}
145
		cvs_client_connect_to_server();
146
		cr.fileproc = cvs_client_sendfile;
147
148
		if (argc > 0)
149
			cvs_file_run(argc, argv, &cr);
150
		else
151
			cvs_file_run(1, &arg, &cr);
152
153
		if (!(flags & CR_RECURSE_DIRS))
154
			cvs_client_send_request("Argument -l");
155
156
		cvs_client_send_logmsg(logmsg);
157
		cvs_client_send_files(argv, argc);
158
		cvs_client_senddir(".");
159
		cvs_client_send_request("ci");
160
		cvs_client_get_responses();
161
	} else {
162
3
		cvs_get_repository_name(".", repo, PATH_MAX);
163
164
3
		line_list = cvs_trigger_getlines(CVS_PATH_COMMITINFO, repo);
165
3
		if (line_list != NULL) {
166
			RB_FOREACH(l, cvs_flisthead, &files_affected) {
167
				fi = xcalloc(1, sizeof(*fi));
168
				fi->file_path = xstrdup(l->file_path);
169
				TAILQ_INSERT_TAIL(&files_info, fi,
170
				    flist);
171
			}
172
173
			if (cvs_trigger_handle(CVS_TRIGGER_COMMITINFO,
174
			    repo, NULL, line_list, &files_info)) {
175
				cvs_log(LP_ERR,
176
				    "Pre-commit check failed");
177
				cvs_trigger_freelist(line_list);
178
				goto end;
179
			}
180
181
			cvs_trigger_freelist(line_list);
182
			cvs_trigger_freeinfo(&files_info);
183
		}
184
185
3
		if (cvs_server_active) {
186
			if (logmsg == NULL)
187
				fatal("no log message specified");
188
3
		} else if (logmsg == NULL) {
189
			logmsg = cvs_logmsg_create(NULL, &files_added,
190
			    &files_removed, &files_modified);
191
			if (logmsg == NULL)
192
				fatal("This shouldnt happen, honestly!");
193
		}
194
195
3
		if (cvs_logmsg_verify(logmsg))
196
			goto end;
197
198
3
		cr.fileproc = cvs_commit_lock_dirs;
199
3
		cvs_file_walklist(&files_affected, &cr);
200
201
3
		line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, repo);
202
203
3
		cr.fileproc = cvs_commit_local;
204
3
		cvs_file_walklist(&files_affected, &cr);
205
206
3
		if (line_list != NULL) {
207
			cvs_commit_loginfo(repo);
208
209
			cvs_trigger_handle(CVS_TRIGGER_LOGINFO, repo,
210
			    loginfo, line_list, &files_info);
211
212
			free(loginfo);
213
			cvs_trigger_freelist(line_list);
214
			cvs_trigger_freeinfo(&files_info);
215
		}
216
217
3
		mc = cvs_module_lookup(repo);
218

3
		if (mc->mc_prog != NULL &&
219
		    (mc->mc_flags & MODULE_RUN_ON_COMMIT))
220
			cvs_exec(mc->mc_prog, NULL, 0);
221
	}
222
223
end:
224
3
	cvs_trigger_freeinfo(&files_info);
225
3
	free(logmsg);
226
3
	return (0);
227
3
}
228
229
void
230
cvs_commit_loginfo(char *repo)
231
{
232
	BUF *buf;
233
	char pwd[PATH_MAX];
234
	struct cvs_filelist *cf;
235
236
	if (getcwd(pwd, sizeof(pwd)) == NULL)
237
		fatal("Can't get working directory");
238
239
	buf = buf_alloc(1024);
240
241
	cvs_trigger_loginfo_header(buf, repo);
242
243
	if (!RB_EMPTY(&files_added)) {
244
		buf_puts(buf, "Added Files:");
245
246
		RB_FOREACH(cf, cvs_flisthead, &files_added) {
247
			buf_putc(buf, '\n');
248
			buf_putc(buf, '\t');
249
			buf_puts(buf, cf->file_path);
250
		}
251
252
		buf_putc(buf, '\n');
253
	}
254
255
	if (!RB_EMPTY(&files_modified)) {
256
		buf_puts(buf, "Modified Files:");
257
258
		RB_FOREACH(cf, cvs_flisthead, &files_modified) {
259
			buf_putc(buf, '\n');
260
			buf_putc(buf, '\t');
261
			buf_puts(buf, cf->file_path);
262
		}
263
264
		buf_putc(buf, '\n');
265
	}
266
267
	if (!RB_EMPTY(&files_removed)) {
268
		buf_puts(buf, "Removed Files:");
269
270
		RB_FOREACH(cf, cvs_flisthead, &files_removed) {
271
			buf_putc(buf, '\n');
272
			buf_putc(buf, '\t');
273
			buf_puts(buf, cf->file_path);
274
		}
275
276
		buf_putc(buf, '\n');
277
	}
278
279
	buf_puts(buf, "Log Message:\n");
280
281
	buf_puts(buf, logmsg);
282
283
	buf_putc(buf, '\n');
284
	buf_putc(buf, '\0');
285
286
	loginfo = buf_release(buf);
287
}
288
289
void
290
cvs_commit_lock_dirs(struct cvs_file *cf)
291
{
292
10
	char repo[PATH_MAX];
293
294
5
	cvs_get_repository_path(cf->file_wd, repo, sizeof(repo));
295
5
	cvs_log(LP_TRACE, "cvs_commit_lock_dirs: %s", repo);
296
297
	/* locks stay in place until we are fully done and exit */
298
5
	cvs_repository_lock(repo, 1);
299
5
}
300
301
void
302
cvs_commit_check_files(struct cvs_file *cf)
303
{
304
	char *tag;
305
	RCSNUM *branch, *brev;
306
307
	branch = brev = NULL;
308
309
32
	cvs_log(LP_TRACE, "cvs_commit_check_files(%s)", cf->file_path);
310
311
16
	if (cvsroot_is_remote())
312
		cvs_remote_classify_file(cf);
313
	else
314
16
		cvs_file_classify(cf, cvs_directory_tag);
315
316
16
	if (cf->file_type == CVS_DIR) {
317
6
		if (verbosity > 1)
318
4
			cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
319
6
		return;
320
	}
321
322
10
	if (cf->file_status == FILE_UPTODATE)
323
5
		return;
324
325

10
	if (cf->file_status == FILE_MERGE ||
326
5
	    cf->file_status == FILE_PATCH ||
327
5
	    cf->file_status == FILE_CHECKOUT ||
328
5
	    cf->file_status == FILE_LOST ||
329
5
	    cf->file_status == FILE_UNLINK) {
330
		cvs_log(LP_ERR, "conflict: %s is not up-to-date",
331
		    cf->file_path);
332
		conflicts_found++;
333
		return;
334
	}
335
336

5
	if (cf->file_status == FILE_CONFLICT &&
337
	   cf->file_ent->ce_conflict != NULL) {
338
		cvs_log(LP_ERR, "conflict: unresolved conflicts in %s from "
339
		    "merging, please fix these first", cf->file_path);
340
		conflicts_found++;
341
		return;
342
	}
343
344

5
	if (cf->file_status == FILE_MODIFIED &&
345
2
	    cf->file_ent->ce_conflict != NULL &&
346
	    update_has_conflict_markers(cf)) {
347
		cvs_log(LP_ERR, "warning: file %s seems to still contain "
348
		    "conflict indicators", cf->file_path);
349
	}
350
351

10
	if (cf->file_ent != NULL && cf->file_ent->ce_date != -1) {
352
		cvs_log(LP_ERR, "conflict: cannot commit to sticky date for %s",
353
		    cf->file_path);
354
		conflicts_found++;
355
		return;
356
	}
357
358
5
	if (cvsroot_is_local()) {
359
5
		tag = cvs_directory_tag;
360
5
		if (cf->file_ent != NULL)
361
5
			tag = cf->file_ent->ce_tag;
362
363

6
		if (tag != NULL && cf->file_rcs != NULL) {
364
1
			brev = rcs_sym_getrev(cf->file_rcs, tag);
365
1
			if (brev != NULL) {
366
1
				if (!RCSNUM_ISBRANCH(brev)) {
367
					cvs_log(LP_ERR, "sticky tag %s is not "
368
					    "a branch for file %s", tag,
369
					    cf->file_path);
370
					conflicts_found++;
371
				}
372
			}
373
		}
374
	}
375
376
	free(branch);
377
5
	free(brev);
378
379

7
	if (cf->file_status != FILE_ADDED &&
380
2
	    cf->file_status != FILE_REMOVED &&
381
2
	    cf->file_status != FILE_MODIFIED)
382
		return;
383
384
10
	cvs_file_get(cf->file_path, 0, &files_affected, CVS_FILE);
385
386

10
	switch (cf->file_status) {
387
	case FILE_ADDED:
388
3
		cvs_file_get(cf->file_path, 0, &files_added, CVS_FILE);
389
3
		break;
390
	case FILE_REMOVED:
391
		cvs_file_get(cf->file_path, 0, &files_removed, CVS_FILE);
392
		break;
393
	case FILE_MODIFIED:
394
2
		cvs_file_get(cf->file_path, 0, &files_modified, CVS_FILE);
395
2
		break;
396
	}
397
21
}
398
399
void
400
cvs_commit_local(struct cvs_file *cf)
401
{
402
	char *tag;
403
	BUF *b, *d;
404
	int onbranch, isnew, histtype, branchadded;
405
	RCSNUM *nrev, *crev, *rrev, *brev;
406
	int openflags, rcsflags;
407
10
	char rbuf[CVS_REV_BUFSZ], nbuf[CVS_REV_BUFSZ];
408
	CVSENTRIES *entlist;
409
5
	char attic[PATH_MAX], repo[PATH_MAX], rcsfile[PATH_MAX];
410
	struct file_info *fi;
411
412
5
	cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path);
413
5
	cvs_file_classify(cf, cvs_directory_tag);
414
415
5
	if (cvs_noexec == 1)
416
		return;
417
418
5
	if (cf->file_type != CVS_FILE)
419
		fatal("cvs_commit_local: '%s' is not a file", cf->file_path);
420
421
5
	tag = cvs_directory_tag;
422

10
	if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL)
423
1
		tag = cf->file_ent->ce_tag;
424
425
	branchadded = 0;
426

5
	switch (cf->file_status) {
427
	case FILE_ADDED:
428
3
		if (cf->file_rcs == NULL && tag != NULL) {
429
			branchadded = 1;
430
			cvs_add_tobranch(cf, tag);
431
		}
432
		break;
433
	case FILE_MODIFIED:
434
	case FILE_REMOVED:
435
2
		if (cf->file_rcs == NULL) {
436
			cvs_log(LP_ERR, "RCS file for %s got lost",
437
			    cf->file_path);
438
			return;
439
		}
440
		break;
441
	default:
442
		cvs_log(LP_ERR, "skipping bogus file `%s'", cf->file_path);
443
		return;
444
	}
445
446
	onbranch = 0;
447
	nrev = RCS_HEAD_REV;
448
	crev = NULL;
449
	rrev = NULL;
450
	d = NULL;
451
452

7
	if (cf->file_rcs != NULL && cf->file_rcs->rf_branch != NULL) {
453
1
		free(cf->file_rcs->rf_branch);
454
1
		cf->file_rcs->rf_branch = NULL;
455
1
	}
456
457
5
	if (cf->file_rcs != NULL) {
458
2
		rrev = rcs_head_get(cf->file_rcs);
459
2
		crev = rcs_head_get(cf->file_rcs);
460
2
		if (crev == NULL || rrev == NULL)
461
			fatal("no head revision in RCS file for %s",
462
			    cf->file_path);
463
464
2
		if (tag != NULL) {
465
1
			free(crev);
466
1
			free(rrev);
467
1
			brev = rcs_sym_getrev(cf->file_rcs, tag);
468
1
			crev = rcs_translate_tag(tag, cf->file_rcs);
469
1
			if (brev == NULL || crev == NULL) {
470
				fatal("failed to resolve existing tag: %s",
471
				    tag);
472
			}
473
474
1
			rrev = rcsnum_alloc();
475
1
			rcsnum_cpy(brev, rrev, brev->rn_len - 1);
476
477

2
			if (RCSNUM_ISBRANCHREV(crev) &&
478
			    rcsnum_cmp(crev, rrev, 0)) {
479
				nrev = rcsnum_alloc();
480
				rcsnum_cpy(crev, nrev, 0);
481
				rcsnum_inc(nrev);
482
1
			} else if (!RCSNUM_ISBRANCH(crev)) {
483
1
				nrev = rcsnum_brtorev(brev);
484
1
				if (nrev == NULL)
485
					fatal("failed to create branch rev");
486
			} else {
487
				fatal("this isnt suppose to happen, honestly");
488
			}
489
490
1
			free(brev);
491
1
			free(rrev);
492
1
			rrev = rcsnum_branch_root(nrev);
493
494
			/* branch stuff was checked in cvs_commit_check_files */
495
			onbranch = 1;
496
1
		}
497
498
2
		rcsnum_tostr(crev, rbuf, sizeof(rbuf));
499
2
	} else {
500
3
		strlcpy(rbuf, "Non-existent", sizeof(rbuf));
501
	}
502
503
5
	free(rrev);
504
	isnew = 0;
505
5
	if (cf->file_status == FILE_ADDED) {
506
		isnew = 1;
507
		rcsflags = RCS_CREATE;
508
		openflags = O_CREAT | O_RDONLY;
509
3
		if (cf->file_rcs != NULL) {
510
			if (!onbranch) {
511
				if (cf->in_attic == 0)
512
					cvs_log(LP_ERR, "warning: expected %s "
513
					    "to be in the Attic",
514
					    cf->file_path);
515
516
				if (cf->file_rcs->rf_dead == 0)
517
					cvs_log(LP_ERR, "warning: expected %s "
518
					    "to be dead", cf->file_path);
519
520
				cvs_get_repository_path(cf->file_wd, repo,
521
				    PATH_MAX);
522
				(void)xsnprintf(rcsfile, PATH_MAX, "%s/%s%s",
523
				    repo, cf->file_name, RCS_FILE_EXT);
524
525
				if (rename(cf->file_rpath, rcsfile) == -1)
526
					fatal("cvs_commit_local: failed to "
527
					    "move %s outside the Attic: %s",
528
					    cf->file_path, strerror(errno));
529
530
				free(cf->file_rpath);
531
				cf->file_rpath = xstrdup(rcsfile);
532
				isnew = 0;
533
			}
534
535
			rcsflags = RCS_READ | RCS_PARSE_FULLY;
536
			openflags = O_RDONLY;
537
			rcs_close(cf->file_rcs);
538
		}
539
540
3
		cf->repo_fd = open(cf->file_rpath, openflags);
541
3
		if (cf->repo_fd < 0)
542
			fatal("cvs_commit_local: %s", strerror(errno));
543
544
3
		cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd,
545
		    rcsflags, 0444);
546
3
		if (cf->file_rcs == NULL)
547
			fatal("cvs_commit_local: failed to create RCS file "
548
			    "for %s", cf->file_path);
549
550
3
		commit_desc_set(cf);
551
552
3
		if (branchadded)
553
			strlcpy(rbuf, "Non-existent", sizeof(rbuf));
554
	}
555
556
5
	if (verbosity > 1) {
557
4
		cvs_printf("Checking in %s:\n", cf->file_path);
558
4
		cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path);
559
4
		cvs_printf("old revision: %s; ", rbuf);
560
4
	}
561
562

7
	if (isnew == 0 && cf->file_rcs->rf_head == NULL)
563
		fatal("no head revision in RCS file for %s", cf->file_path);
564
565
5
	if (isnew == 0 && onbranch == 0)
566
1
		d = commit_diff(cf, cf->file_rcs->rf_head, 0);
567
568
5
	if (cf->file_status == FILE_REMOVED) {
569
		b = rcs_rev_getbuf(cf->file_rcs, crev, 0);
570
5
	} else if (onbranch == 1) {
571
1
		b = commit_diff(cf, crev, 1);
572
1
	} else {
573
4
		b = buf_load_fd(cf->fd);
574
	}
575
576
5
	if (isnew == 0 && onbranch == 0) {
577
1
		if (rcs_deltatext_set(cf->file_rcs, crev, d) == -1)
578
			fatal("cvs_commit_local: failed to set delta");
579
	}
580
581
5
	if (rcs_rev_add(cf->file_rcs, nrev, logmsg, -1, NULL) == -1)
582
		fatal("cvs_commit_local: failed to add new revision");
583
584
5
	if (nrev == RCS_HEAD_REV)
585
4
		nrev = cf->file_rcs->rf_head;
586
587
5
	if (rcs_deltatext_set(cf->file_rcs, nrev, b) == -1)
588
		fatal("cvs_commit_local: failed to set new HEAD delta");
589
590
5
	if (cf->file_status == FILE_REMOVED) {
591
		if (rcs_state_set(cf->file_rcs, nrev, RCS_STATE_DEAD) == -1)
592
			fatal("cvs_commit_local: failed to set state");
593
	}
594
595

8
	if (cf->file_status == FILE_ADDED && cf->file_ent->ce_opts != NULL) {
596
		int cf_kflag;
597
598
		cf_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2);
599
		rcs_kwexp_set(cf->file_rcs, cf_kflag);
600
	}
601
602
5
	rcs_write(cf->file_rcs);
603
604
5
	if (cf->file_status == FILE_REMOVED) {
605
		strlcpy(nbuf, "Removed", sizeof(nbuf));
606
5
	} else if (cf->file_status == FILE_ADDED) {
607
3
		if (cf->file_rcs->rf_dead == 1)
608
			strlcpy(nbuf, "Initial Revision", sizeof(nbuf));
609
		else
610
3
			rcsnum_tostr(nrev, nbuf, sizeof(nbuf));
611
2
	} else if (cf->file_status == FILE_MODIFIED) {
612
2
		rcsnum_tostr(nrev, nbuf, sizeof(nbuf));
613
2
	}
614
615
5
	if (verbosity > 1)
616
4
		cvs_printf("new revision: %s\n", nbuf);
617
618
5
	(void)unlink(cf->file_path);
619
5
	(void)close(cf->fd);
620
5
	cf->fd = -1;
621
622
5
	if (cf->file_status != FILE_REMOVED) {
623
5
		cvs_checkout_file(cf, nrev, NULL, CO_COMMIT);
624
5
	} else {
625
		entlist = cvs_ent_open(cf->file_wd);
626
		cvs_ent_remove(entlist, cf->file_name);
627
628
		cvs_get_repository_path(cf->file_wd, repo, PATH_MAX);
629
630
		(void)xsnprintf(attic, PATH_MAX, "%s/%s",
631
		    repo, CVS_PATH_ATTIC);
632
633
		if (mkdir(attic, 0755) == -1 && errno != EEXIST)
634
			fatal("cvs_commit_local: failed to create Attic");
635
636
		(void)xsnprintf(attic, PATH_MAX, "%s/%s/%s%s", repo,
637
		    CVS_PATH_ATTIC, cf->file_name, RCS_FILE_EXT);
638
639
		if (rename(cf->file_rpath, attic) == -1)
640
			fatal("cvs_commit_local: failed to move %s to Attic",
641
			    cf->file_path);
642
643
		if (cvs_server_active == 1)
644
			cvs_server_update_entry("Remove-entry", cf);
645
	}
646
647
5
	if (verbosity > 1)
648
4
		cvs_printf("done\n");
649
	else {
650
1
		cvs_log(LP_NOTICE, "checking in '%s'; revision %s -> %s",
651
1
		    cf->file_path, rbuf, nbuf);
652
	}
653
654
5
	if (line_list != NULL) {
655
		fi = xcalloc(1, sizeof(*fi));
656
		fi->file_path = xstrdup(cf->file_path);
657
		fi->crevstr = xstrdup(rbuf);
658
		fi->nrevstr = xstrdup(nbuf);
659
		if (tag != NULL)
660
			fi->tag_new = xstrdup(tag);
661
		TAILQ_INSERT_TAIL(&files_info, fi, flist);
662
	}
663
664

5
	switch (cf->file_status) {
665
	case FILE_MODIFIED:
666
		histtype = CVS_HISTORY_COMMIT_MODIFIED;
667
2
		break;
668
	case FILE_ADDED:
669
		histtype = CVS_HISTORY_COMMIT_ADDED;
670
3
		break;
671
	case FILE_REMOVED:
672
		histtype = CVS_HISTORY_COMMIT_REMOVED;
673
		break;
674
	default:
675
		histtype = -1;
676
		break;
677
	}
678
679
5
	free(crev);
680
681
5
	if (histtype != -1)
682
5
		cvs_history_add(histtype, cf, NULL);
683
	else
684
		cvs_log(LP_NOTICE, "histtype was -1 for %s", cf->file_path);
685
10
}
686
687
static BUF *
688
commit_diff(struct cvs_file *cf, RCSNUM *rev, int reverse)
689
{
690
	int fd1, fd2, d;
691
4
	char *p1, *p2;
692
	BUF *b;
693
694
2
	(void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
695
696

2
	if (cf->file_status == FILE_MODIFIED ||
697
	    cf->file_status == FILE_ADDED) {
698
2
		b = buf_load_fd(cf->fd);
699
2
		fd1 = buf_write_stmp(b, p1, NULL);
700
2
		buf_free(b);
701
2
	} else {
702
		fd1 = rcs_rev_write_stmp(cf->file_rcs, rev, p1, 0);
703
	}
704
705
2
	(void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
706
2
	fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE);
707
708
2
	b = buf_alloc(128);
709
710
2
	diff_format = D_RCSDIFF;
711
712
2
	if (reverse == 1)
713
1
		d = diffreg(p2, p1, fd2, fd1, b, D_FORCEASCII);
714
	else
715
1
		d = diffreg(p1, p2, fd1, fd2, b, D_FORCEASCII);
716
2
	if (d == D_ERROR)
717
		fatal("commit_diff: failed to get RCS patch");
718
719
2
	close(fd1);
720
2
	close(fd2);
721
722
2
	free(p1);
723
2
	free(p2);
724
725
2
	return (b);
726
2
}
727
728
static void
729
commit_desc_set(struct cvs_file *cf)
730
{
731
	BUF *bp;
732
	int fd;
733
6
	char desc_path[PATH_MAX], *desc;
734
735
6
	(void)xsnprintf(desc_path, PATH_MAX, "%s/%s/%s%s",
736
3
	    cf->file_wd, CVS_PATH_CVSDIR, cf->file_name, CVS_DESCR_FILE_EXT);
737
738
3
	if ((fd = open(desc_path, O_RDONLY)) == -1)
739
3
		return;
740
741
	bp = buf_load_fd(fd);
742
	buf_putc(bp, '\0');
743
	desc = buf_release(bp);
744
745
	rcs_desc_set(cf->file_rcs, desc);
746
747
	(void)close(fd);
748
	(void)cvs_unlink(desc_path);
749
750
	free(desc);
751
3
}