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