diff options
Diffstat (limited to 'contrib/cvs/src/add.c')
-rw-r--r-- | contrib/cvs/src/add.c | 343 |
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); |