bug-cvs
[Top][All Lists]
Advanced

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

Error on remote cvs diff using a -k option


From: Egbert Eich
Subject: Error on remote cvs diff using a -k option
Date: Thu, 21 Apr 2005 11:09:17 +0200

I found a problem using 'cvs diff' with a -k option running on a remote
repository. The problem occurs when the file to diff is unchanged but
was checked out with a different -k option than the one used in this
command.
On 'cvs diff -ko File.Name' the client receives the error message:

E cvs.save [diff aborted]: cannot open file File.Name for comparing: No such
file or directory

The problem can easily reproduced with test script in Attachment 1.
Just edit the environment variable TESTDIR in the file.

Here is what happens: Since the file is unmodified the client doesn't send
the content to the server. The server rightfully assumes that the checked
out version differs from a version checked out with a different -k option
and attempts to generate a diff. However since no file data has been sent
there is not data to diff against and thus the error message.

The best solution would be to check out the client version using the
-k option that has been originally used when this file has been checked
out and use this data as input for the diff.
Attachment 2 contains a fix for that. The fix is against version 1.12.11
however the problem has been present a long time.

Cheers,
        Egbert.

#!/bin/sh

/* set TESTDIR to the full path of a scratch directory */
TESTDIR=
CVS=cvs

test -d $TESTDIR || mkdir -p $TESTDIR;

rm -rf $TESTDIR/foo;
mkdir $TESTDIR/foo;


rm -rf $TESTDIR/cvs;
mkdir $TESTDIR/cvs; 

$CVS -d$TESTDIR/cvs init; 

echo " " > $TESTDIR/foo/bar;

pushd $TESTDIR/foo &> /dev/null;
$CVS -d$TESTDIR/cvs import -m"first" foo foo foo-1;
popd &> /dev/null;

rm -rf $TESTDIR/foo;
pushd $TESTDIR &> /dev/null;
$CVS -d$TESTDIR/cvs checkout foo;
cd foo;
echo '/* $Id$ */' >> bar;
$CVS commit -m"second" bar;
$CVS update bar;
$CVS diff -kk bar;
$CVS -d:ext:localhost:$TESTDIR/cvs diff -kk bar;
popd &> /dev/null;
I grant permission to distribute this patch under the terms of the 
GNU Public License
--- diff.c.orig 2004-09-15 22:15:27.000000000 +0200
+++ diff.c      2005-04-20 10:51:46.000000000 +0200
@@ -35,7 +35,7 @@
                               int err, const char *update_dir,
                               List *entries);
 static enum diff_file diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
-                                        enum diff_file, char **rev1_cache );
+                                        enum diff_file, char *rev_cache[] );
 static int diff_fileproc (void *callerdat, struct file_info *finfo);
 static void diff_mark_errors (int err);
 
@@ -456,8 +456,9 @@
     char *fname = NULL;
     char *label1;
     char *label2;
-    char *rev1_cache = NULL;
-
+    char *rev_cache[] = { NULL, NULL };
+    int i;
+    
     user_file_rev = 0;
     vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
 
@@ -605,7 +606,7 @@
        }
     }
 
-    empty_file = diff_file_nodiff( finfo, vers, empty_file, &rev1_cache );
+    empty_file = diff_file_nodiff( finfo, vers, empty_file, rev_cache );
     if( empty_file == DIFF_SAME )
     {
        /* In the server case, would be nice to send a "Checked-in"
@@ -657,8 +658,8 @@
        if (empty_file == DIFF_REMOVED)
            label2 = make_file_label (DEVNULL, NULL, NULL);
        else
-           label2 = make_file_label (finfo->fullname, use_rev2,
-                                     vers ? vers->srcfile : NULL);
+           label2 = make_file_label (rev_cache[1] ? DEVNULL : finfo->fullname,
+                                     use_rev2, vers ? vers->srcfile : NULL);
        if (!have_rev1_label)
        {
            if (empty_file == DIFF_ADDED)
@@ -729,9 +730,9 @@
     {
        status = RCS_exec_rcsdiff(vers->srcfile, opts,
                                   *options ? options : vers->options,
-                                  use_rev1, rev1_cache, use_rev2,
+                                  use_rev1, rev_cache[0], use_rev2,
                                   label1, label2,
-                                  finfo->file);
+                                  rev_cache[1] ? rev_cache[1] : finfo->file);
 
     }
 
@@ -773,11 +774,13 @@
            error (0, errno, "cannot remove %s", tmp);
        free (tmp);
     }
-    if( rev1_cache != NULL )
-    {
-       if( CVS_UNLINK( rev1_cache ) < 0 )
-           error( 0, errno, "cannot remove %s", rev1_cache );
-       free( rev1_cache );
+    for (i = 0; i < 2; i++) {
+       if( rev_cache[i] != NULL )
+       {
+           if( CVS_UNLINK( rev_cache[i] ) < 0 )
+               error( 0, errno, "cannot remove %s", rev_cache[i] );
+           free( rev_cache[i] );
+       }
     }
 
     freevers_ts (&vers);
@@ -850,7 +853,7 @@
  * verify that a file is different
  */
 static enum diff_file
-diff_file_nodiff(struct file_info *finfo, Vers_TS *vers, enum diff_file 
empty_file, char **rev1_cache)
+diff_file_nodiff(struct file_info *finfo, Vers_TS *vers, enum diff_file 
empty_file, char *rev_cache[])
                             
                   
                               
@@ -860,6 +863,7 @@
 {
     Vers_TS *xvers;
     int retcode;
+    struct stat sb;
 
     TRACE (TRACE_FUNCTION, "diff_file_nodiff (%s, %d)",
            finfo->fullname ? finfo->fullname : "(null)", empty_file);
@@ -1086,13 +1090,35 @@
     if (empty_file != DIFF_DIFFERENT)
        return empty_file;
 
+    /* If we are remote it can happen that we want to make a diff
+     * but the file to diff against hasn't been sent by the client
+     * for example because it hasn't been modified (This can happen
+     * if the options of the checked out version and the command line
+     * differ.
+     * In this case check out the the version of the checked out file
+     * together with its options.
+     */
+    if (!use_rev2 && CVS_STAT(finfo->file,&sb) < 0) {
+       rev_cache[1] = cvs_temp_name ();
+       retcode = RCS_checkout(vers->srcfile, (char *)NULL,
+                              use_rev1, (char *) NULL,
+                              vers->options, rev_cache[1],
+                              (RCSCHECKOUTPROC) NULL,
+                              (void *) NULL);
+       if (retcode != 0) {
+           error( 0, 0, "no revision for date %s in file %s",
+                  diff_date1, finfo->fullname );
+           return DIFF_ERROR;
+       } 
+    }
+
     /*
      * Run a quick cmp to see if we should bother with a full diff.
      */
 
-    retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache,
+    retcode = RCS_cmp_file( vers->srcfile, use_rev1, &rev_cache[0],
                             use_rev2, *options ? options : vers->options,
-                           finfo->file );
+                           rev_cache[1] ? rev_cache[1] : finfo->file );
 
     return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
 }

reply via email to

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