Hello,

OpenCVS fails to retrieve deltas at ends of revision chains. Because of
this, a checkout of revision 1.1 or the last revision of a branch tends
to give wrong data or crash the program. This issue has been around
several years, and many have reported it in the mailing lists.

The following patch attempts to fix the problem. With the patch, it is
again possible to use OpenCVS as a server and check out the src and
ports trees so that the files, exempting CVS metadata, are equal to ones
checked out with GNU CVS.

Feedback is welcome.

- Visa


Index: regress/usr.bin/cvs/Makefile
===================================================================
RCS file: /cvs/src/regress/usr.bin/cvs/Makefile,v
retrieving revision 1.28
diff -u -p -r1.28 Makefile
--- regress/usr.bin/cvs/Makefile        13 Jul 2010 21:31:17 -0000      1.28
+++ regress/usr.bin/cvs/Makefile        4 Apr 2014 16:22:46 -0000
@@ -44,6 +44,7 @@ LTESTS= cvs-initial \
        cvs-add-dir \
        cvs-add-subdir_file \
        cvs-commit-Fflag \
+       cvs-checkout-rflag-1.1 \
        cvs-checkout \
        cvs-tag-branch \
        cvs-checkout-rflag_branch \
@@ -178,6 +179,8 @@ test-cvs-checkout-rflag-1.1:
        @cd ${REGRESS_WCOPY}; \
            ${CVSCMD} -Q -d ${MYCVSROOT} co -r 1.1 seed > /dev/null
        @test -f ${REGRESS_SEED}/seed1.txt && test -f ${REGRESS_SEED}/seed2.txt
+       @diff -q -I '^\$$Id.*\$$$$' ${.CURDIR}/import_seed/seed1.txt \
+           ${REGRESS_SEED}/seed1.txt
 
 test-cvs-checkout-dflag:
        @rm -rf ${REGRESS_WCOPY}
Index: usr.bin/cvs/rcs.c
===================================================================
RCS file: /cvs/src/usr.bin/cvs/rcs.c,v
retrieving revision 1.311
diff -u -p -r1.311 rcs.c
--- usr.bin/cvs/rcs.c   8 Jan 2014 13:23:55 -0000       1.311
+++ usr.bin/cvs/rcs.c   4 Apr 2014 16:19:07 -0000
@@ -1755,12 +1755,12 @@ rcs_rev_getlines(RCSFILE *rfp, RCSNUM *f
        int annotate, done, i, nextroot;
        RCSNUM *tnum, *bnum;
        struct rcs_branch *brp;
-       struct rcs_delta *hrdp, *prdp, *rdp, *trdp;
+       struct rcs_delta *hrdp, *prdp, *rdp;
        u_char *patch;
        struct rcs_line *line, *nline;
        struct rcs_lines *dlines, *plines;
 
-       hrdp = prdp = rdp = trdp = NULL;
+       hrdp = prdp = rdp = NULL;
 
        if (rfp->rf_head == NULL ||
            (hrdp = rcs_findrev(rfp, rfp->rf_head)) == NULL)
@@ -1819,38 +1819,23 @@ rcs_rev_getlines(RCSFILE *rfp, RCSNUM *f
 
 again:
        for (;;) {
-               if (rdp->rd_next->rn_len != 0) {
-                       trdp = rcs_findrev(rfp, rdp->rd_next);
-                       if (trdp == NULL)
-                               fatal("failed to grab next revision");
-               } else {
-                       /*
-                        * XXX Fail, although the caller does not always do the
-                        * right thing (eg cvs diff when the tree is ahead of
-                        * the repository).
-                        */
-                       break;
-               }
-
+               /* Parse the delta. */
                if (rdp->rd_tlen == 0) {
                        if (rcsparse_deltatexts(rfp, rdp->rd_num))
                                fatal("rcs_rev_getlines: rcsparse_deltatexts");
-                       if (rdp->rd_tlen == 0) {
-                               if (!rcsnum_differ(rdp->rd_num, bnum))
-                                       break;
-                               rdp = trdp;
-                               continue;
-                       }
                }
 
-               plen = rdp->rd_tlen;
-               patch = rdp->rd_text;
-               plines = cvs_splitlines(patch, plen);
-               if (annotate == ANNOTATE_NOW)
-                       rcs_patch_lines(dlines, plines, *alines, prdp);
-               else
-                       rcs_patch_lines(dlines, plines, NULL, NULL);
-               cvs_freelines(plines);
+               /* Process the delta. */
+               if (rdp->rd_tlen != 0) {
+                       plen = rdp->rd_tlen;
+                       patch = rdp->rd_text;
+                       plines = cvs_splitlines(patch, plen);
+                       if (annotate == ANNOTATE_NOW)
+                               rcs_patch_lines(dlines, plines, *alines, prdp);
+                       else
+                               rcs_patch_lines(dlines, plines, NULL, NULL);
+                       cvs_freelines(plines);
+               }
 
                if (!rcsnum_differ(rdp->rd_num, bnum)) {
                        if (annotate != ANNOTATE_LATER)
@@ -1875,8 +1860,20 @@ again:
                                break;
                }
 
+               if (rdp->rd_next->rn_len == 0) {
+                       /*
+                        * XXX Fail, although the caller does not always do the
+                        * right thing (eg cvs diff when the tree is ahead of
+                        * the repository).
+                        */
+                       break;
+               }
+
+               /* Get the next revision. */
                prdp = rdp;
-               rdp = trdp;
+               rdp = rcs_findrev(rfp, rdp->rd_next);
+               if (rdp == NULL)
+                       fatal("failed to grab next revision");
        }
 
 next:

Reply via email to