Annotation of src/usr.bin/cvs/commit.c, Revision 1.45
1.45 ! xsa 1: /* $OpenBSD: commit.c,v 1.44 2005/07/23 11:19:46 joris Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.9 tedu 4: * All rights reserved.
1.1 jfb 5: *
1.9 tedu 6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
1.1 jfb 9: *
1.9 tedu 10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
1.1 jfb 12: * 2. The name of the author may not be used to endorse or promote products
1.9 tedu 13: * derived from this software without specific prior written permission.
1.1 jfb 14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
1.9 tedu 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 25: */
26:
27: #include <sys/types.h>
1.6 jfb 28: #include <sys/queue.h>
1.1 jfb 29: #include <sys/stat.h>
30:
31: #include <errno.h>
1.37 xsa 32: #include <fcntl.h>
1.1 jfb 33: #include <stdio.h>
34: #include <stdlib.h>
1.37 xsa 35: #include <string.h>
1.1 jfb 36: #include <unistd.h>
37:
1.37 xsa 38: #include "buf.h"
1.1 jfb 39: #include "cvs.h"
40: #include "log.h"
1.2 jfb 41: #include "proto.h"
1.1 jfb 42:
43:
1.45 ! xsa 44: static int cvs_commit_init(struct cvs_cmd *, int, char **, int *);
! 45: static int cvs_commit_prepare(CVSFILE *, void *);
! 46: static int cvs_commit_remote(CVSFILE *, void *);
! 47: static int cvs_commit_local(CVSFILE *, void *);
! 48: static int cvs_commit_pre_exec(struct cvsroot *);
1.34 jfb 49:
50: struct cvs_cmd cvs_cmd_commit = {
51: CVS_OP_COMMIT, CVS_REQ_CI, "commit",
52: { "ci", "com" },
53: "Check files into the repository",
54: "[-flR] [-F logfile | -m msg] [-r rev] ...",
55: "F:flm:Rr:",
1.18 joris 56: NULL,
1.34 jfb 57: CF_RECURSE | CF_IGNORE | CF_SORT,
58: cvs_commit_init,
59: cvs_commit_pre_exec,
1.39 xsa 60: cvs_commit_remote,
61: cvs_commit_local,
1.34 jfb 62: NULL,
63: NULL,
1.41 joris 64: CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
1.18 joris 65: };
1.1 jfb 66:
1.18 joris 67: static char *mfile = NULL;
1.35 xsa 68: static char *rev = NULL;
1.32 joris 69: static char **commit_files = NULL;
70: static int commit_fcount = 0;
1.43 joris 71: static int wantedstatus = 0;
1.6 jfb 72:
1.34 jfb 73: static int
74: cvs_commit_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 jfb 75: {
1.18 joris 76: int ch;
1.3 krapht 77:
1.34 jfb 78: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 jfb 79: switch (ch) {
80: case 'F':
81: mfile = optarg;
82: break;
83: case 'f':
1.10 jfb 84: /* XXX half-implemented */
1.34 jfb 85: cmd->file_flags &= ~CF_RECURSE;
1.1 jfb 86: break;
87: case 'l':
1.34 jfb 88: cmd->file_flags &= ~CF_RECURSE;
1.1 jfb 89: break;
90: case 'm':
1.14 jfb 91: cvs_msg = strdup(optarg);
92: if (cvs_msg == NULL) {
93: cvs_log(LP_ERRNO, "failed to copy message");
1.23 joris 94: return (CVS_EX_USAGE);
1.14 jfb 95: }
1.1 jfb 96: break;
97: case 'R':
1.34 jfb 98: cmd->file_flags |= CF_RECURSE;
1.1 jfb 99: break;
1.35 xsa 100: case 'r':
101: rev = optarg;
102: break;
1.1 jfb 103: default:
1.23 joris 104: return (CVS_EX_USAGE);
1.1 jfb 105: }
106: }
107:
1.14 jfb 108: if ((cvs_msg != NULL) && (mfile != NULL)) {
1.1 jfb 109: cvs_log(LP_ERR, "the -F and -m flags are mutually exclusive");
1.23 joris 110: return (CVS_EX_USAGE);
1.1 jfb 111: }
112:
1.14 jfb 113: if ((mfile != NULL) && (cvs_msg = cvs_logmsg_open(mfile)) == NULL)
1.23 joris 114: return (CVS_EX_DATA);
1.1 jfb 115:
1.18 joris 116: *arg = optind;
1.32 joris 117:
118: commit_files = (argv + optind);
119: commit_fcount = (argc - optind);
120:
1.18 joris 121: return (0);
122: }
1.1 jfb 123:
1.18 joris 124: int
1.34 jfb 125: cvs_commit_pre_exec(struct cvsroot *root)
1.18 joris 126: {
127: CVSFILE *cfp;
1.32 joris 128: CVSFILE *tmp;
1.44 joris 129: int ret, i, flags = CF_RECURSE | CF_IGNORE | CF_SORT;
1.43 joris 130: struct cvs_flist added, modified, removed, *cl[3];
131: int stattype[] = { CVS_FST_ADDED, CVS_FST_MODIFIED, CVS_FST_REMOVED };
132:
133: SIMPLEQ_INIT(&added);
134: SIMPLEQ_INIT(&modified);
135: SIMPLEQ_INIT(&removed);
136:
137: cl[0] = &added;
138: cl[1] = &modified;
139: cl[2] = &removed;
140:
1.44 joris 141: if ((tmp = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1)) == NULL)
142: return (CVS_EX_DATA);
143:
1.43 joris 144: /*
145: * Obtain the file lists for the logmessage.
146: */
147: for (i = 0; i < 3; i++) {
148: wantedstatus = stattype[i];
149: if (commit_fcount != 0) {
1.44 joris 150: ret = cvs_file_getspec(commit_files, commit_fcount,
151: flags, cvs_commit_prepare, cl[i], NULL);
1.43 joris 152: } else {
1.44 joris 153: ret = cvs_file_get(".", flags, cvs_commit_prepare,
154: cl[i], NULL);
1.43 joris 155: }
1.32 joris 156:
1.44 joris 157: if (ret != CVS_EX_OK) {
158: cvs_file_free(tmp);
1.43 joris 159: return (CVS_EX_DATA);
1.44 joris 160: }
1.32 joris 161: }
1.1 jfb 162:
1.43 joris 163: /*
164: * If we didn't catch any file, don't call the editor.
165: */
166: if (SIMPLEQ_EMPTY(&added) && SIMPLEQ_EMPTY(&modified) &&
167: SIMPLEQ_EMPTY(&removed)) {
1.32 joris 168: cvs_file_free(tmp);
1.11 jfb 169: return (0);
1.32 joris 170: }
1.7 jfb 171:
1.43 joris 172: /*
173: * Fetch the log message for real, with all the files.
174: */
1.17 joris 175: if (cvs_msg == NULL)
1.43 joris 176: cvs_msg = cvs_logmsg_get(tmp->cf_name, &added, &modified,
177: &removed);
1.32 joris 178:
179: cvs_file_free(tmp);
1.17 joris 180:
1.43 joris 181: /* free the file lists */
182: for (i = 0; i < 3; i++) {
183: while (!SIMPLEQ_EMPTY(cl[i])) {
184: cfp = SIMPLEQ_FIRST(cl[i]);
185: SIMPLEQ_REMOVE_HEAD(cl[i], cf_list);
186: cvs_file_free(cfp);
187: }
1.7 jfb 188: }
1.17 joris 189:
190: if (cvs_msg == NULL)
1.23 joris 191: return (CVS_EX_DATA);
1.35 xsa 192:
193: if (root->cr_method != CVS_METHOD_LOCAL) {
1.36 joris 194: if (cvs_logmsg_send(root, cvs_msg) < 0)
195: return (CVS_EX_PROTO);
196:
1.35 xsa 197: if (rev != NULL) {
198: if ((cvs_sendarg(root, "-r", 0) < 0) ||
199: (cvs_sendarg(root, rev, 0) < 0))
200: return (CVS_EX_PROTO);
201: }
202: }
1.7 jfb 203:
204: return (0);
205: }
206:
207: /*
208: * cvs_commit_prepare()
209: *
210: * Examine the file <cf> to see if it will be part of the commit, in which
211: * case it gets added to the list passed as second argument.
212: */
213: int
214: cvs_commit_prepare(CVSFILE *cf, void *arg)
215: {
216: CVSFILE *copy;
217: struct cvs_flist *clp = (struct cvs_flist *)arg;
218:
1.43 joris 219: if ((cf->cf_type == DT_REG) && (cf->cf_cvstat == wantedstatus)) {
1.7 jfb 220: copy = cvs_file_copy(cf);
221: if (copy == NULL)
1.23 joris 222: return (CVS_EX_DATA);
1.7 jfb 223:
1.26 jfb 224: SIMPLEQ_INSERT_TAIL(clp, copy, cf_list);
1.7 jfb 225: }
1.3 krapht 226:
1.6 jfb 227: return (0);
1.3 krapht 228: }
229:
230:
231: /*
1.39 xsa 232: * cvs_commit_remote()
1.3 krapht 233: *
1.6 jfb 234: * Commit a single file.
1.3 krapht 235: */
1.6 jfb 236: int
1.39 xsa 237: cvs_commit_remote(CVSFILE *cf, void *arg)
1.3 krapht 238: {
1.39 xsa 239: int ret;
240: char *repo, fpath[MAXPATHLEN];
1.6 jfb 241: RCSFILE *rf;
242: struct cvsroot *root;
243:
1.13 jfb 244: ret = 0;
1.7 jfb 245: rf = NULL;
246: repo = NULL;
1.12 jfb 247: root = CVS_DIR_ROOT(cf);
1.6 jfb 248:
249: if (cf->cf_type == DT_DIR) {
1.39 xsa 250: if (cf->cf_cvstat != CVS_FST_UNKNOWN) {
251: if (cvs_senddir(root, cf) < 0)
252: return (CVS_EX_PROTO);
1.6 jfb 253: }
1.33 joris 254: return (0);
1.3 krapht 255: }
256:
1.7 jfb 257: cvs_file_getpath(cf, fpath, sizeof(fpath));
258:
259: if (cf->cf_parent != NULL)
1.26 jfb 260: repo = cf->cf_parent->cf_repo;
1.3 krapht 261:
1.6 jfb 262: if ((cf->cf_cvstat == CVS_FST_ADDED) ||
1.29 jfb 263: (cf->cf_cvstat == CVS_FST_MODIFIED) ||
264: (cf->cf_cvstat == CVS_FST_REMOVED)) {
1.39 xsa 265: if (cvs_sendentry(root, cf) < 0) {
266: return (CVS_EX_PROTO);
267: }
1.31 joris 268:
1.39 xsa 269: /* if it's removed, don't bother sending a
270: * Modified request together with the file its
271: * contents.
272: */
273: if (cf->cf_cvstat == CVS_FST_REMOVED)
274: return (0);
1.16 joris 275:
1.42 joris 276: if (cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name) < 0)
1.39 xsa 277: return (CVS_EX_PROTO);
1.16 joris 278:
1.39 xsa 279: if (cvs_sendfile(root, fpath) < 0) {
280: return (CVS_EX_PROTO);
1.5 krapht 281: }
282: }
1.3 krapht 283:
1.39 xsa 284: return (0);
285: }
286:
287: static int
288: cvs_commit_local(CVSFILE *cf, void *arg)
289: {
290: char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
291:
292: if (cf->cf_type == DT_DIR) {
293: if (verbosity > 1)
294: cvs_log(LP_INFO, "Examining %s", cf->cf_name);
295: return (0);
296: }
297:
298: cvs_file_getpath(cf, fpath, sizeof(fpath));
299:
1.40 xsa 300: if (cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)) == NULL)
1.33 joris 301: return (CVS_EX_DATA);
1.3 krapht 302:
1.6 jfb 303: return (0);
1.1 jfb 304: }