Annotation of src/usr.bin/cvs/add.c, Revision 1.61
1.61 ! xsa 1: /* $OpenBSD: add.c,v 1.60 2006/07/01 12:02:06 reyk Exp $ */
1.1 jfb 2: /*
1.43 joris 3: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.55 xsa 4: * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
1.1 jfb 5: *
1.43 joris 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.
1.1 jfb 9: *
1.43 joris 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.
1.1 jfb 17: */
18:
1.37 xsa 19: #include "includes.h"
1.1 jfb 20:
21: #include "cvs.h"
1.43 joris 22: #include "diff.h"
1.1 jfb 23: #include "log.h"
1.61 ! xsa 24: #include "remote.h"
1.1 jfb 25:
1.48 xsa 26: extern char *__progname;
27:
1.43 joris 28: void cvs_add_local(struct cvs_file *);
1.1 jfb 29:
1.45 joris 30: static void add_directory(struct cvs_file *);
31: static void add_file(struct cvs_file *);
1.55 xsa 32: static void add_entry(struct cvs_file *);
1.45 joris 33:
1.43 joris 34: char *logmsg;
1.21 jfb 35:
36: struct cvs_cmd cvs_cmd_add = {
1.57 joris 37: CVS_OP_ADD, 0, "add",
1.21 jfb 38: { "ad", "new" },
1.43 joris 39: "Add a new file or directory to the repository",
40: "[-m message] ...",
1.47 joris 41: "m:",
1.21 jfb 42: NULL,
1.43 joris 43: cvs_add
1.15 joris 44: };
1.3 jfb 45:
1.43 joris 46: int
47: cvs_add(int argc, char **argv)
1.1 jfb 48: {
1.15 joris 49: int ch;
1.43 joris 50: int flags;
51: struct cvs_recursion cr;
1.1 jfb 52:
1.45 joris 53: flags = CR_REPO;
1.1 jfb 54:
1.43 joris 55: while ((ch = getopt(argc, argv, cvs_cmd_add.cmd_opts)) != -1) {
1.1 jfb 56: switch (ch) {
57: case 'm':
1.43 joris 58: logmsg = xstrdup(optarg);
1.1 jfb 59: break;
60: default:
1.43 joris 61: fatal("%s", cvs_cmd_add.cmd_synopsis);
1.1 jfb 62: }
63: }
64:
1.43 joris 65: argc -= optind;
66: argv += optind;
1.28 xsa 67:
1.46 joris 68: if (argc == 0)
69: fatal("%s", cvs_cmd_add.cmd_synopsis);
70:
1.43 joris 71: cr.enterdir = NULL;
72: cr.leavedir = NULL;
1.61 ! xsa 73:
! 74: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
! 75: cr.fileproc = cvs_client_sendfile;
! 76:
! 77: if (logmsg != NULL)
! 78: cvs_client_send_request("Argument -m%s", logmsg);
! 79: } else {
! 80: cr.fileproc = cvs_add_local;
! 81: }
! 82:
1.43 joris 83: cr.flags = flags;
84:
1.46 joris 85: cvs_file_run(argc, argv, &cr);
1.61 ! xsa 86:
! 87: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
! 88: cvs_client_send_files(argv, argc);
! 89: cvs_client_senddir(".");
! 90: cvs_client_send_request("add");
! 91: cvs_client_get_responses();
! 92: }
! 93:
1.3 jfb 94: return (0);
95: }
96:
1.43 joris 97: void
98: cvs_add_local(struct cvs_file *cf)
1.3 jfb 99: {
1.45 joris 100: cvs_log(LP_TRACE, "cvs_add_local(%s)", cf->file_path);
101:
1.51 joris 102: cvs_file_classify(cf, NULL, 0);
1.49 xsa 103:
104: /* dont use `cvs add *' */
105: if (strcmp(cf->file_name, ".") == 0 ||
106: strcmp(cf->file_name, "..") == 0 ||
107: strcmp(cf->file_name, CVS_PATH_CVSDIR) == 0) {
108: if (verbosity > 1)
109: cvs_log(LP_ERR,
110: "cannot add special file `%s'; skipping",
111: cf->file_name);
112: return;
113: }
1.45 joris 114:
115: if (cf->file_type == CVS_DIR)
116: add_directory(cf);
117: else
118: add_file(cf);
119: }
120:
121: static void
122: add_directory(struct cvs_file *cf)
123: {
1.56 xsa 124: int l, added, nb;
1.45 joris 125: struct stat st;
1.44 joris 126: CVSENTRIES *entlist;
1.56 xsa 127: char *date, *entry, msg[1024], *repo, *tag;
1.45 joris 128:
129: cvs_log(LP_TRACE, "add_directory(%s)", cf->file_path);
1.44 joris 130:
1.45 joris 131: entry = xmalloc(MAXPATHLEN);
132: l = snprintf(entry, MAXPATHLEN, "%s%s", cf->file_rpath, RCS_FILE_EXT);
133: if (l == -1 || l >= MAXPATHLEN)
134: fatal("cvs_add_local: overflow");
135:
1.53 joris 136: added = 1;
1.45 joris 137: if (stat(entry, &st) != -1) {
138: cvs_log(LP_NOTICE, "cannot add directory %s: "
139: "a file with that name already exists",
140: cf->file_path);
1.53 joris 141: added = 0;
1.45 joris 142: } else {
1.56 xsa 143: /* Let's see if we have any per-directory tags first. */
144: cvs_parse_tagfile(cf->file_wd, &tag, &date, &nb);
145:
1.45 joris 146: l = snprintf(entry, MAXPATHLEN, "%s/%s", cf->file_path,
147: CVS_PATH_CVSDIR);
148: if (l == -1 || l >= MAXPATHLEN)
149: fatal("add_directory: overflow");
150:
151: if (stat(entry, &st) != -1) {
152: if (!S_ISDIR(st.st_mode)) {
153: cvs_log(LP_ERR, "%s exists but is not "
154: "directory", entry);
155: } else {
156: cvs_log(LP_NOTICE, "%s already exists",
157: entry);
158: }
1.53 joris 159: added = 0;
160: } else if (cvs_noexec != 1) {
1.45 joris 161: if (mkdir(cf->file_rpath, 0755) == -1 &&
162: errno != EEXIST)
163: fatal("add_directory: %s: %s", cf->file_path,
164: strerror(errno));
165:
166: repo = xmalloc(MAXPATHLEN);
167: cvs_get_repository_name(cf->file_wd, repo,
168: MAXPATHLEN);
169:
170: l = snprintf(entry, MAXPATHLEN, "%s/%s", repo,
1.60 reyk 171: cf->file_name);
1.45 joris 172:
173: cvs_mkadmin(cf->file_path, current_cvsroot->cr_dir,
1.56 xsa 174: entry, tag, date, nb);
1.45 joris 175:
176: xfree(repo);
177: xfree(entry);
178:
179: entry = xmalloc(CVS_ENT_MAXLINELEN);
180: l = snprintf(entry, CVS_ENT_MAXLINELEN,
181: "D/%s/////", cf->file_name);
182: entlist = cvs_ent_open(cf->file_wd);
183: cvs_ent_add(entlist, entry);
184: cvs_ent_close(entlist, ENT_SYNC);
1.53 joris 185: }
186: }
1.45 joris 187:
1.53 joris 188: if (added == 1) {
1.56 xsa 189: snprintf(msg, sizeof(msg),
190: "Directory %s added to the repository", cf->file_rpath);
191:
192: if (tag != NULL) {
193: (void)strlcat(msg,
194: "\n--> Using per-directory sticky tag ",
195: sizeof(msg));
196: (void)strlcat(msg, tag, sizeof(msg));
197: }
198: if (date != NULL) {
199: (void)strlcat(msg,
200: "\n--> Using per-directory sticky date ",
201: sizeof(msg));
202: (void)strlcat(msg, date, sizeof(msg));
203: }
204: cvs_printf("%s\n", msg);
205:
206: if (tag != NULL)
207: xfree(tag);
208: if (date != NULL)
209: xfree(date);
1.45 joris 210: }
211:
212: cf->file_status = FILE_SKIP;
213: xfree(entry);
214: }
1.3 jfb 215:
1.45 joris 216: static void
217: add_file(struct cvs_file *cf)
218: {
1.48 xsa 219: BUF *b;
1.55 xsa 220: int added, stop;
221: char revbuf[16];
1.52 joris 222: RCSNUM *head;
1.10 xsa 223:
1.44 joris 224: if (cf->file_rcs != NULL)
1.52 joris 225: rcsnum_tostr(rcs_head_get(cf->file_rcs),
226: revbuf, sizeof(revbuf));
1.44 joris 227:
1.48 xsa 228: added = stop = 0;
1.43 joris 229: switch (cf->file_status) {
230: case FILE_ADDED:
1.48 xsa 231: if (verbosity > 1)
232: cvs_log(LP_NOTICE, "%s has already been entered",
233: cf->file_path);
234: stop = 1;
235: break;
236: case FILE_REMOVED:
237: if (cf->file_rcs == NULL) {
238: cvs_log(LP_NOTICE, "cannot resurrect %s; "
239: "RCS file removed by second party", cf->file_name);
1.55 xsa 240: } else {
241: add_entry(cf);
1.48 xsa 242:
1.55 xsa 243: /* Restore the file. */
1.52 joris 244: head = rcs_head_get(cf->file_rcs);
245: b = rcs_getrev(cf->file_rcs, head);
1.48 xsa 246: if (b == NULL)
247: fatal("cvs_add_local: failed to get HEAD");
248:
1.53 joris 249: cvs_checkout_file(cf, head, b, 0);
1.48 xsa 250: cvs_printf("U %s\n", cf->file_path);
251:
252: cvs_log(LP_NOTICE, "%s, version %s, resurrected",
253: cf->file_name, revbuf);
254:
255: cf->file_status = FILE_UPTODATE;
256: }
1.44 joris 257: stop = 1;
258: break;
1.50 xsa 259: case FILE_CONFLICT:
260: case FILE_LOST:
261: case FILE_MODIFIED:
1.44 joris 262: case FILE_UPTODATE:
263: if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 0) {
264: cvs_log(LP_NOTICE, "%s already exists, with version "
265: "number %s", cf->file_path, revbuf);
266: stop = 1;
267: }
1.43 joris 268: break;
269: case FILE_UNKNOWN:
1.44 joris 270: if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 1) {
271: cvs_log(LP_NOTICE, "re-adding file %s "
272: "(instead of dead revision %s)",
273: cf->file_path, revbuf);
274: } else {
275: cvs_log(LP_NOTICE, "scheduling file '%s' for addition",
276: cf->file_path);
277: }
1.54 joris 278: added++;
1.43 joris 279: break;
280: default:
281: break;
1.1 jfb 282: }
1.44 joris 283:
284: if (stop == 1)
285: return;
286:
1.55 xsa 287: add_entry(cf);
1.44 joris 288:
1.48 xsa 289: if (added != 0) {
1.59 reyk 290: if (verbosity > 1)
1.48 xsa 291: cvs_log(LP_NOTICE, "use '%s commit' to add %s "
292: "permanently", __progname,
293: (added == 1) ? "this file" : "these files");
294: }
1.55 xsa 295: }
296:
297: static void
298: add_entry(struct cvs_file *cf)
299: {
300: FILE *fp;
301: int l;
302: char *entry, *path, revbuf[16], tbuf[32];
303: CVSENTRIES *entlist;
304:
305: if (cvs_noexec == 1)
306: return;
307:
308: entry = xmalloc(CVS_ENT_MAXLINELEN);
309:
310: if (cf->file_status == FILE_REMOVED) {
311: rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
312:
313: ctime_r(&cf->file_ent->ce_mtime, tbuf);
314: if (tbuf[strlen(tbuf) - 1] == '\n')
315: tbuf[strlen(tbuf) - 1] = '\0';
316:
317: /* Remove the '-' prefixing the version number. */
318: l = snprintf(entry, CVS_ENT_MAXLINELEN,
319: "/%s/%s/%s//", cf->file_name, revbuf, tbuf);
320: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
321: fatal("add_entry: truncation");
322: } else {
323: if (logmsg != NULL) {
324: path = xmalloc(MAXPATHLEN);
325:
326: l = snprintf(path, MAXPATHLEN, "%s/%s%s",
327: CVS_PATH_CVSDIR, cf->file_name, CVS_DESCR_FILE_EXT);
328: if (l == -1 || l >= MAXPATHLEN)
329: fatal("add_entry: truncation");
330:
331: if ((fp = fopen(path, "w+")) == NULL)
332: fatal("add_entry: fopen `%s': %s",
333: path, strerror(errno));
334:
335: if (fputs(logmsg, fp) == EOF) {
336: (void)unlink(path);
337: fatal("add_entry: fputs `%s': %s",
338: path, strerror(errno));
339: }
340: (void)fclose(fp);
341: xfree(path);
342: }
343:
344: l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/0/Initial %s//",
345: cf->file_name, cf->file_name);
346: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
347: fatal("add_entry: truncation");
348: }
349:
350: entlist = cvs_ent_open(cf->file_wd);
351: cvs_ent_add(entlist, entry);
352: cvs_ent_close(entlist, ENT_SYNC);
353:
354: xfree(entry);
1.1 jfb 355: }