add.c revision 81404
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
4 *
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
7 *
8 * Add
9 *
10 * Adds a file or directory to the RCS source repository.  For a file,
11 * the entry is marked as "needing to be added" in the user's own CVS
12 * directory, and really added to the repository when it is committed.
13 * For a directory, it is added at the appropriate place in the source
14 * repository and a CVS directory is generated within the directory.
15 *
16 * The -m option is currently the only supported option.  Some may wish to
17 * supply standard "rcs" options here, but I've found that this causes more
18 * trouble than anything else.
19 *
20 * The user files or directories must already exist.  For a directory, it must
21 * not already have a CVS file in it.
22 *
23 * An "add" on a file that has been "remove"d but not committed will cause the
24 * file to be resurrected.
25 */
26
27#include "cvs.h"
28#include "savecwd.h"
29#include "fileattr.h"
30
31static int add_directory PROTO ((struct file_info *finfo));
32static int build_entry PROTO((char *repository, char *user, char *options,
33		        char *message, List * entries, char *tag));
34
35static const char *const add_usage[] =
36{
37    "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
38    "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
39    "\t-m\tUse \"message\" for the creation log.\n",
40    "(Specify the --help global option for a list of other help options)\n",
41    NULL
42};
43
44int
45add (argc, argv)
46    int argc;
47    char **argv;
48{
49    char *message = NULL;
50    int i;
51    char *repository;
52    int c;
53    int err = 0;
54    int added_files = 0;
55    char *options = NULL;
56    List *entries;
57    Vers_TS *vers;
58    struct saved_cwd cwd;
59    /* Nonzero if we found a slash, and are thus adding files in a
60       subdirectory.  */
61    int found_slash = 0;
62    size_t cvsroot_len;
63
64    if (argc == 1 || argc == -1)
65	usage (add_usage);
66
67    wrap_setup ();
68
69    /* parse args */
70    optind = 0;
71    while ((c = getopt (argc, argv, "+k:m:")) != -1)
72    {
73	switch (c)
74	{
75	    case 'k':
76		if (options)
77		    free (options);
78		options = RCS_check_kflag (optarg);
79		break;
80
81	    case 'm':
82		message = xstrdup (optarg);
83		break;
84	    case '?':
85	    default:
86		usage (add_usage);
87		break;
88	}
89    }
90    argc -= optind;
91    argv += optind;
92
93    if (argc <= 0)
94	usage (add_usage);
95
96    cvsroot_len = strlen (current_parsed_root->directory);
97
98    /* First some sanity checks.  I know that the CVS case is (sort of)
99       also handled by add_directory, but we need to check here so the
100       client won't get all confused in send_file_names.  */
101    for (i = 0; i < argc; i++)
102    {
103	int skip_file = 0;
104
105	/* If it were up to me I'd probably make this a fatal error.
106	   But some people are really fond of their "cvs add *", and
107	   don't seem to object to the warnings.
108	   Whatever.  */
109	strip_trailing_slashes (argv[i]);
110	if (strcmp (argv[i], ".") == 0
111	    || strcmp (argv[i], "..") == 0
112	    || fncmp (argv[i], CVSADM) == 0)
113	{
114	    if (!quiet)
115		error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
116	    skip_file = 1;
117	}
118	else
119	{
120	    char *p;
121	    p = argv[i];
122	    while (*p != '\0')
123	    {
124		if (ISDIRSEP (*p))
125		{
126		    found_slash = 1;
127		    break;
128		}
129		++p;
130	    }
131	}
132
133	if (skip_file)
134	{
135	    int j;
136
137	    /* FIXME: We don't do anything about free'ing argv[i].  But
138	       the problem is that it is only sometimes allocated (see
139	       cvsrc.c).  */
140
141	    for (j = i; j < argc - 1; ++j)
142		argv[j] = argv[j + 1];
143	    --argc;
144	    /* Check the new argv[i] again.  */
145	    --i;
146	    ++err;
147	}
148    }
149
150#ifdef CLIENT_SUPPORT
151    if (current_parsed_root->isremote)
152    {
153	int i;
154
155	if (argc == 0)
156	    /* We snipped out all the arguments in the above sanity
157	       check.  We can just forget the whole thing (and we
158	       better, because if we fired up the server and passed it
159	       nothing, it would spit back a usage message).  */
160	    return err;
161
162	start_server ();
163	ign_setup ();
164	if (options)
165	{
166	    send_arg (options);
167	    free (options);
168	}
169	option_with_arg ("-m", message);
170
171	/* If !found_slash, refrain from sending "Directory", for
172	   CVS 1.9 compatibility.  If we only tried to deal with servers
173	   which are at least CVS 1.9.26 or so, we wouldn't have to
174	   special-case this.  */
175	if (found_slash)
176	{
177	    repository = Name_Repository (NULL, NULL);
178	    send_a_repository ("", repository, "");
179	    free (repository);
180	}
181
182	for (i = 0; i < argc; ++i)
183	{
184	    /* FIXME: Does this erroneously call Create_Admin in error
185	       conditions which are only detected once the server gets its
186	       hands on things?  */
187	    /* FIXME-also: if filenames are case-insensitive on the
188	       client, and the directory in the repository already
189	       exists and is named "foo", and the command is "cvs add
190	       FOO", this call to Create_Admin puts the wrong thing in
191	       CVS/Repository and so a subsequent "cvs update" will
192	       give an error.  The fix will be to have the server report
193	       back what it actually did (e.g. use tagged text for the
194	       "Directory %s added" message), and then Create_Admin,
195	       which should also fix the error handling concerns.  */
196
197	    if (isdir (argv[i]))
198	    {
199		char *tag;
200		char *date;
201		int nonbranch;
202		char *rcsdir;
203		char *p;
204		char *update_dir;
205		/* This is some mungeable storage into which we can point
206		   with p and/or update_dir.  */
207		char *filedir;
208
209		if (save_cwd (&cwd))
210		    error_exit ();
211
212		filedir = xstrdup (argv[i]);
213		p = last_component (filedir);
214		if (p == filedir)
215		{
216		    update_dir = "";
217		}
218		else
219		{
220		    p[-1] = '\0';
221		    update_dir = filedir;
222		    if (CVS_CHDIR (update_dir) < 0)
223			error (1, errno,
224			       "could not chdir to %s", update_dir);
225		}
226
227		/* find the repository associated with our current dir */
228		repository = Name_Repository (NULL, update_dir);
229
230		/* don't add stuff to Emptydir */
231		if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
232		    && ISDIRSEP (repository[cvsroot_len])
233		    && strncmp (repository + cvsroot_len + 1,
234				CVSROOTADM,
235				sizeof CVSROOTADM - 1) == 0
236		    && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
237		    && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
238			       CVSNULLREPOS) == 0)
239		    error (1, 0, "cannot add to %s", repository);
240
241		/* before we do anything else, see if we have any
242		   per-directory tags */
243		ParseTag (&tag, &date, &nonbranch);
244
245		rcsdir = xmalloc (strlen (repository) + strlen (p) + 5);
246		sprintf (rcsdir, "%s/%s", repository, p);
247
248		Create_Admin (p, argv[i], rcsdir, tag, date,
249			      nonbranch, 0, 1);
250
251		if (found_slash)
252		    send_a_repository ("", repository, update_dir);
253
254		if (restore_cwd (&cwd, NULL))
255		    error_exit ();
256		free_cwd (&cwd);
257
258		if (tag)
259		    free (tag);
260		if (date)
261		    free (date);
262		free (rcsdir);
263
264		if (p == filedir)
265		    Subdir_Register ((List *) NULL, (char *) NULL, argv[i]);
266		else
267		{
268		    Subdir_Register ((List *) NULL, update_dir, p);
269		}
270		free (repository);
271		free (filedir);
272	    }
273	}
274	send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
275	send_file_names (argc, argv, SEND_EXPAND_WILD);
276	send_to_server ("add\012", 0);
277	if (message)
278	    free (message);
279	return err + get_responses_and_close ();
280    }
281#endif
282
283    /* walk the arg list adding files/dirs */
284    for (i = 0; i < argc; i++)
285    {
286	int begin_err = err;
287#ifdef SERVER_SUPPORT
288	int begin_added_files = added_files;
289#endif
290	struct file_info finfo;
291	char *p;
292#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
293	char *found_name;
294#endif
295
296	memset (&finfo, 0, sizeof finfo);
297
298	if (save_cwd (&cwd))
299	    error_exit ();
300
301	finfo.fullname = xstrdup (argv[i]);
302	p = last_component (argv[i]);
303	if (p == argv[i])
304	{
305	    finfo.update_dir = "";
306	    finfo.file = p;
307	}
308	else
309	{
310	    p[-1] = '\0';
311	    finfo.update_dir = argv[i];
312	    finfo.file = p;
313	    if (CVS_CHDIR (finfo.update_dir) < 0)
314		error (1, errno, "could not chdir to %s", finfo.update_dir);
315	}
316
317	/* Add wrappers for this directory.  They exist only until
318	   the next call to wrap_add_file.  */
319	wrap_add_file (CVSDOTWRAPPER, 1);
320
321	finfo.rcs = NULL;
322
323	/* Find the repository associated with our current dir.  */
324	repository = Name_Repository (NULL, finfo.update_dir);
325
326	/* don't add stuff to Emptydir */
327	if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
328	    && ISDIRSEP (repository[cvsroot_len])
329	    && strncmp (repository + cvsroot_len + 1,
330			CVSROOTADM,
331			sizeof CVSROOTADM - 1) == 0
332	    && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
333	    && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
334		       CVSNULLREPOS) == 0)
335	    error (1, 0, "cannot add to %s", repository);
336
337	entries = Entries_Open (0, NULL);
338
339	finfo.repository = repository;
340	finfo.entries = entries;
341
342#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
343	if (ign_case)
344	{
345	    /* Need to check whether there is a directory with the
346	       same name but different case.  We'll check for files
347	       with the same name later (when Version_TS calls
348	       RCS_parse which calls fopen_case).  If CVS some day
349	       records directories in the RCS files, then we should be
350	       able to skip the separate check here, which would be
351	       cleaner.  */
352	    DIR *dirp;
353	    struct dirent *dp;
354
355	    dirp = CVS_OPENDIR (finfo.repository);
356	    if (dirp == NULL)
357		error (1, errno, "cannot read directory %s", finfo.repository);
358	    found_name = NULL;
359	    errno = 0;
360	    while ((dp = CVS_READDIR (dirp)) != NULL)
361	    {
362		if (cvs_casecmp (dp->d_name, finfo.file) == 0)
363		{
364		    if (found_name != NULL)
365			error (1, 0, "%s is ambiguous; could mean %s or %s",
366			       finfo.file, dp->d_name, found_name);
367		    found_name = xstrdup (dp->d_name);
368		}
369	    }
370	    if (errno != 0)
371		error (1, errno, "cannot read directory %s", finfo.repository);
372	    CVS_CLOSEDIR (dirp);
373
374	    if (found_name != NULL)
375	    {
376		/* OK, we are about to patch up the name, so patch up
377		   the temporary directory too to match.  The isdir
378		   should "always" be true (since files have ,v), but
379		   I guess we might as well make some attempt to not
380		   get confused by stray files in the repository.  */
381		if (isdir (finfo.file))
382		{
383		    if (CVS_MKDIR (found_name, 0777) < 0
384			&& errno != EEXIST)
385			error (0, errno, "cannot create %s", finfo.file);
386		}
387
388		/* OK, we found a directory with the same name, maybe in
389		   a different case.  Treat it as if the name were the
390		   same.  */
391		finfo.file = found_name;
392	    }
393	}
394#endif
395
396	/* We pass force_tag_match as 1.  If the directory has a
397           sticky branch tag, and there is already an RCS file which
398           does not have that tag, then the head revision is
399           meaningless to us.  */
400	vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
401	if (vers->vn_user == NULL)
402	{
403	    /* No entry available, ts_rcs is invalid */
404	    if (vers->vn_rcs == NULL)
405	    {
406		/* There is no RCS file either */
407		if (vers->ts_user == NULL)
408		{
409		    /* There is no user file either */
410		    error (0, 0, "nothing known about %s", finfo.fullname);
411		    err++;
412		}
413		else if (!isdir (finfo.file)
414			 || wrap_name_has (finfo.file, WRAP_TOCVS))
415		{
416		    /*
417		     * See if a directory exists in the repository with
418		     * the same name.  If so, blow this request off.
419		     */
420		    char *dname = xmalloc (strlen (repository)
421					   + strlen (finfo.file)
422					   + 10);
423		    (void) sprintf (dname, "%s/%s", repository, finfo.file);
424		    if (isdir (dname))
425		    {
426			error (0, 0,
427			       "cannot add file `%s' since the directory",
428			       finfo.fullname);
429			error (0, 0, "`%s' already exists in the repository",
430			       dname);
431			error (1, 0, "illegal filename overlap");
432		    }
433		    free (dname);
434
435		    if (vers->options == NULL || *vers->options == '\0')
436		    {
437			/* No options specified on command line (or in
438			   rcs file if it existed, e.g. the file exists
439			   on another branch).  Check for a value from
440			   the wrapper stuff.  */
441			if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
442			{
443			    if (vers->options)
444				free (vers->options);
445			    vers->options = wrap_rcsoption (finfo.file, 1);
446			}
447		    }
448
449		    if (vers->nonbranch)
450		    {
451			error (0, 0,
452				"cannot add file on non-branch tag %s",
453				vers->tag);
454			++err;
455		    }
456		    else
457		    {
458			/* There is a user file, so build the entry for it */
459			if (build_entry (repository, finfo.file, vers->options,
460					 message, entries, vers->tag) != 0)
461			    err++;
462			else
463			{
464			    added_files++;
465			    if (!quiet)
466			    {
467				if (vers->tag)
468				    error (0, 0, "\
469scheduling %s `%s' for addition on branch `%s'",
470					   (wrap_name_has (finfo.file,
471							   WRAP_TOCVS)
472					    ? "wrapper"
473					    : "file"),
474					   finfo.fullname, vers->tag);
475				else
476				    error (0, 0,
477					   "scheduling %s `%s' for addition",
478					   (wrap_name_has (finfo.file,
479							   WRAP_TOCVS)
480					    ? "wrapper"
481					    : "file"),
482					   finfo.fullname);
483			    }
484			}
485		    }
486		}
487	    }
488	    else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
489	    {
490		if (isdir (finfo.file)
491		    && !wrap_name_has (finfo.file, WRAP_TOCVS))
492		{
493		    error (0, 0, "\
494the directory `%s' cannot be added because a file of the", finfo.fullname);
495		    error (1, 0, "\
496same name already exists in the repository.");
497		}
498		else
499		{
500		    if (vers->nonbranch)
501		    {
502			error (0, 0,
503			       "cannot add file on non-branch tag %s",
504			       vers->tag);
505			++err;
506		    }
507		    else
508		    {
509			if (!quiet)
510			{
511			    if (vers->tag)
512				error (0, 0, "\
513file `%s' will be added on branch `%s' from version %s",
514					finfo.fullname, vers->tag, vers->vn_rcs);
515			    else
516				/* I'm not sure that mentioning
517				   vers->vn_rcs makes any sense here; I
518				   can't think of a way to word the
519				   message which is not confusing.  */
520				error (0, 0, "\
521re-adding file %s (in place of dead revision %s)",
522					finfo.fullname, vers->vn_rcs);
523			}
524			Register (entries, finfo.file, "0", vers->ts_user,
525				  vers->options,
526				  vers->tag, NULL, NULL);
527			++added_files;
528		    }
529		}
530	    }
531	    else
532	    {
533		/*
534		 * There is an RCS file already, so somebody else must've
535		 * added it
536		 */
537		error (0, 0, "%s added independently by second party",
538		       finfo.fullname);
539		err++;
540	    }
541	}
542	else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
543	{
544
545	    /*
546	     * An entry for a new-born file, ts_rcs is dummy, but that is
547	     * inappropriate here
548	     */
549	    if (!quiet)
550		error (0, 0, "%s has already been entered", finfo.fullname);
551	    err++;
552	}
553	else if (vers->vn_user[0] == '-')
554	{
555	    /* An entry for a removed file, ts_rcs is invalid */
556	    if (vers->ts_user == NULL)
557	    {
558		/* There is no user file (as it should be) */
559		if (vers->vn_rcs == NULL)
560		{
561
562		    /*
563		     * There is no RCS file, so somebody else must've removed
564		     * it from under us
565		     */
566		    error (0, 0, "\
567cannot resurrect %s; RCS file removed by second party", finfo.fullname);
568		    err++;
569		}
570		else
571		{
572
573		    /*
574		     * There is an RCS file, so remove the "-" from the
575		     * version number and restore the file
576		     */
577		    char *tmp = xmalloc (strlen (finfo.file) + 50);
578
579		    (void) strcpy (tmp, vers->vn_user + 1);
580		    (void) strcpy (vers->vn_user, tmp);
581		    (void) sprintf (tmp, "Resurrected %s", finfo.file);
582		    Register (entries, finfo.file, vers->vn_user, tmp,
583			      vers->options,
584			      vers->tag, vers->date, vers->ts_conflict);
585		    free (tmp);
586
587		    /* XXX - bugs here; this really resurrect the head */
588		    /* Note that this depends on the Register above actually
589		       having written Entries, or else it won't really
590		       check the file out.  */
591		    if (update (2, argv + i - 1) == 0)
592		    {
593			error (0, 0, "%s, version %s, resurrected",
594			       finfo.fullname,
595			       vers->vn_user);
596		    }
597		    else
598		    {
599			error (0, 0, "could not resurrect %s", finfo.fullname);
600			err++;
601		    }
602		}
603	    }
604	    else
605	    {
606		/* The user file shouldn't be there */
607		error (0, 0, "\
608%s should be removed and is still there (or is back again)", finfo.fullname);
609		err++;
610	    }
611	}
612	else
613	{
614	    /* A normal entry, ts_rcs is valid, so it must already be there */
615	    if (!quiet)
616		error (0, 0, "%s already exists, with version number %s",
617			finfo.fullname,
618			vers->vn_user);
619	    err++;
620	}
621	freevers_ts (&vers);
622
623	/* passed all the checks.  Go ahead and add it if its a directory */
624	if (begin_err == err
625	    && isdir (finfo.file)
626	    && !wrap_name_has (finfo.file, WRAP_TOCVS))
627	{
628	    err += add_directory (&finfo);
629	}
630	else
631	{
632#ifdef SERVER_SUPPORT
633	    if (server_active && begin_added_files != added_files)
634		server_checked_in (finfo.file, finfo.update_dir, repository);
635#endif
636	}
637	free (repository);
638	Entries_Close (entries);
639
640	if (restore_cwd (&cwd, NULL))
641	    error_exit ();
642	free_cwd (&cwd);
643
644	free (finfo.fullname);
645#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
646	if (ign_case && found_name != NULL)
647	    free (found_name);
648#endif
649    }
650    if (added_files && !really_quiet)
651	error (0, 0, "use '%s commit' to add %s permanently",
652	       program_name,
653	       (added_files == 1) ? "this file" : "these files");
654
655    if (message)
656	free (message);
657    if (options)
658	free (options);
659
660    return (err);
661}
662
663/*
664 * The specified user file is really a directory.  So, let's make sure that
665 * it is created in the RCS source repository, and that the user's directory
666 * is updated to include a CVS directory.
667 *
668 * Returns 1 on failure, 0 on success.
669 */
670static int
671add_directory (finfo)
672    struct file_info *finfo;
673{
674    char *repository = finfo->repository;
675    List *entries = finfo->entries;
676    char *dir = finfo->file;
677
678    char *rcsdir = NULL;
679    struct saved_cwd cwd;
680    char *message = NULL;
681    char *tag, *date;
682    int nonbranch;
683    char *attrs;
684
685    if (strchr (dir, '/') != NULL)
686    {
687	/* "Can't happen".  */
688	error (0, 0,
689	       "directory %s not added; must be a direct sub-directory", dir);
690	return (1);
691    }
692    if (fncmp (dir, CVSADM) == 0)
693    {
694	error (0, 0, "cannot add a `%s' directory", CVSADM);
695	return (1);
696    }
697
698    /* before we do anything else, see if we have any per-directory tags */
699    ParseTag (&tag, &date, &nonbranch);
700
701    /* Remember the default attributes from this directory, so we can apply
702       them to the new directory.  */
703    fileattr_startdir (repository);
704    attrs = fileattr_getall (NULL);
705    fileattr_free ();
706
707    /* now, remember where we were, so we can get back */
708    if (save_cwd (&cwd))
709	return (1);
710    if ( CVS_CHDIR (dir) < 0)
711    {
712	error (0, errno, "cannot chdir to %s", finfo->fullname);
713	return (1);
714    }
715#ifdef SERVER_SUPPORT
716    if (!server_active && isfile (CVSADM))
717#else
718    if (isfile (CVSADM))
719#endif
720    {
721	error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
722	goto out;
723    }
724
725    rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5);
726    sprintf (rcsdir, "%s/%s", repository, dir);
727    if (isfile (rcsdir) && !isdir (rcsdir))
728    {
729	error (0, 0, "%s is not a directory; %s not added", rcsdir,
730	       finfo->fullname);
731	goto out;
732    }
733
734    /* setup the log message */
735    message = xmalloc (strlen (rcsdir)
736		       + 80
737		       + (tag == NULL ? 0 : strlen (tag) + 80)
738		       + (date == NULL ? 0 : strlen (date) + 80));
739    (void) sprintf (message, "Directory %s added to the repository\n", rcsdir);
740    if (tag)
741    {
742	(void) strcat (message, "--> Using per-directory sticky tag `");
743	(void) strcat (message, tag);
744	(void) strcat (message, "'\n");
745    }
746    if (date)
747    {
748	(void) strcat (message, "--> Using per-directory sticky date `");
749	(void) strcat (message, date);
750	(void) strcat (message, "'\n");
751    }
752
753    if (!isdir (rcsdir))
754    {
755	mode_t omask;
756	Node *p;
757	List *ulist;
758	struct logfile_info *li;
759
760	/* There used to be some code here which would prompt for
761	   whether to add the directory.  The details of that code had
762	   bitrotted, but more to the point it can't work
763	   client/server, doesn't ask in the right way for GUIs, etc.
764	   A better way of making it harder to accidentally add
765	   directories would be to have to add and commit directories
766	   like for files.  The code was #if 0'd at least since CVS 1.5.  */
767
768	if (!noexec)
769	{
770	    omask = umask (cvsumask);
771	    if (CVS_MKDIR (rcsdir, 0777) < 0)
772	    {
773		error (0, errno, "cannot mkdir %s", rcsdir);
774		(void) umask (omask);
775		goto out;
776	    }
777	    (void) umask (omask);
778	}
779
780	/* Now set the default file attributes to the ones we inherited
781	   from the parent directory.  */
782	fileattr_startdir (rcsdir);
783	fileattr_setall (NULL, attrs);
784	fileattr_write ();
785	fileattr_free ();
786	if (attrs != NULL)
787	    free (attrs);
788
789	/*
790	 * Set up an update list with a single title node for Update_Logfile
791	 */
792	ulist = getlist ();
793	p = getnode ();
794	p->type = UPDATE;
795	p->delproc = update_delproc;
796	p->key = xstrdup ("- New directory");
797	li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
798	li->type = T_TITLE;
799	li->tag = xstrdup (tag);
800	li->rev_old = li->rev_new = NULL;
801	p->data = (char *) li;
802	(void) addnode (ulist, p);
803	Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
804	dellist (&ulist);
805    }
806
807#ifdef SERVER_SUPPORT
808    if (!server_active)
809#endif
810        Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
811    if (tag)
812	free (tag);
813    if (date)
814	free (date);
815
816    if (restore_cwd (&cwd, NULL))
817	error_exit ();
818    free_cwd (&cwd);
819
820    Subdir_Register (entries, (char *) NULL, dir);
821
822    cvs_output (message, 0);
823
824    free (rcsdir);
825    free (message);
826
827    return (0);
828
829out:
830    if (restore_cwd (&cwd, NULL))
831	error_exit ();
832    free_cwd (&cwd);
833    if (rcsdir != NULL)
834	free (rcsdir);
835    return (0);
836}
837
838/*
839 * Builds an entry for a new file and sets up "CVS/file",[pt] by
840 * interrogating the user.  Returns non-zero on error.
841 */
842static int
843build_entry (repository, user, options, message, entries, tag)
844    char *repository;
845    char *user;
846    char *options;
847    char *message;
848    List *entries;
849    char *tag;
850{
851    char *fname;
852    char *line;
853    FILE *fp;
854
855    if (noexec)
856	return (0);
857
858    /*
859     * The requested log is read directly from the user and stored in the
860     * file user,t.  If the "message" argument is set, use it as the
861     * initial creation log (which typically describes the file).
862     */
863    fname = xmalloc (strlen (user) + 80);
864    (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
865    fp = open_file (fname, "w+");
866    if (message && fputs (message, fp) == EOF)
867	    error (1, errno, "cannot write to %s", fname);
868    if (fclose(fp) == EOF)
869        error(1, errno, "cannot close %s", fname);
870    free (fname);
871
872    /*
873     * Create the entry now, since this allows the user to interrupt us above
874     * without needing to clean anything up (well, we could clean up the
875     * ,t file, but who cares).
876     */
877    line = xmalloc (strlen (user) + 20);
878    (void) sprintf (line, "Initial %s", user);
879    Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);
880    free (line);
881    return (0);
882}
883