create_adm.c revision 175262
167754Smsmith/*
267754Smsmith * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
367754Smsmith *
467754Smsmith * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
582367Smsmith *                                  and others.
667754Smsmith *
767754Smsmith * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
867754Smsmith * Portions Copyright (C) 1989-1992, Brian Berliner
967754Smsmith *
1067754Smsmith * You may distribute under the terms of the GNU General Public License as
1167754Smsmith * specified in the README file that comes with the CVS source distribution.
1267754Smsmith *
1371867Smsmith * Create Administration.
1470243Smsmith *
1567754Smsmith * Creates a CVS administration directory based on the argument repository; the
1667754Smsmith * "Entries" file is prefilled from the "initrecord" argument.
1767754Smsmith */
1867754Smsmith
1967754Smsmith#include "cvs.h"
2067754Smsmith
2167754Smsmith/* update_dir includes dir as its last component.
2267754Smsmith
2367754Smsmith   Return value is 0 for success, or 1 if we printed a warning message.
2467754Smsmith   Note that many errors are still fatal; particularly for unlikely errors
2567754Smsmith   a fatal error is probably better than a warning which might be missed
2667754Smsmith   or after which CVS might do something non-useful.  If WARN is zero, then
2767754Smsmith   don't print warnings; all errors are fatal then.  */
2867754Smsmith
2967754Smsmithint
3067754SmsmithCreate_Admin (dir, update_dir, repository, tag, date, nonbranch, warn,
3167754Smsmith	      dotemplate)
3267754Smsmith    const char *dir;
3367754Smsmith    const char *update_dir;
3467754Smsmith    const char *repository;
3567754Smsmith    const char *tag;
3667754Smsmith    const char *date;
3767754Smsmith    int nonbranch;
3867754Smsmith    int warn;
3967754Smsmith    int dotemplate;
4067754Smsmith{
4167754Smsmith    FILE *fout;
4267754Smsmith    char *cp;
4367754Smsmith    char *reposcopy;
4467754Smsmith    char *tmp;
4567754Smsmith
4667754Smsmith    if (trace)
4767754Smsmith    {
4867754Smsmith	fprintf (stderr, "%s-> Create_Admin (%s, %s, %s, %s, %s, %d, %d, %d)\n",
4967754Smsmith		 CLIENT_SERVER_STR,
5067754Smsmith		 dir, update_dir, repository, tag ? tag : "",
5167754Smsmith		 date ? date : "", nonbranch, warn, dotemplate);
5267754Smsmith    }
5367754Smsmith
5467754Smsmith    if (noexec)
5567754Smsmith	return 0;
5667754Smsmith
5767754Smsmith    tmp = xmalloc (strlen (dir) + 100);
5867754Smsmith    (void) sprintf (tmp, "%s/%s", dir, CVSADM);
5967754Smsmith    if (isfile (tmp))
6067754Smsmith	error (1, 0, "there is a version in %s already", update_dir);
6167754Smsmith
6267754Smsmith    if (CVS_MKDIR (tmp, 0777) < 0)
6367754Smsmith    {
6467754Smsmith	/* We want to print out the entire update_dir, since a lot of
6567754Smsmith	   our code calls this function with dir == "." or dir ==
6667754Smsmith	   NULL.  I hope that gives enough information in cases like
6767754Smsmith	   absolute pathnames; printing out xgetwd or something would
6867754Smsmith	   be way too verbose in the common cases.  */
6967754Smsmith
7067754Smsmith	if (warn)
7167754Smsmith	{
7267754Smsmith	    /* The reason that this is a warning, rather than silently
7367754Smsmith	       just skipping creating the directory, is that we don't want
7467754Smsmith	       CVS's behavior to vary subtly based on factors (like directory
7567754Smsmith	       permissions) which are not made clear to the user.  With
7667754Smsmith	       the warning at least we let them know what is going on.  */
7767754Smsmith	    error (0, errno, "warning: cannot make directory %s in %s",
7867754Smsmith		   CVSADM, update_dir);
7967754Smsmith	    free (tmp);
8067754Smsmith	    return 1;
8167754Smsmith	}
8267754Smsmith	else
8367754Smsmith	    error (1, errno, "cannot make directory %s in %s",
8467754Smsmith		   CVSADM, update_dir);
8567754Smsmith    }
8667754Smsmith
8767754Smsmith    /* record the current cvs root for later use */
8867754Smsmith
8967754Smsmith    Create_Root (dir, current_parsed_root->original);
9067754Smsmith    if (dir != NULL)
9167754Smsmith	(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
9267754Smsmith    else
9367754Smsmith	(void) strcpy (tmp, CVSADM_REP);
9467754Smsmith    fout = CVS_FOPEN (tmp, "w+");
9567754Smsmith    if (fout == NULL)
9667754Smsmith    {
9767754Smsmith	if (update_dir[0] == '\0')
9867754Smsmith	    error (1, errno, "cannot open %s", tmp);
9967754Smsmith	else
10067754Smsmith	    error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP);
10167754Smsmith    }
10267754Smsmith    reposcopy = xstrdup (repository);
10367754Smsmith    Sanitize_Repository_Name (reposcopy);
10467754Smsmith
10567754Smsmith    /* The top level of the repository is a special case -- we need to
10667754Smsmith       write it with an extra dot at the end.  This trailing `.' stuff
10767754Smsmith       rubs me the wrong way -- on the other hand, I don't want to
10867754Smsmith       spend the time making sure all of the code can handle it if we
10967754Smsmith       don't do it. */
11067754Smsmith
11167754Smsmith    if (strcmp (reposcopy, current_parsed_root->directory) == 0)
11267754Smsmith    {
11367754Smsmith	reposcopy = xrealloc (reposcopy, strlen (reposcopy) + 3);
11467754Smsmith	strcat (reposcopy, "/.");
11567754Smsmith    }
11667754Smsmith
11767754Smsmith    cp = reposcopy;
11867754Smsmith
11967754Smsmith    /*
12067754Smsmith     * If the Repository file is to hold a relative path, try to strip off
12167754Smsmith     * the leading CVSroot argument.
12267754Smsmith     */
12367754Smsmith    {
12477424Smsmith    char *path = xmalloc (strlen (current_parsed_root->directory) + 2);
12567754Smsmith
12667754Smsmith    (void) sprintf (path, "%s/", current_parsed_root->directory);
12767754Smsmith    if (strncmp (cp, path, strlen (path)) == 0)
12877424Smsmith	cp += strlen (path);
12967754Smsmith    free (path);
13077424Smsmith    }
13167754Smsmith
13267754Smsmith    if (fprintf (fout, "%s\n", cp) < 0)
13367754Smsmith    {
13467754Smsmith	if (update_dir[0] == '\0')
13567754Smsmith	    error (1, errno, "write to %s failed", tmp);
13667754Smsmith	else
13767754Smsmith	    error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP);
13867754Smsmith    }
13977424Smsmith    if (fclose (fout) == EOF)
14067754Smsmith    {
14177424Smsmith	if (update_dir[0] == '\0')
14277424Smsmith	    error (1, errno, "cannot close %s", tmp);
14377424Smsmith	else
14467754Smsmith	    error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP);
14567754Smsmith    }
14667754Smsmith
14777424Smsmith    /* now, do the Entries file */
14877424Smsmith    if (dir != NULL)
14977424Smsmith	(void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
15067754Smsmith    else
15167754Smsmith	(void) strcpy (tmp, CVSADM_ENT);
15277424Smsmith    fout = CVS_FOPEN (tmp, "w+");
15377424Smsmith    if (fout == NULL)
15477424Smsmith    {
15567754Smsmith	if (update_dir[0] == '\0')
15667754Smsmith	    error (1, errno, "cannot open %s", tmp);
15767754Smsmith	else
15867754Smsmith	    error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT);
15967754Smsmith    }
16067754Smsmith    if (fclose (fout) == EOF)
16167754Smsmith    {
16282367Smsmith	if (update_dir[0] == '\0')
16382367Smsmith	    error (1, errno, "cannot close %s", tmp);
16467754Smsmith	else
16567754Smsmith	    error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT);
16667754Smsmith    }
16767754Smsmith
16882367Smsmith    /* Create a new CVS/Tag file */
16967754Smsmith    WriteTag (dir, tag, date, nonbranch, update_dir, repository);
17067754Smsmith
17167754Smsmith#ifdef SERVER_SUPPORT
17282367Smsmith    if (server_active && dotemplate)
17367754Smsmith    {
17467754Smsmith	server_template (update_dir, repository);
17567754Smsmith    }
17682367Smsmith
17767754Smsmith    if (trace)
17867754Smsmith    {
17967754Smsmith	fprintf (stderr, "%c<- Create_Admin\n",
18082367Smsmith		 (server_active) ? 'S' : ' ');
18167754Smsmith    }
18267754Smsmith#endif
18367754Smsmith
18482367Smsmith    free (reposcopy);
18567754Smsmith    free (tmp);
18667754Smsmith    return 0;
18767754Smsmith}
18867754Smsmith