Annotation of src/usr.bin/cvs/add.c, Revision 1.57
1.57 ! joris 1: /* $OpenBSD: add.c,v 1.56 2006/06/14 15:14:47 xsa 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"
24:
1.48 xsa 25: extern char *__progname;
26:
1.43 joris 27: int cvs_add(int, char **);
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;
73: cr.local = cvs_add_local;
74: cr.remote = NULL;
75: cr.flags = flags;
76:
1.46 joris 77: cvs_file_run(argc, argv, &cr);
1.3 jfb 78: return (0);
79: }
80:
1.43 joris 81: void
82: cvs_add_local(struct cvs_file *cf)
1.3 jfb 83: {
1.45 joris 84: cvs_log(LP_TRACE, "cvs_add_local(%s)", cf->file_path);
85:
1.51 joris 86: cvs_file_classify(cf, NULL, 0);
1.49 xsa 87:
88: /* dont use `cvs add *' */
89: if (strcmp(cf->file_name, ".") == 0 ||
90: strcmp(cf->file_name, "..") == 0 ||
91: strcmp(cf->file_name, CVS_PATH_CVSDIR) == 0) {
92: if (verbosity > 1)
93: cvs_log(LP_ERR,
94: "cannot add special file `%s'; skipping",
95: cf->file_name);
96: return;
97: }
1.45 joris 98:
99: if (cf->file_type == CVS_DIR)
100: add_directory(cf);
101: else
102: add_file(cf);
103: }
104:
105: static void
106: add_directory(struct cvs_file *cf)
107: {
1.56 xsa 108: int l, added, nb;
1.45 joris 109: struct stat st;
1.44 joris 110: CVSENTRIES *entlist;
1.56 xsa 111: char *date, *entry, msg[1024], *repo, *tag;
1.45 joris 112:
113: cvs_log(LP_TRACE, "add_directory(%s)", cf->file_path);
1.44 joris 114:
1.45 joris 115: entry = xmalloc(MAXPATHLEN);
116: l = snprintf(entry, MAXPATHLEN, "%s%s", cf->file_rpath, RCS_FILE_EXT);
117: if (l == -1 || l >= MAXPATHLEN)
118: fatal("cvs_add_local: overflow");
119:
1.53 joris 120: added = 1;
1.45 joris 121: if (stat(entry, &st) != -1) {
122: cvs_log(LP_NOTICE, "cannot add directory %s: "
123: "a file with that name already exists",
124: cf->file_path);
1.53 joris 125: added = 0;
1.45 joris 126: } else {
1.56 xsa 127: /* Let's see if we have any per-directory tags first. */
128: cvs_parse_tagfile(cf->file_wd, &tag, &date, &nb);
129:
1.45 joris 130: l = snprintf(entry, MAXPATHLEN, "%s/%s", cf->file_path,
131: CVS_PATH_CVSDIR);
132: if (l == -1 || l >= MAXPATHLEN)
133: fatal("add_directory: overflow");
134:
135: if (stat(entry, &st) != -1) {
136: if (!S_ISDIR(st.st_mode)) {
137: cvs_log(LP_ERR, "%s exists but is not "
138: "directory", entry);
139: } else {
140: cvs_log(LP_NOTICE, "%s already exists",
141: entry);
142: }
1.53 joris 143: added = 0;
144: } else if (cvs_noexec != 1) {
1.45 joris 145: if (mkdir(cf->file_rpath, 0755) == -1 &&
146: errno != EEXIST)
147: fatal("add_directory: %s: %s", cf->file_path,
148: strerror(errno));
149:
150: repo = xmalloc(MAXPATHLEN);
151: cvs_get_repository_name(cf->file_wd, repo,
152: MAXPATHLEN);
153:
154: l = snprintf(entry, MAXPATHLEN, "%s/%s", repo,
155: cf->file_path);
156:
157: cvs_mkadmin(cf->file_path, current_cvsroot->cr_dir,
1.56 xsa 158: entry, tag, date, nb);
1.45 joris 159:
160: xfree(repo);
161: xfree(entry);
162:
163: entry = xmalloc(CVS_ENT_MAXLINELEN);
164: l = snprintf(entry, CVS_ENT_MAXLINELEN,
165: "D/%s/////", cf->file_name);
166: entlist = cvs_ent_open(cf->file_wd);
167: cvs_ent_add(entlist, entry);
168: cvs_ent_close(entlist, ENT_SYNC);
1.53 joris 169: }
170: }
1.45 joris 171:
1.53 joris 172: if (added == 1) {
1.56 xsa 173: snprintf(msg, sizeof(msg),
174: "Directory %s added to the repository", cf->file_rpath);
175:
176: if (tag != NULL) {
177: (void)strlcat(msg,
178: "\n--> Using per-directory sticky tag ",
179: sizeof(msg));
180: (void)strlcat(msg, tag, sizeof(msg));
181: }
182: if (date != NULL) {
183: (void)strlcat(msg,
184: "\n--> Using per-directory sticky date ",
185: sizeof(msg));
186: (void)strlcat(msg, date, sizeof(msg));
187: }
188: cvs_printf("%s\n", msg);
189:
190: if (tag != NULL)
191: xfree(tag);
192: if (date != NULL)
193: xfree(date);
1.45 joris 194: }
195:
196: cf->file_status = FILE_SKIP;
197: xfree(entry);
198: }
1.3 jfb 199:
1.45 joris 200: static void
201: add_file(struct cvs_file *cf)
202: {
1.48 xsa 203: BUF *b;
1.55 xsa 204: int added, stop;
205: char revbuf[16];
1.52 joris 206: RCSNUM *head;
1.10 xsa 207:
1.44 joris 208: if (cf->file_rcs != NULL)
1.52 joris 209: rcsnum_tostr(rcs_head_get(cf->file_rcs),
210: revbuf, sizeof(revbuf));
1.44 joris 211:
1.48 xsa 212: added = stop = 0;
1.43 joris 213: switch (cf->file_status) {
214: case FILE_ADDED:
1.48 xsa 215: if (verbosity > 1)
216: cvs_log(LP_NOTICE, "%s has already been entered",
217: cf->file_path);
218: stop = 1;
219: break;
220: case FILE_REMOVED:
221: if (cf->file_rcs == NULL) {
222: cvs_log(LP_NOTICE, "cannot resurrect %s; "
223: "RCS file removed by second party", cf->file_name);
1.55 xsa 224: } else {
225: add_entry(cf);
1.48 xsa 226:
1.55 xsa 227: /* Restore the file. */
1.52 joris 228: head = rcs_head_get(cf->file_rcs);
229: b = rcs_getrev(cf->file_rcs, head);
1.48 xsa 230: if (b == NULL)
231: fatal("cvs_add_local: failed to get HEAD");
232:
1.53 joris 233: cvs_checkout_file(cf, head, b, 0);
1.48 xsa 234: cvs_printf("U %s\n", cf->file_path);
235:
236: cvs_log(LP_NOTICE, "%s, version %s, resurrected",
237: cf->file_name, revbuf);
238:
239: cf->file_status = FILE_UPTODATE;
240: }
1.44 joris 241: stop = 1;
242: break;
1.50 xsa 243: case FILE_CONFLICT:
244: case FILE_LOST:
245: case FILE_MODIFIED:
1.44 joris 246: case FILE_UPTODATE:
247: if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 0) {
248: cvs_log(LP_NOTICE, "%s already exists, with version "
249: "number %s", cf->file_path, revbuf);
250: stop = 1;
251: }
1.43 joris 252: break;
253: case FILE_UNKNOWN:
1.44 joris 254: if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 1) {
255: cvs_log(LP_NOTICE, "re-adding file %s "
256: "(instead of dead revision %s)",
257: cf->file_path, revbuf);
258: } else {
259: cvs_log(LP_NOTICE, "scheduling file '%s' for addition",
260: cf->file_path);
261: }
1.54 joris 262: added++;
1.43 joris 263: break;
264: default:
265: break;
1.1 jfb 266: }
1.44 joris 267:
268: if (stop == 1)
269: return;
270:
1.55 xsa 271: add_entry(cf);
1.44 joris 272:
1.48 xsa 273: if (added != 0) {
274: if (verbosity > 0)
275: cvs_log(LP_NOTICE, "use '%s commit' to add %s "
276: "permanently", __progname,
277: (added == 1) ? "this file" : "these files");
278: }
1.55 xsa 279: }
280:
281: static void
282: add_entry(struct cvs_file *cf)
283: {
284: FILE *fp;
285: int l;
286: char *entry, *path, revbuf[16], tbuf[32];
287: CVSENTRIES *entlist;
288:
289: if (cvs_noexec == 1)
290: return;
291:
292: entry = xmalloc(CVS_ENT_MAXLINELEN);
293:
294: if (cf->file_status == FILE_REMOVED) {
295: rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
296:
297: ctime_r(&cf->file_ent->ce_mtime, tbuf);
298: if (tbuf[strlen(tbuf) - 1] == '\n')
299: tbuf[strlen(tbuf) - 1] = '\0';
300:
301: /* Remove the '-' prefixing the version number. */
302: l = snprintf(entry, CVS_ENT_MAXLINELEN,
303: "/%s/%s/%s//", cf->file_name, revbuf, tbuf);
304: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
305: fatal("add_entry: truncation");
306: } else {
307: if (logmsg != NULL) {
308: path = xmalloc(MAXPATHLEN);
309:
310: l = snprintf(path, MAXPATHLEN, "%s/%s%s",
311: CVS_PATH_CVSDIR, cf->file_name, CVS_DESCR_FILE_EXT);
312: if (l == -1 || l >= MAXPATHLEN)
313: fatal("add_entry: truncation");
314:
315: if ((fp = fopen(path, "w+")) == NULL)
316: fatal("add_entry: fopen `%s': %s",
317: path, strerror(errno));
318:
319: if (fputs(logmsg, fp) == EOF) {
320: (void)unlink(path);
321: fatal("add_entry: fputs `%s': %s",
322: path, strerror(errno));
323: }
324: (void)fclose(fp);
325: xfree(path);
326: }
327:
328: l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/0/Initial %s//",
329: cf->file_name, cf->file_name);
330: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
331: fatal("add_entry: truncation");
332: }
333:
334: entlist = cvs_ent_open(cf->file_wd);
335: cvs_ent_add(entlist, entry);
336: cvs_ent_close(entlist, ENT_SYNC);
337:
338: xfree(entry);
1.1 jfb 339: }