11e72d8d2Sderaadt /*
21e72d8d2Sderaadt * Copyright (c) 1992, Brian Berliner and Jeff Polk
31e72d8d2Sderaadt * Copyright (c) 1989-1992, Brian Berliner
41e72d8d2Sderaadt *
51e72d8d2Sderaadt * You may distribute under the terms of the GNU General Public License as
62286d8edStholo * specified in the README file that comes with the CVS source distribution.
71e72d8d2Sderaadt */
81e72d8d2Sderaadt
92286d8edStholo #include <assert.h>
101e72d8d2Sderaadt #include "cvs.h"
11780d15dfStholo #include "getline.h"
121e72d8d2Sderaadt
13c2c61682Stholo /* Determine the name of the RCS repository for directory DIR in the
14c2c61682Stholo current working directory, or for the current working directory
15c2c61682Stholo itself if DIR is NULL. Returns the name in a newly-malloc'd
16c2c61682Stholo string. On error, gives a fatal error and does not return.
17c2c61682Stholo UPDATE_DIR is the path from where cvs was invoked (for use in error
18c2c61682Stholo messages), and should contain DIR as its last component.
19c2c61682Stholo UPDATE_DIR can be NULL to signify the directory in which cvs was
20c2c61682Stholo invoked. */
21c2c61682Stholo
221e72d8d2Sderaadt char *
Name_Repository(dir,update_dir)231e72d8d2Sderaadt Name_Repository (dir, update_dir)
241e72d8d2Sderaadt char *dir;
251e72d8d2Sderaadt char *update_dir;
261e72d8d2Sderaadt {
271e72d8d2Sderaadt FILE *fpin;
28780d15dfStholo char *xupdate_dir;
29780d15dfStholo char *repos = NULL;
30780d15dfStholo size_t repos_allocated = 0;
31780d15dfStholo char *tmp;
321e72d8d2Sderaadt char *cp;
331e72d8d2Sderaadt
341e72d8d2Sderaadt if (update_dir && *update_dir)
351e72d8d2Sderaadt xupdate_dir = update_dir;
361e72d8d2Sderaadt else
371e72d8d2Sderaadt xupdate_dir = ".";
381e72d8d2Sderaadt
391e72d8d2Sderaadt if (dir != NULL)
40780d15dfStholo {
41780d15dfStholo tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10);
4250bf276cStholo (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
43780d15dfStholo }
4450bf276cStholo else
45780d15dfStholo tmp = xstrdup (CVSADM_REP);
4650bf276cStholo
4750bf276cStholo /*
4850bf276cStholo * The assumption here is that the repository is always contained in the
4950bf276cStholo * first line of the "Repository" file.
5050bf276cStholo */
5150bf276cStholo fpin = CVS_FOPEN (tmp, "r");
5250bf276cStholo
5350bf276cStholo if (fpin == NULL)
5450bf276cStholo {
5550bf276cStholo int save_errno = errno;
56780d15dfStholo char *cvsadm;
5750bf276cStholo
5850bf276cStholo if (dir != NULL)
59780d15dfStholo {
60780d15dfStholo cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
611e72d8d2Sderaadt (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
62780d15dfStholo }
631e72d8d2Sderaadt else
64780d15dfStholo cvsadm = xstrdup (CVSADM);
651e72d8d2Sderaadt
661e72d8d2Sderaadt if (!isdir (cvsadm))
671e72d8d2Sderaadt {
681e72d8d2Sderaadt error (0, 0, "in directory %s:", xupdate_dir);
691e72d8d2Sderaadt error (1, 0, "there is no version here; do '%s checkout' first",
701e72d8d2Sderaadt program_name);
711e72d8d2Sderaadt }
72780d15dfStholo free (cvsadm);
731e72d8d2Sderaadt
7450bf276cStholo if (existence_error (save_errno))
751e72d8d2Sderaadt {
76461cc63eStholo /* FIXME: This is a very poorly worded error message. It
77461cc63eStholo occurs at least in the case where the user manually
78461cc63eStholo creates a directory named CVS, so the error message
79461cc63eStholo should be more along the lines of "CVS directory found
80461cc63eStholo without administrative files; use CVS to create the CVS
81461cc63eStholo directory, or rename it to something else if the
82461cc63eStholo intention is to store something besides CVS
83461cc63eStholo administrative files". */
841e72d8d2Sderaadt error (0, 0, "in directory %s:", xupdate_dir);
851e72d8d2Sderaadt error (1, 0, "*PANIC* administration files missing");
861e72d8d2Sderaadt }
871e72d8d2Sderaadt
8850bf276cStholo error (1, save_errno, "cannot open %s", tmp);
891e72d8d2Sderaadt }
901e72d8d2Sderaadt
91*f9bbbf45Sfgsch if (get_line (&repos, &repos_allocated, fpin) < 0)
921e72d8d2Sderaadt {
93780d15dfStholo /* FIXME: should be checking for end of file separately. */
941e72d8d2Sderaadt error (0, 0, "in directory %s:", xupdate_dir);
951e72d8d2Sderaadt error (1, errno, "cannot read %s", CVSADM_REP);
961e72d8d2Sderaadt }
972286d8edStholo if (fclose (fpin) < 0)
982286d8edStholo error (0, errno, "cannot close %s", tmp);
992286d8edStholo free (tmp);
1002286d8edStholo
1011e72d8d2Sderaadt if ((cp = strrchr (repos, '\n')) != NULL)
1021e72d8d2Sderaadt *cp = '\0'; /* strip the newline */
1031e72d8d2Sderaadt
1041e72d8d2Sderaadt /*
1051e72d8d2Sderaadt * If this is a relative repository pathname, turn it into an absolute
1061e72d8d2Sderaadt * one by tacking on the CVSROOT environment variable. If the CVSROOT
1071e72d8d2Sderaadt * environment variable is not set, die now.
1081e72d8d2Sderaadt */
1091e72d8d2Sderaadt if (! isabsolute(repos))
1101e72d8d2Sderaadt {
111780d15dfStholo char *newrepos;
112780d15dfStholo
11343c1707eStholo if (current_parsed_root == NULL)
1141e72d8d2Sderaadt {
1151e72d8d2Sderaadt error (0, 0, "in directory %s:", xupdate_dir);
1161e72d8d2Sderaadt error (0, 0, "must set the CVSROOT environment variable\n");
1171e72d8d2Sderaadt error (0, 0, "or specify the '-d' option to %s.", program_name);
1181e72d8d2Sderaadt error (1, 0, "illegal repository setting");
1191e72d8d2Sderaadt }
120e77048c1Stholo if (pathname_levels (repos) > 0)
121e77048c1Stholo {
122e77048c1Stholo error (0, 0, "in directory %s:", xupdate_dir);
123e77048c1Stholo error (0, 0, "`..'-relative repositories are not supported.");
124e77048c1Stholo error (1, 0, "illegal source repository");
125e77048c1Stholo }
12643c1707eStholo newrepos = xmalloc (strlen (current_parsed_root->directory) + strlen (repos) + 2);
12743c1707eStholo (void) sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos);
128780d15dfStholo free (repos);
129780d15dfStholo repos = newrepos;
1301e72d8d2Sderaadt }
1311e72d8d2Sderaadt
1322286d8edStholo Sanitize_Repository_Name (repos);
1332286d8edStholo
134780d15dfStholo return repos;
1351e72d8d2Sderaadt }
1361e72d8d2Sderaadt
1371e72d8d2Sderaadt /*
1381e72d8d2Sderaadt * Return a pointer to the repository name relative to CVSROOT from a
1391e72d8d2Sderaadt * possibly fully qualified repository
1401e72d8d2Sderaadt */
1411e72d8d2Sderaadt char *
Short_Repository(repository)1421e72d8d2Sderaadt Short_Repository (repository)
1431e72d8d2Sderaadt char *repository;
1441e72d8d2Sderaadt {
1451e72d8d2Sderaadt if (repository == NULL)
1461e72d8d2Sderaadt return (NULL);
1471e72d8d2Sderaadt
1481e72d8d2Sderaadt /* If repository matches CVSroot at the beginning, strip off CVSroot */
1491e72d8d2Sderaadt /* And skip leading '/' in rep, in case CVSroot ended with '/'. */
15043c1707eStholo if (strncmp (current_parsed_root->directory, repository,
15143c1707eStholo strlen (current_parsed_root->directory)) == 0)
1521e72d8d2Sderaadt {
15343c1707eStholo char *rep = repository + strlen (current_parsed_root->directory);
1541e72d8d2Sderaadt return (*rep == '/') ? rep+1 : rep;
1551e72d8d2Sderaadt }
1561e72d8d2Sderaadt else
1571e72d8d2Sderaadt return (repository);
1581e72d8d2Sderaadt }
1592286d8edStholo
1602286d8edStholo /* Sanitize the repository name (in place) by removing trailing
1612286d8edStholo * slashes and a trailing "." if present. It should be safe for
1622286d8edStholo * callers to use strcat and friends to create repository names.
1632286d8edStholo * Without this check, names like "/path/to/repos/./foo" and
1642286d8edStholo * "/path/to/repos//foo" would be created. For example, one
1652286d8edStholo * significant case is the CVSROOT-detection code in commit.c. It
1662286d8edStholo * decides whether or not it needs to rebuild the administrative file
1672286d8edStholo * database by doing a string compare. If we've done a `cvs co .' to
1682286d8edStholo * get the CVSROOT files, "/path/to/repos/./CVSROOT" and
1692286d8edStholo * "/path/to/repos/CVSROOT" are the arguments that are compared!
1702286d8edStholo *
1712286d8edStholo * This function ends up being called from the same places as
1722286d8edStholo * strip_path, though what it does is much more conservative. Many
1732286d8edStholo * comments about this operation (which was scattered around in
1742286d8edStholo * several places in the source code) ran thus:
1752286d8edStholo *
1762286d8edStholo * ``repository ends with "/."; omit it. This sort of thing used
1772286d8edStholo * to be taken care of by strip_path. Now we try to be more
1782286d8edStholo * selective. I suspect that it would be even better to push it
1792286d8edStholo * back further someday, so that the trailing "/." doesn't get into
1802286d8edStholo * repository in the first place, but we haven't taken things that
1812286d8edStholo * far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97)
1822286d8edStholo *
1832286d8edStholo * Ahh, all too true. The major consideration is RELATIVE_REPOS. If
1842286d8edStholo * the "/." doesn't end up in the repository while RELATIVE_REPOS is
1852286d8edStholo * defined, there will be nothing in the CVS/Repository file. I
1862286d8edStholo * haven't verified that the remote protocol will handle that
1872286d8edStholo * correctly yet, so I've not made that change. */
1882286d8edStholo
1892286d8edStholo void
Sanitize_Repository_Name(repository)1902286d8edStholo Sanitize_Repository_Name (repository)
1912286d8edStholo char *repository;
1922286d8edStholo {
1932286d8edStholo size_t len;
1942286d8edStholo
1952286d8edStholo assert (repository != NULL);
1962286d8edStholo
1972286d8edStholo strip_trailing_slashes (repository);
1982286d8edStholo
1992286d8edStholo len = strlen (repository);
2002286d8edStholo if (len >= 2
2012286d8edStholo && repository[len - 1] == '.'
2022286d8edStholo && ISDIRSEP (repository[len - 2]))
2032286d8edStholo {
2042286d8edStholo repository[len - 2] = '\0';
2052286d8edStholo }
2062286d8edStholo }
207