117721Speter/* 2175261Sobrien * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 3175261Sobrien * 4175261Sobrien * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 5175261Sobrien * and others. 6175261Sobrien * 7175261Sobrien * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk 8175261Sobrien * Portions Copyright (C) 1989-1992, Brian Berliner 917721Speter * 1017721Speter * You may distribute under the terms of the GNU General Public License as 1132785Speter * specified in the README file that comes with the CVS source distribution. 1217721Speter */ 1317721Speter 1432785Speter#include <assert.h> 1517721Speter#include "cvs.h" 1625839Speter#include "getline.h" 1717721Speter 1817721Speter/* Determine the name of the RCS repository for directory DIR in the 1917721Speter current working directory, or for the current working directory 2017721Speter itself if DIR is NULL. Returns the name in a newly-malloc'd 2117721Speter string. On error, gives a fatal error and does not return. 2217721Speter UPDATE_DIR is the path from where cvs was invoked (for use in error 2317721Speter messages), and should contain DIR as its last component. 2417721Speter UPDATE_DIR can be NULL to signify the directory in which cvs was 2517721Speter invoked. */ 2617721Speter 2717721Speterchar * 2817721SpeterName_Repository (dir, update_dir) 29128266Speter const char *dir; 30128266Speter const char *update_dir; 3117721Speter{ 3217721Speter FILE *fpin; 33128266Speter const char *xupdate_dir; 3425839Speter char *repos = NULL; 3525839Speter size_t repos_allocated = 0; 3625839Speter char *tmp; 3717721Speter char *cp; 3817721Speter 3917721Speter if (update_dir && *update_dir) 4017721Speter xupdate_dir = update_dir; 4117721Speter else 4217721Speter xupdate_dir = "."; 4317721Speter 4417721Speter if (dir != NULL) 4517721Speter { 4625839Speter tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10); 4725839Speter (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP); 4817721Speter } 4917721Speter else 5025839Speter tmp = xstrdup (CVSADM_REP); 5117721Speter 5217721Speter /* 5317721Speter * The assumption here is that the repository is always contained in the 5417721Speter * first line of the "Repository" file. 5517721Speter */ 5625839Speter fpin = CVS_FOPEN (tmp, "r"); 5717721Speter 5825839Speter if (fpin == NULL) 5917721Speter { 6025839Speter int save_errno = errno; 6125839Speter char *cvsadm; 6225839Speter 6325839Speter if (dir != NULL) 6425839Speter { 6525839Speter cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10); 6625839Speter (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); 6725839Speter } 6825839Speter else 6925839Speter cvsadm = xstrdup (CVSADM); 7025839Speter 7125839Speter if (!isdir (cvsadm)) 7225839Speter { 7325839Speter error (0, 0, "in directory %s:", xupdate_dir); 7425839Speter error (1, 0, "there is no version here; do '%s checkout' first", 7525839Speter program_name); 7625839Speter } 7725839Speter free (cvsadm); 7825839Speter 7925839Speter if (existence_error (save_errno)) 8025839Speter { 8125839Speter /* FIXME: This is a very poorly worded error message. It 8225839Speter occurs at least in the case where the user manually 8325839Speter creates a directory named CVS, so the error message 8425839Speter should be more along the lines of "CVS directory found 8525839Speter without administrative files; use CVS to create the CVS 8625839Speter directory, or rename it to something else if the 8725839Speter intention is to store something besides CVS 8825839Speter administrative files". */ 8925839Speter error (0, 0, "in directory %s:", xupdate_dir); 9025839Speter error (1, 0, "*PANIC* administration files missing"); 9125839Speter } 9225839Speter 9325839Speter error (1, save_errno, "cannot open %s", tmp); 9425839Speter } 9525839Speter 9625839Speter if (getline (&repos, &repos_allocated, fpin) < 0) 9725839Speter { 9825839Speter /* FIXME: should be checking for end of file separately. */ 9917721Speter error (0, 0, "in directory %s:", xupdate_dir); 10017721Speter error (1, errno, "cannot read %s", CVSADM_REP); 10117721Speter } 10232785Speter if (fclose (fpin) < 0) 10332785Speter error (0, errno, "cannot close %s", tmp); 10432785Speter free (tmp); 10532785Speter 10617721Speter if ((cp = strrchr (repos, '\n')) != NULL) 10717721Speter *cp = '\0'; /* strip the newline */ 10817721Speter 10917721Speter /* 11017721Speter * If this is a relative repository pathname, turn it into an absolute 11117721Speter * one by tacking on the CVSROOT environment variable. If the CVSROOT 11217721Speter * environment variable is not set, die now. 11317721Speter */ 11417721Speter if (! isabsolute(repos)) 11517721Speter { 11625839Speter char *newrepos; 11725839Speter 11881404Speter if (current_parsed_root == NULL) 11917721Speter { 12017721Speter error (0, 0, "in directory %s:", xupdate_dir); 12117721Speter error (0, 0, "must set the CVSROOT environment variable\n"); 12217721Speter error (0, 0, "or specify the '-d' option to %s.", program_name); 12317721Speter error (1, 0, "illegal repository setting"); 12417721Speter } 12566525Speter if (pathname_levels (repos) > 0) 12666525Speter { 12766525Speter error (0, 0, "in directory %s:", xupdate_dir); 12866525Speter error (0, 0, "`..'-relative repositories are not supported."); 12966525Speter error (1, 0, "illegal source repository"); 13066525Speter } 131128266Speter newrepos = xmalloc (strlen (current_parsed_root->directory) 132128266Speter + strlen (repos) + 2); 133128266Speter sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos); 13425839Speter free (repos); 13525839Speter repos = newrepos; 13617721Speter } 13717721Speter 13832785Speter Sanitize_Repository_Name (repos); 13932785Speter 14025839Speter return repos; 14117721Speter} 14217721Speter 143128266Speter 144128266Speter 14517721Speter/* 14617721Speter * Return a pointer to the repository name relative to CVSROOT from a 14717721Speter * possibly fully qualified repository 14817721Speter */ 149128266Speterconst char * 15017721SpeterShort_Repository (repository) 151128266Speter const char *repository; 15217721Speter{ 15317721Speter if (repository == NULL) 154128266Speter return NULL; 15517721Speter 15617721Speter /* If repository matches CVSroot at the beginning, strip off CVSroot */ 15717721Speter /* And skip leading '/' in rep, in case CVSroot ended with '/'. */ 15881404Speter if (strncmp (current_parsed_root->directory, repository, 15981404Speter strlen (current_parsed_root->directory)) == 0) 16017721Speter { 161128266Speter const char *rep = repository + strlen (current_parsed_root->directory); 16217721Speter return (*rep == '/') ? rep+1 : rep; 16317721Speter } 16417721Speter else 165128266Speter return repository; 16617721Speter} 16732785Speter 168128266Speter 169128266Speter 17032785Speter/* Sanitize the repository name (in place) by removing trailing 17132785Speter * slashes and a trailing "." if present. It should be safe for 17232785Speter * callers to use strcat and friends to create repository names. 17332785Speter * Without this check, names like "/path/to/repos/./foo" and 17432785Speter * "/path/to/repos//foo" would be created. For example, one 17532785Speter * significant case is the CVSROOT-detection code in commit.c. It 17632785Speter * decides whether or not it needs to rebuild the administrative file 17732785Speter * database by doing a string compare. If we've done a `cvs co .' to 17832785Speter * get the CVSROOT files, "/path/to/repos/./CVSROOT" and 17932785Speter * "/path/to/repos/CVSROOT" are the arguments that are compared! 18032785Speter * 18132785Speter * This function ends up being called from the same places as 18232785Speter * strip_path, though what it does is much more conservative. Many 18332785Speter * comments about this operation (which was scattered around in 18432785Speter * several places in the source code) ran thus: 18532785Speter * 18632785Speter * ``repository ends with "/."; omit it. This sort of thing used 18732785Speter * to be taken care of by strip_path. Now we try to be more 18832785Speter * selective. I suspect that it would be even better to push it 18932785Speter * back further someday, so that the trailing "/." doesn't get into 19032785Speter * repository in the first place, but we haven't taken things that 19132785Speter * far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97) 192128266Speter */ 19332785Speter 19432785Spetervoid 19532785SpeterSanitize_Repository_Name (repository) 19632785Speter char *repository; 19732785Speter{ 19832785Speter size_t len; 19932785Speter 20032785Speter assert (repository != NULL); 20132785Speter 20232785Speter strip_trailing_slashes (repository); 20332785Speter 20432785Speter len = strlen (repository); 20532785Speter if (len >= 2 20632785Speter && repository[len - 1] == '.' 20732785Speter && ISDIRSEP (repository[len - 2])) 20832785Speter { 20932785Speter repository[len - 2] = '\0'; 21032785Speter } 21132785Speter} 212