212 lines
6.3 KiB
C
212 lines
6.3 KiB
C
/*
|
|
* Copyright (C) 1986-2005 The Free Software Foundation, Inc.
|
|
*
|
|
* Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
|
|
* and others.
|
|
*
|
|
* Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
|
|
* Portions Copyright (C) 1989-1992, Brian Berliner
|
|
*
|
|
* You may distribute under the terms of the GNU General Public License as
|
|
* specified in the README file that comes with the CVS source distribution.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include "cvs.h"
|
|
#include "getline.h"
|
|
|
|
/* Determine the name of the RCS repository for directory DIR in the
|
|
current working directory, or for the current working directory
|
|
itself if DIR is NULL. Returns the name in a newly-malloc'd
|
|
string. On error, gives a fatal error and does not return.
|
|
UPDATE_DIR is the path from where cvs was invoked (for use in error
|
|
messages), and should contain DIR as its last component.
|
|
UPDATE_DIR can be NULL to signify the directory in which cvs was
|
|
invoked. */
|
|
|
|
char *
|
|
Name_Repository (dir, update_dir)
|
|
const char *dir;
|
|
const char *update_dir;
|
|
{
|
|
FILE *fpin;
|
|
const char *xupdate_dir;
|
|
char *repos = NULL;
|
|
size_t repos_allocated = 0;
|
|
char *tmp;
|
|
char *cp;
|
|
|
|
if (update_dir && *update_dir)
|
|
xupdate_dir = update_dir;
|
|
else
|
|
xupdate_dir = ".";
|
|
|
|
if (dir != NULL)
|
|
{
|
|
tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10);
|
|
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
|
|
}
|
|
else
|
|
tmp = xstrdup (CVSADM_REP);
|
|
|
|
/*
|
|
* The assumption here is that the repository is always contained in the
|
|
* first line of the "Repository" file.
|
|
*/
|
|
fpin = CVS_FOPEN (tmp, "r");
|
|
|
|
if (fpin == NULL)
|
|
{
|
|
int save_errno = errno;
|
|
char *cvsadm;
|
|
|
|
if (dir != NULL)
|
|
{
|
|
cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
|
|
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
|
|
}
|
|
else
|
|
cvsadm = xstrdup (CVSADM);
|
|
|
|
if (!isdir (cvsadm))
|
|
{
|
|
error (0, 0, "in directory %s:", xupdate_dir);
|
|
error (1, 0, "there is no version here; do '%s checkout' first",
|
|
program_name);
|
|
}
|
|
free (cvsadm);
|
|
|
|
if (existence_error (save_errno))
|
|
{
|
|
/* FIXME: This is a very poorly worded error message. It
|
|
occurs at least in the case where the user manually
|
|
creates a directory named CVS, so the error message
|
|
should be more along the lines of "CVS directory found
|
|
without administrative files; use CVS to create the CVS
|
|
directory, or rename it to something else if the
|
|
intention is to store something besides CVS
|
|
administrative files". */
|
|
error (0, 0, "in directory %s:", xupdate_dir);
|
|
error (1, 0, "*PANIC* administration files missing");
|
|
}
|
|
|
|
error (1, save_errno, "cannot open %s", tmp);
|
|
}
|
|
|
|
if (getline (&repos, &repos_allocated, fpin) < 0)
|
|
{
|
|
/* FIXME: should be checking for end of file separately. */
|
|
error (0, 0, "in directory %s:", xupdate_dir);
|
|
error (1, errno, "cannot read %s", CVSADM_REP);
|
|
}
|
|
if (fclose (fpin) < 0)
|
|
error (0, errno, "cannot close %s", tmp);
|
|
free (tmp);
|
|
|
|
if ((cp = strrchr (repos, '\n')) != NULL)
|
|
*cp = '\0'; /* strip the newline */
|
|
|
|
/*
|
|
* If this is a relative repository pathname, turn it into an absolute
|
|
* one by tacking on the CVSROOT environment variable. If the CVSROOT
|
|
* environment variable is not set, die now.
|
|
*/
|
|
if (! isabsolute(repos))
|
|
{
|
|
char *newrepos;
|
|
|
|
if (current_parsed_root == NULL)
|
|
{
|
|
error (0, 0, "in directory %s:", xupdate_dir);
|
|
error (0, 0, "must set the CVSROOT environment variable\n");
|
|
error (0, 0, "or specify the '-d' option to %s.", program_name);
|
|
error (1, 0, "illegal repository setting");
|
|
}
|
|
if (pathname_levels (repos) > 0)
|
|
{
|
|
error (0, 0, "in directory %s:", xupdate_dir);
|
|
error (0, 0, "`..'-relative repositories are not supported.");
|
|
error (1, 0, "illegal source repository");
|
|
}
|
|
newrepos = xmalloc (strlen (current_parsed_root->directory)
|
|
+ strlen (repos) + 2);
|
|
sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos);
|
|
free (repos);
|
|
repos = newrepos;
|
|
}
|
|
|
|
Sanitize_Repository_Name (repos);
|
|
|
|
return repos;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Return a pointer to the repository name relative to CVSROOT from a
|
|
* possibly fully qualified repository
|
|
*/
|
|
const char *
|
|
Short_Repository (repository)
|
|
const char *repository;
|
|
{
|
|
if (repository == NULL)
|
|
return NULL;
|
|
|
|
/* If repository matches CVSroot at the beginning, strip off CVSroot */
|
|
/* And skip leading '/' in rep, in case CVSroot ended with '/'. */
|
|
if (strncmp (current_parsed_root->directory, repository,
|
|
strlen (current_parsed_root->directory)) == 0)
|
|
{
|
|
const char *rep = repository + strlen (current_parsed_root->directory);
|
|
return (*rep == '/') ? rep+1 : rep;
|
|
}
|
|
else
|
|
return repository;
|
|
}
|
|
|
|
|
|
|
|
/* Sanitize the repository name (in place) by removing trailing
|
|
* slashes and a trailing "." if present. It should be safe for
|
|
* callers to use strcat and friends to create repository names.
|
|
* Without this check, names like "/path/to/repos/./foo" and
|
|
* "/path/to/repos//foo" would be created. For example, one
|
|
* significant case is the CVSROOT-detection code in commit.c. It
|
|
* decides whether or not it needs to rebuild the administrative file
|
|
* database by doing a string compare. If we've done a `cvs co .' to
|
|
* get the CVSROOT files, "/path/to/repos/./CVSROOT" and
|
|
* "/path/to/repos/CVSROOT" are the arguments that are compared!
|
|
*
|
|
* This function ends up being called from the same places as
|
|
* strip_path, though what it does is much more conservative. Many
|
|
* comments about this operation (which was scattered around in
|
|
* several places in the source code) ran thus:
|
|
*
|
|
* ``repository ends with "/."; omit it. This sort of thing used
|
|
* to be taken care of by strip_path. Now we try to be more
|
|
* selective. I suspect that it would be even better to push it
|
|
* back further someday, so that the trailing "/." doesn't get into
|
|
* repository in the first place, but we haven't taken things that
|
|
* far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97)
|
|
*/
|
|
|
|
void
|
|
Sanitize_Repository_Name (repository)
|
|
char *repository;
|
|
{
|
|
size_t len;
|
|
|
|
assert (repository != NULL);
|
|
|
|
strip_trailing_slashes (repository);
|
|
|
|
len = strlen (repository);
|
|
if (len >= 2
|
|
&& repository[len - 1] == '.'
|
|
&& ISDIRSEP (repository[len - 2]))
|
|
{
|
|
repository[len - 2] = '\0';
|
|
}
|
|
}
|