cvs-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Cvs-cvs] Changes to ccvs/src/add.c [signed-commits]


From: Derek Robert Price
Subject: [Cvs-cvs] Changes to ccvs/src/add.c [signed-commits]
Date: Tue, 11 Oct 2005 22:46:40 -0400

Index: ccvs/src/add.c
diff -u /dev/null ccvs/src/add.c:1.121.2.1
--- /dev/null   Wed Oct 12 02:46:40 2005
+++ ccvs/src/add.c      Wed Oct 12 02:46:36 2005
@@ -0,0 +1,924 @@
+/*
+ * 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.
+ * 
+ * Add
+ * 
+ * Adds a file or directory to the RCS source repository.  For a file,
+ * the entry is marked as "needing to be added" in the user's own CVS
+ * directory, and really added to the repository when it is committed.
+ * For a directory, it is added at the appropriate place in the source
+ * repository and a CVS directory is generated within the directory.
+ * 
+ * `cvs add' supports `-k <mode>' and `-m <description>' options.
+ * Some may wish to supply other standard "rcs" options here, but I've
+ * found that this causes more trouble than anything else.
+ * 
+ * The user files or directories must already exist.  For a directory, it must
+ * not already have a CVS file in it.
+ * 
+ * An "add" on a file that has been "remove"d but not committed will cause the
+ * file to be resurrected.
+ */
+
+#include <assert.h>
+#include "cvs.h"
+#include "save-cwd.h"
+#include "fileattr.h"
+
+static int add_directory (struct file_info *finfo);
+static int build_entry (const char *repository, const char *user,
+                        const char *options, const char *message,
+                        List * entries, const char *tag);
+
+static const char *const add_usage[] =
+{
+    "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
+    "\t-k rcs-kflag\tUse \"rcs-kflag\" to add the file with the specified\n",
+    "\t\t\tkflag.\n",
+    "\t-m message\tUse \"message\" for the creation log.\n",
+    "(Specify the --help global option for a list of other help options)\n",
+    NULL
+};
+
+int
+add (int argc, char **argv)
+{
+    char *message = NULL;
+    int i;
+    char *repository;
+    int c;
+    int err = 0;
+    int added_files = 0;
+    char *options = NULL;
+    List *entries;
+    Vers_TS *vers;
+    struct saved_cwd cwd;
+    /* Nonzero if we found a slash, and are thus adding files in a
+       subdirectory.  */
+    int found_slash = 0;
+    size_t cvsroot_len;
+
+    if (argc == 1 || argc == -1)
+       usage (add_usage);
+
+    wrap_setup ();
+
+    /* parse args */
+    optind = 0;
+    while ((c = getopt (argc, argv, "+k:m:")) != -1)
+    {
+       switch (c)
+       {
+           case 'k':
+               if (options) free (options);
+               options = RCS_check_kflag (optarg);
+               break;
+
+           case 'm':
+               if (message) free (message);
+               message = xstrdup (optarg);
+               break;
+           case '?':
+           default:
+               usage (add_usage);
+               break;
+       }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc <= 0)
+       usage (add_usage);
+
+    cvsroot_len = strlen (current_parsed_root->directory);
+
+    /* 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)
+       {
+           if (!quiet)
+               error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
+           skip_file = 1;
+       }
+       else
+       {
+           char *p;
+           p = argv[i];
+           while (*p != '\0')
+           {
+               if (ISSLASH (*p))
+               {
+                   found_slash = 1;
+                   break;
+               }
+               ++p;
+           }
+       }
+
+       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 (current_parsed_root->isremote)
+    {
+       int j;
+
+       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);
+           free (options);
+       }
+       option_with_arg ("-m", message);
+       send_arg ("--");
+
+       /* If !found_slash, refrain from sending "Directory", for
+          CVS 1.9 compatibility.  If we only tried to deal with servers
+          which are at least CVS 1.9.26 or so, we wouldn't have to
+          special-case this.  */
+       if (found_slash)
+       {
+           repository = Name_Repository (NULL, NULL);
+           send_a_repository ("", repository, "");
+           free (repository);
+       }
+
+       for (j = 0; j < argc; ++j)
+       {
+           /* FIXME: Does this erroneously call Create_Admin in error
+              conditions which are only detected once the server gets its
+              hands on things?  */
+           if (isdir (argv[j]))
+           {
+               char *tag;
+               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 (1, errno, "Failed to save current directory.");
+
+               filedir = xstrdup (argv[j]);
+                /* Deliberately discard the const below since we know we just
+                 * allocated filedir and can do what we like with it.
+                 */
+               p = (char *)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);
+
+               /* don't add stuff to Emptydir */
+               if (strncmp (repository, current_parsed_root->directory, 
cvsroot_len) == 0
+                   && ISSLASH (repository[cvsroot_len])
+                   && strncmp (repository + cvsroot_len + 1,
+                               CVSROOTADM,
+                               sizeof CVSROOTADM - 1) == 0
+                   && ISSLASH (repository[cvsroot_len + sizeof CVSROOTADM])
+                   && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
+                              CVSNULLREPOS) == 0)
+                   error (1, 0, "cannot add to `%s'", repository);
+
+               /* before we do anything else, see if we have any
+                  per-directory tags */
+               ParseTag (&tag, &date, &nonbranch);
+
+               rcsdir = Xasprintf ("%s/%s", repository, p);
+
+               Create_Admin (p, argv[j], rcsdir, tag, date,
+                             nonbranch, 0, 1);
+
+               if (found_slash)
+                   send_a_repository ("", repository, update_dir);
+
+               if (restore_cwd (&cwd))
+                   error (1, errno,
+                          "Failed to restore current directory, `%s'.",
+                          cwd.name);
+               free_cwd (&cwd);
+
+               if (tag)
+                   free (tag);
+               if (date)
+                   free (date);
+               free (rcsdir);
+
+               if (p == filedir)
+                   Subdir_Register (NULL, NULL, argv[j]);
+               else
+               {
+                   Subdir_Register (NULL, update_dir, p);
+               }
+               free (repository);
+               free (filedir);
+           }
+       }
+       send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS,
+                   SIGN_NEVER, NULL, NULL);
+       send_file_names (argc, argv, SEND_EXPAND_WILD);
+       send_to_server ("add\012", 0);
+       if (message)
+           free (message);
+       return err + get_responses_and_close ();
+    }
+#endif
+
+    /* walk the arg list adding files/dirs */
+    for (i = 0; i < argc; i++)
+    {
+       int begin_err = err;
+#ifdef SERVER_SUPPORT
+       int begin_added_files = added_files;
+#endif
+       struct file_info finfo;
+       char *filename, *p;
+
+       memset (&finfo, 0, sizeof finfo);
+
+       if (save_cwd (&cwd))
+           error (1, errno, "Failed to save current directory.");
+
+       finfo.fullname = xstrdup (argv[i]);
+       filename = xstrdup (argv[i]);
+       /* We know we can discard the const below since we just allocated
+        * filename and can do as we like with it.
+         */
+       p = (char *)last_component (filename);
+       if (p == filename)
+       {
+           finfo.update_dir = "";
+           finfo.file = p;
+       }
+       else
+       {
+           p[-1] = '\0';
+           finfo.update_dir = filename;
+           finfo.file = p;
+           if (CVS_CHDIR (finfo.update_dir) < 0)
+               error (1, errno, "could not chdir to `%s'", finfo.update_dir);
+       }
+
+       /* 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);
+
+       /* don't add stuff to Emptydir */
+       if (strncmp (repository, current_parsed_root->directory,
+                    cvsroot_len) == 0
+           && ISSLASH (repository[cvsroot_len])
+           && strncmp (repository + cvsroot_len + 1,
+                       CVSROOTADM,
+                       sizeof CVSROOTADM - 1) == 0
+           && ISSLASH (repository[cvsroot_len + sizeof CVSROOTADM])
+           && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
+                      CVSNULLREPOS) == 0)
+           error (1, 0, "cannot add to `%s'", repository);
+
+       entries = Entries_Open (0, NULL);
+
+       finfo.repository = repository;
+       finfo.entries = entries;
+
+       /* We pass force_tag_match as 1.  If the directory has a
+           sticky branch tag, and there is already an RCS file which
+           does not have that tag, then the head revision is
+           meaningless to us.  */
+       vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
+       if (vers->vn_user == NULL)
+       {
+           /* No entry available, ts_rcs is invalid */
+           if (vers->vn_rcs == NULL)
+           {
+               /* There is no RCS file either */
+               if (vers->ts_user == NULL)
+               {
+                   /* There is no user file either */
+                   error (0, 0, "nothing known about `%s'", finfo.fullname);
+                   err++;
+               }
+               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 = Xasprintf ("%s/%s", repository, finfo.file);
+                   if (isdir (dname))
+                   {
+                       error (0, 0,
+                              "cannot add file `%s' since the directory",
+                              finfo.fullname);
+                       error (0, 0, "`%s' already exists in the repository",
+                              dname);
+                       error (1, 0, "invalid filename overlap");
+                   }
+                   free (dname);
+
+                   if (vers->options == NULL || *vers->options == '\0')
+                   {
+                       /* No options specified on command line (or in
+                          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 (finfo.file, WRAP_RCSOPTION))
+                       {
+                           if (vers->options)
+                               free (vers->options);
+                           vers->options = wrap_rcsoption (finfo.file, 1);
+                       }
+                   }
+
+                   if (vers->nonbranch)
+                   {
+                       error (0, 0,
+                               "cannot add file on non-branch tag `%s'",
+                               vers->tag);
+                       ++err;
+                   }
+                   else
+                   {
+                       /* There is a user file, so build the entry for it */
+                       if (build_entry (repository, finfo.file, vers->options,
+                                        message, entries, vers->tag) != 0)
+                           err++;
+                       else
+                       {
+                           added_files++;
+                           if (!quiet)
+                           {
+                               if (vers->tag)
+                                   error (0, 0, "scheduling %s `%s' for"
+                                          " addition on branch `%s'",
+                                          (wrap_name_has (finfo.file,
+                                                          WRAP_TOCVS)
+                                           ? "wrapper"
+                                           : "file"),
+                                          finfo.fullname, vers->tag);
+                               else
+                                   error (0, 0,
+                                          "scheduling %s `%s' for addition",
+                                          (wrap_name_has (finfo.file,
+                                                          WRAP_TOCVS)
+                                           ? "wrapper"
+                                           : "file"),
+                                          finfo.fullname);
+                           }
+                       }
+                   }
+               }
+           }
+           else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
+           {
+               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", finfo.fullname);
+                   error (1, 0, "same name already exists in the repository.");
+               }
+               else
+               {
+                   if (vers->nonbranch)
+                   {
+                       error (0, 0,
+                              "cannot add file on non-branch tag `%s'",
+                              vers->tag);
+                       ++err;
+                   }
+                   else
+                   {
+                       char *timestamp = NULL;
+                       if (vers->ts_user == NULL)
+                       {
+                           /* If this file does not exist locally, assume that
+                            * the last version on the branch is being
+                            * resurrected.
+                            *
+                            * Compute previous revision.  We assume that it
+                            * exists and that it is not a revision on the
+                            * trunk of the form X.1 (1.1, 2.1, 3.1, ...).  We
+                            * also assume that it is not dead, which seems
+                            * fair since we know vers->vn_rcs is dead
+                            * and we shouldn't see two dead revisions in a
+                            * row.
+                            */
+                           char *prev = previous_rev (vers->srcfile,
+                                                      vers->vn_rcs);
+                           int status;
+                           if (prev == NULL)
+                           {
+                               /* There is no previous revision.  Either:
+                                *
+                                *  * Revision 1.1 was dead, as when a file was
+                                *    inititially added on a branch, 
+                                *
+                                * or
+                                *
+                                *  * All previous revisions have been deleted.
+                                *    For instance, via `admin -o'.
+                                */
+                               if (!really_quiet)
+                                   error (0, 0,
+"File `%s' has no previous revision to resurrect.",
+                                          finfo.fullname);
+                               free (prev);
+                               goto skip_this_file;
+                           }
+                           if (!quiet)
+                               error (0, 0,
+"Resurrecting file `%s' from revision %s.",
+                                      finfo.fullname, prev);
+                           status = RCS_checkout (vers->srcfile, finfo.file,
+                                                  prev, vers->tag,
+                                                  vers->options, RUN_TTY,
+                                                  NULL, NULL);
+                           xchmod (finfo.file, 1);
+                           if (status != 0)
+                           {
+                               error (0, 0, "Failed to resurrect revision %s",
+                                      prev);
+                               err++;
+                           }
+                           else
+                           {
+                               /* I don't actually set vers->ts_user here
+                                * because it would confuse server_update().
+                                */
+                               timestamp = time_stamp (finfo.file);
+                               if (!really_quiet)
+                                   write_letter (&finfo, 'U');
+                           }
+                           free (prev);
+                       }
+                       if (!quiet)
+                       {
+                           char *bbuf;
+                           if (vers->tag)
+                           {
+                               bbuf = Xasprintf (" on branch `%s'",
+                                                 vers->tag);
+                           }
+                           else
+                               bbuf = "";
+                           error (0, 0,
+"Re-adding file `%s'%s after dead revision %s.",
+                                  finfo.fullname, bbuf, vers->vn_rcs);
+                           if (vers->tag)
+                               free (bbuf);
+                       }
+                       Register (entries, finfo.file, "0",
+                                 timestamp ? timestamp : vers->ts_user,
+                                 vers->options, vers->tag, vers->date, NULL);
+                       if (timestamp) free (timestamp);
+#ifdef SERVER_SUPPORT
+                       if (server_active && vers->ts_user == NULL)
+                       {
+                           /* If we resurrected the file from the archive, we
+                            * need to tell the client about it.
+                            */
+                           server_updated (&finfo, vers,
+                                           SERVER_UPDATED,
+                                           (mode_t) -1, NULL, NULL);
+                           /* This is kinda hacky or, at least, it renders the
+                            * name "begin_added_files" obsolete, but we want
+                            * the added_files to be counted without triggering
+                            * the check that causes server_checked_in() to be
+                            * called below since we have already called
+                            * server_updated() to complete the resurrection.
+                            */
+                           ++begin_added_files;
+                       }
+#endif
+                       ++added_files;
+                   }
+               }
+           }
+           else
+           {
+               /*
+                * There is an RCS file already, so somebody else must've
+                * added it
+                */
+               error (0, 0, "`%s' added independently by second party",
+                      finfo.fullname);
+               err++;
+           }
+       }
+       else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+       {
+
+           /*
+            * An entry for a new-born file, ts_rcs is dummy, but that is
+            * inappropriate here
+            */
+           if (!quiet)
+               error (0, 0, "`%s' has already been entered", finfo.fullname);
+           err++;
+       }
+       else if (vers->vn_user[0] == '-')
+       {
+           /* An entry for a removed file, ts_rcs is invalid */
+           if (vers->ts_user == NULL)
+           {
+               /* There is no user file (as it should be) */
+               if (vers->vn_rcs == NULL)
+               {
+
+                   /*
+                    * There is no RCS file, so somebody else must've removed
+                    * it from under us
+                    */
+                   error (0, 0,
+                          "cannot resurrect `%s'; RCS file removed by"
+                          " second party", finfo.fullname);
+                   err++;
+               }
+               else
+               {
+                   int status;
+                   /*
+                    * There is an RCS file, so remove the "-" from the
+                    * version number and restore the file
+                    */
+                   char *tmp = xstrdup (vers->vn_user + 1);
+                   (void) strcpy (vers->vn_user, tmp);
+                   free (tmp);
+                   status = RCS_checkout (vers->srcfile, finfo.file,
+                                          vers->vn_user, vers->tag,
+                                          vers->options, RUN_TTY,
+                                          NULL, NULL);
+                   xchmod (finfo.file, cvswrite);
+                   if (status != 0)
+                   {
+                       error (0, 0, "Failed to resurrect revision %s.",
+                              vers->vn_user);
+                       err++;
+                       tmp = NULL;
+                   }
+                   else
+                   {
+                       /* I don't actually set vers->ts_user here because it
+                        * would confuse server_update().
+                        */
+                       tmp = time_stamp (finfo.file);
+                       write_letter (&finfo, 'U');
+                       if (!quiet)
+                            error (0, 0, "`%s', version %s, resurrected",
+                                   finfo.fullname, vers->vn_user);
+                   }
+                   Register (entries, finfo.file, vers->vn_user,
+                              tmp, vers->options,
+                             vers->tag, vers->date, NULL);
+                   if (tmp) free (tmp);
+#ifdef SERVER_SUPPORT
+                   if (server_active)
+                   {
+                       /* If we resurrected the file from the archive, we
+                        * need to tell the client about it.
+                        */
+                       server_updated (&finfo, vers,
+                                       SERVER_UPDATED,
+                                       (mode_t) -1, NULL, NULL);
+                   }
+                  /* We don't increment added_files here because this isn't
+                   * a change that needs to be committed.
+                   */
+#endif
+               }
+           }
+           else
+           {
+               /* The user file shouldn't be there */
+               error (0, 0, "\
+`%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 */
+           if (!quiet)
+               error (0, 0, "`%s' already exists, with version number %s",
+                       finfo.fullname,
+                       vers->vn_user);
+           err++;
+       }
+       freevers_ts (&vers);
+
+       /* passed all the checks.  Go ahead and add it if its a directory */
+       if (begin_err == err
+           && isdir (finfo.file)
+           && !wrap_name_has (finfo.file, WRAP_TOCVS))
+       {
+           err += add_directory (&finfo);
+       }
+       else
+       {
+#ifdef SERVER_SUPPORT
+           if (server_active && begin_added_files != added_files)
+               server_checked_in (finfo.file, finfo.update_dir, repository);
+#endif
+       }
+
+skip_this_file:
+       free (repository);
+       Entries_Close (entries);
+
+       if (restore_cwd (&cwd))
+           error (1, errno, "Failed to restore current directory, `%s'.",
+                  cwd.name);
+       free_cwd (&cwd);
+
+       /* It's okay to discard the const to free this - we allocated this
+        * above.  The const is for everybody else.
+        */
+       free ((char *) finfo.fullname);
+       free (filename);
+    }
+    if (added_files && !really_quiet)
+       error (0, 0, "use `%s commit' to add %s permanently",
+              program_name,
+              (added_files == 1) ? "this file" : "these files");
+
+    if (message)
+       free (message);
+    if (options)
+       free (options);
+
+    return err;
+}
+
+
+
+/*
+ * The specified user file is really a directory.  So, let's make sure that
+ * it is created in the RCS source repository, and that the user's directory
+ * is updated to include a CVS directory.
+ * 
+ * Returns 1 on failure, 0 on success.
+ */
+static int
+add_directory (struct file_info *finfo)
+{
+    const char *repository = finfo->repository;
+    List *entries = finfo->entries;
+    const 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 (fncmp (dir, CVSADM) == 0)
+    {
+       error (0, 0, "cannot add a `%s' directory", CVSADM);
+       return 1;
+    }
+
+    /* 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))
+    {
+       error (0, errno, "Failed to save current directory.");
+       return 1;
+    }
+    if (CVS_CHDIR (dir) < 0)
+    {
+       error (0, errno, "cannot chdir to %s", finfo->fullname);
+       return 1;
+    }
+    if (!server_active && isfile (CVSADM))
+    {
+       error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
+       goto out;
+    }
+
+    rcsdir = Xasprintf ("%s/%s", repository, dir);
+    if (isfile (rcsdir) && !isdir (rcsdir))
+    {
+       error (0, 0, "%s is not a directory; %s not added", rcsdir,
+              finfo->fullname);
+       goto out;
+    }
+
+    /* setup the log message */
+    message = Xasprintf ("Directory %s added to the repository\n%s%s%s%s%s%s",
+                        rcsdir,
+                        tag ? "--> Using per-directory sticky tag `" : "",
+                        tag ? tag : "", tag ? "'\n" : "",
+                        date ? "--> Using per-directory sticky date `" : "",
+                        date ? date : "", date ? "'\n" : "");
+
+    if (!isdir (rcsdir))
+    {
+       mode_t omask;
+       Node *p;
+       List *ulist;
+       struct logfile_info *li;
+
+       /* There used to be some code here which would prompt for
+          whether to add the directory.  The details of that code had
+          bitrotted, but more to the point it can't work
+          client/server, doesn't ask in the right way for GUIs, etc.
+          A better way of making it harder to accidentally add
+          directories would be to have to add and commit directories
+          like for files.  The code was #if 0'd at least since CVS 1.5.  */
+
+       if (!noexec)
+       {
+           omask = umask (cvsumask);
+           if (CVS_MKDIR (rcsdir, 0777) < 0)
+           {
+               error (0, errno, "cannot mkdir %s", rcsdir);
+               (void) umask (omask);
+               goto out;
+           }
+           (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
+        */
+       ulist = getlist ();
+       p = getnode ();
+       p->type = UPDATE;
+       p->delproc = update_delproc;
+       p->key = xstrdup ("- New directory");
+       li = xmalloc (sizeof (struct logfile_info));
+       li->type = T_TITLE;
+       li->tag = xstrdup (tag);
+       li->rev_old = li->rev_new = NULL;
+       p->data = li;
+       (void) addnode (ulist, p);
+       Update_Logfile (rcsdir, message, NULL, ulist);
+       dellist (&ulist);
+    }
+
+    if (server_active)
+       WriteTemplate (finfo->fullname, 1, rcsdir);
+    else
+       Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
+
+    if (tag)
+       free (tag);
+    if (date)
+       free (date);
+
+    if (restore_cwd (&cwd))
+       error (1, errno, "Failed to restore current directory, `%s'.",
+              cwd.name);
+    free_cwd (&cwd);
+
+    Subdir_Register (entries, NULL, dir);
+
+    if (!really_quiet)
+       cvs_output (message, 0);
+
+    free (rcsdir);
+    free (message);
+
+    return 0;
+
+out:
+    if (restore_cwd (&cwd))
+       error (1, errno, "Failed to restore current directory, `%s'.",
+              cwd.name);
+    free_cwd (&cwd);
+    if (message) free (message);
+    if (rcsdir != NULL)
+       free (rcsdir);
+    return 0;
+}
+
+
+
+/*
+ * Builds an entry for a new file and sets up "CVS/file",[pt] by
+ * interrogating the user.  Returns non-zero on error.
+ */
+static int
+build_entry (const char *repository, const char *user, const char *options,
+             const char *message, List *entries, const char *tag)
+{
+    char *fname;
+    char *line;
+    FILE *fp;
+
+    if (noexec)
+       return 0;
+
+    /*
+     * The requested log is read directly from the user and stored in the
+     * file user,t.  If the "message" argument is set, use it as the
+     * initial creation log (which typically describes the file).
+     */
+    fname = Xasprintf ("%s/%s%s", CVSADM, user, CVSEXT_LOG);
+    fp = xfopen (fname, "w+");
+    if (message && fputs (message, fp) == EOF)
+           error (1, errno, "cannot write to %s", fname);
+    if (fclose (fp) == EOF)
+        error (1, errno, "cannot close %s", fname);
+    free (fname);
+
+    /*
+     * Create the entry now, since this allows the user to interrupt us above
+     * without needing to clean anything up (well, we could clean up the
+     * ,t file, but who cares).
+     */
+    line = Xasprintf ("Initial %s", user);
+    Register (entries, user, "0", line, options, tag, NULL, NULL);
+    free (line);
+    return 0;
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]