summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/add.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/add.c')
-rw-r--r--contrib/cvs/src/add.c343
1 files changed, 218 insertions, 125 deletions
diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c
index 9220930..ab667df 100644
--- a/contrib/cvs/src/add.c
+++ b/contrib/cvs/src/add.c
@@ -3,7 +3,7 @@
* 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 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*
* Add
*
@@ -26,8 +26,9 @@
#include "cvs.h"
#include "savecwd.h"
+#include "fileattr.h"
-static int add_directory PROTO((char *repository, List *, char *dir));
+static int add_directory PROTO ((struct file_info *finfo));
static int build_entry PROTO((char *repository, char *user, char *options,
char *message, List * entries, char *tag));
@@ -36,57 +37,16 @@ static const char *const add_usage[] =
"Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
"\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
"\t-m\tUse \"message\" for the creation log.\n",
+ "(Specify the --help global option for a list of other help options)\n",
NULL
};
-static char *combine_dir PROTO ((char *, char *));
-
-/* Given a directory DIR and a subdirectory within it, SUBDIR, combine
- the two into a new directory name. Returns a newly malloc'd string.
- For now this is a fairly simple affair, but perhaps it will want
- to have grander ambitions in the context of VMS or others (or perhaps
- not, perhaps that should all be hidden inside CVS_FOPEN and libc and so
- on, and CVS should just see foo/bar/baz style pathnames). */
-static char *
-combine_dir (dir, subdir)
- char *dir;
- char *subdir;
-{
- char *retval;
- size_t dir_len;
-
- dir_len = strlen (dir);
- retval = xmalloc (dir_len + strlen (subdir) + 10);
- if (dir_len >= 2
- && dir[dir_len - 1] == '.'
- && ISDIRSEP (dir[dir_len - 2]))
- {
- /* The dir name has an extraneous "." at the end.
- I'm not completely sure that this is the best place
- to strip it off--it is possible that Name_Repository
- should do so, or it shouldn't be in the CVS/Repository
- file in the first place. Fixing it here seems like
- a safe, small change, but I'm not sure it catches
- all the cases. */
- strncpy (retval, dir, dir_len - 2);
- retval[dir_len - 2] = '\0';
- }
- else
- {
- strcpy (retval, dir);
- }
- strcat (retval, "/");
- strcat (retval, subdir);
- return retval;
-}
-
int
add (argc, argv)
int argc;
char **argv;
{
char *message = NULL;
- char *user;
int i;
char *repository;
int c;
@@ -95,6 +55,7 @@ add (argc, argv)
char *options = NULL;
List *entries;
Vers_TS *vers;
+ struct saved_cwd cwd;
if (argc == 1 || argc == -1)
usage (add_usage);
@@ -128,17 +89,64 @@ add (argc, argv)
if (argc <= 0)
usage (add_usage);
- /* find the repository associated with our current dir */
- repository = Name_Repository ((char *) NULL, (char *) NULL);
+ /* First some sanity checks. I know that the CVS case is (sort of)
+ also handled by add_directory, but we need to check here so the
+ client won't get all confused in send_file_names. */
+ for (i = 0; i < argc; i++)
+ {
+ int skip_file = 0;
+
+ /* If it were up to me I'd probably make this a fatal error.
+ But some people are really fond of their "cvs add *", and
+ don't seem to object to the warnings.
+ Whatever. */
+ strip_trailing_slashes (argv[i]);
+ if (strcmp (argv[i], ".") == 0
+ || strcmp (argv[i], "..") == 0
+ || fncmp (argv[i], CVSADM) == 0)
+ {
+ error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
+ skip_file = 1;
+ }
+
+ if (skip_file)
+ {
+ int j;
+
+ /* FIXME: We don't do anything about free'ing argv[i]. But
+ the problem is that it is only sometimes allocated (see
+ cvsrc.c). */
+
+ for (j = i; j < argc - 1; ++j)
+ argv[j] = argv[j + 1];
+ --argc;
+ /* Check the new argv[i] again. */
+ --i;
+ ++err;
+ }
+ }
#ifdef CLIENT_SUPPORT
if (client_active)
{
int i;
+
+ if (argc == 0)
+ /* We snipped out all the arguments in the above sanity
+ check. We can just forget the whole thing (and we
+ better, because if we fired up the server and passed it
+ nothing, it would spit back a usage message). */
+ return err;
+
start_server ();
ign_setup ();
if (options) send_arg(options);
option_with_arg ("-m", message);
+
+ repository = Name_Repository (NULL, NULL);
+ send_a_repository ("", repository, "");
+ free (repository);
+
for (i = 0; i < argc; ++i)
/* FIXME: Does this erroneously call Create_Admin in error
conditions which are only detected once the server gets its
@@ -149,16 +157,48 @@ add (argc, argv)
char *date;
int nonbranch;
char *rcsdir;
+ char *p;
+ char *update_dir;
+ /* This is some mungeable storage into which we can point
+ with p and/or update_dir. */
+ char *filedir;
+
+ if (save_cwd (&cwd))
+ error_exit ();
+
+ filedir = xstrdup (argv[i]);
+ p = last_component (filedir);
+ if (p == filedir)
+ {
+ update_dir = "";
+ }
+ else
+ {
+ p[-1] = '\0';
+ update_dir = filedir;
+ if (CVS_CHDIR (update_dir) < 0)
+ error (1, errno,
+ "could not chdir to %s", update_dir);
+ }
+
+ /* find the repository associated with our current dir */
+ repository = Name_Repository (NULL, update_dir);
/* before we do anything else, see if we have any
per-directory tags */
ParseTag (&tag, &date, &nonbranch);
- rcsdir = combine_dir (repository, argv[i]);
+ rcsdir = xmalloc (strlen (repository) + strlen (p) + 5);
+ sprintf (rcsdir, "%s/%s", repository, p);
+
+ Create_Admin (p, argv[i], rcsdir, tag, date,
+ nonbranch, 0);
- strip_trailing_slashes (argv[i]);
+ send_a_repository ("", repository, update_dir);
- Create_Admin (argv[i], argv[i], rcsdir, tag, date, nonbranch);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
if (tag)
free (tag);
@@ -166,32 +206,24 @@ add (argc, argv)
free (date);
free (rcsdir);
- if (strchr (argv[i], '/') == NULL)
+ if (p == filedir)
Subdir_Register ((List *) NULL, (char *) NULL, argv[i]);
else
{
- char *cp, *b;
-
- cp = xstrdup (argv[i]);
- b = strrchr (cp, '/');
- *b++ = '\0';
- Subdir_Register ((List *) NULL, cp, b);
- free (cp);
+ Subdir_Register ((List *) NULL, update_dir, p);
}
+ free (repository);
+ free (filedir);
}
send_file_names (argc, argv, SEND_EXPAND_WILD);
- /* FIXME: should be able to pass SEND_NO_CONTENTS, I think. */
- send_files (argc, argv, 0, 0, SEND_BUILD_DIRS);
+ send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
send_to_server ("add\012", 0);
if (message)
free (message);
- free (repository);
- return get_responses_and_close ();
+ return err + get_responses_and_close ();
}
#endif
- entries = Entries_Open (0);
-
/* walk the arg list adding files/dirs */
for (i = 0; i < argc; i++)
{
@@ -200,24 +232,42 @@ add (argc, argv)
int begin_added_files = added_files;
#endif
struct file_info finfo;
+ char *p;
+
+ memset (&finfo, 0, sizeof finfo);
- user = argv[i];
- strip_trailing_slashes (user);
- if (strchr (user, '/') != NULL)
+ if (save_cwd (&cwd))
+ error_exit ();
+
+ finfo.fullname = xstrdup (argv[i]);
+ p = last_component (argv[i]);
+ if (p == argv[i])
{
- error (0, 0,
- "cannot add files with '/' in their name; %s not added", user);
- err++;
- continue;
+ finfo.update_dir = "";
+ finfo.file = p;
+ }
+ else
+ {
+ p[-1] = '\0';
+ finfo.update_dir = argv[i];
+ finfo.file = p;
+ if (CVS_CHDIR (finfo.update_dir) < 0)
+ error (1, errno, "could not chdir to %s", finfo.update_dir);
}
- memset (&finfo, 0, sizeof finfo);
- finfo.file = user;
- finfo.update_dir = "";
- finfo.fullname = user;
+ /* Add wrappers for this directory. They exist only until
+ the next call to wrap_add_file. */
+ wrap_add_file (CVSDOTWRAPPER, 1);
+
+ finfo.rcs = NULL;
+
+ /* Find the repository associated with our current dir. */
+ repository = Name_Repository (NULL, finfo.update_dir);
+
+ entries = Entries_Open (0);
+
finfo.repository = repository;
finfo.entries = entries;
- finfo.rcs = NULL;
/* We pass force_tag_match as 1. If the directory has a
sticky branch tag, and there is already an RCS file which
@@ -233,23 +283,25 @@ add (argc, argv)
if (vers->ts_user == NULL)
{
/* There is no user file either */
- error (0, 0, "nothing known about %s", user);
+ error (0, 0, "nothing known about %s", finfo.fullname);
err++;
}
- else if (!isdir (user) || wrap_name_has (user, WRAP_TOCVS))
+ else if (!isdir (finfo.file)
+ || wrap_name_has (finfo.file, WRAP_TOCVS))
{
/*
* See if a directory exists in the repository with
* the same name. If so, blow this request off.
*/
- char *dname = xmalloc (strlen (repository) + strlen (user)
+ char *dname = xmalloc (strlen (repository)
+ + strlen (finfo.file)
+ 10);
- (void) sprintf (dname, "%s/%s", repository, user);
+ (void) sprintf (dname, "%s/%s", repository, finfo.file);
if (isdir (dname))
{
error (0, 0,
"cannot add file `%s' since the directory",
- user);
+ finfo.fullname);
error (0, 0, "`%s' already exists in the repository",
dname);
error (1, 0, "illegal filename overlap");
@@ -262,11 +314,11 @@ add (argc, argv)
rcs file if it existed, e.g. the file exists
on another branch). Check for a value from
the wrapper stuff. */
- if (wrap_name_has (user, WRAP_RCSOPTION))
+ if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
{
if (vers->options)
free (vers->options);
- vers->options = wrap_rcsoption (user, 1);
+ vers->options = wrap_rcsoption (finfo.file, 1);
}
}
@@ -280,7 +332,7 @@ add (argc, argv)
else
{
/* There is a user file, so build the entry for it */
- if (build_entry (repository, user, vers->options,
+ if (build_entry (repository, finfo.file, vers->options,
message, entries, vers->tag) != 0)
err++;
else
@@ -291,17 +343,19 @@ add (argc, argv)
if (vers->tag)
error (0, 0, "\
scheduling %s `%s' for addition on branch `%s'",
- (wrap_name_has (user, WRAP_TOCVS)
+ (wrap_name_has (finfo.file,
+ WRAP_TOCVS)
? "wrapper"
: "file"),
- user, vers->tag);
+ finfo.fullname, vers->tag);
else
error (0, 0,
"scheduling %s `%s' for addition",
- (wrap_name_has (user, WRAP_TOCVS)
+ (wrap_name_has (finfo.file,
+ WRAP_TOCVS)
? "wrapper"
: "file"),
- user);
+ finfo.fullname);
}
}
}
@@ -309,10 +363,11 @@ scheduling %s `%s' for addition on branch `%s'",
}
else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
{
- if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS))
+ if (isdir (finfo.file)
+ && !wrap_name_has (finfo.file, WRAP_TOCVS))
{
error (0, 0, "\
-the directory `%s' cannot be added because a file of the", user);
+the directory `%s' cannot be added because a file of the", finfo.fullname);
error (1, 0, "\
same name already exists in the repository.");
}
@@ -330,7 +385,7 @@ same name already exists in the repository.");
if (vers->tag)
error (0, 0, "\
file `%s' will be added on branch `%s' from version %s",
- user, vers->tag, vers->vn_rcs);
+ finfo.fullname, vers->tag, vers->vn_rcs);
else
/* I'm not sure that mentioning
vers->vn_rcs makes any sense here; I
@@ -338,8 +393,9 @@ file `%s' will be added on branch `%s' from version %s",
message which is not confusing. */
error (0, 0, "\
re-adding file %s (in place of dead revision %s)",
- user, vers->vn_rcs);
- Register (entries, user, "0", vers->ts_user, NULL,
+ finfo.fullname, vers->vn_rcs);
+ Register (entries, finfo.file, "0", vers->ts_user,
+ NULL,
vers->tag, NULL, NULL);
++added_files;
}
@@ -351,7 +407,8 @@ re-adding file %s (in place of dead revision %s)",
* There is an RCS file already, so somebody else must've
* added it
*/
- error (0, 0, "%s added independently by second party", user);
+ error (0, 0, "%s added independently by second party",
+ finfo.fullname);
err++;
}
}
@@ -362,7 +419,7 @@ re-adding file %s (in place of dead revision %s)",
* An entry for a new-born file, ts_rcs is dummy, but that is
* inappropriate here
*/
- error (0, 0, "%s has already been entered", user);
+ error (0, 0, "%s has already been entered", finfo.fullname);
err++;
}
else if (vers->vn_user[0] == '-')
@@ -379,7 +436,7 @@ re-adding file %s (in place of dead revision %s)",
* it from under us
*/
error (0, 0, "\
-cannot resurrect %s; RCS file removed by second party", user);
+cannot resurrect %s; RCS file removed by second party", finfo.fullname);
err++;
}
else
@@ -389,12 +446,13 @@ cannot resurrect %s; RCS file removed by second party", user);
* There is an RCS file, so remove the "-" from the
* version number and restore the file
*/
- char *tmp = xmalloc (strlen (user) + 50);
+ char *tmp = xmalloc (strlen (finfo.file) + 50);
(void) strcpy (tmp, vers->vn_user + 1);
(void) strcpy (vers->vn_user, tmp);
- (void) sprintf (tmp, "Resurrected %s", user);
- Register (entries, user, vers->vn_user, tmp, vers->options,
+ (void) sprintf (tmp, "Resurrected %s", finfo.file);
+ Register (entries, finfo.file, vers->vn_user, tmp,
+ vers->options,
vers->tag, vers->date, vers->ts_conflict);
free (tmp);
@@ -404,12 +462,13 @@ cannot resurrect %s; RCS file removed by second party", user);
check the file out. */
if (update (2, argv + i - 1) == 0)
{
- error (0, 0, "%s, version %s, resurrected", user,
+ error (0, 0, "%s, version %s, resurrected",
+ finfo.fullname,
vers->vn_user);
}
else
{
- error (0, 0, "could not resurrect %s", user);
+ error (0, 0, "could not resurrect %s", finfo.fullname);
err++;
}
}
@@ -418,14 +477,15 @@ cannot resurrect %s; RCS file removed by second party", user);
{
/* The user file shouldn't be there */
error (0, 0, "\
-%s should be removed and is still there (or is back again)", user);
+%s should be removed and is still there (or is back again)", finfo.fullname);
err++;
}
}
else
{
/* A normal entry, ts_rcs is valid, so it must already be there */
- error (0, 0, "%s already exists, with version number %s", user,
+ error (0, 0, "%s already exists, with version number %s",
+ finfo.fullname,
vers->vn_user);
err++;
}
@@ -433,26 +493,34 @@ cannot resurrect %s; RCS file removed by second party", user);
/* passed all the checks. Go ahead and add it if its a directory */
if (begin_err == err
- && isdir (user)
- && !wrap_name_has (user, WRAP_TOCVS))
+ && isdir (finfo.file)
+ && !wrap_name_has (finfo.file, WRAP_TOCVS))
{
- err += add_directory (repository, entries, user);
- continue;
+ err += add_directory (&finfo);
}
+ else
+ {
#ifdef SERVER_SUPPORT
- if (server_active && begin_added_files != added_files)
- server_checked_in (user, ".", repository);
+ if (server_active && begin_added_files != added_files)
+ server_checked_in (finfo.file, finfo.update_dir, repository);
#endif
+ }
+ free (repository);
+ Entries_Close (entries);
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
+
+ free (finfo.fullname);
}
if (added_files)
- error (0, 0, "use 'cvs commit' to add %s permanently",
+ error (0, 0, "use '%s commit' to add %s permanently",
+ program_name,
(added_files == 1) ? "this file" : "these files");
- Entries_Close (entries);
-
if (message)
free (message);
- free (repository);
return (err);
}
@@ -465,24 +533,28 @@ cannot resurrect %s; RCS file removed by second party", user);
* Returns 1 on failure, 0 on success.
*/
static int
-add_directory (repository, entries, dir)
- char *repository;
- List *entries;
- char *dir;
+add_directory (finfo)
+ struct file_info *finfo;
{
+ char *repository = finfo->repository;
+ List *entries = finfo->entries;
+ char *dir = finfo->file;
+
char *rcsdir = NULL;
struct saved_cwd cwd;
char *message = NULL;
char *tag, *date;
int nonbranch;
+ char *attrs;
if (strchr (dir, '/') != NULL)
{
+ /* "Can't happen". */
error (0, 0,
"directory %s not added; must be a direct sub-directory", dir);
return (1);
}
- if (strcmp (dir, CVSADM) == 0)
+ if (fncmp (dir, CVSADM) == 0)
{
error (0, 0, "cannot add a `%s' directory", CVSADM);
return (1);
@@ -491,12 +563,18 @@ add_directory (repository, entries, dir)
/* before we do anything else, see if we have any per-directory tags */
ParseTag (&tag, &date, &nonbranch);
+ /* Remember the default attributes from this directory, so we can apply
+ them to the new directory. */
+ fileattr_startdir (repository);
+ attrs = fileattr_getall (NULL);
+ fileattr_free ();
+
/* now, remember where we were, so we can get back */
if (save_cwd (&cwd))
return (1);
if ( CVS_CHDIR (dir) < 0)
{
- error (0, errno, "cannot chdir to %s", dir);
+ error (0, errno, "cannot chdir to %s", finfo->fullname);
return (1);
}
#ifdef SERVER_SUPPORT
@@ -505,19 +583,24 @@ add_directory (repository, entries, dir)
if (isfile (CVSADM))
#endif
{
- error (0, 0, "%s/%s already exists", dir, CVSADM);
+ error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
goto out;
}
- rcsdir = combine_dir (repository, dir);
+ rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5);
+ sprintf (rcsdir, "%s/%s", repository, dir);
if (isfile (rcsdir) && !isdir (rcsdir))
{
- error (0, 0, "%s is not a directory; %s not added", rcsdir, dir);
+ error (0, 0, "%s is not a directory; %s not added", rcsdir,
+ finfo->fullname);
goto out;
}
/* setup the log message */
- message = xmalloc (strlen (rcsdir) + 80);
+ message = xmalloc (strlen (rcsdir)
+ + 80
+ + (tag == NULL ? 0 : strlen (tag) + 80)
+ + (date == NULL ? 0 : strlen (date) + 80));
(void) sprintf (message, "Directory %s added to the repository\n", rcsdir);
if (tag)
{
@@ -559,6 +642,15 @@ add_directory (repository, entries, dir)
(void) umask (omask);
}
+ /* Now set the default file attributes to the ones we inherited
+ from the parent directory. */
+ fileattr_startdir (rcsdir);
+ fileattr_setall (NULL, attrs);
+ fileattr_write ();
+ fileattr_free ();
+ if (attrs != NULL)
+ free (attrs);
+
/*
* Set up an update list with a single title node for Update_Logfile
*/
@@ -579,9 +671,9 @@ add_directory (repository, entries, dir)
#ifdef SERVER_SUPPORT
if (!server_active)
- Create_Admin (".", dir, rcsdir, tag, date, nonbranch);
+ Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0);
#else
- Create_Admin (".", dir, rcsdir, tag, date, nonbranch);
+ Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0);
#endif
if (tag)
free (tag);
@@ -594,7 +686,8 @@ add_directory (repository, entries, dir)
Subdir_Register (entries, (char *) NULL, dir);
- (void) printf ("%s", message);
+ cvs_output (message, 0);
+
free (rcsdir);
free (message);
OpenPOWER on IntegriCloud