1*3aaa63ebSderaadt /* $OpenBSD: commit.c,v 1.160 2019/06/28 13:35:00 deraadt Exp $ */
208f90673Sjfb /*
33ad3fb45Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
42ec286b3Sxsa * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org>
508f90673Sjfb *
63ad3fb45Sjoris * Permission to use, copy, modify, and distribute this software for any
73ad3fb45Sjoris * purpose with or without fee is hereby granted, provided that the above
83ad3fb45Sjoris * copyright notice and this permission notice appear in all copies.
908f90673Sjfb *
103ad3fb45Sjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113ad3fb45Sjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123ad3fb45Sjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133ad3fb45Sjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143ad3fb45Sjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153ad3fb45Sjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163ad3fb45Sjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1708f90673Sjfb */
1808f90673Sjfb
191f8531bdSotto #include <sys/stat.h>
201f8531bdSotto
211f8531bdSotto #include <errno.h>
221f8531bdSotto #include <fcntl.h>
23397ddb8aSnicm #include <stdlib.h>
241f8531bdSotto #include <string.h>
251f8531bdSotto #include <unistd.h>
2608f90673Sjfb
2708f90673Sjfb #include "cvs.h"
283ad3fb45Sjoris #include "diff.h"
299fac60a5Sjoris #include "remote.h"
3008f90673Sjfb
3184920933Stobias void cvs_commit_local(struct cvs_file *);
3284920933Stobias void cvs_commit_check_files(struct cvs_file *);
33e2ec91a3Sjoris void cvs_commit_loginfo(char *);
3484920933Stobias void cvs_commit_lock_dirs(struct cvs_file *);
3584920933Stobias
3684920933Stobias static BUF *commit_diff(struct cvs_file *, RCSNUM *, int);
3784920933Stobias static void commit_desc_set(struct cvs_file *);
3884920933Stobias
39b034d592Sjoris struct file_info_list files_info;
40b034d592Sjoris struct trigger_list *line_list;
41db758d52Sjoris
42e2ec91a3Sjoris struct cvs_flisthead files_affected;
43e2ec91a3Sjoris struct cvs_flisthead files_added;
44e2ec91a3Sjoris struct cvs_flisthead files_removed;
45e2ec91a3Sjoris struct cvs_flisthead files_modified;
46e2ec91a3Sjoris
47db758d52Sjoris char *logmsg = NULL;
48b034d592Sjoris char *loginfo = NULL;
4908f90673Sjfb
5063c546bcSnicm static int conflicts_found;
5163c546bcSnicm
52e4276007Sjfb struct cvs_cmd cvs_cmd_commit = {
53beba978cSjoris CVS_OP_COMMIT, CVS_USE_WDIR, "commit",
54e4276007Sjfb { "ci", "com" },
55e4276007Sjfb "Check files into the repository",
56e4276007Sjfb "[-flR] [-F logfile | -m msg] [-r rev] ...",
57e4276007Sjfb "F:flm:Rr:",
5816cfc147Sjoris NULL,
593ad3fb45Sjoris cvs_commit
6016cfc147Sjoris };
6108f90673Sjfb
623ad3fb45Sjoris int
cvs_commit(int argc,char ** argv)633ad3fb45Sjoris cvs_commit(int argc, char **argv)
6408f90673Sjfb {
651890abdaSjoris int flags;
66ea48eba6Sjoris int ch, Fflag, mflag;
67ea48eba6Sjoris struct module_checkout *mc;
683ad3fb45Sjoris struct cvs_recursion cr;
69b034d592Sjoris struct cvs_filelist *l;
70b034d592Sjoris struct file_info *fi;
71b9fc9a72Sderaadt char *arg = ".", repo[PATH_MAX];
7208f90673Sjfb
731890abdaSjoris flags = CR_RECURSE_DIRS;
74f4d74cd1Stobias Fflag = mflag = 0;
751890abdaSjoris
763ad3fb45Sjoris while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) {
7708f90673Sjfb switch (ch) {
783ad3fb45Sjoris case 'F':
79f4d74cd1Stobias /* free previously assigned value */
80397ddb8aSnicm free(logmsg);
8116190807Sjoris logmsg = cvs_logmsg_read(optarg);
82f4d74cd1Stobias Fflag = 1;
8308f90673Sjfb break;
846f8f2f56Sxsa case 'f':
856f8f2f56Sxsa break;
8608f90673Sjfb case 'l':
871890abdaSjoris flags &= ~CR_RECURSE_DIRS;
8808f90673Sjfb break;
8908f90673Sjfb case 'm':
90f4d74cd1Stobias /* free previously assigned value */
91397ddb8aSnicm free(logmsg);
923ad3fb45Sjoris logmsg = xstrdup(optarg);
93f4d74cd1Stobias mflag = 1;
9408f90673Sjfb break;
953ad3fb45Sjoris case 'R':
96bcf22459Stobias flags |= CR_RECURSE_DIRS;
978d550b2eSxsa break;
986f8f2f56Sxsa case 'r':
996f8f2f56Sxsa break;
10008f90673Sjfb default:
1013ad3fb45Sjoris fatal("%s", cvs_cmd_commit.cmd_synopsis);
10208f90673Sjfb }
10308f90673Sjfb }
10408f90673Sjfb
1053ad3fb45Sjoris argc -= optind;
1063ad3fb45Sjoris argv += optind;
10708f90673Sjfb
108f4d74cd1Stobias /* -F and -m are mutually exclusive */
109f4d74cd1Stobias if (Fflag && mflag)
110f4d74cd1Stobias fatal("cannot specify both a log file and a message");
111f4d74cd1Stobias
112f106b389Sjoris RB_INIT(&files_affected);
113f106b389Sjoris RB_INIT(&files_added);
114f106b389Sjoris RB_INIT(&files_removed);
115f106b389Sjoris RB_INIT(&files_modified);
116e2ec91a3Sjoris
117b034d592Sjoris TAILQ_INIT(&files_info);
118db758d52Sjoris conflicts_found = 0;
11908f90673Sjfb
1209fac60a5Sjoris cr.enterdir = NULL;
1219fac60a5Sjoris cr.leavedir = NULL;
122db758d52Sjoris cr.fileproc = cvs_commit_check_files;
1239fac60a5Sjoris cr.flags = flags;
1249fac60a5Sjoris
1259fac60a5Sjoris if (argc > 0)
1269fac60a5Sjoris cvs_file_run(argc, argv, &cr);
1279fac60a5Sjoris else
1289fac60a5Sjoris cvs_file_run(1, &arg, &cr);
1299fac60a5Sjoris
130db758d52Sjoris if (conflicts_found != 0)
131db758d52Sjoris fatal("%d conflicts found, please correct these first",
132db758d52Sjoris conflicts_found);
133db758d52Sjoris
134f106b389Sjoris if (RB_EMPTY(&files_affected))
135a066adb3Sjoris return (0);
136a066adb3Sjoris
1374dcde513Sjoris if (cvsroot_is_remote()) {
13813b057d9Stobias if (logmsg == NULL) {
13913b057d9Stobias logmsg = cvs_logmsg_create(NULL, &files_added,
14013b057d9Stobias &files_removed, &files_modified);
141db758d52Sjoris if (logmsg == NULL)
142db758d52Sjoris fatal("This shouldnt happen, honestly!");
143e2ec91a3Sjoris }
14480f6ca9bSjoris cvs_client_connect_to_server();
145db758d52Sjoris cr.fileproc = cvs_client_sendfile;
146db758d52Sjoris
147db758d52Sjoris if (argc > 0)
148db758d52Sjoris cvs_file_run(argc, argv, &cr);
149db758d52Sjoris else
150db758d52Sjoris cvs_file_run(1, &arg, &cr);
151db758d52Sjoris
152585a1783Sxsa if (!(flags & CR_RECURSE_DIRS))
153585a1783Sxsa cvs_client_send_request("Argument -l");
154585a1783Sxsa
155f76ce13cSjoris cvs_client_send_logmsg(logmsg);
1569fac60a5Sjoris cvs_client_send_files(argv, argc);
1579fac60a5Sjoris cvs_client_senddir(".");
1589fac60a5Sjoris cvs_client_send_request("ci");
1599fac60a5Sjoris cvs_client_get_responses();
160db758d52Sjoris } else {
161b9fc9a72Sderaadt cvs_get_repository_name(".", repo, PATH_MAX);
162b034d592Sjoris
163e2ec91a3Sjoris line_list = cvs_trigger_getlines(CVS_PATH_COMMITINFO, repo);
164b034d592Sjoris if (line_list != NULL) {
165f106b389Sjoris RB_FOREACH(l, cvs_flisthead, &files_affected) {
166b034d592Sjoris fi = xcalloc(1, sizeof(*fi));
167b034d592Sjoris fi->file_path = xstrdup(l->file_path);
168b034d592Sjoris TAILQ_INSERT_TAIL(&files_info, fi,
169b034d592Sjoris flist);
170b034d592Sjoris }
171e2ec91a3Sjoris
172b034d592Sjoris if (cvs_trigger_handle(CVS_TRIGGER_COMMITINFO,
173b034d592Sjoris repo, NULL, line_list, &files_info)) {
174b034d592Sjoris cvs_log(LP_ERR,
175b034d592Sjoris "Pre-commit check failed");
176b034d592Sjoris cvs_trigger_freelist(line_list);
177b034d592Sjoris goto end;
178b034d592Sjoris }
179e2ec91a3Sjoris
180b034d592Sjoris cvs_trigger_freelist(line_list);
181b034d592Sjoris cvs_trigger_freeinfo(&files_info);
182b034d592Sjoris }
183b034d592Sjoris
18413b057d9Stobias if (cvs_server_active) {
18513b057d9Stobias if (logmsg == NULL)
18613b057d9Stobias fatal("no log message specified");
18713b057d9Stobias } else if (logmsg == NULL) {
18813b057d9Stobias logmsg = cvs_logmsg_create(NULL, &files_added,
18913b057d9Stobias &files_removed, &files_modified);
19013b057d9Stobias if (logmsg == NULL)
19113b057d9Stobias fatal("This shouldnt happen, honestly!");
19213b057d9Stobias }
19313b057d9Stobias
194b034d592Sjoris if (cvs_logmsg_verify(logmsg))
195b034d592Sjoris goto end;
196b034d592Sjoris
197fb3beb6cSjoris cr.fileproc = cvs_commit_lock_dirs;
198e2ec91a3Sjoris cvs_file_walklist(&files_affected, &cr);
199fb3beb6cSjoris
200e2ec91a3Sjoris line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, repo);
201b034d592Sjoris
202bc5d89feSjoris cr.fileproc = cvs_commit_local;
203e2ec91a3Sjoris cvs_file_walklist(&files_affected, &cr);
204ea48eba6Sjoris
205b034d592Sjoris if (line_list != NULL) {
206e2ec91a3Sjoris cvs_commit_loginfo(repo);
207b034d592Sjoris
208b034d592Sjoris cvs_trigger_handle(CVS_TRIGGER_LOGINFO, repo,
209b034d592Sjoris loginfo, line_list, &files_info);
210b034d592Sjoris
211397ddb8aSnicm free(loginfo);
212b034d592Sjoris cvs_trigger_freelist(line_list);
213b034d592Sjoris cvs_trigger_freeinfo(&files_info);
214b034d592Sjoris }
215b034d592Sjoris
216ea48eba6Sjoris mc = cvs_module_lookup(repo);
217ea48eba6Sjoris if (mc->mc_prog != NULL &&
218ea48eba6Sjoris (mc->mc_flags & MODULE_RUN_ON_COMMIT))
219b034d592Sjoris cvs_exec(mc->mc_prog, NULL, 0);
220db758d52Sjoris }
22184920933Stobias
222b034d592Sjoris end:
223b034d592Sjoris cvs_trigger_freeinfo(&files_info);
224397ddb8aSnicm free(logmsg);
22516cfc147Sjoris return (0);
226c710bc5aSjfb }
227c710bc5aSjfb
2283ad3fb45Sjoris void
cvs_commit_loginfo(char * repo)229e2ec91a3Sjoris cvs_commit_loginfo(char *repo)
230b034d592Sjoris {
231b034d592Sjoris BUF *buf;
232b9fc9a72Sderaadt char pwd[PATH_MAX];
233b034d592Sjoris struct cvs_filelist *cf;
234b034d592Sjoris
235b034d592Sjoris if (getcwd(pwd, sizeof(pwd)) == NULL)
236b034d592Sjoris fatal("Can't get working directory");
237b034d592Sjoris
2387bb3ddb0Sray buf = buf_alloc(1024);
239b034d592Sjoris
240b034d592Sjoris cvs_trigger_loginfo_header(buf, repo);
241b034d592Sjoris
242f106b389Sjoris if (!RB_EMPTY(&files_added)) {
2437bb3ddb0Sray buf_puts(buf, "Added Files:");
244b034d592Sjoris
245f106b389Sjoris RB_FOREACH(cf, cvs_flisthead, &files_added) {
2467bb3ddb0Sray buf_putc(buf, '\n');
2477bb3ddb0Sray buf_putc(buf, '\t');
2487bb3ddb0Sray buf_puts(buf, cf->file_path);
249b034d592Sjoris }
250b034d592Sjoris
2517bb3ddb0Sray buf_putc(buf, '\n');
252b034d592Sjoris }
253b034d592Sjoris
254f106b389Sjoris if (!RB_EMPTY(&files_modified)) {
2557bb3ddb0Sray buf_puts(buf, "Modified Files:");
256b034d592Sjoris
257f106b389Sjoris RB_FOREACH(cf, cvs_flisthead, &files_modified) {
2587bb3ddb0Sray buf_putc(buf, '\n');
2597bb3ddb0Sray buf_putc(buf, '\t');
2607bb3ddb0Sray buf_puts(buf, cf->file_path);
261b034d592Sjoris }
262b034d592Sjoris
2637bb3ddb0Sray buf_putc(buf, '\n');
264b034d592Sjoris }
265b034d592Sjoris
266f106b389Sjoris if (!RB_EMPTY(&files_removed)) {
2677bb3ddb0Sray buf_puts(buf, "Removed Files:");
268b034d592Sjoris
269f106b389Sjoris RB_FOREACH(cf, cvs_flisthead, &files_removed) {
2707bb3ddb0Sray buf_putc(buf, '\n');
2717bb3ddb0Sray buf_putc(buf, '\t');
2727bb3ddb0Sray buf_puts(buf, cf->file_path);
273b034d592Sjoris }
274b034d592Sjoris
2757bb3ddb0Sray buf_putc(buf, '\n');
276b034d592Sjoris }
277b034d592Sjoris
2787bb3ddb0Sray buf_puts(buf, "Log Message:\n");
279b034d592Sjoris
2807bb3ddb0Sray buf_puts(buf, logmsg);
281b034d592Sjoris
2827bb3ddb0Sray buf_putc(buf, '\n');
2837bb3ddb0Sray buf_putc(buf, '\0');
284b034d592Sjoris
2857bb3ddb0Sray loginfo = buf_release(buf);
286b034d592Sjoris }
287b034d592Sjoris
288b034d592Sjoris void
cvs_commit_lock_dirs(struct cvs_file * cf)289fb3beb6cSjoris cvs_commit_lock_dirs(struct cvs_file *cf)
290fb3beb6cSjoris {
291b9fc9a72Sderaadt char repo[PATH_MAX];
292fb3beb6cSjoris
293fb3beb6cSjoris cvs_get_repository_path(cf->file_wd, repo, sizeof(repo));
294fb3beb6cSjoris cvs_log(LP_TRACE, "cvs_commit_lock_dirs: %s", repo);
295fb3beb6cSjoris
296fb3beb6cSjoris /* locks stay in place until we are fully done and exit */
297fb3beb6cSjoris cvs_repository_lock(repo, 1);
298fb3beb6cSjoris }
299fb3beb6cSjoris
300fb3beb6cSjoris void
cvs_commit_check_files(struct cvs_file * cf)301db758d52Sjoris cvs_commit_check_files(struct cvs_file *cf)
30216cfc147Sjoris {
30318cf7829Sjoris char *tag;
30418cf7829Sjoris RCSNUM *branch, *brev;
30518cf7829Sjoris
30654de3f21Stobias branch = brev = NULL;
30754de3f21Stobias
308db758d52Sjoris cvs_log(LP_TRACE, "cvs_commit_check_files(%s)", cf->file_path);
3095805c4b0Sjoris
3104dcde513Sjoris if (cvsroot_is_remote())
3117cffd7e4Sjoris cvs_remote_classify_file(cf);
3127cffd7e4Sjoris else
31351ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag);
3143ad3fb45Sjoris
315c1fe09b4Sjoris if (cf->file_type == CVS_DIR) {
316c1fe09b4Sjoris if (verbosity > 1)
317c1fe09b4Sjoris cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
318c1fe09b4Sjoris return;
319c1fe09b4Sjoris }
320c1fe09b4Sjoris
32109d28507Stobias if (cf->file_status == FILE_UPTODATE)
32209d28507Stobias return;
32309d28507Stobias
32409d28507Stobias if (cf->file_status == FILE_MERGE ||
32509d28507Stobias cf->file_status == FILE_PATCH ||
32609d28507Stobias cf->file_status == FILE_CHECKOUT ||
32709d28507Stobias cf->file_status == FILE_LOST ||
328846e2b74Sjoris cf->file_status == FILE_UNLINK) {
32909d28507Stobias cvs_log(LP_ERR, "conflict: %s is not up-to-date",
33009d28507Stobias cf->file_path);
3313ad3fb45Sjoris conflicts_found++;
332846e2b74Sjoris return;
333846e2b74Sjoris }
3343ad3fb45Sjoris
33509d28507Stobias if (cf->file_status == FILE_CONFLICT &&
33609d28507Stobias cf->file_ent->ce_conflict != NULL) {
337f9872b43Sjoris cvs_log(LP_ERR, "conflict: unresolved conflicts in %s from "
338f9872b43Sjoris "merging, please fix these first", cf->file_path);
339f9872b43Sjoris conflicts_found++;
340846e2b74Sjoris return;
341f9872b43Sjoris }
342f9872b43Sjoris
34309d28507Stobias if (cf->file_status == FILE_MODIFIED &&
34409d28507Stobias cf->file_ent->ce_conflict != NULL &&
34509d28507Stobias update_has_conflict_markers(cf)) {
34609d28507Stobias cvs_log(LP_ERR, "warning: file %s seems to still contain "
34709d28507Stobias "conflict indicators", cf->file_path);
3482a132f99Sjoris }
3492a132f99Sjoris
35062312420Sjoris if (cf->file_ent != NULL && cf->file_ent->ce_date != -1) {
35162312420Sjoris cvs_log(LP_ERR, "conflict: cannot commit to sticky date for %s",
35262312420Sjoris cf->file_path);
35362312420Sjoris conflicts_found++;
35462312420Sjoris return;
35562312420Sjoris }
35662312420Sjoris
3574dcde513Sjoris if (cvsroot_is_local()) {
35818cf7829Sjoris tag = cvs_directory_tag;
35918cf7829Sjoris if (cf->file_ent != NULL)
36018cf7829Sjoris tag = cf->file_ent->ce_tag;
36118cf7829Sjoris
36218cf7829Sjoris if (tag != NULL && cf->file_rcs != NULL) {
36318cf7829Sjoris brev = rcs_sym_getrev(cf->file_rcs, tag);
36418cf7829Sjoris if (brev != NULL) {
36559eae9b8Sjoris if (!RCSNUM_ISBRANCH(brev)) {
36609d28507Stobias cvs_log(LP_ERR, "sticky tag %s is not "
36709d28507Stobias "a branch for file %s", tag,
36809d28507Stobias cf->file_path);
36918cf7829Sjoris conflicts_found++;
37018cf7829Sjoris }
37118cf7829Sjoris }
37218cf7829Sjoris }
37318cf7829Sjoris }
37418cf7829Sjoris
37553ce2177Sfcambus free(branch);
37653ce2177Sfcambus free(brev);
37754de3f21Stobias
37884920933Stobias if (cf->file_status != FILE_ADDED &&
37984920933Stobias cf->file_status != FILE_REMOVED &&
38084920933Stobias cf->file_status != FILE_MODIFIED)
38184920933Stobias return;
38284920933Stobias
3834cb553bbSjoris cvs_file_get(cf->file_path, 0, &files_affected, CVS_FILE);
384db758d52Sjoris
385db758d52Sjoris switch (cf->file_status) {
386db758d52Sjoris case FILE_ADDED:
3874cb553bbSjoris cvs_file_get(cf->file_path, 0, &files_added, CVS_FILE);
388db758d52Sjoris break;
389db758d52Sjoris case FILE_REMOVED:
3904cb553bbSjoris cvs_file_get(cf->file_path, 0, &files_removed, CVS_FILE);
391db758d52Sjoris break;
392db758d52Sjoris case FILE_MODIFIED:
3934cb553bbSjoris cvs_file_get(cf->file_path, 0, &files_modified, CVS_FILE);
394db758d52Sjoris break;
395db758d52Sjoris }
396ef6e385cSjoris }
397ef6e385cSjoris
3983ad3fb45Sjoris void
cvs_commit_local(struct cvs_file * cf)3993ad3fb45Sjoris cvs_commit_local(struct cvs_file *cf)
400213afef1Sjfb {
40118cf7829Sjoris char *tag;
4024d33f394Sjoris BUF *b, *d;
40345b98c07Stobias int onbranch, isnew, histtype, branchadded;
40418cf7829Sjoris RCSNUM *nrev, *crev, *rrev, *brev;
405c486465dSxsa int openflags, rcsflags;
4067fa064caStobias char rbuf[CVS_REV_BUFSZ], nbuf[CVS_REV_BUFSZ];
407d77e7b73Sjoris CVSENTRIES *entlist;
408b9fc9a72Sderaadt char attic[PATH_MAX], repo[PATH_MAX], rcsfile[PATH_MAX];
409b034d592Sjoris struct file_info *fi;
410213afef1Sjfb
4113ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path);
41251ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag);
413213afef1Sjfb
4147938e528Sjoris if (cvs_noexec == 1)
4157938e528Sjoris return;
4167938e528Sjoris
4177fcaca70Sjoris if (cf->file_type != CVS_FILE)
4187fcaca70Sjoris fatal("cvs_commit_local: '%s' is not a file", cf->file_path);
4197fcaca70Sjoris
42045b98c07Stobias tag = cvs_directory_tag;
42145b98c07Stobias if (cf->file_ent != NULL && cf->file_ent->ce_tag != NULL)
42245b98c07Stobias tag = cf->file_ent->ce_tag;
42345b98c07Stobias
42445b98c07Stobias branchadded = 0;
42545b98c07Stobias switch (cf->file_status) {
42645b98c07Stobias case FILE_ADDED:
42745b98c07Stobias if (cf->file_rcs == NULL && tag != NULL) {
42845b98c07Stobias branchadded = 1;
42945b98c07Stobias cvs_add_tobranch(cf, tag);
43045b98c07Stobias }
43145b98c07Stobias break;
43245b98c07Stobias case FILE_MODIFIED:
43345b98c07Stobias case FILE_REMOVED:
43445b98c07Stobias if (cf->file_rcs == NULL) {
43545b98c07Stobias cvs_log(LP_ERR, "RCS file for %s got lost",
43645b98c07Stobias cf->file_path);
43745b98c07Stobias return;
43845b98c07Stobias }
43945b98c07Stobias break;
44045b98c07Stobias default:
4413901dfa5Sjoris cvs_log(LP_ERR, "skipping bogus file `%s'", cf->file_path);
4423901dfa5Sjoris return;
4433901dfa5Sjoris }
4443901dfa5Sjoris
44518cf7829Sjoris onbranch = 0;
44618cf7829Sjoris nrev = RCS_HEAD_REV;
44718cf7829Sjoris crev = NULL;
44818cf7829Sjoris rrev = NULL;
4494cd27328Sjoris d = NULL;
45018cf7829Sjoris
451eb6d38a6Sjoris if (cf->file_rcs != NULL && cf->file_rcs->rf_branch != NULL) {
45253ce2177Sfcambus free(cf->file_rcs->rf_branch);
453b6bee913Sjoris cf->file_rcs->rf_branch = NULL;
454b6bee913Sjoris }
455b6bee913Sjoris
45645b98c07Stobias if (cf->file_rcs != NULL) {
45718cf7829Sjoris rrev = rcs_head_get(cf->file_rcs);
45818cf7829Sjoris crev = rcs_head_get(cf->file_rcs);
4599af0ab72Stobias if (crev == NULL || rrev == NULL)
460e28eda4eStobias fatal("no head revision in RCS file for %s",
461e28eda4eStobias cf->file_path);
46218cf7829Sjoris
46318cf7829Sjoris if (tag != NULL) {
46453ce2177Sfcambus free(crev);
46553ce2177Sfcambus free(rrev);
466e1936db1Stobias brev = rcs_sym_getrev(cf->file_rcs, tag);
46718cf7829Sjoris crev = rcs_translate_tag(tag, cf->file_rcs);
468e1936db1Stobias if (brev == NULL || crev == NULL) {
46918cf7829Sjoris fatal("failed to resolve existing tag: %s",
47018cf7829Sjoris tag);
47118cf7829Sjoris }
47218cf7829Sjoris
473e1936db1Stobias rrev = rcsnum_alloc();
474e1936db1Stobias rcsnum_cpy(brev, rrev, brev->rn_len - 1);
475e1936db1Stobias
476e1936db1Stobias if (RCSNUM_ISBRANCHREV(crev) &&
477e1936db1Stobias rcsnum_cmp(crev, rrev, 0)) {
47818cf7829Sjoris nrev = rcsnum_alloc();
47918cf7829Sjoris rcsnum_cpy(crev, nrev, 0);
48018cf7829Sjoris rcsnum_inc(nrev);
48118cf7829Sjoris } else if (!RCSNUM_ISBRANCH(crev)) {
48218cf7829Sjoris nrev = rcsnum_brtorev(brev);
48318cf7829Sjoris if (nrev == NULL)
48418cf7829Sjoris fatal("failed to create branch rev");
48518cf7829Sjoris } else {
48618cf7829Sjoris fatal("this isnt suppose to happen, honestly");
48718cf7829Sjoris }
48818cf7829Sjoris
48953ce2177Sfcambus free(brev);
49053ce2177Sfcambus free(rrev);
49118cf7829Sjoris rrev = rcsnum_branch_root(nrev);
49218cf7829Sjoris
49318cf7829Sjoris /* branch stuff was checked in cvs_commit_check_files */
49418cf7829Sjoris onbranch = 1;
49518cf7829Sjoris }
49618cf7829Sjoris
49718cf7829Sjoris rcsnum_tostr(crev, rbuf, sizeof(rbuf));
498570941ffSjoris } else {
4996bbad201Sjoris strlcpy(rbuf, "Non-existent", sizeof(rbuf));
500570941ffSjoris }
5016bbad201Sjoris
50253ce2177Sfcambus free(rrev);
50343c5228fSjoris isnew = 0;
50461e51155Sjoris if (cf->file_status == FILE_ADDED) {
50543c5228fSjoris isnew = 1;
50661e51155Sjoris rcsflags = RCS_CREATE;
50745b98c07Stobias openflags = O_CREAT | O_RDONLY;
50861e51155Sjoris if (cf->file_rcs != NULL) {
50945b98c07Stobias if (!onbranch) {
510ca2dc546Sniallo if (cf->in_attic == 0)
51161e51155Sjoris cvs_log(LP_ERR, "warning: expected %s "
51245b98c07Stobias "to be in the Attic",
51345b98c07Stobias cf->file_path);
51461e51155Sjoris
51561e51155Sjoris if (cf->file_rcs->rf_dead == 0)
51661e51155Sjoris cvs_log(LP_ERR, "warning: expected %s "
51761e51155Sjoris "to be dead", cf->file_path);
51861e51155Sjoris
51945b98c07Stobias cvs_get_repository_path(cf->file_wd, repo,
520b9fc9a72Sderaadt PATH_MAX);
521b9fc9a72Sderaadt (void)xsnprintf(rcsfile, PATH_MAX, "%s/%s%s",
52261e51155Sjoris repo, cf->file_name, RCS_FILE_EXT);
52361e51155Sjoris
52461e51155Sjoris if (rename(cf->file_rpath, rcsfile) == -1)
52545b98c07Stobias fatal("cvs_commit_local: failed to "
52645b98c07Stobias "move %s outside the Attic: %s",
52745b98c07Stobias cf->file_path, strerror(errno));
52861e51155Sjoris
529397ddb8aSnicm free(cf->file_rpath);
53061e51155Sjoris cf->file_rpath = xstrdup(rcsfile);
53145b98c07Stobias isnew = 0;
53245b98c07Stobias }
53361e51155Sjoris
53461e51155Sjoris rcsflags = RCS_READ | RCS_PARSE_FULLY;
53561e51155Sjoris openflags = O_RDONLY;
53661e51155Sjoris rcs_close(cf->file_rcs);
53761e51155Sjoris }
53861e51155Sjoris
53961e51155Sjoris cf->repo_fd = open(cf->file_rpath, openflags);
540*3aaa63ebSderaadt if (cf->repo_fd == -1)
5416bbad201Sjoris fatal("cvs_commit_local: %s", strerror(errno));
5426bbad201Sjoris
5436bbad201Sjoris cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd,
544998f3c00Sotto rcsflags, 0444);
5456bbad201Sjoris if (cf->file_rcs == NULL)
5466bbad201Sjoris fatal("cvs_commit_local: failed to create RCS file "
5476bbad201Sjoris "for %s", cf->file_path);
5482ec286b3Sxsa
5492ec286b3Sxsa commit_desc_set(cf);
55045b98c07Stobias
55145b98c07Stobias if (branchadded)
55245b98c07Stobias strlcpy(rbuf, "Non-existent", sizeof(rbuf));
5536bbad201Sjoris }
5543ad3fb45Sjoris
5552868ee63Sreyk if (verbosity > 1) {
5563ad3fb45Sjoris cvs_printf("Checking in %s:\n", cf->file_path);
5573ad3fb45Sjoris cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path);
5583ad3fb45Sjoris cvs_printf("old revision: %s; ", rbuf);
5592868ee63Sreyk }
5603ad3fb45Sjoris
561e28eda4eStobias if (isnew == 0 && cf->file_rcs->rf_head == NULL)
562e28eda4eStobias fatal("no head revision in RCS file for %s", cf->file_path);
563e28eda4eStobias
56418cf7829Sjoris if (isnew == 0 && onbranch == 0)
56518cf7829Sjoris d = commit_diff(cf, cf->file_rcs->rf_head, 0);
5663ad3fb45Sjoris
567d77e7b73Sjoris if (cf->file_status == FILE_REMOVED) {
56818cf7829Sjoris b = rcs_rev_getbuf(cf->file_rcs, crev, 0);
56918cf7829Sjoris } else if (onbranch == 1) {
57018cf7829Sjoris b = commit_diff(cf, crev, 1);
5716bbad201Sjoris } else {
5727bb3ddb0Sray b = buf_load_fd(cf->fd);
573d77e7b73Sjoris }
5743ad3fb45Sjoris
57518cf7829Sjoris if (isnew == 0 && onbranch == 0) {
57618cf7829Sjoris if (rcs_deltatext_set(cf->file_rcs, crev, d) == -1)
5773ad3fb45Sjoris fatal("cvs_commit_local: failed to set delta");
5786bbad201Sjoris }
5793ad3fb45Sjoris
58018cf7829Sjoris if (rcs_rev_add(cf->file_rcs, nrev, logmsg, -1, NULL) == -1)
5813ad3fb45Sjoris fatal("cvs_commit_local: failed to add new revision");
5823ad3fb45Sjoris
58318cf7829Sjoris if (nrev == RCS_HEAD_REV)
58418cf7829Sjoris nrev = cf->file_rcs->rf_head;
58518cf7829Sjoris
58618cf7829Sjoris if (rcs_deltatext_set(cf->file_rcs, nrev, b) == -1)
5873ad3fb45Sjoris fatal("cvs_commit_local: failed to set new HEAD delta");
5883ad3fb45Sjoris
589d77e7b73Sjoris if (cf->file_status == FILE_REMOVED) {
59018cf7829Sjoris if (rcs_state_set(cf->file_rcs, nrev, RCS_STATE_DEAD) == -1)
591d77e7b73Sjoris fatal("cvs_commit_local: failed to set state");
592d77e7b73Sjoris }
593d77e7b73Sjoris
59456f996a2Sxsa if (cf->file_status == FILE_ADDED && cf->file_ent->ce_opts != NULL) {
59537fdff3fStobias int cf_kflag;
59656f996a2Sxsa
59737fdff3fStobias cf_kflag = rcs_kflag_get(cf->file_ent->ce_opts + 2);
59837fdff3fStobias rcs_kwexp_set(cf->file_rcs, cf_kflag);
59956f996a2Sxsa }
60056f996a2Sxsa
6013ad3fb45Sjoris rcs_write(cf->file_rcs);
6023ad3fb45Sjoris
603d77e7b73Sjoris if (cf->file_status == FILE_REMOVED) {
6042868ee63Sreyk strlcpy(nbuf, "Removed", sizeof(nbuf));
6056bbad201Sjoris } else if (cf->file_status == FILE_ADDED) {
60661e51155Sjoris if (cf->file_rcs->rf_dead == 1)
6072868ee63Sreyk strlcpy(nbuf, "Initial Revision", sizeof(nbuf));
60819615a73Sjoris else
60918cf7829Sjoris rcsnum_tostr(nrev, nbuf, sizeof(nbuf));
610d77e7b73Sjoris } else if (cf->file_status == FILE_MODIFIED) {
61118cf7829Sjoris rcsnum_tostr(nrev, nbuf, sizeof(nbuf));
612d77e7b73Sjoris }
613d77e7b73Sjoris
6142868ee63Sreyk if (verbosity > 1)
6152868ee63Sreyk cvs_printf("new revision: %s\n", nbuf);
6163ad3fb45Sjoris
6173ad3fb45Sjoris (void)unlink(cf->file_path);
6183ad3fb45Sjoris (void)close(cf->fd);
6193ad3fb45Sjoris cf->fd = -1;
620d77e7b73Sjoris
621d77e7b73Sjoris if (cf->file_status != FILE_REMOVED) {
62218cf7829Sjoris cvs_checkout_file(cf, nrev, NULL, CO_COMMIT);
623d77e7b73Sjoris } else {
624d77e7b73Sjoris entlist = cvs_ent_open(cf->file_wd);
625d77e7b73Sjoris cvs_ent_remove(entlist, cf->file_name);
6267fcaca70Sjoris
627b9fc9a72Sderaadt cvs_get_repository_path(cf->file_wd, repo, PATH_MAX);
6287fcaca70Sjoris
629b9fc9a72Sderaadt (void)xsnprintf(attic, PATH_MAX, "%s/%s",
630c486465dSxsa repo, CVS_PATH_ATTIC);
6317fcaca70Sjoris
6327fcaca70Sjoris if (mkdir(attic, 0755) == -1 && errno != EEXIST)
6337fcaca70Sjoris fatal("cvs_commit_local: failed to create Attic");
6347fcaca70Sjoris
635b9fc9a72Sderaadt (void)xsnprintf(attic, PATH_MAX, "%s/%s/%s%s", repo,
6367fcaca70Sjoris CVS_PATH_ATTIC, cf->file_name, RCS_FILE_EXT);
6377fcaca70Sjoris
6387fcaca70Sjoris if (rename(cf->file_rpath, attic) == -1)
6397fcaca70Sjoris fatal("cvs_commit_local: failed to move %s to Attic",
6407fcaca70Sjoris cf->file_path);
6417fcaca70Sjoris
642408908afSjoris if (cvs_server_active == 1)
643408908afSjoris cvs_server_update_entry("Remove-entry", cf);
644d77e7b73Sjoris }
6453ad3fb45Sjoris
6462868ee63Sreyk if (verbosity > 1)
6473ad3fb45Sjoris cvs_printf("done\n");
6482868ee63Sreyk else {
6492868ee63Sreyk cvs_log(LP_NOTICE, "checking in '%s'; revision %s -> %s",
6502868ee63Sreyk cf->file_path, rbuf, nbuf);
6512868ee63Sreyk }
6523901dfa5Sjoris
653b034d592Sjoris if (line_list != NULL) {
654b034d592Sjoris fi = xcalloc(1, sizeof(*fi));
655b034d592Sjoris fi->file_path = xstrdup(cf->file_path);
656b034d592Sjoris fi->crevstr = xstrdup(rbuf);
657b034d592Sjoris fi->nrevstr = xstrdup(nbuf);
658241113ffSjoris if (tag != NULL)
659241113ffSjoris fi->tag_new = xstrdup(tag);
660b034d592Sjoris TAILQ_INSERT_TAIL(&files_info, fi, flist);
661b034d592Sjoris }
662b034d592Sjoris
6633901dfa5Sjoris switch (cf->file_status) {
6643901dfa5Sjoris case FILE_MODIFIED:
6653901dfa5Sjoris histtype = CVS_HISTORY_COMMIT_MODIFIED;
6663901dfa5Sjoris break;
6673901dfa5Sjoris case FILE_ADDED:
6683901dfa5Sjoris histtype = CVS_HISTORY_COMMIT_ADDED;
6693901dfa5Sjoris break;
6703901dfa5Sjoris case FILE_REMOVED:
6713901dfa5Sjoris histtype = CVS_HISTORY_COMMIT_REMOVED;
6723901dfa5Sjoris break;
6734cd27328Sjoris default:
6744cd27328Sjoris histtype = -1;
6754cd27328Sjoris break;
6763901dfa5Sjoris }
6773901dfa5Sjoris
67853ce2177Sfcambus free(crev);
6794649b416Sjoris
6804cd27328Sjoris if (histtype != -1)
6813901dfa5Sjoris cvs_history_add(histtype, cf, NULL);
6824cd27328Sjoris else
6834cd27328Sjoris cvs_log(LP_NOTICE, "histtype was -1 for %s", cf->file_path);
684213afef1Sjfb }
685c710bc5aSjfb
6864d33f394Sjoris static BUF *
commit_diff(struct cvs_file * cf,RCSNUM * rev,int reverse)68718cf7829Sjoris commit_diff(struct cvs_file *cf, RCSNUM *rev, int reverse)
68808f90673Sjfb {
6897945e3ffSnicm int fd1, fd2, d;
6907945e3ffSnicm char *p1, *p2;
691b794e5f5Stobias BUF *b;
692924e91c6Sjoris
693924e91c6Sjoris (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
69408f90673Sjfb
69519615a73Sjoris if (cf->file_status == FILE_MODIFIED ||
69619615a73Sjoris cf->file_status == FILE_ADDED) {
6977bb3ddb0Sray b = buf_load_fd(cf->fd);
6987bb3ddb0Sray fd1 = buf_write_stmp(b, p1, NULL);
6997bb3ddb0Sray buf_free(b);
700924e91c6Sjoris } else {
7012e0d696aSjoris fd1 = rcs_rev_write_stmp(cf->file_rcs, rev, p1, 0);
702924e91c6Sjoris }
7036169aed9Skrapht
7043ad3fb45Sjoris (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
7052e0d696aSjoris fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE);
706924e91c6Sjoris
7077bb3ddb0Sray b = buf_alloc(128);
70838c61fc2Sjoris
7093ad3fb45Sjoris diff_format = D_RCSDIFF;
71018cf7829Sjoris
7117945e3ffSnicm if (reverse == 1)
7127945e3ffSnicm d = diffreg(p2, p1, fd2, fd1, b, D_FORCEASCII);
7137945e3ffSnicm else
7147945e3ffSnicm d = diffreg(p1, p2, fd1, fd2, b, D_FORCEASCII);
7157945e3ffSnicm if (d == D_ERROR)
71618cf7829Sjoris fatal("commit_diff: failed to get RCS patch");
717740595fcSxsa
7182e0d696aSjoris close(fd1);
7192e0d696aSjoris close(fd2);
7202e0d696aSjoris
721397ddb8aSnicm free(p1);
722397ddb8aSnicm free(p2);
7238787a230Sjoris
724b794e5f5Stobias return (b);
7256169aed9Skrapht }
7262ec286b3Sxsa
7272ec286b3Sxsa static void
commit_desc_set(struct cvs_file * cf)7282ec286b3Sxsa commit_desc_set(struct cvs_file *cf)
7292ec286b3Sxsa {
7302ec286b3Sxsa BUF *bp;
731c486465dSxsa int fd;
732b9fc9a72Sderaadt char desc_path[PATH_MAX], *desc;
7332ec286b3Sxsa
734b9fc9a72Sderaadt (void)xsnprintf(desc_path, PATH_MAX, "%s/%s/%s%s",
735c4d292c1Stobias cf->file_wd, CVS_PATH_CVSDIR, cf->file_name, CVS_DESCR_FILE_EXT);
7362ec286b3Sxsa
737ba7b4b60Sotto if ((fd = open(desc_path, O_RDONLY)) == -1)
7382ec286b3Sxsa return;
7392ec286b3Sxsa
7407bb3ddb0Sray bp = buf_load_fd(fd);
7417bb3ddb0Sray buf_putc(bp, '\0');
7427bb3ddb0Sray desc = buf_release(bp);
7432ec286b3Sxsa
7442ec286b3Sxsa rcs_desc_set(cf->file_rcs, desc);
7452ec286b3Sxsa
7462d02866cSjoris (void)close(fd);
7472ec286b3Sxsa (void)cvs_unlink(desc_path);
7482ec286b3Sxsa
749397ddb8aSnicm free(desc);
7502ec286b3Sxsa }
751