Hello,

Gave this a try out of curiosity. I've been able to reproduce the bug
both on 7.8 and on current. Thank you for the detailed report and the
script, they helped a lot. :)

The bug resides in a verification that the revision specified using the
-r parameter is not higher than the current head. The implementation is
incorrect, as it gives the same priority to major and minor versions.
E.g. 1.3 is being detected as higher than 2.2, since 2 < 3 on the minor
version. This is obviously incorrect.

Due to this, the verification fails and the generic error that you see is
returned.

The following diff should fix the issue both for rcsdiff and co.


Index: usr.bin/rcs/co.c
===================================================================
RCS file: /cvs/src/usr.bin/rcs/co.c,v
diff -u -p -u -p -r1.127 co.c
--- usr.bin/rcs/co.c    11 Aug 2023 05:02:21 -0000      1.127
+++ usr.bin/rcs/co.c    3 Jan 2026 23:57:04 -0000
@@ -243,7 +243,6 @@ checkout_rev(RCSFILE *file, RCSNUM *frev
     const char *date)
 {
        BUF *bp;
-       u_int i;
        int fd, lcount;
        char buf[RCS_REV_BUFSZ];
        mode_t mode = DEFFILEMODE;
@@ -265,15 +264,10 @@ checkout_rev(RCSFILE *file, RCSNUM *frev
                (void)fprintf(stderr,
                    "no revisions present; generating empty revision 0.0\n");
- /* XXX rcsnum_cmp()
-        * Check out the latest revision if <frev> is greater than HEAD
-        */
+       /* Check out the latest revision if <frev> is greater than HEAD */
        if (file->rf_ndelta != 0) {
-               for (i = 0; i < file->rf_head->rn_len; i++) {
-                       if (file->rf_head->rn_id[i] < frev->rn_id[i]) {
-                               frev = file->rf_head;
-                               break;
-                       }
+               if (rcsnum_cmp(file->rf_head, frev, 0) == 1) {
+                       frev = file->rf_head;
                }
        }
Index: usr.bin/rcs/rcs.c
===================================================================
RCS file: /cvs/src/usr.bin/rcs/rcs.c,v
diff -u -p -u -p -r1.89 rcs.c
--- usr.bin/rcs/rcs.c   28 Nov 2021 19:28:42 -0000      1.89
+++ usr.bin/rcs/rcs.c   3 Jan 2026 23:57:04 -0000
@@ -921,12 +921,9 @@ rcs_getrev(RCSFILE *rfp, RCSNUM *frev)
        else
                rev = frev;
- /* XXX rcsnum_cmp() */
-       for (i = 0; i < rfp->rf_head->rn_len; i++) {
-               if (rfp->rf_head->rn_id[i] < rev->rn_id[i]) {
-                       rcs_errno = RCS_ERR_NOENT;
-                       return (NULL);
-               }
+       if (rcsnum_cmp(rfp->rf_head, rev, 0) == 1) {
+               rcs_errno = RCS_ERR_NOENT;
+               return (NULL);
        }
/* No matter what, we'll need everything parsed up until the description


On 12/31/25 7:34 PM, Tomas Rippl wrote:

Hello,


I believe I have found a bug in OpenRCS (base system) related to
revision retrieval after changing the release number using `ci -r`.

Environment:
------------
OpenBSD:   OpenBSD srv-public.my.domain 7.8 GENERIC.MP#1 amd64
OpenRCS:   OpenRCS 4.5
Program:   co / rcsdiff

Summary:
--------
After creating a new release using `ci -r2.1`, older revisions on the
trunk become unretrievable. Specifically, `rcsdiff` and `co -r` fail
to retrieve revision 1.3, even though the revision exists, rlog shows
a correct revision tree, and the deltatext is logically valid.

This does not occur if the trunk continues normally (1.4, 1.5, ...);
it only occurs after an explicit release-number jump using `ci -r2.1`.

Minimal reproduction:
---------------------

The following script reliably reproduces the problem:


printf "a\n" >> z.txt
ci -q -i -t-"test" -m"1.1" z.txt
co -q -l z.txt
printf "b\n" >> z.txt
ci -q -u -m"1.2" z.txt
co -q -l z.txt
printf "c\n" >> z.txt
ci -q -u -m"1.3" z.txt
co -q -l z.txt
printf "\nd\n" >> z.txt
ci -q -r2.1 -m"2.1" z.txt
co -q -l z.txt
printf "e\n" >> z.txt
ci -q -u -m"2.2" z.txt
rcsdiff -r1.2 -r1.3 z.txt

Observed result:
----------------

rcsdiff: failed to retrieve revision 1.3

Additional observations:
------------------------
- `rlog z.txt,v` shows a correct revision tree:
   1.1 -> 1.2 -> 1.3 -> 2.1 -> 2.2
- The `next` chain in the RCS file is correct.
- `co -p -r2.1` and `co -p -r2.2` work.
- The deltatext for revision 1.3 is valid diff -n output.
- The failure appears to be in revision reconstruction, not metadata.

Control case (works as expected):
---------------------------------
If the same history continues on the trunk without changing the
release number, the problem does not occur:


printf "\nd\n" >> z.txt
ci -q -u -m"1.4" z.txt
printf "e\n" >> z.txt
ci -q -u -m"1.5" z.txt
rcsdiff -r1.2 -r1.3 z.txt

This correctly produces:

diff -r1.2 -r1.3
2a3
c

Conclusion:
-----------
It appears that after `ci -r2.1`, OpenRCS applies or selects deltas
incorrectly when retrieving older trunk revisions, causing
`rcsdiff` / `co` to fail even though the revision exists and its
deltatext is consistent.

Please let me know if you would like the generated `z.txt,v` file
attached.

Best regards,
Tom




Reply via email to