xref: /openbsd-src/usr.bin/cvs/add.c (revision 3aaa63eb46949490a39db9c6d82aacc8ee5d8551)
1*3aaa63ebSderaadt /*	$OpenBSD: add.c,v 1.115 2019/06/28 13:35:00 deraadt Exp $	*/
291e2b091Sjoris /*
391e2b091Sjoris  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
42ec286b3Sxsa  * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
591e2b091Sjoris  *
691e2b091Sjoris  * Permission to use, copy, modify, and distribute this software for any
791e2b091Sjoris  * purpose with or without fee is hereby granted, provided that the above
891e2b091Sjoris  * copyright notice and this permission notice appear in all copies.
991e2b091Sjoris  *
1091e2b091Sjoris  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1191e2b091Sjoris  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1291e2b091Sjoris  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1391e2b091Sjoris  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1491e2b091Sjoris  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1591e2b091Sjoris  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1691e2b091Sjoris  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1791e2b091Sjoris  */
1891e2b091Sjoris 
191f8531bdSotto #include <sys/stat.h>
201f8531bdSotto 
211f8531bdSotto #include <errno.h>
2245b98c07Stobias #include <fcntl.h>
23397ddb8aSnicm #include <stdlib.h>
241f8531bdSotto #include <string.h>
251f8531bdSotto #include <unistd.h>
2691e2b091Sjoris 
2791e2b091Sjoris #include "cvs.h"
2877a3e292Sxsa #include "remote.h"
2991e2b091Sjoris 
30932258d9Sxsa extern char *__progname;
31932258d9Sxsa 
32b034d592Sjoris void	cvs_add_loginfo(char *);
33e453c9e9Sjoris void	cvs_add_entry(struct cvs_file *);
340096e8ebStobias void	cvs_add_remote(struct cvs_file *);
3591e2b091Sjoris 
36ee416d02Sjoris static void add_directory(struct cvs_file *);
37ee416d02Sjoris static void add_file(struct cvs_file *);
382ec286b3Sxsa static void add_entry(struct cvs_file *);
39ee416d02Sjoris 
4037fdff3fStobias int		kflag = 0;
41e0439b1cSzinovik static u_int	added_files = 0;
4237fdff3fStobias static char	kbuf[8];
4356f996a2Sxsa 
44b034d592Sjoris extern char	*logmsg;
45b034d592Sjoris extern char	*loginfo;
4691e2b091Sjoris 
4791e2b091Sjoris struct cvs_cmd cvs_cmd_add = {
48f331ff59Stobias 	CVS_OP_ADD, CVS_USE_WDIR, "add",
4991e2b091Sjoris 	{ "ad", "new" },
5091e2b091Sjoris 	"Add a new file or directory to the repository",
5156f996a2Sxsa 	"[-k mode] [-m message] ...",
5256f996a2Sxsa 	"k:m:",
5391e2b091Sjoris 	NULL,
5491e2b091Sjoris 	cvs_add
5591e2b091Sjoris };
5691e2b091Sjoris 
5791e2b091Sjoris int
cvs_add(int argc,char ** argv)5891e2b091Sjoris cvs_add(int argc, char **argv)
5991e2b091Sjoris {
6091e2b091Sjoris 	int ch;
6191e2b091Sjoris 	int flags;
6291e2b091Sjoris 	struct cvs_recursion cr;
6391e2b091Sjoris 
64ee416d02Sjoris 	flags = CR_REPO;
6591e2b091Sjoris 
6691e2b091Sjoris 	while ((ch = getopt(argc, argv, cvs_cmd_add.cmd_opts)) != -1) {
6791e2b091Sjoris 		switch (ch) {
6856f996a2Sxsa 		case 'k':
6937fdff3fStobias 			kflag = rcs_kflag_get(optarg);
7056f996a2Sxsa 			if (RCS_KWEXP_INVAL(kflag)) {
7156f996a2Sxsa 				cvs_log(LP_ERR,
720bc1d395Stobias 				    "invalid RCS keyword expansion mode");
7356f996a2Sxsa 				fatal("%s", cvs_cmd_add.cmd_synopsis);
7456f996a2Sxsa 			}
7537fdff3fStobias 			(void)xsnprintf(kbuf, sizeof(kbuf), "-k%s", optarg);
7656f996a2Sxsa 			break;
7791e2b091Sjoris 		case 'm':
784f1ce0f6Stobias 			logmsg = optarg;
7991e2b091Sjoris 			break;
8091e2b091Sjoris 		default:
8191e2b091Sjoris 			fatal("%s", cvs_cmd_add.cmd_synopsis);
8291e2b091Sjoris 		}
8391e2b091Sjoris 	}
8491e2b091Sjoris 
8591e2b091Sjoris 	argc -= optind;
8691e2b091Sjoris 	argv += optind;
8791e2b091Sjoris 
882a7e332fSjoris 	if (argc == 0)
892a7e332fSjoris 		fatal("%s", cvs_cmd_add.cmd_synopsis);
902a7e332fSjoris 
9191e2b091Sjoris 	cr.enterdir = NULL;
9291e2b091Sjoris 	cr.leavedir = NULL;
9377a3e292Sxsa 
944dcde513Sjoris 	if (cvsroot_is_remote()) {
9580f6ca9bSjoris 		cvs_client_connect_to_server();
960096e8ebStobias 		cr.fileproc = cvs_add_remote;
97bc0ff6ffSjoris 		flags = 0;
9877a3e292Sxsa 
998076d4ceSjoris 		if (kflag)
10056f996a2Sxsa 			cvs_client_send_request("Argument %s", kbuf);
10156f996a2Sxsa 
10277a3e292Sxsa 		if (logmsg != NULL)
103f76ce13cSjoris 			cvs_client_send_logmsg(logmsg);
10477a3e292Sxsa 	} else {
105b034d592Sjoris 		if (logmsg != NULL && cvs_logmsg_verify(logmsg))
106b034d592Sjoris 			return (0);
107b034d592Sjoris 
108bc5d89feSjoris 		cr.fileproc = cvs_add_local;
10977a3e292Sxsa 	}
11077a3e292Sxsa 
11191e2b091Sjoris 	cr.flags = flags;
11291e2b091Sjoris 
11391e2b091Sjoris 	cvs_file_run(argc, argv, &cr);
11477a3e292Sxsa 
115e0439b1cSzinovik 	if (added_files != 0) {
116e0439b1cSzinovik 		cvs_log(LP_NOTICE, "use '%s commit' to add %s "
117e0439b1cSzinovik 		    "permanently", __progname,
118e0439b1cSzinovik 		    (added_files == 1) ? "this file" : "these files");
119e0439b1cSzinovik 	}
120e0439b1cSzinovik 
1214dcde513Sjoris 	if (cvsroot_is_remote()) {
12277a3e292Sxsa 		cvs_client_senddir(".");
1230096e8ebStobias 		cvs_client_send_files(argv, argc);
12477a3e292Sxsa 		cvs_client_send_request("add");
12577a3e292Sxsa 		cvs_client_get_responses();
126e453c9e9Sjoris 
127e453c9e9Sjoris 		if (server_response == SERVER_OK) {
128e453c9e9Sjoris 			cr.fileproc = cvs_add_entry;
129e453c9e9Sjoris 			cvs_file_run(argc, argv, &cr);
130e453c9e9Sjoris 		}
13177a3e292Sxsa 	}
13277a3e292Sxsa 
13391e2b091Sjoris 	return (0);
13491e2b091Sjoris }
13591e2b091Sjoris 
13691e2b091Sjoris void
cvs_add_entry(struct cvs_file * cf)137e453c9e9Sjoris cvs_add_entry(struct cvs_file *cf)
138e453c9e9Sjoris {
139ae83823aSxsa 	char *entry;
140e453c9e9Sjoris 	CVSENTRIES *entlist;
141e453c9e9Sjoris 
142e453c9e9Sjoris 	if (cf->file_type == CVS_DIR) {
143ae83823aSxsa 		entry = xmalloc(CVS_ENT_MAXLINELEN);
144ae83823aSxsa 		cvs_ent_line_str(cf->file_name, NULL, NULL, NULL, NULL, 1, 0,
145ae83823aSxsa 		    entry, CVS_ENT_MAXLINELEN);
146428adc2bSjoris 
147e453c9e9Sjoris 		entlist = cvs_ent_open(cf->file_wd);
148e453c9e9Sjoris 		cvs_ent_add(entlist, entry);
149ae83823aSxsa 
150397ddb8aSnicm 		free(entry);
151e453c9e9Sjoris 	} else {
152e453c9e9Sjoris 		add_entry(cf);
153e453c9e9Sjoris 	}
154e453c9e9Sjoris }
155e453c9e9Sjoris 
156e453c9e9Sjoris void
cvs_add_local(struct cvs_file * cf)15791e2b091Sjoris cvs_add_local(struct cvs_file *cf)
15891e2b091Sjoris {
15991e2b091Sjoris 	cvs_log(LP_TRACE, "cvs_add_local(%s)", cf->file_path);
16091e2b091Sjoris 
16125d391d7Sjoris 	if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_UPDATE)
16251ef6581Sjoris 		cvs_file_classify(cf, cvs_directory_tag);
16391e2b091Sjoris 
16423aa6532Sxsa 	/* dont use `cvs add *' */
16523aa6532Sxsa 	if (strcmp(cf->file_name, ".") == 0 ||
16623aa6532Sxsa 	    strcmp(cf->file_name, "..") == 0 ||
16723aa6532Sxsa 	    strcmp(cf->file_name, CVS_PATH_CVSDIR) == 0) {
16823aa6532Sxsa 		if (verbosity > 1)
16923aa6532Sxsa 			cvs_log(LP_ERR,
17023aa6532Sxsa 			    "cannot add special file `%s'; skipping",
17123aa6532Sxsa 			    cf->file_name);
17223aa6532Sxsa 		return;
17323aa6532Sxsa 	}
17423aa6532Sxsa 
175ee416d02Sjoris 	if (cf->file_type == CVS_DIR)
176ee416d02Sjoris 		add_directory(cf);
177ee416d02Sjoris 	else
178ee416d02Sjoris 		add_file(cf);
179ee416d02Sjoris }
180ee416d02Sjoris 
1810096e8ebStobias void
cvs_add_remote(struct cvs_file * cf)1820096e8ebStobias cvs_add_remote(struct cvs_file *cf)
1830096e8ebStobias {
184b9fc9a72Sderaadt 	char path[PATH_MAX];
1850096e8ebStobias 
1860096e8ebStobias 	cvs_log(LP_TRACE, "cvs_add_remote(%s)", cf->file_path);
1870096e8ebStobias 
1880096e8ebStobias 	cvs_file_classify(cf, cvs_directory_tag);
1890096e8ebStobias 
1900096e8ebStobias 	if (cf->file_type == CVS_DIR) {
191b9fc9a72Sderaadt 		cvs_get_repository_path(cf->file_wd, path, PATH_MAX);
1920096e8ebStobias 		if (strlcat(path, "/", sizeof(path)) >= sizeof(path))
1930096e8ebStobias 			fatal("cvs_add_remote: truncation");
1940096e8ebStobias 		if (strlcat(path, cf->file_path, sizeof(path)) >= sizeof(path))
1950096e8ebStobias 			fatal("cvs_add_remote: truncation");
1960096e8ebStobias 		cvs_client_send_request("Directory %s\n%s", cf->file_path,
1970096e8ebStobias 		    path);
1980096e8ebStobias 
1990096e8ebStobias 		add_directory(cf);
2000096e8ebStobias 	} else {
2010096e8ebStobias 		cvs_client_sendfile(cf);
2020096e8ebStobias 	}
2030096e8ebStobias }
2040096e8ebStobias 
205b034d592Sjoris void
cvs_add_loginfo(char * repo)206b034d592Sjoris cvs_add_loginfo(char *repo)
207b034d592Sjoris {
208b034d592Sjoris 	BUF *buf;
209b9fc9a72Sderaadt 	char pwd[PATH_MAX];
210b034d592Sjoris 
211b034d592Sjoris 	if (getcwd(pwd, sizeof(pwd)) == NULL)
212b034d592Sjoris 		fatal("Can't get working directory");
213b034d592Sjoris 
2147bb3ddb0Sray 	buf = buf_alloc(1024);
215b034d592Sjoris 
216b034d592Sjoris 	cvs_trigger_loginfo_header(buf, repo);
217b034d592Sjoris 
2187bb3ddb0Sray 	buf_puts(buf, "Log Message:\nDirectory ");
2197bb3ddb0Sray 	buf_puts(buf, current_cvsroot->cr_dir);
2207bb3ddb0Sray 	buf_putc(buf, '/');
2217bb3ddb0Sray 	buf_puts(buf, repo);
2227bb3ddb0Sray 	buf_puts(buf, " added to the repository\n");
223b034d592Sjoris 
2247bb3ddb0Sray 	buf_putc(buf, '\0');
225b034d592Sjoris 
2267bb3ddb0Sray 	loginfo = buf_release(buf);
227b034d592Sjoris }
228b034d592Sjoris 
22945b98c07Stobias void
cvs_add_tobranch(struct cvs_file * cf,char * tag)23045b98c07Stobias cvs_add_tobranch(struct cvs_file *cf, char *tag)
23145b98c07Stobias {
23245b98c07Stobias 	BUF *bp;
233b9fc9a72Sderaadt 	char attic[PATH_MAX], repo[PATH_MAX];
23445b98c07Stobias 	char *msg;
23545b98c07Stobias 	struct stat st;
23645b98c07Stobias 	RCSNUM *branch;
23745b98c07Stobias 
23845b98c07Stobias 	cvs_log(LP_TRACE, "cvs_add_tobranch(%s)", cf->file_name);
23945b98c07Stobias 
24045b98c07Stobias 	if (cvs_noexec == 1)
24145b98c07Stobias 		return;
24245b98c07Stobias 
24345b98c07Stobias 	if (fstat(cf->fd, &st) == -1)
24445b98c07Stobias 		fatal("cvs_add_tobranch: %s", strerror(errno));
24545b98c07Stobias 
246b9fc9a72Sderaadt 	cvs_get_repository_path(cf->file_wd, repo, PATH_MAX);
247b9fc9a72Sderaadt 	(void)xsnprintf(attic, PATH_MAX, "%s/%s",
24845b98c07Stobias 	    repo, CVS_PATH_ATTIC);
24945b98c07Stobias 
25045b98c07Stobias 	if (mkdir(attic, 0755) == -1 && errno != EEXIST)
25145b98c07Stobias 		fatal("cvs_add_tobranch: failed to create Attic");
25245b98c07Stobias 
253b9fc9a72Sderaadt 	(void)xsnprintf(attic, PATH_MAX, "%s/%s/%s%s", repo,
25445b98c07Stobias 	    CVS_PATH_ATTIC, cf->file_name, RCS_FILE_EXT);
25545b98c07Stobias 
256397ddb8aSnicm 	free(cf->file_rpath);
25745b98c07Stobias 	cf->file_rpath = xstrdup(attic);
25845b98c07Stobias 
25945b98c07Stobias 	cf->repo_fd = open(cf->file_rpath, O_CREAT|O_RDONLY);
260*3aaa63ebSderaadt 	if (cf->repo_fd == -1)
26145b98c07Stobias 		fatal("cvs_add_tobranch: %s: %s", cf->file_rpath,
26245b98c07Stobias 		    strerror(errno));
26345b98c07Stobias 
26445b98c07Stobias 	cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd,
26545b98c07Stobias 	    RCS_CREATE|RCS_WRITE, 0444);
26645b98c07Stobias 	if (cf->file_rcs == NULL)
26745b98c07Stobias 		fatal("cvs_add_tobranch: failed to create RCS file for %s",
26845b98c07Stobias 		    cf->file_path);
26945b98c07Stobias 
27045b98c07Stobias 	if ((branch = rcsnum_parse("1.1.2")) == NULL)
27145b98c07Stobias 		fatal("cvs_add_tobranch: failed to parse branch");
27245b98c07Stobias 
27345b98c07Stobias 	if (rcs_sym_add(cf->file_rcs, tag, branch) == -1)
27445b98c07Stobias 		fatal("cvs_add_tobranch: failed to add vendor tag");
27545b98c07Stobias 
27645b98c07Stobias 	(void)xasprintf(&msg, "file %s was initially added on branch %s.",
27745b98c07Stobias 	    cf->file_name, tag);
27845b98c07Stobias 	if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, msg, -1, NULL) == -1)
27945b98c07Stobias 		fatal("cvs_add_tobranch: failed to create first branch "
28045b98c07Stobias 		    "revision");
281397ddb8aSnicm 	free(msg);
28245b98c07Stobias 
2834fc7a9b5Snicm 	if (rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head) == NULL)
28445b98c07Stobias 		fatal("cvs_add_tobranch: cannot find newly added revision");
28545b98c07Stobias 
2867bb3ddb0Sray 	bp = buf_alloc(1);
28745b98c07Stobias 
28845b98c07Stobias 	if (rcs_deltatext_set(cf->file_rcs,
28945b98c07Stobias 	    cf->file_rcs->rf_head, bp) == -1)
29045b98c07Stobias 		fatal("cvs_add_tobranch: failed to set deltatext");
29145b98c07Stobias 
29245b98c07Stobias 	rcs_comment_set(cf->file_rcs, " * ");
29345b98c07Stobias 
29445b98c07Stobias 	if (rcs_state_set(cf->file_rcs, cf->file_rcs->rf_head, RCS_STATE_DEAD)
29545b98c07Stobias 	    == -1)
29645b98c07Stobias 		fatal("cvs_add_tobranch: failed to set state");
29745b98c07Stobias }
29845b98c07Stobias 
299ee416d02Sjoris static void
add_directory(struct cvs_file * cf)300ee416d02Sjoris add_directory(struct cvs_file *cf)
301ee416d02Sjoris {
302c486465dSxsa 	int added, nb;
303ee416d02Sjoris 	struct stat st;
304ee416d02Sjoris 	CVSENTRIES *entlist;
305b9fc9a72Sderaadt 	char *date, entry[PATH_MAX], msg[1024], repo[PATH_MAX], *tag, *p;
306b034d592Sjoris 	struct file_info_list files_info;
307b034d592Sjoris 	struct file_info *fi;
308b034d592Sjoris 	struct trigger_list *line_list;
309ee416d02Sjoris 
310ee416d02Sjoris 	cvs_log(LP_TRACE, "add_directory(%s)", cf->file_path);
311ee416d02Sjoris 
312b9fc9a72Sderaadt 	(void)xsnprintf(entry, PATH_MAX, "%s%s",
313c486465dSxsa 	    cf->file_rpath, RCS_FILE_EXT);
314ee416d02Sjoris 
3157938e528Sjoris 	added = 1;
316ee416d02Sjoris 	if (stat(entry, &st) != -1) {
317ee416d02Sjoris 		cvs_log(LP_NOTICE, "cannot add directory %s: "
318ee416d02Sjoris 		    "a file with that name already exists",
319ee416d02Sjoris 		    cf->file_path);
3207938e528Sjoris 		added = 0;
321ee416d02Sjoris 	} else {
322890ecb5aSxsa 		/* Let's see if we have any per-directory tags first. */
323890ecb5aSxsa 		cvs_parse_tagfile(cf->file_wd, &tag, &date, &nb);
324890ecb5aSxsa 
325b9fc9a72Sderaadt 		(void)xsnprintf(entry, PATH_MAX, "%s/%s",
326e40de241Sxsa 		    cf->file_path, CVS_PATH_CVSDIR);
327ee416d02Sjoris 
3280096e8ebStobias 		if (cvs_server_active) {
3290096e8ebStobias 			if (mkdir(cf->file_rpath, 0755) == -1 &&
3300096e8ebStobias 			    errno != EEXIST)
3310096e8ebStobias 				fatal("add_directory: %s: %s", cf->file_rpath,
3320096e8ebStobias 				    strerror(errno));
3330096e8ebStobias 		} else if (stat(entry, &st) != -1) {
334ee416d02Sjoris 			if (!S_ISDIR(st.st_mode)) {
335ee416d02Sjoris 				cvs_log(LP_ERR, "%s exists but is not "
336ee416d02Sjoris 				    "directory", entry);
337ee416d02Sjoris 			} else {
338ee416d02Sjoris 				cvs_log(LP_NOTICE, "%s already exists",
339ee416d02Sjoris 				    entry);
340ee416d02Sjoris 			}
3417938e528Sjoris 			added = 0;
3427938e528Sjoris 		} else if (cvs_noexec != 1) {
343ee416d02Sjoris 			if (mkdir(cf->file_rpath, 0755) == -1 &&
344ee416d02Sjoris 			    errno != EEXIST)
3450096e8ebStobias 				fatal("add_directory: %s: %s", cf->file_rpath,
346ee416d02Sjoris 				    strerror(errno));
347ee416d02Sjoris 
348ee416d02Sjoris 			cvs_get_repository_name(cf->file_wd, repo,
349b9fc9a72Sderaadt 			    PATH_MAX);
350ee416d02Sjoris 
351b9fc9a72Sderaadt 			(void)xsnprintf(entry, PATH_MAX, "%s/%s",
352e40de241Sxsa 			    repo, cf->file_name);
353ee416d02Sjoris 
354ee416d02Sjoris 			cvs_mkadmin(cf->file_path, current_cvsroot->cr_dir,
3552dec954eStobias 			    entry, tag, date);
356ee416d02Sjoris 
357ba7b4b60Sotto 			p = xmalloc(CVS_ENT_MAXLINELEN);
358ae83823aSxsa 			cvs_ent_line_str(cf->file_name, NULL, NULL, NULL,
359ae83823aSxsa 			    NULL, 1, 0, p, CVS_ENT_MAXLINELEN);
360ae83823aSxsa 
361ee416d02Sjoris 			entlist = cvs_ent_open(cf->file_wd);
362ba7b4b60Sotto 			cvs_ent_add(entlist, p);
363397ddb8aSnicm 			free(p);
3647938e528Sjoris 		}
3657938e528Sjoris 	}
366ee416d02Sjoris 
3674dcde513Sjoris 	if (added == 1 && cvsroot_is_local()) {
368c486465dSxsa 		(void)xsnprintf(msg, sizeof(msg),
369890ecb5aSxsa 		    "Directory %s added to the repository", cf->file_rpath);
370890ecb5aSxsa 
371890ecb5aSxsa 		if (tag != NULL) {
372890ecb5aSxsa 			(void)strlcat(msg,
373890ecb5aSxsa 			    "\n--> Using per-directory sticky tag ",
374890ecb5aSxsa 			    sizeof(msg));
375890ecb5aSxsa 			(void)strlcat(msg, tag, sizeof(msg));
376890ecb5aSxsa 		}
377890ecb5aSxsa 		if (date != NULL) {
378890ecb5aSxsa 			(void)strlcat(msg,
379890ecb5aSxsa 			    "\n--> Using per-directory sticky date ",
380890ecb5aSxsa 			    sizeof(msg));
381890ecb5aSxsa 			(void)strlcat(msg, date, sizeof(msg));
382890ecb5aSxsa 		}
383890ecb5aSxsa 		cvs_printf("%s\n", msg);
384890ecb5aSxsa 
385397ddb8aSnicm 		free(tag);
386397ddb8aSnicm 		free(date);
387b034d592Sjoris 
388b9fc9a72Sderaadt 		cvs_get_repository_name(cf->file_path, repo, PATH_MAX);
389b034d592Sjoris 		line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, repo);
390b034d592Sjoris 		if (line_list != NULL) {
391b034d592Sjoris 			TAILQ_INIT(&files_info);
392b034d592Sjoris 			fi = xcalloc(1, sizeof(*fi));
393b034d592Sjoris 			fi->file_path = xstrdup(cf->file_path);
394b034d592Sjoris 			TAILQ_INSERT_TAIL(&files_info, fi, flist);
395b034d592Sjoris 
396b034d592Sjoris 			cvs_add_loginfo(repo);
397b034d592Sjoris 			cvs_trigger_handle(CVS_TRIGGER_LOGINFO, repo,
398b034d592Sjoris 			    loginfo, line_list, &files_info);
399b034d592Sjoris 
400b034d592Sjoris 			cvs_trigger_freeinfo(&files_info);
401b034d592Sjoris 			cvs_trigger_freelist(line_list);
402397ddb8aSnicm 			free(loginfo);
403b034d592Sjoris 		}
404ee416d02Sjoris 	}
405ee416d02Sjoris 
406ee416d02Sjoris 	cf->file_status = FILE_SKIP;
407ee416d02Sjoris }
408ee416d02Sjoris 
409ee416d02Sjoris static void
add_file(struct cvs_file * cf)410ee416d02Sjoris add_file(struct cvs_file *cf)
411ee416d02Sjoris {
412e0439b1cSzinovik 	int nb, stop;
4130a7da307Sxsa 	char revbuf[CVS_REV_BUFSZ];
414e28eda4eStobias 	RCSNUM *head = NULL;
415f92abd44Stobias 	char *tag;
416f92abd44Stobias 
417f92abd44Stobias 	cvs_parse_tagfile(cf->file_wd, &tag, NULL, &nb);
418f92abd44Stobias 	if (nb) {
419f92abd44Stobias 		cvs_log(LP_ERR, "cannot add file on non-branch tag %s", tag);
420f92abd44Stobias 		return;
421f92abd44Stobias 	}
422ee416d02Sjoris 
423570941ffSjoris 	if (cf->file_rcs != NULL) {
424570941ffSjoris 		head = rcs_head_get(cf->file_rcs);
425e28eda4eStobias 		if (head == NULL) {
426e28eda4eStobias 			cvs_log(LP_NOTICE, "no head revision in RCS file for "
427e28eda4eStobias 			    "%s", cf->file_path);
428e28eda4eStobias 		}
429570941ffSjoris 		rcsnum_tostr(head, revbuf, sizeof(revbuf));
430570941ffSjoris 	}
43119615a73Sjoris 
432e0439b1cSzinovik 	stop = 0;
43391e2b091Sjoris 	switch (cf->file_status) {
43491e2b091Sjoris 	case FILE_ADDED:
435efc9c26fStobias 	case FILE_CHECKOUT:
436932258d9Sxsa 		if (verbosity > 1)
43791e2b091Sjoris 			cvs_log(LP_NOTICE, "%s has already been entered",
43891e2b091Sjoris 			    cf->file_path);
43919615a73Sjoris 		stop = 1;
44019615a73Sjoris 		break;
441932258d9Sxsa 	case FILE_REMOVED:
442932258d9Sxsa 		if (cf->file_rcs == NULL) {
443932258d9Sxsa 			cvs_log(LP_NOTICE, "cannot resurrect %s; "
444932258d9Sxsa 			    "RCS file removed by second party", cf->file_name);
4455cf15c45Sjoris 		} else if (!(cf->file_flags & FILE_ON_DISK)) {
4462ec286b3Sxsa 			add_entry(cf);
447932258d9Sxsa 
4482ec286b3Sxsa 			/* Restore the file. */
4495d320860Sjoris 			cvs_checkout_file(cf, head, NULL, 0);
450570941ffSjoris 
451932258d9Sxsa 			cvs_printf("U %s\n", cf->file_path);
452932258d9Sxsa 
453932258d9Sxsa 			cvs_log(LP_NOTICE, "%s, version %s, resurrected",
454932258d9Sxsa 			    cf->file_name, revbuf);
455932258d9Sxsa 
456932258d9Sxsa 			cf->file_status = FILE_UPTODATE;
457932258d9Sxsa 		}
458932258d9Sxsa 		stop = 1;
459932258d9Sxsa 		break;
460e10eccadSxsa 	case FILE_CONFLICT:
461e10eccadSxsa 	case FILE_LOST:
462e10eccadSxsa 	case FILE_MODIFIED:
46319615a73Sjoris 	case FILE_UPTODATE:
46419615a73Sjoris 		if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 0) {
46519615a73Sjoris 			cvs_log(LP_NOTICE, "%s already exists, with version "
46619615a73Sjoris 			     "number %s", cf->file_path, revbuf);
46719615a73Sjoris 			stop = 1;
46819615a73Sjoris 		}
46991e2b091Sjoris 		break;
47091e2b091Sjoris 	case FILE_UNKNOWN:
47119615a73Sjoris 		if (cf->file_rcs != NULL && cf->file_rcs->rf_dead == 1) {
47219615a73Sjoris 			cvs_log(LP_NOTICE, "re-adding file %s "
47319615a73Sjoris 			    "(instead of dead revision %s)",
47419615a73Sjoris 			    cf->file_path, revbuf);
475e0439b1cSzinovik 			added_files++;
4765cf15c45Sjoris 		} else if (cf->file_flags & FILE_ON_DISK) {
47719615a73Sjoris 			cvs_log(LP_NOTICE, "scheduling file '%s' for addition",
47891e2b091Sjoris 			    cf->file_path);
479e0439b1cSzinovik 			added_files++;
4808085e067Sjoris 		} else {
4818085e067Sjoris 			stop = 1;
4828085e067Sjoris 		}
48391e2b091Sjoris 		break;
48491e2b091Sjoris 	default:
48591e2b091Sjoris 		break;
48691e2b091Sjoris 	}
48719615a73Sjoris 
48853ce2177Sfcambus 	free(head);
489e28eda4eStobias 
49019615a73Sjoris 	if (stop == 1)
49119615a73Sjoris 		return;
49219615a73Sjoris 
4932ec286b3Sxsa 	add_entry(cf);
49491e2b091Sjoris }
4952ec286b3Sxsa 
4962ec286b3Sxsa static void
add_entry(struct cvs_file * cf)4972ec286b3Sxsa add_entry(struct cvs_file *cf)
4982ec286b3Sxsa {
4992ec286b3Sxsa 	FILE *fp;
500b9fc9a72Sderaadt 	char *entry, path[PATH_MAX];
5010a7da307Sxsa 	char revbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ];
502f92abd44Stobias 	char sticky[CVS_ENT_MAXLINELEN];
5032ec286b3Sxsa 	CVSENTRIES *entlist;
5042ec286b3Sxsa 
5052ec286b3Sxsa 	if (cvs_noexec == 1)
5062ec286b3Sxsa 		return;
5072ec286b3Sxsa 
508f92abd44Stobias 	sticky[0] = '\0';
509ae83823aSxsa 	entry = xmalloc(CVS_ENT_MAXLINELEN);
510f92abd44Stobias 
5112ec286b3Sxsa 	if (cf->file_status == FILE_REMOVED) {
5122ec286b3Sxsa 		rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
5132ec286b3Sxsa 
5142ec286b3Sxsa 		ctime_r(&cf->file_ent->ce_mtime, tbuf);
5152820b891Stobias 		tbuf[strcspn(tbuf, "\n")] = '\0';
5162ec286b3Sxsa 
517f92abd44Stobias 		if (cf->file_ent->ce_tag != NULL)
518f92abd44Stobias 			(void)xsnprintf(sticky, sizeof(sticky), "T%s",
519f92abd44Stobias 			    cf->file_ent->ce_tag);
520f92abd44Stobias 
5212ec286b3Sxsa 		/* Remove the '-' prefixing the version number. */
522ae83823aSxsa 		cvs_ent_line_str(cf->file_name, revbuf, tbuf,
523ae83823aSxsa 		    cf->file_ent->ce_opts ? cf->file_ent->ce_opts : "", sticky,
524ae83823aSxsa 		    0, 0, entry, CVS_ENT_MAXLINELEN);
5252ec286b3Sxsa 	} else {
5262ec286b3Sxsa 		if (logmsg != NULL) {
527b9fc9a72Sderaadt 			(void)xsnprintf(path, PATH_MAX, "%s/%s/%s%s",
528c4d292c1Stobias 			    cf->file_wd, CVS_PATH_CVSDIR, cf->file_name,
529c4d292c1Stobias 			    CVS_DESCR_FILE_EXT);
5302ec286b3Sxsa 
5312ec286b3Sxsa 			if ((fp = fopen(path, "w+")) == NULL)
5322ec286b3Sxsa 				fatal("add_entry: fopen `%s': %s",
5332ec286b3Sxsa 				    path, strerror(errno));
5342ec286b3Sxsa 
5352ec286b3Sxsa 			if (fputs(logmsg, fp) == EOF) {
5362ec286b3Sxsa 				(void)unlink(path);
5372ec286b3Sxsa 				fatal("add_entry: fputs `%s': %s",
5382ec286b3Sxsa 				    path, strerror(errno));
5392ec286b3Sxsa 			}
5402ec286b3Sxsa 			(void)fclose(fp);
5412ec286b3Sxsa 		}
5422ec286b3Sxsa 
543f92abd44Stobias 		if (cvs_directory_tag != NULL)
544f92abd44Stobias 			(void)xsnprintf(sticky, sizeof(sticky), "T%s",
545f92abd44Stobias 			    cvs_directory_tag);
546f92abd44Stobias 
547f92abd44Stobias 		tbuf[0] = '\0';
548f92abd44Stobias 		if (!cvs_server_active)
549f92abd44Stobias 			(void)xsnprintf(tbuf, sizeof(tbuf), "Initial %s",
550f92abd44Stobias 			    cf->file_name);
551f92abd44Stobias 
552ae83823aSxsa 		cvs_ent_line_str(cf->file_name, "0", tbuf, kflag ? kbuf : "",
553ae83823aSxsa 		    sticky, 0, 0, entry, CVS_ENT_MAXLINELEN);
5542ec286b3Sxsa 	}
5552ec286b3Sxsa 
5567bd344d4Stobias 	if (cvs_server_active) {
5577bd344d4Stobias 		cvs_server_send_response("Checked-in %s/", cf->file_wd);
55822872efdScanacar 		cvs_server_send_response("%s", cf->file_path);
55922872efdScanacar 		cvs_server_send_response("%s", entry);
5607bd344d4Stobias 	} else {
5612ec286b3Sxsa 		entlist = cvs_ent_open(cf->file_wd);
5622ec286b3Sxsa 		cvs_ent_add(entlist, entry);
5632ec286b3Sxsa 	}
564397ddb8aSnicm 	free(entry);
5657bd344d4Stobias }
566