cvs-cvs
[Top][All Lists]
Advanced

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

[Cvs-cvs] Changes to ccvs/src/base.c [signed-commits2]


From: Derek Robert Price
Subject: [Cvs-cvs] Changes to ccvs/src/base.c [signed-commits2]
Date: Thu, 08 Dec 2005 10:02:39 -0500

Index: ccvs/src/base.c
diff -u ccvs/src/base.c:1.1.2.10 ccvs/src/base.c:1.1.2.11
--- ccvs/src/base.c:1.1.2.10    Fri Dec  2 23:50:48 2005
+++ ccvs/src/base.c     Thu Dec  8 15:02:36 2005
@@ -257,6 +257,9 @@
     TRACE (TRACE_FUNCTION, "base_checkout (%s, %s, %s, %s, %s, %s, %s)",
           finfo->fullname, prev, rev, ptag, tag, poptions, options);
 
+    if (noexec)
+       return 0;
+
     mkdir_if_needed (CVSADM_BASE);
 
     assert (!current_parsed_root->isremote);
@@ -280,6 +283,121 @@
 
 
 
+static char *
+temp_checkout (RCSNode *rcs, struct file_info *finfo,
+              const char *prev, const char *rev, const char *ptag,
+              const char *tag, const char *poptions, const char *options)
+{
+    char *tempfile;
+    bool save_noexec;
+
+    TRACE (TRACE_FUNCTION, "temp_checkout (%s, %s, %s, %s, %s, %s, %s)",
+          finfo->fullname, prev, rev, ptag, tag, poptions, options);
+
+    assert (!current_parsed_root->isremote);
+
+    tempfile = cvs_temp_name ();
+    save_noexec = noexec;
+    noexec = false;
+    if (RCS_checkout (rcs, tempfile, rev, tag, options, NULL, NULL, NULL))
+    {
+       error (0, 0, "Failed to check out revision %s of `%s'",
+              rev, finfo->fullname);
+       free (tempfile);
+       noexec = save_noexec;
+       return NULL;
+    }
+    noexec = save_noexec;
+
+    assert (strcmp (cvs_cmd_name, "export"));
+    if (server_active)
+       server_temp_checkout (rcs, finfo, prev, rev, ptag, tag,
+                             poptions, options, tempfile);
+
+    return tempfile;
+}
+
+
+
+enum update_existing
+translate_exists (const char *exists)
+{
+    if (*exists == 'n') return UPDATE_ENTRIES_NEW;
+    if (*exists == 'y') return UPDATE_ENTRIES_EXISTING;
+    if (*exists == 'm') return UPDATE_ENTRIES_EXISTING_OR_NEW;
+    /* The error below should only happen due to a programming error or when
+     * the server sends a bad response.
+     */
+    error (1, 0, "unknown existence code received from server: `%s'",
+          exists);
+    assert (!"Internal error");  /* Placate GCC.  */
+}
+
+
+
+/* Validate the existance of FILENAME against whether we think it should exist
+ * or not.  If it should exist and doesn't, issue a warning and return success.
+ * If it shouldn't exist and does, issue a warning and return false to avoid
+ * accidentally overwriting a user's changes.
+ */
+bool
+validate_change (enum update_existing existp, const char *filename,
+                const char *fullname)
+{
+    /* Note that checking this separately from writing the file is
+       a race condition: if the existence or lack thereof of the
+       file changes between now and the actual calls which
+       operate on it, we lose.  However (a) there are so many
+       cases, I'm reluctant to try to fix them all, (b) in some
+       cases the system might not even have a system call which
+       does the right thing, and (c) it isn't clear this needs to
+       work.  */
+    if (existp == UPDATE_ENTRIES_EXISTING
+       && !isfile (filename))
+       /* Emit a warning and update the file anyway.  */
+       error (0, 0, "warning: %s unexpectedly disappeared", fullname);
+    else if (existp == UPDATE_ENTRIES_NEW
+       && isfile (filename))
+    {
+       /* This error might be confusing; it isn't really clear to
+          the user what to do about it.  Keep in mind that it has
+          several causes: (1) something/someone creates the file
+          during the time that CVS is running, (2) the repository
+          has two files whose names clash for the client because
+          of case-insensitivity or similar causes, See 3 for
+          additional notes.  (3) a special case of this is that a
+          file gets renamed for example from a.c to A.C.  A
+          "cvs update" on a case-insensitive client will get this
+          error.  In this case and in case 2, the filename
+          (short_pathname) printed in the error message will likely _not_
+          have the same case as seen by the user in a directory listing.
+          (4) the client has a file which the server doesn't know
+          about (e.g. "? foo" file), and that name clashes with a file
+          the server does know about, (5) classify.c will print the same
+          message for other reasons.
+
+          I hope the above paragraph makes it clear that making this
+          clearer is not a one-line fix.  */
+       error (0, 0, "move away `%s'; it is in the way", fullname);
+
+       /* The Mode, Mod-time, and Checksum responses should not carry
+        * over to a subsequent Created (or whatever) response, even
+        * in the error case.
+        */
+       if (!really_quiet)
+       {
+           cvs_output ("C ", 0);
+           cvs_output (fullname, 0);
+           cvs_output ("\n", 1);
+       }
+       return false;
+    }
+
+    return true;
+}
+
+
+
 void
 base_copy (struct file_info *finfo, const char *rev, const char *flags)
 {
@@ -290,9 +408,20 @@
 
     assert (flags && flags[0] && flags[1]);
 
+    if (!server_active /* The server still doesn't stay perfectly in sync with
+                       * the client workspace.
+                       */
+       && !validate_change (translate_exists (flags), finfo->file,
+                            finfo->fullname))
+       exit (EXIT_FAILURE);
+
+    if (noexec)
+       return;
+
     basefile = make_base_file_name (finfo->file, rev);
     if (isfile (finfo->file))
        xchmod (finfo->file, true);
+
     copy_file (basefile, finfo->file);
     if (flags[1] == 'y')
        xchmod (finfo->file, true);
@@ -324,7 +453,7 @@
 int
 base_merge (RCSNode *rcs, struct file_info *finfo, const char *ptag,
            const char *poptions, const char *options, const char *urev,
-           const char *rev1, const char *rev2)
+           const char *rev1, const char *rev2, bool join)
 {
     char *f1, *f2;
     int retval;
@@ -336,16 +465,26 @@
        fails is not very informative -- it is taken verbatim from RCS 5.7,
        and relies on RCS_checkout saying something intelligent upon failure. */
 
-    if (base_checkout (rcs, finfo, urev, rev1, ptag, rev1, poptions, options))
+    if (!(f1 = temp_checkout (rcs, finfo, urev, rev1, ptag, rev1, poptions,
+                             options)))
        error (1, 0, "checkout of revision %s of `%s' failed.\n",
               rev1, finfo->fullname);
+    if (join || noexec)
+    {
+       if (!(f2 = temp_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions,
+                                 options)))
+           error (1, 0, "checkout of revision %s of `%s' failed.\n",
+                  rev2, finfo->fullname);
+    }
+    else
+    {
+       if (base_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions,
+                          options))
+           error (1, 0, "checkout of revision %s of `%s' failed.\n",
+                  rev2, finfo->fullname);
+       f2 = make_base_file_name (finfo->file, rev2);
+    }
 
-    if (base_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions, options))
-       error (1, 0, "checkout of revision %s of `%s' failed.\n",
-              rev2, finfo->fullname);
-
-    f1 = make_base_file_name (finfo->file, rev1);
-    f2 = make_base_file_name (finfo->file, rev2);
 
     if (!server_active || !server_use_bases())
     {
@@ -354,18 +493,21 @@
         * files on the server as will be generated on the client, but I do not
         * believe that they are being used currently and it saves server CPU.
         */
-       cvs_output ("Merging differences between revisions ", 0);
-       cvs_output (rev1, 0);
-       cvs_output (" and ", 5);
-       cvs_output (rev2, 0);
-       cvs_output (" into `", 7);
-       if (!finfo->update_dir || !strcmp (finfo->update_dir, "."))
-           cvs_output (finfo->file, 0);
-       else
-           cvs_output (finfo->fullname, 0);
-       cvs_output ("'\n", 2);
+       if (!really_quiet)
+       {
+           cvs_output ("Merging differences between ", 0);
+           cvs_output (rev1, 0);
+           cvs_output (" and ", 5);
+           cvs_output (rev2, 0);
+           cvs_output (" into `", 7);
+           if (!finfo->update_dir || !strcmp (finfo->update_dir, "."))
+               cvs_output (finfo->file, 0);
+           else
+               cvs_output (finfo->fullname, 0);
+           cvs_output ("'\n", 2);
+       }
 
-       retval = merge (finfo->file, finfo->file, f1, f2, rev1, rev2);
+       retval = merge (finfo->file, finfo->file, f1, rev1, f2, rev2);
     }
     else
        retval = 0;
@@ -373,10 +515,18 @@
     if (server_active)
        server_base_merge (finfo, rev1, rev2);
 
-    if (strcmp (urev, rev1) && unlink_file (f1) < 0)
+    if (CVS_UNLINK (f1) < 0)
        error (0, errno, "unable to remove `%s'", f1);
-    if (strcmp (urev, rev2) && unlink_file (f2) < 0)
-       error (0, errno, "unable to remove `%s'", f2);
+    /* Using a base file instead of a temp file here and not deleting it is an
+     * optimization since, for instance, on merge from 1.1 to 1.4 with local
+     * changes, the client is going to want to leave base 1.4 and delete base
+     * 1.1 rather than the other way around.
+     */
+    if (join || noexec)
+    {
+       if (CVS_UNLINK (f2) < 0)
+           error (0, errno, "unable to remove `%s'", f2);
+    }
     free (f1);
     free (f2);
 




reply via email to

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