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