1/* 2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 3 * 4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 5 * and others. 6 * 7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk 8 * Portions Copyright (C) 1989-1992, Brian Berliner 9 * 10 * You may distribute under the terms of the GNU General Public License as 11 * specified in the README file that comes with the CVS source distribution. 12 * 13 * The routines contained in this file do all the rcs file parsing and 14 * manipulation 15 * 16 * $FreeBSD$ 17 */ 18 19#include <assert.h> 20#include "cvs.h" 21#include "edit.h" 22#include "hardlink.h" 23 24/* These need to be source after cvs.h or HAVE_MMAP won't be set... */ 25#ifdef HAVE_MMAP 26# include <sys/mman.h> 27# ifndef HAVE_GETPAGESIZE 28# include "getpagesize.h" 29# endif 30# ifndef MAP_FAILED 31# define MAP_FAILED NULL 32# endif 33#endif 34 35#ifdef MMAP_FALLBACK_TEST 36void *my_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 37{ 38 if (rand() & 1) return mmap(addr, len, prot, flags, fd, offset); 39 return NULL; 40} 41#define mmap my_mmap 42#endif 43 44int datesep = '/'; 45int preserve_perms = 0; 46 47/* The RCS -k options, and a set of enums that must match the array. 48 These come first so that we can use enum kflag in function 49 prototypes. */ 50static const char *const kflags[] = 51 {"kv", "kvl", "k", "v", "o", "b", (char *) NULL}; 52enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B }; 53 54/* A structure we use to buffer the contents of an RCS file. The 55 various fields are only referenced directly by the rcsbuf_* 56 functions. We declare the struct here so that we can allocate it 57 on the stack, rather than in memory. */ 58 59struct rcsbuffer 60{ 61 /* Points to the current position in the buffer. */ 62 char *ptr; 63 /* Points just after the last valid character in the buffer. */ 64 char *ptrend; 65 /* The file. */ 66 FILE *fp; 67 /* The name of the file, used for error messages. */ 68 const char *filename; 69 /* The starting file position of the data in the buffer. */ 70 unsigned long pos; 71 /* The length of the value. */ 72 size_t vlen; 73 /* Whether the value contains an '@' string. If so, we can not 74 compress whitespace characters. */ 75 int at_string; 76 /* The number of embedded '@' characters in an '@' string. If 77 this is non-zero, we must search the string for pairs of '@' 78 and convert them to a single '@'. */ 79 int embedded_at; 80 /* Whether the buffer has been mmap'ed or not. */ 81 int mmapped; 82}; 83 84static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile)); 85static char *RCS_getdatebranch PROTO((RCSNode * rcs, const char *date, 86 const char *branch)); 87static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp, 88 const char *filename, unsigned long pos)); 89static void rcsbuf_close PROTO ((struct rcsbuffer *)); 90static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp, 91 char **valp)); 92static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp)); 93static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp, 94 char **valp)); 95static int rcsbuf_valcmp PROTO ((struct rcsbuffer *)); 96static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish, 97 size_t *lenp)); 98static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish, 99 size_t *lenp)); 100static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to, 101 const char *from, size_t *lenp)); 102static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *)); 103static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap, 104 size_t *lenp)); 105static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *)); 106static void rcsbuf_cache_close PROTO ((void)); 107static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **, 108 struct rcsbuffer *)); 109static int checkmagic_proc PROTO((Node *p, void *closure)); 110static void do_branches PROTO((List * list, char *val)); 111static void do_symbols PROTO((List * list, char *val)); 112static void do_locks PROTO((List * list, char *val)); 113static void free_rcsnode_contents PROTO((RCSNode *)); 114static void free_rcsvers_contents PROTO((RCSVers *)); 115static void rcsvers_delproc PROTO((Node * p)); 116static char *translate_symtag PROTO((RCSNode *, const char *)); 117static char *RCS_addbranch PROTO ((RCSNode *, const char *)); 118static char *truncate_revnum_in_place PROTO ((char *)); 119static char *truncate_revnum PROTO ((const char *)); 120static char *printable_date PROTO((const char *)); 121static char *escape_keyword_value PROTO ((const char *, int *)); 122static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *, 123 const char *, size_t, enum kflag, char *, 124 size_t, char **, size_t *)); 125static void cmp_file_buffer PROTO((void *, const char *, size_t)); 126 127/* Routines for reading, parsing and writing RCS files. */ 128static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **, 129 char **)); 130static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *, 131 struct rcsbuffer *)); 132static void freedeltatext PROTO ((Deltatext *)); 133 134static void RCS_putadmin PROTO ((RCSNode *, FILE *)); 135static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *)); 136static void RCS_putdesc PROTO ((RCSNode *, FILE *)); 137static void putdelta PROTO ((RCSVers *, FILE *)); 138static int putrcsfield_proc PROTO ((Node *, void *)); 139static int putsymbol_proc PROTO ((Node *, void *)); 140static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, 141 FILE *, Deltatext *, char *)); 142static int count_delta_actions PROTO ((Node *, void *)); 143static void putdeltatext PROTO ((FILE *, Deltatext *)); 144 145static FILE *rcs_internal_lockfile PROTO ((char *)); 146static void rcs_internal_unlockfile PROTO ((FILE *, char *)); 147static char *rcs_lockfilename PROTO ((const char *)); 148 149/* The RCS file reading functions are called a lot, and they do some 150 string comparisons. This macro speeds things up a bit by skipping 151 the function call when the first characters are different. It 152 evaluates its arguments multiple times. */ 153#define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0) 154 155static char * getfullCVSname PROTO ((char *, char **)); 156 157/* 158 * We don't want to use isspace() from the C library because: 159 * 160 * 1. The definition of "whitespace" in RCS files includes ASCII 161 * backspace, but the C locale doesn't. 162 * 2. isspace is an very expensive function call in some implementations 163 * due to the addition of wide character support. 164 */ 165static const char spacetab[] = { 166 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */ 167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ 168 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ 169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ 170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ 171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ 172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */ 173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ 174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ 175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ 176 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ 177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ 178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ 179 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ 180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ 181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */ 182}; 183 184#define whitespace(c) (spacetab[(unsigned char)c] != 0) 185 186static char *rcs_lockfile; 187static int rcs_lockfd = -1; 188 189 190 191/* 192 * char * 193 * locate_rcs ( const char* file, const char *repository , int *inattic ) 194 * 195 * Find an RCS file in the repository, case insensitively when the cased name 196 * doesn't exist, we are running as the server, and a client has asked us to 197 * ignore case. 198 * 199 * Most parts of CVS will want to rely instead on RCS_parse which calls this 200 * function and is called by recurse.c which then puts the result in useful 201 * places like the rcs field of struct file_info. 202 * 203 * INPUTS 204 * 205 * repository the repository (including the directory) 206 * file the filename within that directory (without RCSEXT). 207 * inattic NULL or a pointer to the output boolean 208 * 209 * OUTPUTS 210 * 211 * inattic If this input was non-null, the destination will be 212 * set to true if the file was found in the attic or 213 * false if not. If no RCS file is found, this value 214 * is undefined. 215 * 216 * RETURNS 217 * 218 * a newly-malloc'd array containing the absolute pathname of the RCS 219 * file that was found or NULL when none was found. 220 * 221 * ERRORS 222 * 223 * errno can be set by the return value of the final call to 224 * locate_file_in_dir(). This should resolve to the system's existence error 225 * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if 226 * the Attic was found but no matching files were found in the Attic or its 227 * parent. 228 */ 229static char * 230locate_rcs (repository, file, inattic) 231 const char *repository; 232 const char *file; 233 int *inattic; 234{ 235 char *retval; 236 237 /* First, try to find the file as cased. */ 238 retval = xmalloc (strlen (repository) 239 + sizeof (CVSATTIC) 240 + strlen (file) 241 + sizeof (RCSEXT) 242 + 3); 243 sprintf (retval, "%s/%s%s", repository, file, RCSEXT); 244 if (isreadable (retval)) 245 { 246 if (inattic) 247 *inattic = 0; 248 return retval; 249 } 250 sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); 251 if (isreadable (retval)) 252 { 253 if (inattic) 254 *inattic = 1; 255 return retval; 256 } 257 free (retval); 258 259 return NULL; 260} 261 262 263 264/* A few generic thoughts on error handling, in particular the 265 printing of unexpected characters that we find in the RCS file 266 (that is, why we use '\x%x' rather than %c or some such). 267 268 * Avoiding %c means we don't have to worry about what is printable 269 and other such stuff. In error handling, often better to keep it 270 simple. 271 272 * Hex rather than decimal or octal because character set standards 273 tend to use hex. 274 275 * Saying "character 0x%x" might make it sound like we are printing 276 a file offset. So we use '\x%x'. 277 278 * Would be nice to print the offset within the file, but I can 279 imagine various portability hassles (in particular, whether 280 unsigned long is always big enough to hold file offsets). */ 281 282/* Parse an rcsfile given a user file name and a repository. If there is 283 an error, we print an error message and return NULL. If the file 284 does not exist, we return NULL without printing anything (I'm not 285 sure this allows the caller to do anything reasonable, but it is 286 the current behavior). */ 287RCSNode * 288RCS_parse (file, repos) 289 const char *file; 290 const char *repos; 291{ 292 RCSNode *rcs; 293 FILE *fp; 294 RCSNode *retval = NULL; 295 char *rcsfile; 296 int inattic; 297 298 /* We're creating a new RCSNode, so there is no hope of finding it 299 in the cache. */ 300 rcsbuf_cache_close (); 301 302 if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL) 303 { 304 /* Handle the error cases */ 305 } 306 else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL) 307 { 308 rcs = RCS_parsercsfile_i(fp, rcsfile); 309 if (rcs != NULL) 310 { 311 rcs->flags |= VALID; 312 if ( inattic ) 313 rcs->flags |= INATTIC; 314 } 315 316 free ( rcsfile ); 317 retval = rcs; 318 } 319 else if (! existence_error (errno)) 320 { 321 error (0, errno, "cannot open %s", rcsfile); 322 free (rcsfile); 323 } 324 325 return retval; 326} 327 328/* 329 * Parse a specific rcsfile. 330 */ 331RCSNode * 332RCS_parsercsfile (rcsfile) 333 const char *rcsfile; 334{ 335 FILE *fp; 336 RCSNode *rcs; 337 338 /* We're creating a new RCSNode, so there is no hope of finding it 339 in the cache. */ 340 rcsbuf_cache_close (); 341 342 /* open the rcsfile */ 343 if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL) 344 { 345 error (0, errno, "Couldn't open rcs file `%s'", rcsfile); 346 return (NULL); 347 } 348 349 rcs = RCS_parsercsfile_i (fp, rcsfile); 350 351 return (rcs); 352} 353 354 355 356/* 357 */ 358static RCSNode * 359RCS_parsercsfile_i (fp, rcsfile) 360 FILE *fp; 361 const char *rcsfile; 362{ 363 RCSNode *rdata; 364 struct rcsbuffer rcsbuf; 365 char *key, *value; 366 367 /* make a node */ 368 rdata = (RCSNode *) xmalloc (sizeof (RCSNode)); 369 memset ((char *)rdata, 0, sizeof (RCSNode)); 370 rdata->refcount = 1; 371 rdata->path = xstrdup (rcsfile); 372 373 /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header. 374 375 Most cvs operations on the main branch don't need any more 376 information. Those that do call RCS_reparsercsfile to parse 377 the rest of the header and the deltas. */ 378 379 rcsbuf_open (&rcsbuf, fp, rcsfile, 0); 380 381 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 382 goto l_error; 383 if (STREQ (key, RCSDESC)) 384 goto l_error; 385 386 if (STREQ (RCSHEAD, key) && value != NULL) 387 rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL); 388 389 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 390 goto l_error; 391 if (STREQ (key, RCSDESC)) 392 goto l_error; 393 394 if (STREQ (RCSBRANCH, key) && value != NULL) 395 { 396 char *cp; 397 398 rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL); 399 if ((numdots (rdata->branch) & 1) != 0) 400 { 401 /* turn it into a branch if it's a revision */ 402 cp = strrchr (rdata->branch, '.'); 403 *cp = '\0'; 404 } 405 } 406 407 /* Look ahead for expand, stopping when we see desc or a revision 408 number. */ 409 while (1) 410 { 411 char *cp; 412 413 if (STREQ (RCSEXPAND, key)) 414 { 415 rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, 416 (size_t *)NULL); 417 break; 418 } 419 420 for (cp = key; 421 (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0'; 422 cp++) 423 /* do nothing */ ; 424 if (*cp == '\0') 425 break; 426 427 if (STREQ (RCSDESC, key)) 428 break; 429 430 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 431 break; 432 } 433 434 rdata->flags |= PARTIAL; 435 436 rcsbuf_cache (rdata, &rcsbuf); 437 438 return rdata; 439 440l_error: 441 error (0, 0, "`%s' does not appear to be a valid rcs file", 442 rcsfile); 443 rcsbuf_close (&rcsbuf); 444 freercsnode (&rdata); 445 fclose (fp); 446 return NULL; 447} 448 449 450 451/* Do the real work of parsing an RCS file. 452 453 On error, die with a fatal error; if it returns at all it was successful. 454 455 If PFP is NULL, close the file when done. Otherwise, leave it open 456 and store the FILE * in *PFP. */ 457void 458RCS_reparsercsfile (rdata, pfp, rcsbufp) 459 RCSNode *rdata; 460 FILE **pfp; 461 struct rcsbuffer *rcsbufp; 462{ 463 FILE *fp; 464 char *rcsfile; 465 struct rcsbuffer rcsbuf; 466 Node *q, *kv; 467 RCSVers *vnode; 468 int gotkey; 469 char *cp; 470 char *key, *value; 471 472 assert (rdata != NULL); 473 rcsfile = rdata->path; 474 475 rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf); 476 477 /* make a node */ 478 /* This probably shouldn't be done until later: if a file has an 479 empty revision tree (which is permissible), rdata->versions 480 should be NULL. -twp */ 481 rdata->versions = getlist (); 482 483 /* 484 * process all the special header information, break out when we get to 485 * the first revision delta 486 */ 487 gotkey = 0; 488 for (;;) 489 { 490 /* get the next key/value pair */ 491 if (!gotkey) 492 { 493 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 494 { 495 error (1, 0, "`%s' does not appear to be a valid rcs file", 496 rcsfile); 497 } 498 } 499 500 gotkey = 0; 501 502 /* Skip head, branch and expand tags; we already have them. */ 503 if (STREQ (key, RCSHEAD) 504 || STREQ (key, RCSBRANCH) 505 || STREQ (key, RCSEXPAND)) 506 { 507 continue; 508 } 509 510 if (STREQ (key, "access")) 511 { 512 if (value != NULL) 513 { 514 /* We pass the POLISH parameter as 1 because 515 RCS_addaccess expects nothing but spaces. FIXME: 516 It would be easy and more efficient to change 517 RCS_addaccess. */ 518 if (rdata->access) 519 { 520 error (0, 0, 521 "Duplicate `access' keyword found in RCS file."); 522 free (rdata->access); 523 } 524 rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL); 525 } 526 continue; 527 } 528 529 /* We always save lock information, so that we can handle 530 -kkvl correctly when checking out a file. */ 531 if (STREQ (key, "locks")) 532 { 533 if (value != NULL) 534 { 535 if (rdata->locks_data) 536 { 537 error (0, 0, 538 "Duplicate `locks' keyword found in RCS file."); 539 free (rdata->locks_data); 540 } 541 rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 542 } 543 if (! rcsbuf_getkey (&rcsbuf, &key, &value)) 544 { 545 error (1, 0, "premature end of file reading %s", rcsfile); 546 } 547 if (STREQ (key, "strict") && value == NULL) 548 { 549 rdata->strict_locks = 1; 550 } 551 else 552 gotkey = 1; 553 continue; 554 } 555 556 if (STREQ (RCSSYMBOLS, key)) 557 { 558 if (value != NULL) 559 { 560 if (rdata->symbols_data) 561 { 562 error (0, 0, 563 "Duplicate `%s' keyword found in RCS file.", 564 RCSSYMBOLS); 565 free (rdata->symbols_data); 566 } 567 rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 568 } 569 continue; 570 } 571 572 /* 573 * check key for '.''s and digits (probably a rev) if it is a 574 * revision or `desc', we are done with the headers and are down to the 575 * revision deltas, so we break out of the loop 576 */ 577 for (cp = key; 578 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 579 cp++) 580 /* do nothing */ ; 581 /* Note that when comparing with RCSDATE, we are not massaging 582 VALUE from the string found in the RCS file. This is OK 583 since we know exactly what to expect. */ 584 if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0) 585 break; 586 587 if (STREQ (key, RCSDESC)) 588 break; 589 590 if (STREQ (key, "comment")) 591 { 592 if (rdata->comment) 593 { 594 error (0, 0, 595 "warning: duplicate key `%s' in RCS file `%s'", 596 key, rcsfile); 597 free (rdata->comment); 598 } 599 rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); 600 continue; 601 } 602 if (rdata->other == NULL) 603 rdata->other = getlist (); 604 kv = getnode (); 605 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; 606 kv->key = xstrdup (key); 607 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, 608 (size_t *) NULL); 609 if (addnode (rdata->other, kv) != 0) 610 { 611 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", 612 key, rcsfile); 613 freenode (kv); 614 } 615 616 /* if we haven't grabbed it yet, we didn't want it */ 617 } 618 619 /* We got out of the loop, so we have the first part of the first 620 revision delta in KEY (the revision) and VALUE (the date key 621 and its value). This is what getdelta expects to receive. */ 622 623 while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL) 624 { 625 /* get the node */ 626 q = getnode (); 627 q->type = RCSVERS; 628 q->delproc = rcsvers_delproc; 629 q->data = vnode; 630 q->key = vnode->version; 631 632 /* add the nodes to the list */ 633 if (addnode (rdata->versions, q)) 634 error (1, 0, "Multiple %s revision deltas found in `%s'", 635 q->key, rcsfile); 636 } 637 638 /* Here KEY and VALUE are whatever caused getdelta to return NULL. */ 639 640 if (STREQ (key, RCSDESC)) 641 { 642 if (rdata->desc != NULL) 643 { 644 error (0, 0, 645 "warning: duplicate key `%s' in RCS file `%s'", 646 key, rcsfile); 647 free (rdata->desc); 648 } 649 rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); 650 } 651 652 rdata->delta_pos = rcsbuf_ftell (&rcsbuf); 653 654 if (pfp == NULL) 655 rcsbuf_cache (rdata, &rcsbuf); 656 else 657 { 658 *pfp = fp; 659 *rcsbufp = rcsbuf; 660 } 661 rdata->flags &= ~PARTIAL; 662} 663 664/* Move RCS into or out of the Attic, depending on TOATTIC. If the 665 file is already in the desired place, return without doing 666 anything. At some point may want to think about how this relates 667 to RCS_rewrite but that is a bit hairy (if one wants renames to be 668 atomic, or that kind of thing). If there is an error, print a message 669 and return 1. On success, return 0. */ 670int 671RCS_setattic (rcs, toattic) 672 RCSNode *rcs; 673 int toattic; 674{ 675 char *newpath; 676 const char *p; 677 char *q; 678 679 /* Some systems aren't going to let us rename an open file. */ 680 rcsbuf_cache_close (); 681 682 /* Could make the pathname computations in this file, and probably 683 in other parts of rcs.c too, easier if the REPOS and FILE 684 arguments to RCS_parse got stashed in the RCSNode. */ 685 686 if (toattic) 687 { 688 mode_t omask; 689 690 if (rcs->flags & INATTIC) 691 return 0; 692 693 /* Example: rcs->path is "/foo/bar/baz,v". */ 694 newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5); 695 p = last_component (rcs->path); 696 strncpy (newpath, rcs->path, p - rcs->path); 697 strcpy (newpath + (p - rcs->path), CVSATTIC); 698 699 /* Create the Attic directory if it doesn't exist. */ 700 omask = umask (cvsumask); 701 if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST) 702 error (0, errno, "cannot make directory %s", newpath); 703 (void) umask (omask); 704 705 strcat (newpath, "/"); 706 strcat (newpath, p); 707 708 if (CVS_RENAME (rcs->path, newpath) < 0) 709 { 710 int save_errno = errno; 711 712 /* The checks for isreadable look awfully fishy, but 713 I'm going to leave them here for now until I 714 can think harder about whether they take care of 715 some cases which should be handled somehow. */ 716 717 if (isreadable (rcs->path) || !isreadable (newpath)) 718 { 719 error (0, save_errno, "cannot rename %s to %s", 720 rcs->path, newpath); 721 free (newpath); 722 return 1; 723 } 724 } 725 } 726 else 727 { 728 if (!(rcs->flags & INATTIC)) 729 return 0; 730 731 newpath = xmalloc (strlen (rcs->path)); 732 733 /* Example: rcs->path is "/foo/bar/Attic/baz,v". */ 734 p = last_component (rcs->path); 735 strncpy (newpath, rcs->path, p - rcs->path - 1); 736 newpath[p - rcs->path - 1] = '\0'; 737 q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1); 738 assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0); 739 strcpy (q, p); 740 741 if (CVS_RENAME (rcs->path, newpath) < 0) 742 { 743 error (0, errno, "failed to move `%s' out of the attic", 744 rcs->path); 745 free (newpath); 746 return 1; 747 } 748 } 749 750 free (rcs->path); 751 rcs->path = newpath; 752 753 return 0; 754} 755 756/* 757 * Fully parse the RCS file. Store all keyword/value pairs, fetch the 758 * log messages for each revision, and fetch add and delete counts for 759 * each revision (we could fetch the entire text for each revision, 760 * but the only caller, log_fileproc, doesn't need that information, 761 * so we don't waste the memory required to store it). The add and 762 * delete counts are stored on the OTHER field of the RCSVERSNODE 763 * structure, under the names ";add" and ";delete", so that we don't 764 * waste the memory space of extra fields in RCSVERSNODE for code 765 * which doesn't need this information. 766 */ 767 768void 769RCS_fully_parse (rcs) 770 RCSNode *rcs; 771{ 772 FILE *fp; 773 struct rcsbuffer rcsbuf; 774 775 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 776 777 while (1) 778 { 779 char *key, *value; 780 Node *vers; 781 RCSVers *vnode; 782 783 /* Rather than try to keep track of how much information we 784 have read, just read to the end of the file. */ 785 if (!rcsbuf_getrevnum (&rcsbuf, &key)) 786 break; 787 788 vers = findnode (rcs->versions, key); 789 if (!vers) 790 error (1, 0, 791 "Delta text %s without revision information in `%s'.", 792 key, rcs->path); 793 794 vnode = vers->data; 795 796 while (rcsbuf_getkey (&rcsbuf, &key, &value)) 797 { 798 if (!STREQ (key, "text")) 799 { 800 Node *kv; 801 802 if (vnode->other == NULL) 803 vnode->other = getlist (); 804 kv = getnode (); 805 kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; 806 kv->key = xstrdup (key); 807 kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, 808 (size_t *)NULL); 809 if (addnode (vnode->other, kv) != 0) 810 { 811 error (0, 0, 812 "\ 813warning: duplicate key `%s' in version `%s' of RCS file `%s'", 814 key, vnode->version, rcs->path); 815 freenode (kv); 816 } 817 818 continue; 819 } 820 821 if (!STREQ (vnode->version, rcs->head)) 822 { 823 unsigned long add, del; 824 char buf[50]; 825 Node *kv; 826 827 /* This is a change text. Store the add and delete 828 counts. */ 829 add = 0; 830 del = 0; 831 if (value != NULL) 832 { 833 size_t vallen; 834 const char *cp; 835 836 rcsbuf_valpolish (&rcsbuf, value, 0, &vallen); 837 cp = value; 838 while (cp < value + vallen) 839 { 840 char op; 841 unsigned long count; 842 843 op = *cp++; 844 if (op != 'a' && op != 'd') 845 error (1, 0, "\ 846unrecognized operation '\\x%x' in %s revision %s", 847 op, rcs->path, vnode->version); 848 (void) strtoul (cp, (char **) &cp, 10); 849 if (*cp++ != ' ') 850 error (1, 0, "space expected in %s revision %s", 851 rcs->path, vnode->version); 852 count = strtoul (cp, (char **) &cp, 10); 853 if (*cp++ != '\012') 854 error (1, 0, "linefeed expected in %s revision %s", 855 rcs->path, vnode->version); 856 857 if (op == 'd') 858 del += count; 859 else 860 { 861 add += count; 862 while (count != 0) 863 { 864 if (*cp == '\012') 865 --count; 866 else if (cp == value + vallen) 867 { 868 if (count != 1) 869 error (1, 0, "\ 870premature end of value in %s revision %s", 871 rcs->path, vnode->version); 872 else 873 break; 874 } 875 ++cp; 876 } 877 } 878 } 879 } 880 881 sprintf (buf, "%lu", add); 882 kv = getnode (); 883 kv->type = RCSFIELD; 884 kv->key = xstrdup (";add"); 885 kv->data = xstrdup (buf); 886 if (addnode (vnode->other, kv) != 0) 887 { 888 error (0, 0, 889 "\ 890warning: duplicate key `%s' in version `%s' of RCS file `%s'", 891 key, vnode->version, rcs->path); 892 freenode (kv); 893 } 894 895 sprintf (buf, "%lu", del); 896 kv = getnode (); 897 kv->type = RCSFIELD; 898 kv->key = xstrdup (";delete"); 899 kv->data = xstrdup (buf); 900 if (addnode (vnode->other, kv) != 0) 901 { 902 error (0, 0, 903 "\ 904warning: duplicate key `%s' in version `%s' of RCS file `%s'", 905 key, vnode->version, rcs->path); 906 freenode (kv); 907 } 908 } 909 910 /* We have found the "text" key which ends the data for 911 this revision. Break out of the loop and go on to the 912 next revision. */ 913 break; 914 } 915 } 916 917 rcsbuf_cache (rcs, &rcsbuf); 918} 919 920 921 922/* 923 * freercsnode - free up the info for an RCSNode 924 */ 925void 926freercsnode (rnodep) 927 RCSNode **rnodep; 928{ 929 if (rnodep == NULL || *rnodep == NULL) 930 return; 931 932 ((*rnodep)->refcount)--; 933 if ((*rnodep)->refcount != 0) 934 { 935 *rnodep = (RCSNode *) NULL; 936 return; 937 } 938 free ((*rnodep)->path); 939 if ((*rnodep)->head != (char *) NULL) 940 free ((*rnodep)->head); 941 if ((*rnodep)->branch != (char *) NULL) 942 free ((*rnodep)->branch); 943 free_rcsnode_contents (*rnodep); 944 free ((char *) *rnodep); 945 *rnodep = (RCSNode *) NULL; 946} 947 948/* 949 * free_rcsnode_contents - free up the contents of an RCSNode without 950 * freeing the node itself, or the file name, or the head, or the 951 * path. This returns the RCSNode to the state it is in immediately 952 * after a call to RCS_parse. 953 */ 954static void 955free_rcsnode_contents (rnode) 956 RCSNode *rnode; 957{ 958 dellist (&rnode->versions); 959 if (rnode->symbols != (List *) NULL) 960 dellist (&rnode->symbols); 961 if (rnode->symbols_data != (char *) NULL) 962 free (rnode->symbols_data); 963 if (rnode->expand != NULL) 964 free (rnode->expand); 965 if (rnode->other != (List *) NULL) 966 dellist (&rnode->other); 967 if (rnode->access != NULL) 968 free (rnode->access); 969 if (rnode->locks_data != NULL) 970 free (rnode->locks_data); 971 if (rnode->locks != (List *) NULL) 972 dellist (&rnode->locks); 973 if (rnode->comment != NULL) 974 free (rnode->comment); 975 if (rnode->desc != NULL) 976 free (rnode->desc); 977} 978 979/* free_rcsvers_contents -- free up the contents of an RCSVers node, 980 but also free the pointer to the node itself. */ 981/* Note: The `hardlinks' list is *not* freed, since it is merely a 982 pointer into the `hardlist' structure (defined in hardlink.c), and 983 that structure is freed elsewhere in the program. */ 984 985static void 986free_rcsvers_contents (rnode) 987 RCSVers *rnode; 988{ 989 if (rnode->branches != (List *) NULL) 990 dellist (&rnode->branches); 991 if (rnode->date != (char *) NULL) 992 free (rnode->date); 993 if (rnode->next != (char *) NULL) 994 free (rnode->next); 995 if (rnode->author != (char *) NULL) 996 free (rnode->author); 997 if (rnode->state != (char *) NULL) 998 free (rnode->state); 999 if (rnode->other != (List *) NULL) 1000 dellist (&rnode->other); 1001 if (rnode->other_delta != NULL) 1002 dellist (&rnode->other_delta); 1003 if (rnode->text != NULL) 1004 freedeltatext (rnode->text); 1005 free ((char *) rnode); 1006} 1007 1008/* 1009 * rcsvers_delproc - free up an RCSVers type node 1010 */ 1011static void 1012rcsvers_delproc (p) 1013 Node *p; 1014{ 1015 free_rcsvers_contents (p->data); 1016} 1017 1018/* These functions retrieve keys and values from an RCS file using a 1019 buffer. We use this somewhat complex approach because it turns out 1020 that for many common operations, CVS spends most of its time 1021 reading keys, so it's worth doing some fairly hairy optimization. */ 1022 1023/* The number of bytes we try to read each time we need more data. */ 1024 1025#define RCSBUF_BUFSIZE (8192) 1026 1027/* The buffer we use to store data. This grows as needed. */ 1028 1029static char *rcsbuf_buffer = NULL; 1030static size_t rcsbuf_buffer_size = 0; 1031 1032/* Whether rcsbuf_buffer is in use. This is used as a sanity check. */ 1033 1034static int rcsbuf_inuse; 1035 1036/* Set up to start gathering keys and values from an RCS file. This 1037 initializes RCSBUF. */ 1038 1039static void 1040rcsbuf_open (rcsbuf, fp, filename, pos) 1041 struct rcsbuffer *rcsbuf; 1042 FILE *fp; 1043 const char *filename; 1044 unsigned long pos; 1045{ 1046#ifdef HAVE_MMAP 1047 void *p; 1048 struct stat fs; 1049 size_t mmap_off = 0; 1050#endif 1051 1052 if (rcsbuf_inuse) 1053 error (1, 0, "rcsbuf_open: internal error"); 1054 rcsbuf_inuse = 1; 1055 1056#ifdef HAVE_MMAP 1057 /* When we have mmap, it is much more efficient to let the system do the 1058 * buffering and caching for us 1059 */ 1060 1061 if ( fstat (fileno(fp), &fs) < 0 ) 1062 error ( 1, errno, "Could not stat RCS archive %s for mapping", filename ); 1063 1064 if (pos) 1065 { 1066 size_t ps = getpagesize (); 1067 mmap_off = ( pos / ps ) * ps; 1068 } 1069 1070 /* Map private here since this particular buffer is read only */ 1071 p = mmap ( NULL, fs.st_size - mmap_off, PROT_READ | PROT_WRITE, 1072 MAP_PRIVATE, fileno(fp), mmap_off ); 1073 if (p != NULL && p != MAP_FAILED) 1074 { 1075 if (rcsbuf_buffer) free (rcsbuf_buffer); 1076 rcsbuf_buffer = p; 1077 rcsbuf_buffer_size = fs.st_size - mmap_off; 1078 rcsbuf->mmapped = 1; 1079 rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off; 1080 rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off; 1081 rcsbuf->pos = mmap_off; 1082 } 1083 else 1084 { 1085#ifndef MMAP_FALLBACK_TEST 1086 error (0, errno, "Could not map memory to RCS archive %s", filename); 1087#endif 1088#endif /* HAVE_MMAP */ 1089 if (rcsbuf_buffer_size < RCSBUF_BUFSIZE) 1090 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE); 1091 1092 rcsbuf->mmapped = 0; 1093 rcsbuf->ptr = rcsbuf_buffer; 1094 rcsbuf->ptrend = rcsbuf_buffer; 1095 rcsbuf->pos = pos; 1096#ifdef HAVE_MMAP 1097 } 1098#endif /* HAVE_MMAP */ 1099 rcsbuf->fp = fp; 1100 rcsbuf->filename = filename; 1101 rcsbuf->vlen = 0; 1102 rcsbuf->at_string = 0; 1103 rcsbuf->embedded_at = 0; 1104} 1105 1106/* Stop gathering keys from an RCS file. */ 1107 1108static void 1109rcsbuf_close (rcsbuf) 1110 struct rcsbuffer *rcsbuf; 1111{ 1112 if (! rcsbuf_inuse) 1113 error (1, 0, "rcsbuf_close: internal error"); 1114#ifdef HAVE_MMAP 1115 if (rcsbuf->mmapped) 1116 { 1117 munmap ( rcsbuf_buffer, rcsbuf_buffer_size ); 1118 rcsbuf_buffer = NULL; 1119 rcsbuf_buffer_size = 0; 1120 } 1121#endif 1122 rcsbuf_inuse = 0; 1123} 1124 1125/* Read a key/value pair from an RCS file. This sets *KEYP to point 1126 to the key, and *VALUEP to point to the value. A missing or empty 1127 value is indicated by setting *VALUEP to NULL. 1128 1129 This function returns 1 on success, or 0 on EOF. If there is an 1130 error reading the file, or an EOF in an unexpected location, it 1131 gives a fatal error. 1132 1133 This sets *KEYP and *VALUEP to point to storage managed by 1134 rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the 1135 RCS format: it may contain embedded whitespace and embedded '@' 1136 characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do 1137 appropriate massaging. */ 1138 1139/* Note that the extreme hair in rcsbuf_getkey is because profiling 1140 statistics show that it was worth it. */ 1141 1142static int 1143rcsbuf_getkey (rcsbuf, keyp, valp) 1144 struct rcsbuffer *rcsbuf; 1145 char **keyp; 1146 char **valp; 1147{ 1148 register const char * const my_spacetab = spacetab; 1149 register char *ptr, *ptrend; 1150 char c; 1151 1152#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) 1153 1154 rcsbuf->vlen = 0; 1155 rcsbuf->at_string = 0; 1156 rcsbuf->embedded_at = 0; 1157 1158 ptr = rcsbuf->ptr; 1159 ptrend = rcsbuf->ptrend; 1160 1161 /* Sanity check. */ 1162 assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size); 1163 assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size); 1164 1165 /* If the pointer is more than RCSBUF_BUFSIZE bytes into the 1166 buffer, move back to the start of the buffer. This keeps the 1167 buffer from growing indefinitely. */ 1168 if (!rcsbuf->mmapped && ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) 1169 { 1170 int len; 1171 1172 len = ptrend - ptr; 1173 1174 /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes 1175 at a time, so we can't have more bytes than that past PTR. */ 1176 assert (len <= RCSBUF_BUFSIZE); 1177 1178 /* Update the POS field, which holds the file offset of the 1179 first byte in the RCSBUF_BUFFER buffer. */ 1180 rcsbuf->pos += ptr - rcsbuf_buffer; 1181 1182 memcpy (rcsbuf_buffer, ptr, len); 1183 ptr = rcsbuf_buffer; 1184 ptrend = ptr + len; 1185 rcsbuf->ptrend = ptrend; 1186 } 1187 1188 /* Skip leading whitespace. */ 1189 1190 while (1) 1191 { 1192 if (ptr >= ptrend) 1193 { 1194 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); 1195 if (ptr == NULL) 1196 return 0; 1197 ptrend = rcsbuf->ptrend; 1198 } 1199 1200 c = *ptr; 1201 if (! my_whitespace (c)) 1202 break; 1203 1204 ++ptr; 1205 } 1206 1207 /* We've found the start of the key. */ 1208 1209 *keyp = ptr; 1210 1211 if (c != ';') 1212 { 1213 while (1) 1214 { 1215 ++ptr; 1216 if (ptr >= ptrend) 1217 { 1218 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL); 1219 if (ptr == NULL) 1220 error (1, 0, "EOF in key in RCS file %s", 1221 rcsbuf->filename); 1222 ptrend = rcsbuf->ptrend; 1223 } 1224 c = *ptr; 1225 if (c == ';' || my_whitespace (c)) 1226 break; 1227 } 1228 } 1229 1230 /* Here *KEYP points to the key in the buffer, C is the character 1231 we found at the of the key, and PTR points to the location in 1232 the buffer where we found C. We must set *PTR to \0 in order 1233 to terminate the key. If the key ended with ';', then there is 1234 no value. */ 1235 1236 *ptr = '\0'; 1237 ++ptr; 1238 1239 if (c == ';') 1240 { 1241 *valp = NULL; 1242 rcsbuf->ptr = ptr; 1243 return 1; 1244 } 1245 1246 /* C must be whitespace. Skip whitespace between the key and the 1247 value. If we find ';' now, there is no value. */ 1248 1249 while (1) 1250 { 1251 if (ptr >= ptrend) 1252 { 1253 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL); 1254 if (ptr == NULL) 1255 error (1, 0, "EOF while looking for value in RCS file %s", 1256 rcsbuf->filename); 1257 ptrend = rcsbuf->ptrend; 1258 } 1259 c = *ptr; 1260 if (c == ';') 1261 { 1262 *valp = NULL; 1263 rcsbuf->ptr = ptr + 1; 1264 return 1; 1265 } 1266 if (! my_whitespace (c)) 1267 break; 1268 ++ptr; 1269 } 1270 1271 /* Now PTR points to the start of the value, and C is the first 1272 character of the value. */ 1273 1274 if (c != '@') 1275 *valp = ptr; 1276 else 1277 { 1278 char *pat; 1279 size_t vlen; 1280 1281 /* Optimize the common case of a value composed of a single 1282 '@' string. */ 1283 1284 rcsbuf->at_string = 1; 1285 1286 ++ptr; 1287 1288 *valp = ptr; 1289 1290 while (1) 1291 { 1292 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) 1293 { 1294 /* Note that we pass PTREND as the PTR value to 1295 rcsbuf_fill, so that we will wind up setting PTR to 1296 the location corresponding to the old PTREND, so 1297 that we don't search the same bytes again. */ 1298 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1299 if (ptr == NULL) 1300 error (1, 0, 1301 "EOF while looking for end of string in RCS file %s", 1302 rcsbuf->filename); 1303 ptrend = rcsbuf->ptrend; 1304 } 1305 1306 /* Handle the special case of an '@' right at the end of 1307 the known bytes. */ 1308 if (pat + 1 >= ptrend) 1309 { 1310 /* Note that we pass PAT, not PTR, here. */ 1311 pat = rcsbuf_fill (rcsbuf, pat, keyp, valp); 1312 if (pat == NULL) 1313 { 1314 /* EOF here is OK; it just means that the last 1315 character of the file was an '@' terminating a 1316 value for a key type which does not require a 1317 trailing ';'. */ 1318 pat = rcsbuf->ptrend - 1; 1319 1320 } 1321 ptrend = rcsbuf->ptrend; 1322 1323 /* Note that the value of PTR is bogus here. This is 1324 OK, because we don't use it. */ 1325 } 1326 1327 if (pat + 1 >= ptrend || pat[1] != '@') 1328 break; 1329 1330 /* We found an '@' pair in the string. Keep looking. */ 1331 ++rcsbuf->embedded_at; 1332 ptr = pat + 2; 1333 } 1334 1335 /* Here PAT points to the final '@' in the string. */ 1336 1337 *pat = '\0'; 1338 1339 vlen = pat - *valp; 1340 if (vlen == 0) 1341 *valp = NULL; 1342 rcsbuf->vlen = vlen; 1343 1344 ptr = pat + 1; 1345 } 1346 1347 /* Certain keywords only have a '@' string. If there is no '@' 1348 string, then the old getrcskey function assumed that they had 1349 no value, and we do the same. */ 1350 1351 { 1352 char *k; 1353 1354 k = *keyp; 1355 if (STREQ (k, RCSDESC) 1356 || STREQ (k, "text") 1357 || STREQ (k, "log")) 1358 { 1359 if (c != '@') 1360 *valp = NULL; 1361 rcsbuf->ptr = ptr; 1362 return 1; 1363 } 1364 } 1365 1366 /* If we've already gathered a '@' string, try to skip whitespace 1367 and find a ';'. */ 1368 if (c == '@') 1369 { 1370 while (1) 1371 { 1372 char n; 1373 1374 if (ptr >= ptrend) 1375 { 1376 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); 1377 if (ptr == NULL) 1378 error (1, 0, "EOF in value in RCS file %s", 1379 rcsbuf->filename); 1380 ptrend = rcsbuf->ptrend; 1381 } 1382 n = *ptr; 1383 if (n == ';') 1384 { 1385 /* We're done. We already set everything up for this 1386 case above. */ 1387 rcsbuf->ptr = ptr + 1; 1388 return 1; 1389 } 1390 if (! my_whitespace (n)) 1391 break; 1392 ++ptr; 1393 } 1394 1395 /* The value extends past the '@' string. We need to undo the 1396 '@' stripping done in the default case above. This 1397 case never happens in a plain RCS file, but it can happen 1398 if user defined phrases are used. */ 1399 ((*valp)--)[rcsbuf->vlen++] = '@'; 1400 } 1401 1402 /* Here we have a value which is not a simple '@' string. We need 1403 to gather up everything until the next ';', including any '@' 1404 strings. *VALP points to the start of the value. If 1405 RCSBUF->VLEN is not zero, then we have already read an '@' 1406 string, and PTR points to the data following the '@' string. 1407 Otherwise, PTR points to the start of the value. */ 1408 1409 while (1) 1410 { 1411 char *start, *psemi, *pat; 1412 1413 /* Find the ';' which must end the value. */ 1414 start = ptr; 1415 while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL) 1416 { 1417 int slen; 1418 1419 /* Note that we pass PTREND as the PTR value to 1420 rcsbuf_fill, so that we will wind up setting PTR to the 1421 location corresponding to the old PTREND, so that we 1422 don't search the same bytes again. */ 1423 slen = start - *valp; 1424 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1425 if (ptr == NULL) 1426 error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename); 1427 start = *valp + slen; 1428 ptrend = rcsbuf->ptrend; 1429 } 1430 1431 /* See if there are any '@' strings in the value. */ 1432 pat = memchr (start, '@', psemi - start); 1433 1434 if (pat == NULL) 1435 { 1436 size_t vlen; 1437 1438 /* We're done with the value. Trim any trailing 1439 whitespace. */ 1440 1441 rcsbuf->ptr = psemi + 1; 1442 1443 start = *valp; 1444 while (psemi > start && my_whitespace (psemi[-1])) 1445 --psemi; 1446 *psemi = '\0'; 1447 1448 vlen = psemi - start; 1449 if (vlen == 0) 1450 *valp = NULL; 1451 rcsbuf->vlen = vlen; 1452 1453 return 1; 1454 } 1455 1456 /* We found an '@' string in the value. We set RCSBUF->AT_STRING 1457 and RCSBUF->EMBEDDED_AT to indicate that we won't be able to 1458 compress whitespace correctly for this type of value. 1459 Since this type of value never arises in a normal RCS file, 1460 this should not be a big deal. It means that if anybody 1461 adds a phrase which can have both an '@' string and regular 1462 text, they will have to handle whitespace compression 1463 themselves. */ 1464 1465 rcsbuf->at_string = 1; 1466 rcsbuf->embedded_at = -1; 1467 1468 ptr = pat + 1; 1469 1470 while (1) 1471 { 1472 while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) 1473 { 1474 /* Note that we pass PTREND as the PTR value to 1475 rcsbuff_fill, so that we will wind up setting PTR 1476 to the location corresponding to the old PTREND, so 1477 that we don't search the same bytes again. */ 1478 ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); 1479 if (ptr == NULL) 1480 error (1, 0, 1481 "EOF while looking for end of string in RCS file %s", 1482 rcsbuf->filename); 1483 ptrend = rcsbuf->ptrend; 1484 } 1485 1486 /* Handle the special case of an '@' right at the end of 1487 the known bytes. */ 1488 if (pat + 1 >= ptrend) 1489 { 1490 ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); 1491 if (ptr == NULL) 1492 error (1, 0, "EOF in value in RCS file %s", 1493 rcsbuf->filename); 1494 ptrend = rcsbuf->ptrend; 1495 } 1496 1497 if (pat[1] != '@') 1498 break; 1499 1500 /* We found an '@' pair in the string. Keep looking. */ 1501 ptr = pat + 2; 1502 } 1503 1504 /* Here PAT points to the final '@' in the string. */ 1505 ptr = pat + 1; 1506 } 1507 1508#undef my_whitespace 1509} 1510 1511/* Read an RCS revision number from an RCS file. This sets *REVP to 1512 point to the revision number; it will point to space that is 1513 managed by the rcsbuf functions, and is only good until the next 1514 call to rcsbuf_getkey or rcsbuf_getrevnum. 1515 1516 This function returns 1 on success, or 0 on EOF. If there is an 1517 error reading the file, or an EOF in an unexpected location, it 1518 gives a fatal error. */ 1519 1520static int 1521rcsbuf_getrevnum (rcsbuf, revp) 1522 struct rcsbuffer *rcsbuf; 1523 char **revp; 1524{ 1525 char *ptr, *ptrend; 1526 char c; 1527 1528 ptr = rcsbuf->ptr; 1529 ptrend = rcsbuf->ptrend; 1530 1531 *revp = NULL; 1532 1533 /* Skip leading whitespace. */ 1534 1535 while (1) 1536 { 1537 if (ptr >= ptrend) 1538 { 1539 ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); 1540 if (ptr == NULL) 1541 return 0; 1542 ptrend = rcsbuf->ptrend; 1543 } 1544 1545 c = *ptr; 1546 if (! whitespace (c)) 1547 break; 1548 1549 ++ptr; 1550 } 1551 1552 if (! isdigit ((unsigned char) c) && c != '.') 1553 error (1, 0, 1554 "\ 1555unexpected '\\x%x' reading revision number in RCS file %s", 1556 c, rcsbuf->filename); 1557 1558 *revp = ptr; 1559 1560 do 1561 { 1562 ++ptr; 1563 if (ptr >= ptrend) 1564 { 1565 ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL); 1566 if (ptr == NULL) 1567 error (1, 0, 1568 "unexpected EOF reading revision number in RCS file %s", 1569 rcsbuf->filename); 1570 ptrend = rcsbuf->ptrend; 1571 } 1572 1573 c = *ptr; 1574 } 1575 while (isdigit ((unsigned char) c) || c == '.'); 1576 1577 if (! whitespace (c)) 1578 error (1, 0, "\ 1579unexpected '\\x%x' reading revision number in RCS file %s", 1580 c, rcsbuf->filename); 1581 1582 *ptr = '\0'; 1583 1584 rcsbuf->ptr = ptr + 1; 1585 1586 return 1; 1587} 1588 1589/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF, 1590 updating PTR and the PTREND field. If KEYP and *KEYP are not NULL, 1591 then *KEYP points into the buffer, and must be adjusted if the 1592 buffer is changed. Likewise for VALP. Returns the new value of 1593 PTR, or NULL on error. */ 1594 1595static char * 1596rcsbuf_fill (rcsbuf, ptr, keyp, valp) 1597 struct rcsbuffer *rcsbuf; 1598 char *ptr; 1599 char **keyp; 1600 char **valp; 1601{ 1602 int got; 1603 1604 if (rcsbuf->mmapped) 1605 return NULL; 1606 1607 if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size) 1608 { 1609 int poff, peoff, koff, voff; 1610 1611 poff = ptr - rcsbuf_buffer; 1612 peoff = rcsbuf->ptrend - rcsbuf_buffer; 1613 koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer; 1614 voff = valp == NULL ? 0 : *valp - rcsbuf_buffer; 1615 1616 expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, 1617 rcsbuf_buffer_size + RCSBUF_BUFSIZE); 1618 1619 ptr = rcsbuf_buffer + poff; 1620 rcsbuf->ptrend = rcsbuf_buffer + peoff; 1621 if (keyp != NULL) 1622 *keyp = rcsbuf_buffer + koff; 1623 if (valp != NULL) 1624 *valp = rcsbuf_buffer + voff; 1625 } 1626 1627 got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp); 1628 if (got == 0) 1629 { 1630 if (ferror (rcsbuf->fp)) 1631 error (1, errno, "cannot read %s", rcsbuf->filename); 1632 return NULL; 1633 } 1634 1635 rcsbuf->ptrend += got; 1636 1637 return ptr; 1638} 1639 1640/* Test whether the last value returned by rcsbuf_getkey is a composite 1641 value or not. */ 1642 1643static int 1644rcsbuf_valcmp (rcsbuf) 1645 struct rcsbuffer *rcsbuf; 1646{ 1647 return rcsbuf->at_string && rcsbuf->embedded_at < 0; 1648} 1649 1650/* Copy the value VAL returned by rcsbuf_getkey into a memory buffer, 1651 returning the memory buffer. Polish the value like 1652 rcsbuf_valpolish, q.v. */ 1653 1654static char * 1655rcsbuf_valcopy (rcsbuf, val, polish, lenp) 1656 struct rcsbuffer *rcsbuf; 1657 char *val; 1658 int polish; 1659 size_t *lenp; 1660{ 1661 size_t vlen; 1662 int embedded_at; 1663 char *ret; 1664 1665 if (val == NULL) 1666 { 1667 if (lenp != NULL) 1668 *lenp = 0; 1669 return NULL; 1670 } 1671 1672 vlen = rcsbuf->vlen; 1673 embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at; 1674 1675 ret = xmalloc (vlen - embedded_at + 1); 1676 1677 if (rcsbuf->at_string ? embedded_at == 0 : ! polish) 1678 { 1679 /* No special action to take. */ 1680 memcpy (ret, val, vlen + 1); 1681 if (lenp != NULL) 1682 *lenp = vlen; 1683 return ret; 1684 } 1685 1686 rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp); 1687 return ret; 1688} 1689 1690/* Polish the value VAL returned by rcsbuf_getkey. The POLISH 1691 parameter is non-zero if multiple embedded whitespace characters 1692 should be compressed into a single whitespace character. Note that 1693 leading and trailing whitespace was already removed by 1694 rcsbuf_getkey. Within an '@' string, pairs of '@' characters are 1695 compressed into a single '@' character regardless of the value of 1696 POLISH. If LENP is not NULL, set *LENP to the length of the value. */ 1697 1698static void 1699rcsbuf_valpolish (rcsbuf, val, polish, lenp) 1700 struct rcsbuffer *rcsbuf; 1701 char *val; 1702 int polish; 1703 size_t *lenp; 1704{ 1705 if (val == NULL) 1706 { 1707 if (lenp != NULL) 1708 *lenp= 0; 1709 return; 1710 } 1711 1712 if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish) 1713 { 1714 /* No special action to take. */ 1715 if (lenp != NULL) 1716 *lenp = rcsbuf->vlen; 1717 return; 1718 } 1719 1720 rcsbuf_valpolish_internal (rcsbuf, val, val, lenp); 1721} 1722 1723/* Internal polishing routine, called from rcsbuf_valcopy and 1724 rcsbuf_valpolish. */ 1725 1726static void 1727rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) 1728 struct rcsbuffer *rcsbuf; 1729 char *to; 1730 const char *from; 1731 size_t *lenp; 1732{ 1733 size_t len; 1734 1735 len = rcsbuf->vlen; 1736 1737 if (! rcsbuf->at_string) 1738 { 1739 char *orig_to; 1740 size_t clen; 1741 1742 orig_to = to; 1743 1744 for (clen = len; clen > 0; ++from, --clen) 1745 { 1746 char c; 1747 1748 c = *from; 1749 if (whitespace (c)) 1750 { 1751 /* Note that we know that clen can not drop to zero 1752 while we have whitespace, because we know there is 1753 no trailing whitespace. */ 1754 while (whitespace (from[1])) 1755 { 1756 ++from; 1757 --clen; 1758 } 1759 c = ' '; 1760 } 1761 *to++ = c; 1762 } 1763 1764 *to = '\0'; 1765 1766 if (lenp != NULL) 1767 *lenp = to - orig_to; 1768 } 1769 else 1770 { 1771 const char *orig_from; 1772 char *orig_to; 1773 int embedded_at; 1774 size_t clen; 1775 1776 orig_from = from; 1777 orig_to = to; 1778 1779 embedded_at = rcsbuf->embedded_at; 1780 assert (embedded_at > 0); 1781 1782 if (lenp != NULL) 1783 *lenp = len - embedded_at; 1784 1785 for (clen = len; clen > 0; ++from, --clen) 1786 { 1787 char c; 1788 1789 c = *from; 1790 *to++ = c; 1791 if (c == '@') 1792 { 1793 ++from; 1794 1795 /* Sanity check. 1796 * 1797 * FIXME: I restored this to an abort from an assert based on 1798 * advice from Larry Jones that asserts should not be used to 1799 * confirm the validity of an RCS file... This leaves two 1800 * issues here: 1) I am uncertain that the fact that we will 1801 * only find double '@'s hasn't already been confirmed; and: 1802 * 2) If this is the proper place to spot the error in the RCS 1803 * file, then we should print a much clearer error here for the 1804 * user!!!!!!! 1805 * 1806 * - DRP 1807 */ 1808 if (*from != '@' || clen == 0) 1809 abort (); 1810 1811 --clen; 1812 1813 --embedded_at; 1814 if (embedded_at == 0) 1815 { 1816 /* We've found all the embedded '@' characters. 1817 We can just memcpy the rest of the buffer after 1818 this '@' character. */ 1819 if (orig_to != orig_from) 1820 memcpy (to, from + 1, clen - 1); 1821 else 1822 memmove (to, from + 1, clen - 1); 1823 from += clen; 1824 to += clen - 1; 1825 break; 1826 } 1827 } 1828 } 1829 1830 /* Sanity check. */ 1831 assert (from == orig_from + len 1832 && to == orig_to + (len - rcsbuf->embedded_at)); 1833 1834 *to = '\0'; 1835 } 1836} 1837 1838#ifdef PRESERVE_PERMISSIONS_SUPPORT 1839 1840/* Copy the next word from the value VALP returned by rcsbuf_getkey into a 1841 memory buffer, updating VALP and returning the memory buffer. Return 1842 NULL when there are no more words. */ 1843 1844static char * 1845rcsbuf_valword (rcsbuf, valp) 1846 struct rcsbuffer *rcsbuf; 1847 char **valp; 1848{ 1849 register const char * const my_spacetab = spacetab; 1850 register char *ptr, *pat; 1851 char c; 1852 1853# define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) 1854 1855 if (*valp == NULL) 1856 return NULL; 1857 1858 for (ptr = *valp; my_whitespace (*ptr); ++ptr) ; 1859 if (*ptr == '\0') 1860 { 1861 assert (ptr - *valp == rcsbuf->vlen); 1862 *valp = NULL; 1863 rcsbuf->vlen = 0; 1864 return NULL; 1865 } 1866 1867 /* PTR now points to the start of a value. Find out whether it is 1868 a num, an id, a string or a colon. */ 1869 c = *ptr; 1870 if (c == ':') 1871 { 1872 rcsbuf->vlen -= ++ptr - *valp; 1873 *valp = ptr; 1874 return xstrdup (":"); 1875 } 1876 1877 if (c == '@') 1878 { 1879 int embedded_at = 0; 1880 size_t vlen; 1881 1882 pat = ++ptr; 1883 while ((pat = strchr (pat, '@')) != NULL) 1884 { 1885 if (pat[1] != '@') 1886 break; 1887 ++embedded_at; 1888 pat += 2; 1889 } 1890 1891 /* Here PAT points to the final '@' in the string. */ 1892 *pat++ = '\0'; 1893 assert (rcsbuf->at_string); 1894 vlen = rcsbuf->vlen - (pat - *valp); 1895 rcsbuf->vlen = pat - ptr - 1; 1896 rcsbuf->embedded_at = embedded_at; 1897 ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL); 1898 *valp = pat; 1899 rcsbuf->vlen = vlen; 1900 if (strchr (pat, '@') == NULL) 1901 rcsbuf->at_string = 0; 1902 else 1903 rcsbuf->embedded_at = -1; 1904 return ptr; 1905 } 1906 1907 /* *PTR is neither `:', `;' nor `@', so it should be the start of a num 1908 or an id. Make sure it is not another special character. */ 1909 if (c == '$' || c == '.' || c == ',') 1910 { 1911 error (1, 0, "invalid special character in RCS field in %s", 1912 rcsbuf->filename); 1913 } 1914 1915 pat = ptr; 1916 while (1) 1917 { 1918 /* Legitimate ID characters are digits, dots and any `graphic 1919 printing character that is not a special.' This test ought 1920 to do the trick. */ 1921 c = *++pat; 1922 if (!isprint ((unsigned char) c) || 1923 c == ';' || c == '$' || c == ',' || c == '@' || c == ':') 1924 break; 1925 } 1926 1927 /* PAT points to the last non-id character in this word, and C is 1928 the character in its memory cell. Check to make sure that it 1929 is a legitimate word delimiter -- whitespace or end. */ 1930 if (c != '\0' && !my_whitespace (c)) 1931 error (1, 0, "invalid special character in RCS field in %s", 1932 rcsbuf->filename); 1933 1934 *pat = '\0'; 1935 rcsbuf->vlen -= pat - *valp; 1936 *valp = pat; 1937 return xstrdup (ptr); 1938 1939# undef my_whitespace 1940} 1941 1942#endif 1943 1944/* Return the current position of an rcsbuf. */ 1945 1946static unsigned long 1947rcsbuf_ftell (rcsbuf) 1948 struct rcsbuffer *rcsbuf; 1949{ 1950 return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer); 1951} 1952 1953/* Return a pointer to any data buffered for RCSBUF, along with the 1954 length. */ 1955 1956static void 1957rcsbuf_get_buffered (rcsbuf, datap, lenp) 1958 struct rcsbuffer *rcsbuf; 1959 char **datap; 1960 size_t *lenp; 1961{ 1962 *datap = rcsbuf->ptr; 1963 *lenp = rcsbuf->ptrend - rcsbuf->ptr; 1964} 1965 1966/* CVS optimizes by quickly reading some header information from a 1967 file. If it decides it needs to do more with the file, it reopens 1968 it. We speed that up here by maintaining a cache of a single open 1969 file, to save the time it takes to reopen the file in the common 1970 case. */ 1971 1972static RCSNode *cached_rcs; 1973static struct rcsbuffer cached_rcsbuf; 1974 1975/* Cache RCS and RCSBUF. This takes responsibility for closing 1976 RCSBUF->FP. */ 1977 1978static void 1979rcsbuf_cache (rcs, rcsbuf) 1980 RCSNode *rcs; 1981 struct rcsbuffer *rcsbuf; 1982{ 1983 if (cached_rcs != NULL) 1984 rcsbuf_cache_close (); 1985 cached_rcs = rcs; 1986 ++rcs->refcount; 1987 cached_rcsbuf = *rcsbuf; 1988} 1989 1990/* If there is anything in the cache, close it. */ 1991 1992static void 1993rcsbuf_cache_close () 1994{ 1995 if (cached_rcs != NULL) 1996 { 1997 rcsbuf_close (&cached_rcsbuf); 1998 if (fclose (cached_rcsbuf.fp) != 0) 1999 error (0, errno, "cannot close %s", cached_rcsbuf.filename); 2000 freercsnode (&cached_rcs); 2001 cached_rcs = NULL; 2002 } 2003} 2004 2005/* Open an rcsbuffer for RCS, getting it from the cache if possible. 2006 Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should 2007 be put at position POS. */ 2008 2009static void 2010rcsbuf_cache_open (rcs, pos, pfp, prcsbuf) 2011 RCSNode *rcs; 2012 long pos; 2013 FILE **pfp; 2014 struct rcsbuffer *prcsbuf; 2015{ 2016 if (cached_rcs == rcs && !cached_rcsbuf.mmapped) 2017 { 2018 if (rcsbuf_ftell (&cached_rcsbuf) != pos) 2019 { 2020 if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0) 2021 error (1, 0, "cannot fseek RCS file %s", 2022 cached_rcsbuf.filename); 2023 cached_rcsbuf.ptr = rcsbuf_buffer; 2024 cached_rcsbuf.ptrend = rcsbuf_buffer; 2025 cached_rcsbuf.pos = pos; 2026 } 2027 *pfp = cached_rcsbuf.fp; 2028 2029 /* When RCS_parse opens a file using fopen_case, it frees the 2030 filename which we cached in CACHED_RCSBUF and stores a new 2031 file name in RCS->PATH. We avoid problems here by always 2032 copying the filename over. FIXME: This is hackish. */ 2033 cached_rcsbuf.filename = rcs->path; 2034 2035 *prcsbuf = cached_rcsbuf; 2036 2037 cached_rcs = NULL; 2038 2039 /* Removing RCS from the cache removes a reference to it. */ 2040 --rcs->refcount; 2041 if (rcs->refcount <= 0) 2042 error (1, 0, "rcsbuf_cache_open: internal error"); 2043 } 2044 else 2045 { 2046 /* FIXME: If these routines can be rewritten to not write to the 2047 * rcs file buffer, there would be a considerably larger memory savings 2048 * from using mmap since the shared file would never need be copied to 2049 * process memory. 2050 * 2051 * If this happens, cached mmapped buffers would be usable, but don't 2052 * forget to make sure rcs->pos < pos here... 2053 */ 2054 if (cached_rcs != NULL) 2055 rcsbuf_cache_close (); 2056 2057 *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ); 2058 if (*pfp == NULL) 2059 error (1, 0, "unable to reopen `%s'", rcs->path); 2060 if (pos != 0) 2061 { 2062 if (fseek (*pfp, pos, SEEK_SET) != 0) 2063 error (1, 0, "cannot fseek RCS file %s", rcs->path); 2064 } 2065 rcsbuf_open (prcsbuf, *pfp, rcs->path, pos); 2066 } 2067} 2068 2069 2070/* 2071 * process the symbols list of the rcs file 2072 */ 2073static void 2074do_symbols (list, val) 2075 List *list; 2076 char *val; 2077{ 2078 Node *p; 2079 char *cp = val; 2080 char *tag, *rev; 2081 2082 assert (cp); 2083 2084 for (;;) 2085 { 2086 /* skip leading whitespace */ 2087 while (whitespace (*cp)) 2088 cp++; 2089 2090 /* if we got to the end, we are done */ 2091 if (*cp == '\0') 2092 break; 2093 2094 /* split it up into tag and rev */ 2095 tag = cp; 2096 cp = strchr (cp, ':'); 2097 *cp++ = '\0'; 2098 rev = cp; 2099 while (!whitespace (*cp) && *cp != '\0') 2100 cp++; 2101 if (*cp != '\0') 2102 *cp++ = '\0'; 2103 2104 /* make a new node and add it to the list */ 2105 p = getnode (); 2106 p->key = xstrdup (tag); 2107 p->data = xstrdup (rev); 2108 (void) addnode (list, p); 2109 } 2110} 2111 2112/* 2113 * process the locks list of the rcs file 2114 * Like do_symbols, but hash entries are keyed backwards: i.e. 2115 * an entry like `user:rev' is keyed on REV rather than on USER. 2116 */ 2117static void 2118do_locks (list, val) 2119 List *list; 2120 char *val; 2121{ 2122 Node *p; 2123 char *cp = val; 2124 char *user, *rev; 2125 2126 assert (cp); 2127 2128 for (;;) 2129 { 2130 /* skip leading whitespace */ 2131 while (whitespace (*cp)) 2132 cp++; 2133 2134 /* if we got to the end, we are done */ 2135 if (*cp == '\0') 2136 break; 2137 2138 /* split it up into user and rev */ 2139 user = cp; 2140 cp = strchr (cp, ':'); 2141 *cp++ = '\0'; 2142 rev = cp; 2143 while (!whitespace (*cp) && *cp != '\0') 2144 cp++; 2145 if (*cp != '\0') 2146 *cp++ = '\0'; 2147 2148 /* make a new node and add it to the list */ 2149 p = getnode (); 2150 p->key = xstrdup (rev); 2151 p->data = xstrdup (user); 2152 (void) addnode (list, p); 2153 } 2154} 2155 2156/* 2157 * process the branches list of a revision delta 2158 */ 2159static void 2160do_branches (list, val) 2161 List *list; 2162 char *val; 2163{ 2164 Node *p; 2165 char *cp = val; 2166 char *branch; 2167 2168 for (;;) 2169 { 2170 /* skip leading whitespace */ 2171 while (whitespace (*cp)) 2172 cp++; 2173 2174 /* if we got to the end, we are done */ 2175 if (*cp == '\0') 2176 break; 2177 2178 /* find the end of this branch */ 2179 branch = cp; 2180 while (!whitespace (*cp) && *cp != '\0') 2181 cp++; 2182 if (*cp != '\0') 2183 *cp++ = '\0'; 2184 2185 /* make a new node and add it to the list */ 2186 p = getnode (); 2187 p->key = xstrdup (branch); 2188 (void) addnode (list, p); 2189 } 2190} 2191 2192/* 2193 * Version Number 2194 * 2195 * Returns the requested version number of the RCS file, satisfying tags and/or 2196 * dates, and walking branches, if necessary. 2197 * 2198 * The result is returned; null-string if error. 2199 */ 2200char * 2201RCS_getversion (rcs, tag, date, force_tag_match, simple_tag) 2202 RCSNode *rcs; 2203 const char *tag; 2204 const char *date; 2205 int force_tag_match; 2206 int *simple_tag; 2207{ 2208 if (simple_tag != NULL) 2209 *simple_tag = 0; 2210 2211 /* make sure we have something to look at... */ 2212 assert (rcs != NULL); 2213 2214 if (tag && date) 2215 { 2216 char *branch, *rev; 2217 2218 if (! RCS_nodeisbranch (rcs, tag)) 2219 { 2220 /* We can't get a particular date if the tag is not a 2221 branch. */ 2222 return NULL; 2223 } 2224 2225 /* Work out the branch. */ 2226 if (! isdigit ((unsigned char) tag[0])) 2227 branch = RCS_whatbranch (rcs, tag); 2228 else 2229 branch = xstrdup (tag); 2230 2231 /* Fetch the revision of branch as of date. */ 2232 rev = RCS_getdatebranch (rcs, date, branch); 2233 free (branch); 2234 return (rev); 2235 } 2236 else if (tag) 2237 return RCS_gettag (rcs, tag, force_tag_match, simple_tag); 2238 else if (date) 2239 return RCS_getdate (rcs, date, force_tag_match); 2240 else 2241 return RCS_head (rcs); 2242 2243} 2244 2245 2246 2247/* 2248 * Get existing revision number corresponding to tag or revision. 2249 * Similar to RCS_gettag but less interpretation imposed. 2250 * For example: 2251 * -- If tag designates a magic branch, RCS_tag2rev 2252 * returns the magic branch number. 2253 * -- If tag is a branch tag, returns the branch number, not 2254 * the revision of the head of the branch. 2255 * If tag or revision is not valid or does not exist in file, 2256 * return NULL. 2257 */ 2258char * 2259RCS_tag2rev (rcs, tag) 2260 RCSNode *rcs; 2261 char *tag; 2262{ 2263 char *rev, *pa, *pb; 2264 int i; 2265 2266 assert (rcs != NULL); 2267 2268 if (rcs->flags & PARTIAL) 2269 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 2270 2271 /* If a valid revision, try to look it up */ 2272 if ( RCS_valid_rev (tag) ) 2273 { 2274 /* Make a copy so we can scribble on it */ 2275 rev = xstrdup (tag); 2276 2277 /* If revision exists, return the copy */ 2278 if (RCS_exist_rev (rcs, tag)) 2279 return rev; 2280 2281 /* Nope, none such. If tag is not a branch we're done. */ 2282 i = numdots (rev); 2283 if ((i & 1) == 1 ) 2284 { 2285 pa = strrchr (rev, '.'); 2286 if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.') 2287 { 2288 free (rev); 2289 error (1, 0, "revision `%s' does not exist", tag); 2290 } 2291 } 2292 2293 /* Try for a real (that is, exists in the RCS deltas) branch 2294 (RCS_exist_rev just checks for real revisions and revisions 2295 which have tags pointing to them). */ 2296 pa = RCS_getbranch (rcs, rev, 1); 2297 if (pa != NULL) 2298 { 2299 free (pa); 2300 return rev; 2301 } 2302 2303 /* Tag is branch, but does not exist, try corresponding 2304 * magic branch tag. 2305 * 2306 * FIXME: assumes all magic branches are of 2307 * form "n.n.n ... .0.n". I'll fix if somebody can 2308 * send me a method to get a magic branch tag with 2309 * the 0 in some other position -- <dan@gasboy.com> 2310 */ 2311 pa = strrchr (rev, '.'); 2312 if (!pa) 2313 /* This might happen, for instance, if an RCS file only contained 2314 * revisions 2.x and higher, and REV == "1". 2315 */ 2316 error (1, 0, "revision `%s' does not exist", tag); 2317 2318 pb = xmalloc (strlen (rev) + 3); 2319 *pa++ = 0; 2320 (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa); 2321 free (rev); 2322 rev = pb; 2323 if (RCS_exist_rev (rcs, rev)) 2324 return rev; 2325 error (1, 0, "revision `%s' does not exist", tag); 2326 } 2327 2328 2329 RCS_check_tag (tag); /* exit if not a valid tag */ 2330 2331 /* If tag is "HEAD", special case to get head RCS revision */ 2332 if (tag && STREQ (tag, TAG_HEAD)) 2333 return (RCS_head (rcs)); 2334 2335 /* If valid tag let translate_symtag say yea or nay. */ 2336 rev = translate_symtag (rcs, tag); 2337 2338 if (rev) 2339 return rev; 2340 2341 /* Trust the caller to print warnings. */ 2342 return NULL; 2343} 2344 2345/* 2346 * Find the revision for a specific tag. 2347 * If force_tag_match is set, return NULL if an exact match is not 2348 * possible otherwise return RCS_head (). We are careful to look for 2349 * and handle "magic" revisions specially. 2350 * 2351 * If the matched tag is a branch tag, find the head of the branch. 2352 * 2353 * Returns pointer to newly malloc'd string, or NULL. 2354 */ 2355char * 2356RCS_gettag (rcs, symtag, force_tag_match, simple_tag) 2357 RCSNode *rcs; 2358 const char *symtag; 2359 int force_tag_match; 2360 int *simple_tag; 2361{ 2362 char *tag; 2363 2364 if (simple_tag != NULL) 2365 *simple_tag = 0; 2366 2367 /* make sure we have something to look at... */ 2368 assert (rcs != NULL); 2369 2370 /* XXX this is probably not necessary, --jtc */ 2371 if (rcs->flags & PARTIAL) 2372 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 2373 2374 /* If symtag is "HEAD", special case to get head RCS revision */ 2375 if (symtag && STREQ (symtag, TAG_HEAD)) 2376#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */ 2377 if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC)) 2378 return ((char *) NULL); /* head request for removed file */ 2379 else 2380#endif 2381 return RCS_head (rcs); 2382 2383 if (!isdigit ((unsigned char) symtag[0])) 2384 { 2385 char *version; 2386 2387 /* If we got a symbolic tag, resolve it to a numeric */ 2388 version = translate_symtag (rcs, symtag); 2389 if (version != NULL) 2390 { 2391 int dots; 2392 char *magic, *branch, *cp; 2393 2394 tag = version; 2395 2396 /* 2397 * If this is a magic revision, we turn it into either its 2398 * physical branch equivalent (if one exists) or into 2399 * its base revision, which we assume exists. 2400 */ 2401 dots = numdots (tag); 2402 if (dots > 2 && (dots & 1) != 0) 2403 { 2404 branch = strrchr (tag, '.'); 2405 cp = branch++ - 1; 2406 while (*cp != '.') 2407 cp--; 2408 2409 /* see if we have .magic-branch. (".0.") */ 2410 magic = xmalloc (strlen (tag) + 1); 2411 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); 2412 if (strncmp (magic, cp, strlen (magic)) == 0) 2413 { 2414 /* it's magic. See if the branch exists */ 2415 *cp = '\0'; /* turn it into a revision */ 2416 (void) sprintf (magic, "%s.%s", tag, branch); 2417 branch = RCS_getbranch (rcs, magic, 1); 2418 free (magic); 2419 if (branch != NULL) 2420 { 2421 free (tag); 2422 return branch; 2423 } 2424 return tag; 2425 } 2426 free (magic); 2427 } 2428 } 2429 else 2430 { 2431 /* The tag wasn't there, so return the head or NULL */ 2432 if (force_tag_match) 2433 return NULL; 2434 else 2435 return RCS_head (rcs); 2436 } 2437 } 2438 else 2439 tag = xstrdup (symtag); 2440 2441 /* tag is always allocated and numeric now. */ 2442 2443 /* 2444 * numeric tag processing: 2445 * 1) revision number - just return it 2446 * 2) branch number - find head of branch 2447 */ 2448 2449 /* strip trailing dots */ 2450 while (tag[strlen (tag) - 1] == '.') 2451 tag[strlen (tag) - 1] = '\0'; 2452 2453 if ((numdots (tag) & 1) == 0) 2454 { 2455 char *branch; 2456 2457 /* we have a branch tag, so we need to walk the branch */ 2458 branch = RCS_getbranch (rcs, tag, force_tag_match); 2459 free (tag); 2460 return branch; 2461 } 2462 else 2463 { 2464 Node *p; 2465 2466 /* we have a revision tag, so make sure it exists */ 2467 p = findnode (rcs->versions, tag); 2468 if (p != NULL) 2469 { 2470 /* We have found a numeric revision for the revision tag. 2471 To support expanding the RCS keyword Name, if 2472 SIMPLE_TAG is not NULL, tell the the caller that this 2473 is a simple tag which co will recognize. FIXME: Are 2474 there other cases in which we should set this? In 2475 particular, what if we expand RCS keywords internally 2476 without calling co? */ 2477 if (simple_tag != NULL) 2478 *simple_tag = 1; 2479 return tag; 2480 } 2481 else 2482 { 2483 /* The revision wasn't there, so return the head or NULL */ 2484 free (tag); 2485 if (force_tag_match) 2486 return NULL; 2487 else 2488 return RCS_head (rcs); 2489 } 2490 } 2491} 2492 2493/* 2494 * Return a "magic" revision as a virtual branch off of REV for the RCS file. 2495 * A "magic" revision is one which is unique in the RCS file. By unique, I 2496 * mean we return a revision which: 2497 * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH) 2498 * - has a revision component which is not an existing branch off REV 2499 * - has a revision component which is not an existing magic revision 2500 * - is an even-numbered revision, to avoid conflicts with vendor branches 2501 * The first point is what makes it "magic". 2502 * 2503 * As an example, if we pass in 1.37 as REV, we will look for an existing 2504 * branch called 1.37.2. If it did not exist, we would look for an 2505 * existing symbolic tag with a numeric part equal to 1.37.0.2. If that 2506 * didn't exist, then we know that the 1.37.2 branch can be reserved by 2507 * creating a symbolic tag with 1.37.0.2 as the numeric part. 2508 * 2509 * This allows us to fork development with very little overhead -- just a 2510 * symbolic tag is used in the RCS file. When a commit is done, a physical 2511 * branch is dynamically created to hold the new revision. 2512 * 2513 * Note: We assume that REV is an RCS revision and not a branch number. 2514 */ 2515static char *check_rev; 2516char * 2517RCS_magicrev (rcs, rev) 2518 RCSNode *rcs; 2519 char *rev; 2520{ 2521 int rev_num; 2522 char *xrev, *test_branch, *local_branch_num; 2523 2524 xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */ 2525 check_rev = xrev; 2526 2527 local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM"); 2528 if (local_branch_num) 2529 { 2530 rev_num = atoi(local_branch_num); 2531 if (rev_num < 2) 2532 rev_num = 2; 2533 else 2534 rev_num &= ~1; 2535 } 2536 else 2537 rev_num = 2; 2538 2539 /* only look at even numbered branches */ 2540 for ( ; ; rev_num += 2) 2541 { 2542 /* see if the physical branch exists */ 2543 (void) sprintf (xrev, "%s.%d", rev, rev_num); 2544 test_branch = RCS_getbranch (rcs, xrev, 1); 2545 if (test_branch != NULL) /* it did, so keep looking */ 2546 { 2547 free (test_branch); 2548 continue; 2549 } 2550 2551 /* now, create a "magic" revision */ 2552 (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num); 2553 2554 /* walk the symbols list to see if a magic one already exists */ 2555 if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0) 2556 continue; 2557 2558 /* we found a free magic branch. Claim it as ours */ 2559 return (xrev); 2560 } 2561} 2562 2563/* 2564 * walklist proc to look for a match in the symbols list. 2565 * Returns 0 if the symbol does not match, 1 if it does. 2566 */ 2567static int 2568checkmagic_proc (p, closure) 2569 Node *p; 2570 void *closure; 2571{ 2572 if (STREQ (check_rev, p->data)) 2573 return (1); 2574 else 2575 return (0); 2576} 2577 2578/* 2579 * Given an RCSNode, returns non-zero if the specified revision number 2580 * or symbolic tag resolves to a "branch" within the rcs file. 2581 * 2582 * FIXME: this is the same as RCS_nodeisbranch except for the special 2583 * case for handling a null rcsnode. 2584 */ 2585int 2586RCS_isbranch (rcs, rev) 2587 RCSNode *rcs; 2588 const char *rev; 2589{ 2590 /* numeric revisions are easy -- even number of dots is a branch */ 2591 if (isdigit ((unsigned char) *rev)) 2592 return ((numdots (rev) & 1) == 0); 2593 2594 /* assume a revision if you can't find the RCS info */ 2595 if (rcs == NULL) 2596 return (0); 2597 2598 /* now, look for a match in the symbols list */ 2599 return (RCS_nodeisbranch (rcs, rev)); 2600} 2601 2602/* 2603 * Given an RCSNode, returns non-zero if the specified revision number 2604 * or symbolic tag resolves to a "branch" within the rcs file. We do 2605 * take into account any magic branches as well. 2606 */ 2607int 2608RCS_nodeisbranch (rcs, rev) 2609 RCSNode *rcs; 2610 const char *rev; 2611{ 2612 int dots; 2613 char *version; 2614 2615 assert (rcs != NULL); 2616 2617 /* numeric revisions are easy -- even number of dots is a branch */ 2618 if (isdigit ((unsigned char) *rev)) 2619 return ((numdots (rev) & 1) == 0); 2620 2621 version = translate_symtag (rcs, rev); 2622 if (version == NULL) 2623 return (0); 2624 dots = numdots (version); 2625 if ((dots & 1) == 0) 2626 { 2627 free (version); 2628 return (1); 2629 } 2630 2631 /* got a symbolic tag match, but it's not a branch; see if it's magic */ 2632 if (dots > 2) 2633 { 2634 char *magic; 2635 char *branch = strrchr (version, '.'); 2636 char *cp = branch - 1; 2637 while (*cp != '.') 2638 cp--; 2639 2640 /* see if we have .magic-branch. (".0.") */ 2641 magic = xmalloc (strlen (version) + 1); 2642 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); 2643 if (strncmp (magic, cp, strlen (magic)) == 0) 2644 { 2645 free (magic); 2646 free (version); 2647 return (1); 2648 } 2649 free (magic); 2650 } 2651 free (version); 2652 return (0); 2653} 2654 2655/* 2656 * Returns a pointer to malloc'ed memory which contains the branch 2657 * for the specified *symbolic* tag. Magic branches are handled correctly. 2658 */ 2659char * 2660RCS_whatbranch (rcs, rev) 2661 RCSNode *rcs; 2662 const char *rev; 2663{ 2664 char *version; 2665 int dots; 2666 2667 /* assume no branch if you can't find the RCS info */ 2668 if (rcs == NULL) 2669 return ((char *) NULL); 2670 2671 /* now, look for a match in the symbols list */ 2672 version = translate_symtag (rcs, rev); 2673 if (version == NULL) 2674 return ((char *) NULL); 2675 dots = numdots (version); 2676 if ((dots & 1) == 0) 2677 return (version); 2678 2679 /* got a symbolic tag match, but it's not a branch; see if it's magic */ 2680 if (dots > 2) 2681 { 2682 char *magic; 2683 char *branch = strrchr (version, '.'); 2684 char *cp = branch++ - 1; 2685 while (*cp != '.') 2686 cp--; 2687 2688 /* see if we have .magic-branch. (".0.") */ 2689 magic = xmalloc (strlen (version) + 1); 2690 (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); 2691 if (strncmp (magic, cp, strlen (magic)) == 0) 2692 { 2693 /* yep. it's magic. now, construct the real branch */ 2694 *cp = '\0'; /* turn it into a revision */ 2695 (void) sprintf (magic, "%s.%s", version, branch); 2696 free (version); 2697 return (magic); 2698 } 2699 free (magic); 2700 } 2701 free (version); 2702 return ((char *) NULL); 2703} 2704 2705/* 2706 * Get the head of the specified branch. If the branch does not exist, 2707 * return NULL or RCS_head depending on force_tag_match. 2708 * Returns NULL or a newly malloc'd string. 2709 */ 2710char * 2711RCS_getbranch (rcs, tag, force_tag_match) 2712 RCSNode *rcs; 2713 const char *tag; 2714 int force_tag_match; 2715{ 2716 Node *p, *head; 2717 RCSVers *vn; 2718 char *xtag; 2719 char *nextvers; 2720 char *cp; 2721 2722 /* make sure we have something to look at... */ 2723 assert (rcs != NULL); 2724 2725 if (rcs->flags & PARTIAL) 2726 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 2727 2728 /* find out if the tag contains a dot, or is on the trunk */ 2729 cp = strrchr (tag, '.'); 2730 2731 /* trunk processing is the special case */ 2732 if (cp == NULL) 2733 { 2734 xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */ 2735 (void) strcpy (xtag, tag); 2736 (void) strcat (xtag, "."); 2737 for (cp = rcs->head; cp != NULL;) 2738 { 2739 if (strncmp (xtag, cp, strlen (xtag)) == 0) 2740 break; 2741 p = findnode (rcs->versions, cp); 2742 if (p == NULL) 2743 { 2744 free (xtag); 2745 if (force_tag_match) 2746 return (NULL); 2747 else 2748 return (RCS_head (rcs)); 2749 } 2750 vn = p->data; 2751 cp = vn->next; 2752 } 2753 free (xtag); 2754 if (cp == NULL) 2755 { 2756 if (force_tag_match) 2757 return (NULL); 2758 else 2759 return (RCS_head (rcs)); 2760 } 2761 return (xstrdup (cp)); 2762 } 2763 2764 /* if it had a `.', terminate the string so we have the base revision */ 2765 *cp = '\0'; 2766 2767 /* look up the revision this branch is based on */ 2768 p = findnode (rcs->versions, tag); 2769 2770 /* put the . back so we have the branch again */ 2771 *cp = '.'; 2772 2773 if (p == NULL) 2774 { 2775 /* if the base revision didn't exist, return head or NULL */ 2776 if (force_tag_match) 2777 return (NULL); 2778 else 2779 return (RCS_head (rcs)); 2780 } 2781 2782 /* find the first element of the branch we are looking for */ 2783 vn = p->data; 2784 if (vn->branches == NULL) 2785 return (NULL); 2786 xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */ 2787 (void) strcpy (xtag, tag); 2788 (void) strcat (xtag, "."); 2789 head = vn->branches->list; 2790 for (p = head->next; p != head; p = p->next) 2791 if (strncmp (p->key, xtag, strlen (xtag)) == 0) 2792 break; 2793 free (xtag); 2794 2795 if (p == head) 2796 { 2797 /* we didn't find a match so return head or NULL */ 2798 if (force_tag_match) 2799 return (NULL); 2800 else 2801 return (RCS_head (rcs)); 2802 } 2803 2804 /* now walk the next pointers of the branch */ 2805 nextvers = p->key; 2806 do 2807 { 2808 p = findnode (rcs->versions, nextvers); 2809 if (p == NULL) 2810 { 2811 /* a link in the chain is missing - return head or NULL */ 2812 if (force_tag_match) 2813 return (NULL); 2814 else 2815 return (RCS_head (rcs)); 2816 } 2817 vn = p->data; 2818 nextvers = vn->next; 2819 } while (nextvers != NULL); 2820 2821 /* we have the version in our hand, so go for it */ 2822 return (xstrdup (vn->version)); 2823} 2824 2825/* Returns the head of the branch which REV is on. REV can be a 2826 branch tag or non-branch tag; symbolic or numeric. 2827 2828 Returns a newly malloc'd string. Returns NULL if a symbolic name 2829 isn't found. */ 2830 2831char * 2832RCS_branch_head (rcs, rev) 2833 RCSNode *rcs; 2834 char *rev; 2835{ 2836 char *num; 2837 char *br; 2838 char *retval; 2839 2840 assert (rcs != NULL); 2841 2842 if (RCS_nodeisbranch (rcs, rev)) 2843 return RCS_getbranch (rcs, rev, 1); 2844 2845 if (isdigit ((unsigned char) *rev)) 2846 num = xstrdup (rev); 2847 else 2848 { 2849 num = translate_symtag (rcs, rev); 2850 if (num == NULL) 2851 return NULL; 2852 } 2853 br = truncate_revnum (num); 2854 retval = RCS_getbranch (rcs, br, 1); 2855 free (br); 2856 free (num); 2857 return retval; 2858} 2859 2860/* Get the branch point for a particular branch, that is the first 2861 revision on that branch. For example, RCS_getbranchpoint (rcs, 2862 "1.3.2") will normally return "1.3.2.1". TARGET may be either a 2863 branch number or a revision number; if a revnum, find the 2864 branchpoint of the branch to which TARGET belongs. 2865 2866 Return RCS_head if TARGET is on the trunk or if the root node could 2867 not be found (this is sort of backwards from our behavior on a branch; 2868 the rationale is that the return value is a revision from which you 2869 can start walking the next fields and end up at TARGET). 2870 Return NULL on error. */ 2871 2872static char * 2873RCS_getbranchpoint (rcs, target) 2874 RCSNode *rcs; 2875 char *target; 2876{ 2877 char *branch, *bp; 2878 Node *vp; 2879 RCSVers *rev; 2880 int dots, isrevnum, brlen; 2881 2882 dots = numdots (target); 2883 isrevnum = dots & 1; 2884 2885 if (dots == 1) 2886 /* TARGET is a trunk revision; return rcs->head. */ 2887 return (RCS_head (rcs)); 2888 2889 /* Get the revision number of the node at which TARGET's branch is 2890 rooted. If TARGET is a branch number, lop off the last field; 2891 if it's a revision number, lop off the last *two* fields. */ 2892 branch = xstrdup (target); 2893 bp = strrchr (branch, '.'); 2894 if (bp == NULL) 2895 error (1, 0, "%s: confused revision number %s", 2896 rcs->path, target); 2897 if (isrevnum) 2898 while (*--bp != '.') 2899 ; 2900 *bp = '\0'; 2901 2902 vp = findnode (rcs->versions, branch); 2903 if (vp == NULL) 2904 { 2905 error (0, 0, "%s: can't find branch point %s", rcs->path, target); 2906 free (branch); 2907 return NULL; 2908 } 2909 rev = vp->data; 2910 2911 *bp++ = '.'; 2912 while (*bp && *bp != '.') 2913 ++bp; 2914 brlen = bp - branch; 2915 2916 vp = rev->branches->list->next; 2917 while (vp != rev->branches->list) 2918 { 2919 /* BRANCH may be a genuine branch number, e.g. `1.1.3', or 2920 maybe a full revision number, e.g. `1.1.3.6'. We have 2921 found our branch point if the first BRANCHLEN characters 2922 of the revision number match, *and* if the following 2923 character is a dot. */ 2924 if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.') 2925 break; 2926 vp = vp->next; 2927 } 2928 2929 free (branch); 2930 if (vp == rev->branches->list) 2931 { 2932 error (0, 0, "%s: can't find branch point %s", rcs->path, target); 2933 return NULL; 2934 } 2935 else 2936 return (xstrdup (vp->key)); 2937} 2938 2939/* 2940 * Get the head of the RCS file. If branch is set, this is the head of the 2941 * branch, otherwise the real head. 2942 * Returns NULL or a newly malloc'd string. 2943 */ 2944char * 2945RCS_head (rcs) 2946 RCSNode *rcs; 2947{ 2948 /* make sure we have something to look at... */ 2949 assert (rcs != NULL); 2950 2951 /* 2952 * NOTE: we call getbranch with force_tag_match set to avoid any 2953 * possibility of recursion 2954 */ 2955 if (rcs->branch) 2956 return (RCS_getbranch (rcs, rcs->branch, 1)); 2957 else 2958 return (xstrdup (rcs->head)); 2959} 2960 2961/* 2962 * Get the most recent revision, based on the supplied date, but use some 2963 * funky stuff and follow the vendor branch maybe 2964 */ 2965char * 2966RCS_getdate (rcs, date, force_tag_match) 2967 RCSNode *rcs; 2968 const char *date; 2969 int force_tag_match; 2970{ 2971 char *cur_rev = NULL; 2972 char *retval = NULL; 2973 Node *p; 2974 RCSVers *vers = NULL; 2975 2976 /* make sure we have something to look at... */ 2977 assert (rcs != NULL); 2978 2979 if (rcs->flags & PARTIAL) 2980 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 2981 2982 /* if the head is on a branch, try the branch first */ 2983 if (rcs->branch != NULL) 2984 { 2985 retval = RCS_getdatebranch (rcs, date, rcs->branch); 2986 if (retval != NULL) 2987 return (retval); 2988 } 2989 2990 /* otherwise if we have a trunk, try it */ 2991 if (rcs->head) 2992 { 2993 p = findnode (rcs->versions, rcs->head); 2994 if (p == NULL) 2995 { 2996 error (0, 0, "%s: head revision %s doesn't exist", rcs->path, 2997 rcs->head); 2998 } 2999 while (p != NULL) 3000 { 3001 /* if the date of this one is before date, take it */ 3002 vers = p->data; 3003 if (RCS_datecmp (vers->date, date) <= 0) 3004 { 3005 cur_rev = vers->version; 3006 break; 3007 } 3008 3009 /* if there is a next version, find the node */ 3010 if (vers->next != NULL) 3011 p = findnode (rcs->versions, vers->next); 3012 else 3013 p = (Node *) NULL; 3014 } 3015 } 3016 else 3017 error (0, 0, "%s: no head revision", rcs->path); 3018 3019 /* 3020 * at this point, either we have the revision we want, or we have the 3021 * first revision on the trunk (1.1?) in our hands, or we've come up 3022 * completely empty 3023 */ 3024 3025 /* if we found what we're looking for, and it's not 1.1 return it */ 3026 if (cur_rev != NULL) 3027 { 3028 if (! STREQ (cur_rev, "1.1")) 3029 return (xstrdup (cur_rev)); 3030 3031 /* This is 1.1; if the date of 1.1 is not the same as that for the 3032 1.1.1.1 version, then return 1.1. This happens when the first 3033 version of a file is created by a regular cvs add and commit, 3034 and there is a subsequent cvs import of the same file. */ 3035 p = findnode (rcs->versions, "1.1.1.1"); 3036 if (p) 3037 { 3038 char *date_1_1 = vers->date; 3039 3040 assert (p->data != NULL); 3041 3042 vers = p->data; 3043 if (RCS_datecmp (vers->date, date_1_1) != 0) 3044 return xstrdup ("1.1"); 3045 } 3046 } 3047 3048 /* look on the vendor branch */ 3049 retval = RCS_getdatebranch (rcs, date, CVSBRANCH); 3050 3051 /* 3052 * if we found a match, return it; otherwise, we return the first 3053 * revision on the trunk or NULL depending on force_tag_match and the 3054 * date of the first rev 3055 */ 3056 if (retval != NULL) 3057 return (retval); 3058 3059 if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)) 3060 return xstrdup (vers->version); 3061 else 3062 return NULL; 3063} 3064 3065 3066 3067/* 3068 * Look up the last element on a branch that was put in before the specified 3069 * date (return the rev or NULL) 3070 */ 3071static char * 3072RCS_getdatebranch (rcs, date, branch) 3073 RCSNode *rcs; 3074 const char *date; 3075 const char *branch; 3076{ 3077 char *cur_rev = NULL; 3078 char *cp; 3079 char *xbranch, *xrev; 3080 Node *p; 3081 RCSVers *vers; 3082 3083 /* look up the first revision on the branch */ 3084 xrev = xstrdup (branch); 3085 cp = strrchr (xrev, '.'); 3086 if (cp == NULL) 3087 { 3088 free (xrev); 3089 return (NULL); 3090 } 3091 *cp = '\0'; /* turn it into a revision */ 3092 3093 assert (rcs != NULL); 3094 3095 if (rcs->flags & PARTIAL) 3096 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3097 3098 p = findnode (rcs->versions, xrev); 3099 free (xrev); 3100 if (p == NULL) 3101 return (NULL); 3102 vers = p->data; 3103 3104 /* Tentatively use this revision, if it is early enough. */ 3105 if (RCS_datecmp (vers->date, date) <= 0) 3106 cur_rev = vers->version; 3107 3108 /* If no branches list, return now. This is what happens if the branch 3109 is a (magic) branch with no revisions yet. */ 3110 if (vers->branches == NULL) 3111 return xstrdup (cur_rev); 3112 3113 /* walk the branches list looking for the branch number */ 3114 xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */ 3115 (void) strcpy (xbranch, branch); 3116 (void) strcat (xbranch, "."); 3117 for (p = vers->branches->list->next; p != vers->branches->list; p = p->next) 3118 if (strncmp (p->key, xbranch, strlen (xbranch)) == 0) 3119 break; 3120 free (xbranch); 3121 if (p == vers->branches->list) 3122 { 3123 /* This is what happens if the branch is a (magic) branch with 3124 no revisions yet. Similar to the case where vers->branches == 3125 NULL, except here there was a another branch off the same 3126 branchpoint. */ 3127 return xstrdup (cur_rev); 3128 } 3129 3130 p = findnode (rcs->versions, p->key); 3131 3132 /* walk the next pointers until you find the end, or the date is too late */ 3133 while (p != NULL) 3134 { 3135 vers = p->data; 3136 if (RCS_datecmp (vers->date, date) <= 0) 3137 cur_rev = vers->version; 3138 else 3139 break; 3140 3141 /* if there is a next version, find the node */ 3142 if (vers->next != NULL) 3143 p = findnode (rcs->versions, vers->next); 3144 else 3145 p = (Node *) NULL; 3146 } 3147 3148 /* Return whatever we found, which may be NULL. */ 3149 return xstrdup (cur_rev); 3150} 3151 3152 3153 3154/* 3155 * Compare two dates in RCS format. Beware the change in format on January 1, 3156 * 2000, when years go from 2-digit to full format. 3157 */ 3158int 3159RCS_datecmp (date1, date2) 3160 const char *date1, *date2; 3161{ 3162 int length_diff = strlen (date1) - strlen (date2); 3163 3164 return length_diff ? length_diff : strcmp (date1, date2); 3165} 3166 3167 3168 3169/* Look up revision REV in RCS and return the date specified for the 3170 revision minus FUDGE seconds (FUDGE will generally be one, so that the 3171 logically previous revision will be found later, or zero, if we want 3172 the exact date). 3173 3174 The return value is the date being returned as a time_t, or (time_t)-1 3175 on error (previously was documented as zero on error; I haven't checked 3176 the callers to make sure that they really check for (time_t)-1, but 3177 the latter is what this function really returns). If DATE is non-NULL, 3178 then it must point to MAXDATELEN characters, and we store the same 3179 return value there in DATEFORM format. */ 3180time_t 3181RCS_getrevtime (rcs, rev, date, fudge) 3182 RCSNode *rcs; 3183 const char *rev; 3184 char *date; 3185 int fudge; 3186{ 3187 char tdate[MAXDATELEN]; 3188 struct tm xtm, *ftm; 3189 time_t revdate = 0; 3190 Node *p; 3191 RCSVers *vers; 3192 3193 /* make sure we have something to look at... */ 3194 assert (rcs != NULL); 3195 3196 if (rcs->flags & PARTIAL) 3197 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3198 3199 /* look up the revision */ 3200 p = findnode (rcs->versions, rev); 3201 if (p == NULL) 3202 return (-1); 3203 vers = p->data; 3204 3205 /* split up the date */ 3206 if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon, 3207 &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6) 3208 error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path, 3209 rev, vers->date); 3210 3211 /* If the year is from 1900 to 1999, RCS files contain only two 3212 digits, and sscanf gives us a year from 0-99. If the year is 3213 2000+, RCS files contain all four digits and we subtract 1900, 3214 because the tm_year field should contain years since 1900. */ 3215 3216 if (xtm.tm_year >= 100 && xtm.tm_year < 2000) 3217 error (0, 0, "%s: non-standard date format for revision %s (%s)", 3218 rcs->path, rev, vers->date); 3219 if (xtm.tm_year >= 1900) 3220 xtm.tm_year -= 1900; 3221 3222 /* put the date in a form getdate can grok */ 3223 (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon, 3224 xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour, 3225 xtm.tm_min, xtm.tm_sec); 3226 3227 /* turn it into seconds since the epoch */ 3228 revdate = get_date (tdate, (struct timeb *) NULL); 3229 if (revdate != (time_t) -1) 3230 { 3231 revdate -= fudge; /* remove "fudge" seconds */ 3232 if (date) 3233 { 3234 /* put an appropriate string into ``date'' if we were given one */ 3235 ftm = gmtime (&revdate); 3236 (void) sprintf (date, DATEFORM, 3237 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 3238 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 3239 ftm->tm_min, ftm->tm_sec); 3240 } 3241 } 3242 return revdate; 3243} 3244 3245List * 3246RCS_getlocks (rcs) 3247 RCSNode *rcs; 3248{ 3249 assert(rcs != NULL); 3250 3251 if (rcs->flags & PARTIAL) 3252 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3253 3254 if (rcs->locks_data) { 3255 rcs->locks = getlist (); 3256 do_locks (rcs->locks, rcs->locks_data); 3257 free(rcs->locks_data); 3258 rcs->locks_data = NULL; 3259 } 3260 3261 return rcs->locks; 3262} 3263 3264List * 3265RCS_symbols(rcs) 3266 RCSNode *rcs; 3267{ 3268 assert(rcs != NULL); 3269 3270 if (rcs->flags & PARTIAL) 3271 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3272 3273 if (rcs->symbols_data) { 3274 rcs->symbols = getlist (); 3275 do_symbols (rcs->symbols, rcs->symbols_data); 3276 free(rcs->symbols_data); 3277 rcs->symbols_data = NULL; 3278 } 3279 3280 return rcs->symbols; 3281} 3282 3283/* 3284 * Return the version associated with a particular symbolic tag. 3285 * Returns NULL or a newly malloc'd string. 3286 */ 3287static char * 3288translate_symtag (rcs, tag) 3289 RCSNode *rcs; 3290 const char *tag; 3291{ 3292 if (rcs->flags & PARTIAL) 3293 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3294 3295 if (rcs->symbols != NULL) 3296 { 3297 Node *p; 3298 3299 /* The symbols have already been converted into a list. */ 3300 p = findnode (rcs->symbols, tag); 3301 if (p == NULL) 3302 return NULL; 3303 3304 return xstrdup (p->data); 3305 } 3306 3307 if (rcs->symbols_data != NULL) 3308 { 3309 size_t len; 3310 char *cp, *last; 3311 3312 /* Look through the RCS symbols information. This is like 3313 do_symbols, but we don't add the information to a list. In 3314 most cases, we will only be called once for this file, so 3315 generating the list is unnecessary overhead. */ 3316 3317 len = strlen (tag); 3318 cp = rcs->symbols_data; 3319 /* Keeping track of LAST below isn't strictly necessary, now that tags 3320 * should be parsed for validity before they are accepted, but tags 3321 * with spaces used to cause the code below to loop indefintely, so 3322 * I have corrected for that. Now, in the event that I missed 3323 * something, the server cannot be hung. -DRP 3324 */ 3325 last = NULL; 3326 while ((cp = strchr (cp, tag[0])) != NULL) 3327 { 3328 if (cp == last) break; 3329 if ((cp == rcs->symbols_data || whitespace (cp[-1])) 3330 && strncmp (cp, tag, len) == 0 3331 && cp[len] == ':') 3332 { 3333 char *v, *r; 3334 3335 /* We found the tag. Return the version number. */ 3336 3337 cp += len + 1; 3338 v = cp; 3339 while (! whitespace (*cp) && *cp != '\0') 3340 ++cp; 3341 r = xmalloc (cp - v + 1); 3342 strncpy (r, v, cp - v); 3343 r[cp - v] = '\0'; 3344 return r; 3345 } 3346 3347 while (! whitespace (*cp) && *cp != '\0') 3348 ++cp; 3349 if (*cp == '\0') 3350 break; 3351 last = cp; 3352 } 3353 } 3354 3355 return NULL; 3356} 3357 3358/* 3359 * The argument ARG is the getopt remainder of the -k option specified on the 3360 * command line. This function returns malloc'ed space that can be used 3361 * directly in calls to RCS V5, with the -k flag munged correctly. 3362 */ 3363char * 3364RCS_check_kflag (arg) 3365 const char *arg; 3366{ 3367 static const char *const keyword_usage[] = 3368 { 3369 "%s %s: invalid RCS keyword expansion mode\n", 3370 "Valid expansion modes include:\n", 3371 " -kkv\tGenerate keywords using the default form.\n", 3372 " -kkvl\tLike -kkv, except locker's name inserted.\n", 3373 " -kk\tGenerate only keyword names in keyword strings.\n", 3374 " -kv\tGenerate only keyword values in keyword strings.\n", 3375 " -ko\tGenerate the old keyword string (no changes from checked in file).\n", 3376 " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n", 3377 "(Specify the --help global option for a list of other help options)\n", 3378 NULL, 3379 }; 3380 /* Big enough to hold any of the strings from kflags. */ 3381 char karg[10]; 3382 char const *const *cpp = NULL; 3383 3384 if (arg) 3385 { 3386 for (cpp = kflags; *cpp != NULL; cpp++) 3387 { 3388 if (STREQ (arg, *cpp)) 3389 break; 3390 } 3391 } 3392 3393 if (arg == NULL || *cpp == NULL) 3394 { 3395 usage (keyword_usage); 3396 } 3397 3398 (void) sprintf (karg, "-k%s", *cpp); 3399 return (xstrdup (karg)); 3400} 3401 3402/* 3403 * Do some consistency checks on the symbolic tag... These should equate 3404 * pretty close to what RCS checks, though I don't know for certain. 3405 */ 3406void 3407RCS_check_tag (tag) 3408 const char *tag; 3409{ 3410 char *invalid = "$,.:;@"; /* invalid RCS tag characters */ 3411 const char *cp; 3412 3413 /* 3414 * The first character must be an alphabetic letter. The remaining 3415 * characters cannot be non-visible graphic characters, and must not be 3416 * in the set of "invalid" RCS identifier characters. 3417 */ 3418 if (isalpha ((unsigned char) *tag)) 3419 { 3420 for (cp = tag; *cp; cp++) 3421 { 3422 if (!isgraph ((unsigned char) *cp)) 3423 error (1, 0, "tag `%s' has non-visible graphic characters", 3424 tag); 3425 if (strchr (invalid, *cp)) 3426 error (1, 0, "tag `%s' must not contain the characters `%s'", 3427 tag, invalid); 3428 } 3429 } 3430 else 3431 error (1, 0, "tag `%s' must start with a letter", tag); 3432} 3433 3434/* 3435 * TRUE if argument has valid syntax for an RCS revision or 3436 * branch number. All characters must be digits or dots, first 3437 * and last characters must be digits, and no two consecutive 3438 * characters may be dots. 3439 * 3440 * Intended for classifying things, so this function doesn't 3441 * call error. 3442 */ 3443int 3444RCS_valid_rev (rev) 3445 char *rev; 3446{ 3447 char last, c; 3448 last = *rev++; 3449 if (!isdigit ((unsigned char) last)) 3450 return 0; 3451 while ((c = *rev++)) /* Extra parens placate -Wall gcc option */ 3452 { 3453 if (c == '.') 3454 { 3455 if (last == '.') 3456 return 0; 3457 continue; 3458 } 3459 last = c; 3460 if (!isdigit ((unsigned char) c)) 3461 return 0; 3462 } 3463 if (!isdigit ((unsigned char) last)) 3464 return 0; 3465 return 1; 3466} 3467 3468/* 3469 * Return true if RCS revision with TAG is a dead revision. 3470 */ 3471int 3472RCS_isdead (rcs, tag) 3473 RCSNode *rcs; 3474 const char *tag; 3475{ 3476 Node *p; 3477 RCSVers *version; 3478 3479 assert (rcs != NULL); 3480 3481 if (rcs->flags & PARTIAL) 3482 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 3483 3484 p = findnode (rcs->versions, tag); 3485 if (p == NULL) 3486 return (0); 3487 3488 version = p->data; 3489 return (version->dead); 3490} 3491 3492/* Return the RCS keyword expansion mode. For example "b" for binary. 3493 Returns a pointer into storage which is allocated and freed along with 3494 the rest of the RCS information; the caller should not modify this 3495 storage. Returns NULL if the RCS file does not specify a keyword 3496 expansion mode; for all other errors, die with a fatal error. */ 3497char * 3498RCS_getexpand (rcs) 3499 RCSNode *rcs; 3500{ 3501 /* Since RCS_parsercsfile_i now reads expand, don't need to worry 3502 about RCS_reparsercsfile. */ 3503 assert (rcs != NULL); 3504 return rcs->expand; 3505} 3506 3507/* Set keyword expansion mode to EXPAND. For example "b" for binary. */ 3508void 3509RCS_setexpand (rcs, expand) 3510 RCSNode *rcs; 3511 const char *expand; 3512{ 3513 /* Since RCS_parsercsfile_i now reads expand, don't need to worry 3514 about RCS_reparsercsfile. */ 3515 assert (rcs != NULL); 3516 if (rcs->expand != NULL) 3517 free (rcs->expand); 3518 rcs->expand = xstrdup (expand); 3519} 3520 3521/* RCS keywords, and a matching enum. */ 3522struct rcs_keyword 3523{ 3524 const char *string; 3525 size_t len; 3526 int expandit; 3527}; 3528#define KEYWORD_INIT(s) (s), sizeof (s) - 1 3529static struct rcs_keyword keywords[] = 3530{ 3531 { KEYWORD_INIT ("Author"), 1 }, 3532 { KEYWORD_INIT ("Date"), 1 }, 3533 { KEYWORD_INIT ("CVSHeader"), 1 }, 3534 { KEYWORD_INIT ("Header"), 1 }, 3535 { KEYWORD_INIT ("Id"), 1 }, 3536 { KEYWORD_INIT ("Locker"), 1 }, 3537 { KEYWORD_INIT ("Log"), 1 }, 3538 { KEYWORD_INIT ("Name"), 1 }, 3539 { KEYWORD_INIT ("RCSfile"), 1 }, 3540 { KEYWORD_INIT ("Revision"), 1 }, 3541 { KEYWORD_INIT ("Source"), 1 }, 3542 { KEYWORD_INIT ("State"), 1 }, 3543 { NULL, 0, 0 }, 3544 { NULL, 0, 0 } 3545}; 3546enum keyword 3547{ 3548 KEYWORD_AUTHOR = 0, 3549 KEYWORD_DATE, 3550 KEYWORD_CVSHEADER, 3551 KEYWORD_HEADER, 3552 KEYWORD_ID, 3553 KEYWORD_LOCKER, 3554 KEYWORD_LOG, 3555 KEYWORD_NAME, 3556 KEYWORD_RCSFILE, 3557 KEYWORD_REVISION, 3558 KEYWORD_SOURCE, 3559 KEYWORD_STATE, 3560 KEYWORD_LOCALID 3561}; 3562enum keyword keyword_local = KEYWORD_ID; 3563 3564/* Convert an RCS date string into a readable string. This is like 3565 the RCS date2str function. */ 3566 3567static char * 3568printable_date (rcs_date) 3569 const char *rcs_date; 3570{ 3571 int year, mon, mday, hour, min, sec; 3572 char buf[100]; 3573 3574 (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min, 3575 &sec); 3576 if (year < 1900) 3577 year += 1900; 3578 sprintf (buf, "%04d%c%02d%c%02d %02d:%02d:%02d", 3579 year, datesep, mon, datesep, mday, hour, min, sec); 3580 return xstrdup (buf); 3581} 3582 3583/* Escape the characters in a string so that it can be included in an 3584 RCS value. */ 3585 3586static char * 3587escape_keyword_value (value, free_value) 3588 const char *value; 3589 int *free_value; 3590{ 3591 char *ret, *t; 3592 const char *s; 3593 3594 for (s = value; *s != '\0'; s++) 3595 { 3596 char c; 3597 3598 c = *s; 3599 if (c == '\t' 3600 || c == '\n' 3601 || c == '\\' 3602 || c == ' ' 3603 || c == '$') 3604 { 3605 break; 3606 } 3607 } 3608 3609 if (*s == '\0') 3610 { 3611 *free_value = 0; 3612 return (char *) value; 3613 } 3614 3615 ret = xmalloc (strlen (value) * 4 + 1); 3616 *free_value = 1; 3617 3618 for (s = value, t = ret; *s != '\0'; s++, t++) 3619 { 3620 switch (*s) 3621 { 3622 default: 3623 *t = *s; 3624 break; 3625 case '\t': 3626 *t++ = '\\'; 3627 *t = 't'; 3628 break; 3629 case '\n': 3630 *t++ = '\\'; 3631 *t = 'n'; 3632 break; 3633 case '\\': 3634 *t++ = '\\'; 3635 *t = '\\'; 3636 break; 3637 case ' ': 3638 *t++ = '\\'; 3639 *t++ = '0'; 3640 *t++ = '4'; 3641 *t = '0'; 3642 break; 3643 case '$': 3644 *t++ = '\\'; 3645 *t++ = '0'; 3646 *t++ = '4'; 3647 *t = '4'; 3648 break; 3649 } 3650 } 3651 3652 *t = '\0'; 3653 3654 return ret; 3655} 3656 3657/* Expand RCS keywords in the memory buffer BUF of length LEN. This 3658 applies to file RCS and version VERS. If NAME is not NULL, and is 3659 not a numeric revision, then it is the symbolic tag used for the 3660 checkout. EXPAND indicates how to expand the keywords. This 3661 function sets *RETBUF and *RETLEN to the new buffer and length. 3662 This function may modify the buffer BUF. If BUF != *RETBUF, then 3663 RETBUF is a newly allocated buffer. */ 3664 3665static void 3666expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) 3667 RCSNode *rcs; 3668 RCSVers *ver; 3669 const char *name; 3670 const char *log; 3671 size_t loglen; 3672 enum kflag expand; 3673 char *buf; 3674 size_t len; 3675 char **retbuf; 3676 size_t *retlen; 3677{ 3678 struct expand_buffer 3679 { 3680 struct expand_buffer *next; 3681 char *data; 3682 size_t len; 3683 int free_data; 3684 } *ebufs = NULL; 3685 struct expand_buffer *ebuf_last = NULL; 3686 size_t ebuf_len = 0; 3687 char *locker; 3688 char *srch, *srch_next; 3689 size_t srch_len; 3690 3691 if (expand == KFLAG_O || expand == KFLAG_B) 3692 { 3693 *retbuf = buf; 3694 *retlen = len; 3695 return; 3696 } 3697 3698 /* If we are using -kkvl, dig out the locker information if any. */ 3699 locker = NULL; 3700 if (expand == KFLAG_KVL) 3701 { 3702 Node *lock; 3703 lock = findnode (RCS_getlocks(rcs), ver->version); 3704 if (lock != NULL) 3705 locker = xstrdup (lock->data); 3706 } 3707 3708 /* RCS keywords look like $STRING$ or $STRING: VALUE$. */ 3709 srch = buf; 3710 srch_len = len; 3711 while ((srch_next = memchr (srch, '$', srch_len)) != NULL) 3712 { 3713 char *s, *send; 3714 size_t slen; 3715 const struct rcs_keyword *keyword; 3716 enum keyword kw; 3717 char *value; 3718 int free_value; 3719 char *sub; 3720 size_t sublen; 3721 3722 srch_len -= (srch_next + 1) - srch; 3723 srch = srch_next + 1; 3724 3725 /* Look for the first non alphabetic character after the '$'. */ 3726 send = srch + srch_len; 3727 for (s = srch; s < send; s++) 3728 if (! isalpha ((unsigned char) *s)) 3729 break; 3730 3731 /* If the first non alphabetic character is not '$' or ':', 3732 then this is not an RCS keyword. */ 3733 if (s == send || (*s != '$' && *s != ':')) 3734 continue; 3735 3736 /* See if this is one of the keywords. */ 3737 slen = s - srch; 3738 for (keyword = keywords; keyword->string != NULL; keyword++) 3739 { 3740 if (keyword->expandit 3741 && keyword->len == slen 3742 && strncmp (keyword->string, srch, slen) == 0) 3743 { 3744 break; 3745 } 3746 } 3747 if (keyword->string == NULL) 3748 continue; 3749 3750 kw = (enum keyword) (keyword - keywords); 3751 3752 /* If the keyword ends with a ':', then the old value consists 3753 of the characters up to the next '$'. If there is no '$' 3754 before the end of the line, though, then this wasn't an RCS 3755 keyword after all. */ 3756 if (*s == ':') 3757 { 3758 for (; s < send; s++) 3759 if (*s == '$' || *s == '\n') 3760 break; 3761 if (s == send || *s != '$') 3762 continue; 3763 } 3764 3765 /* At this point we must replace the string from SRCH to S 3766 with the expansion of the keyword KW. */ 3767 3768 /* Get the value to use. */ 3769 free_value = 0; 3770 if (expand == KFLAG_K) 3771 value = NULL; 3772 else 3773 { 3774 switch (kw) 3775 { 3776 default: 3777 abort (); 3778 3779 case KEYWORD_AUTHOR: 3780 value = ver->author; 3781 break; 3782 3783 case KEYWORD_DATE: 3784 value = printable_date (ver->date); 3785 free_value = 1; 3786 break; 3787 3788 case KEYWORD_CVSHEADER: 3789 case KEYWORD_HEADER: 3790 case KEYWORD_ID: 3791 case KEYWORD_LOCALID: 3792 { 3793 const char *path; 3794 int free_path; 3795 char *date; 3796 char *old_path; 3797 3798 old_path = NULL; 3799 if (kw == KEYWORD_HEADER || 3800 (kw == KEYWORD_LOCALID && 3801 keyword_local == KEYWORD_HEADER)) 3802 path = rcs->path; 3803 else if (kw == KEYWORD_CVSHEADER || 3804 (kw == KEYWORD_LOCALID && 3805 keyword_local == KEYWORD_CVSHEADER)) 3806 path = getfullCVSname(rcs->path, &old_path); 3807 else 3808 path = last_component (rcs->path); 3809 path = escape_keyword_value (path, &free_path); 3810 date = printable_date (ver->date); 3811 value = xmalloc (strlen (path) 3812 + strlen (ver->version) 3813 + strlen (date) 3814 + strlen (ver->author) 3815 + strlen (ver->state) 3816 + (locker == NULL ? 0 : strlen (locker)) 3817 + 20); 3818 3819 sprintf (value, "%s %s %s %s %s%s%s", 3820 path, ver->version, date, ver->author, 3821 ver->state, 3822 locker != NULL ? " " : "", 3823 locker != NULL ? locker : ""); 3824 if (free_path) 3825 /* If free_path is set then we know we allocated path 3826 * and we can discard the const. 3827 */ 3828 free ((char *)path); 3829 if (old_path) 3830 free (old_path); 3831 free (date); 3832 free_value = 1; 3833 } 3834 break; 3835 3836 case KEYWORD_LOCKER: 3837 value = locker; 3838 break; 3839 3840 case KEYWORD_LOG: 3841 case KEYWORD_RCSFILE: 3842 value = escape_keyword_value (last_component (rcs->path), 3843 &free_value); 3844 break; 3845 3846 case KEYWORD_NAME: 3847 if (name != NULL && ! isdigit ((unsigned char) *name)) 3848 value = (char *) name; 3849 else 3850 value = NULL; 3851 break; 3852 3853 case KEYWORD_REVISION: 3854 value = ver->version; 3855 break; 3856 3857 case KEYWORD_SOURCE: 3858 value = escape_keyword_value (rcs->path, &free_value); 3859 break; 3860 3861 case KEYWORD_STATE: 3862 value = ver->state; 3863 break; 3864 } 3865 } 3866 3867 sub = xmalloc (keyword->len 3868 + (value == NULL ? 0 : strlen (value)) 3869 + 10); 3870 if (expand == KFLAG_V) 3871 { 3872 /* Decrement SRCH and increment S to remove the $ 3873 characters. */ 3874 --srch; 3875 ++srch_len; 3876 ++s; 3877 sublen = 0; 3878 } 3879 else 3880 { 3881 strcpy (sub, keyword->string); 3882 sublen = strlen (keyword->string); 3883 if (expand != KFLAG_K) 3884 { 3885 sub[sublen] = ':'; 3886 sub[sublen + 1] = ' '; 3887 sublen += 2; 3888 } 3889 } 3890 if (value != NULL) 3891 { 3892 strcpy (sub + sublen, value); 3893 sublen += strlen (value); 3894 } 3895 if (expand != KFLAG_V && expand != KFLAG_K) 3896 { 3897 sub[sublen] = ' '; 3898 ++sublen; 3899 sub[sublen] = '\0'; 3900 } 3901 3902 if (free_value) 3903 free (value); 3904 3905 /* The Log keyword requires special handling. This behaviour 3906 is taken from RCS 5.7. The special log message is what RCS 3907 uses for ci -k. */ 3908 if (kw == KEYWORD_LOG 3909 && (sizeof "checked in with -k by " <= loglen 3910 || log == NULL 3911 || strncmp (log, "checked in with -k by ", 3912 sizeof "checked in with -k by " - 1) != 0)) 3913 { 3914 char *start; 3915 char *leader; 3916 size_t leader_len, leader_sp_len; 3917 const char *logend; 3918 const char *snl; 3919 int cnl; 3920 char *date; 3921 const char *sl; 3922 3923 /* We are going to insert the trailing $ ourselves, before 3924 the log message, so we must remove it from S, if we 3925 haven't done so already. */ 3926 if (expand != KFLAG_V) 3927 ++s; 3928 3929 /* CVS never has empty log messages, but old RCS files might. */ 3930 if (log == NULL) 3931 log = ""; 3932 3933 /* Find the start of the line. */ 3934 start = srch; 3935 while (start > buf && start[-1] != '\n') 3936 --start; 3937 3938 /* Copy the start of the line to use as a comment leader. */ 3939 leader_len = srch - start; 3940 if (expand != KFLAG_V) 3941 --leader_len; 3942 leader = xmalloc (leader_len); 3943 memcpy (leader, start, leader_len); 3944 leader_sp_len = leader_len; 3945 while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ') 3946 --leader_sp_len; 3947 3948 /* RCS does some checking for an old style of Log here, 3949 but we don't bother. RCS issues a warning if it 3950 changes anything. */ 3951 3952 /* Count the number of newlines in the log message so that 3953 we know how many copies of the leader we will need. */ 3954 cnl = 0; 3955 logend = log + loglen; 3956 for (snl = log; snl < logend; snl++) 3957 if (*snl == '\n') 3958 ++cnl; 3959 3960 /* If the log message did not end in a newline, increment 3961 * the newline count so we have space for the extra leader. 3962 * Failure to do so results in a buffer overrun. 3963 */ 3964 if (loglen && snl[-1] != '\n') 3965 ++cnl; 3966 3967 date = printable_date (ver->date); 3968 sub = xrealloc (sub, 3969 (sublen 3970 + sizeof "Revision" 3971 + strlen (ver->version) 3972 + strlen (date) 3973 + strlen (ver->author) 3974 + loglen 3975 /* Use CNL + 2 below: One leader for each log 3976 * line, plus the Revision/Author/Date line, 3977 * plus a trailing blank line. 3978 */ 3979 + (cnl + 2) * leader_len 3980 + 20)); 3981 if (expand != KFLAG_V) 3982 { 3983 sub[sublen] = '$'; 3984 ++sublen; 3985 } 3986 sub[sublen] = '\n'; 3987 ++sublen; 3988 memcpy (sub + sublen, leader, leader_len); 3989 sublen += leader_len; 3990 sprintf (sub + sublen, "Revision %s %s %s\n", 3991 ver->version, date, ver->author); 3992 sublen += strlen (sub + sublen); 3993 free (date); 3994 3995 sl = log; 3996 while (sl < logend) 3997 { 3998 if (*sl == '\n') 3999 { 4000 memcpy (sub + sublen, leader, leader_sp_len); 4001 sublen += leader_sp_len; 4002 sub[sublen] = '\n'; 4003 ++sublen; 4004 ++sl; 4005 } 4006 else 4007 { 4008 const char *slnl; 4009 4010 memcpy (sub + sublen, leader, leader_len); 4011 sublen += leader_len; 4012 for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl) 4013 ; 4014 if (slnl < logend) 4015 ++slnl; 4016 memcpy (sub + sublen, sl, slnl - sl); 4017 sublen += slnl - sl; 4018 if (slnl == logend && slnl[-1] != '\n') 4019 { 4020 /* There was no EOL at the end of the log message. Add 4021 * one. 4022 */ 4023 sub[sublen] = '\n'; 4024 ++sublen; 4025 } 4026 sl = slnl; 4027 } 4028 } 4029 4030 memcpy (sub + sublen, leader, leader_sp_len); 4031 sublen += leader_sp_len; 4032 4033 free (leader); 4034 } 4035 4036 /* Now SUB contains a string which is to replace the string 4037 from SRCH to S. SUBLEN is the length of SUB. */ 4038 4039 if (srch + sublen == s) 4040 { 4041 memcpy (srch, sub, sublen); 4042 free (sub); 4043 } 4044 else 4045 { 4046 struct expand_buffer *ebuf; 4047 4048 /* We need to change the size of the buffer. We build a 4049 list of expand_buffer structures. Each expand_buffer 4050 structure represents a portion of the final output. We 4051 concatenate them back into a single buffer when we are 4052 done. This minimizes the number of potentially large 4053 buffer copies we must do. */ 4054 4055 if (ebufs == NULL) 4056 { 4057 ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf); 4058 ebufs->next = NULL; 4059 ebufs->data = buf; 4060 ebufs->free_data = 0; 4061 ebuf_len = srch - buf; 4062 ebufs->len = ebuf_len; 4063 ebuf_last = ebufs; 4064 } 4065 else 4066 { 4067 assert (srch >= ebuf_last->data); 4068 assert (srch <= ebuf_last->data + ebuf_last->len); 4069 ebuf_len -= ebuf_last->len - (srch - ebuf_last->data); 4070 ebuf_last->len = srch - ebuf_last->data; 4071 } 4072 4073 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); 4074 ebuf->data = sub; 4075 ebuf->len = sublen; 4076 ebuf->free_data = 1; 4077 ebuf->next = NULL; 4078 ebuf_last->next = ebuf; 4079 ebuf_last = ebuf; 4080 ebuf_len += sublen; 4081 4082 ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); 4083 ebuf->data = s; 4084 ebuf->len = srch_len - (s - srch); 4085 ebuf->free_data = 0; 4086 ebuf->next = NULL; 4087 ebuf_last->next = ebuf; 4088 ebuf_last = ebuf; 4089 ebuf_len += srch_len - (s - srch); 4090 } 4091 4092 srch_len -= (s - srch); 4093 srch = s; 4094 } 4095 4096 if (locker != NULL) 4097 free (locker); 4098 4099 if (ebufs == NULL) 4100 { 4101 *retbuf = buf; 4102 *retlen = len; 4103 } 4104 else 4105 { 4106 char *ret; 4107 4108 ret = xmalloc (ebuf_len); 4109 *retbuf = ret; 4110 *retlen = ebuf_len; 4111 while (ebufs != NULL) 4112 { 4113 struct expand_buffer *next; 4114 4115 memcpy (ret, ebufs->data, ebufs->len); 4116 ret += ebufs->len; 4117 if (ebufs->free_data) 4118 free (ebufs->data); 4119 next = ebufs->next; 4120 free (ebufs); 4121 ebufs = next; 4122 } 4123 } 4124} 4125 4126 4127 4128/* Check out a revision from an RCS file. 4129 4130 If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero 4131 or more times with the contents of the file. CALLERDAT is passed, 4132 uninterpreted, to PFN. (The current code will always call PFN 4133 exactly once for a non empty file; however, the current code 4134 assumes that it can hold the entire file contents in memory, which 4135 is not a good assumption, and might change in the future). 4136 4137 Otherwise, if WORKFILE is not NULL, check out the revision to 4138 WORKFILE. However, if WORKFILE is not NULL, and noexec is set, 4139 then don't do anything. 4140 4141 Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If 4142 SOUT is RUN_TTY, then write the contents of the revision to 4143 standard output. When using SOUT, the output is generally a 4144 temporary file; don't bother to get the file modes correct. When 4145 NOEXEC is set, WORKFILEs are not written but SOUTs are. 4146 4147 REV is the numeric revision to check out. It may be NULL, which 4148 means to check out the head of the default branch. 4149 4150 If NAMETAG is not NULL, and is not a numeric revision, then it is 4151 the tag that should be used when expanding the RCS Name keyword. 4152 4153 OPTIONS is a string such as "-kb" or "-kv" for keyword expansion 4154 options. It may be NULL to use the default expansion mode of the 4155 file, typically "-kkv". 4156 4157 On an error which prevented checking out the file, either print a 4158 nonfatal error and return 1, or give a fatal error. On success, 4159 return 0. */ 4160 4161/* This function mimics the behavior of `rcs co' almost exactly. The 4162 chief difference is in its support for preserving file ownership, 4163 permissions, and special files across checkin and checkout -- see 4164 comments in RCS_checkin for some issues about this. -twp */ 4165 4166int 4167RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) 4168 RCSNode *rcs; 4169 const char *workfile; 4170 const char *rev; 4171 const char *nametag; 4172 const char *options; 4173 const char *sout; 4174 RCSCHECKOUTPROC pfn; 4175 void *callerdat; 4176{ 4177 int free_rev = 0; 4178 enum kflag expand; 4179 FILE *fp; 4180 FILE *ofp = NULL; 4181 struct stat sb; 4182 struct rcsbuffer rcsbuf; 4183 char *key; 4184 char *value; 4185 size_t len; 4186 int free_value = 0; 4187 char *log = NULL; 4188 size_t loglen = 0; 4189 Node *vp = NULL; 4190#ifdef PRESERVE_PERMISSIONS_SUPPORT 4191 uid_t rcs_owner = (uid_t) -1; 4192 gid_t rcs_group = (gid_t) -1; 4193 mode_t rcs_mode; 4194 int change_rcs_owner_or_group = 0; 4195 int change_rcs_mode = 0; 4196 int special_file = 0; 4197 unsigned long devnum_long; 4198 dev_t devnum = 0; 4199#endif 4200 4201 if (trace) 4202 { 4203 (void) fprintf (stderr, "%s-> RCS_checkout (%s, %s, %s, %s, %s)\n", 4204#ifdef SERVER_SUPPORT 4205 server_active ? "S" : " ", 4206#else 4207 "", 4208#endif 4209 rcs->path, 4210 rev != NULL ? rev : "", 4211 nametag != NULL ? nametag : "", 4212 options != NULL ? options : "", 4213 (pfn != NULL ? "(function)" 4214 : (workfile != NULL 4215 ? workfile 4216 : (sout != RUN_TTY ? sout : "(stdout)")))); 4217 } 4218 4219 assert (rev == NULL || isdigit ((unsigned char) *rev)); 4220 4221 if (noexec && !server_active && workfile != NULL) 4222 return 0; 4223 4224 assert (sout == RUN_TTY || workfile == NULL); 4225 assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL)); 4226 4227 /* Some callers, such as Checkin or remove_file, will pass us a 4228 branch. */ 4229 if (rev != NULL && (numdots (rev) & 1) == 0) 4230 { 4231 rev = RCS_getbranch (rcs, rev, 1); 4232 if (rev == NULL) 4233 error (1, 0, "internal error: bad branch tag in checkout"); 4234 free_rev = 1; 4235 } 4236 4237 if (rev == NULL || STREQ (rev, rcs->head)) 4238 { 4239 int gothead; 4240 4241 /* We want the head revision. Try to read it directly. */ 4242 4243 if (rcs->flags & PARTIAL) 4244 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4245 else 4246 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf); 4247 4248 gothead = 0; 4249 if (! rcsbuf_getrevnum (&rcsbuf, &key)) 4250 error (1, 0, "unexpected EOF reading %s", rcs->path); 4251 4252 if (!STREQ (rcs->head, key)) 4253 error (1, 0, "Expected head revision %s, found %s.", 4254 rcs->head, key); 4255 4256 while (rcsbuf_getkey (&rcsbuf, &key, &value)) 4257 { 4258 if (STREQ (key, "log")) 4259 { 4260 if (log) 4261 { 4262 error (0, 0, 4263"Duplicate log keyword found for head revision in RCS file."); 4264 free (log); 4265 } 4266 log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen); 4267 } 4268 else if (STREQ (key, "text")) 4269 { 4270 gothead = 1; 4271 break; 4272 } 4273 } 4274 4275 if (! gothead) 4276 { 4277 error (0, 0, "internal error: cannot find head text"); 4278 if (free_rev) 4279 /* It's okay to discard the const when free_rev is set, because 4280 * we know we allocated it in this function. 4281 */ 4282 free ((char *)rev); 4283 return 1; 4284 } 4285 4286 rcsbuf_valpolish (&rcsbuf, value, 0, &len); 4287 4288 if (fstat (fileno (fp), &sb) < 0) 4289 error (1, errno, "cannot fstat %s", rcs->path); 4290 4291 rcsbuf_cache (rcs, &rcsbuf); 4292 } 4293 else 4294 { 4295 struct rcsbuffer *rcsbufp; 4296 4297 /* It isn't the head revision of the trunk. We'll need to 4298 walk through the deltas. */ 4299 4300 fp = NULL; 4301 if (rcs->flags & PARTIAL) 4302 RCS_reparsercsfile (rcs, &fp, &rcsbuf); 4303 4304 if (fp == NULL) 4305 { 4306 /* If RCS_deltas didn't close the file, we could use fstat 4307 here too. Probably should change it thusly.... */ 4308 if (stat (rcs->path, &sb) < 0) 4309 error (1, errno, "cannot stat %s", rcs->path); 4310 rcsbufp = NULL; 4311 } 4312 else 4313 { 4314 if (fstat (fileno (fp), &sb) < 0) 4315 error (1, errno, "cannot fstat %s", rcs->path); 4316 rcsbufp = &rcsbuf; 4317 } 4318 4319 RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len, 4320 &log, &loglen); 4321 free_value = 1; 4322 } 4323 4324 /* If OPTIONS is NULL or the empty string, then the old code would 4325 invoke the RCS co program with no -k option, which means that 4326 co would use the string we have stored in rcs->expand. */ 4327 if ((options == NULL || options[0] == '\0') && rcs->expand == NULL) 4328 expand = KFLAG_KV; 4329 else 4330 { 4331 const char *ouroptions; 4332 const char * const *cpp; 4333 4334 if (options != NULL && options[0] != '\0') 4335 { 4336 assert (options[0] == '-' && options[1] == 'k'); 4337 ouroptions = options + 2; 4338 } 4339 else 4340 ouroptions = rcs->expand; 4341 4342 for (cpp = kflags; *cpp != NULL; cpp++) 4343 if (STREQ (*cpp, ouroptions)) 4344 break; 4345 4346 if (*cpp != NULL) 4347 expand = (enum kflag) (cpp - kflags); 4348 else 4349 { 4350 error (0, 0, 4351 "internal error: unsupported substitution string -k%s", 4352 ouroptions); 4353 expand = KFLAG_KV; 4354 } 4355 } 4356 4357#ifdef PRESERVE_PERMISSIONS_SUPPORT 4358 /* Handle special files and permissions, if that is desired. */ 4359 if (preserve_perms) 4360 { 4361 RCSVers *vers; 4362 Node *info; 4363 4364 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4365 if (vp == NULL) 4366 error (1, 0, "internal error: no revision information for %s", 4367 rev == NULL ? rcs->head : rev); 4368 vers = vp->data; 4369 4370 /* First we look for symlinks, which are simplest to handle. */ 4371 info = findnode (vers->other_delta, "symlink"); 4372 if (info != NULL) 4373 { 4374 char *dest; 4375 4376 if (pfn != NULL || (workfile == NULL && sout == RUN_TTY)) 4377 error (1, 0, "symbolic link %s:%s cannot be piped", 4378 rcs->path, vers->version); 4379 if (workfile == NULL) 4380 dest = sout; 4381 else 4382 dest = workfile; 4383 4384 /* Remove `dest', just in case. It's okay to get ENOENT here, 4385 since we just want the file not to be there. (TODO: decide 4386 whether it should be considered an error for `dest' to exist 4387 at this point. If so, the unlink call should be removed and 4388 `symlink' should signal the error. -twp) */ 4389 if (CVS_UNLINK (dest) < 0 && !existence_error (errno)) 4390 error (1, errno, "cannot remove %s", dest); 4391 if (symlink (info->data, dest) < 0) 4392 error (1, errno, "cannot create symbolic link from %s to %s", 4393 dest, (char *)info->data); 4394 if (free_value) 4395 free (value); 4396 if (free_rev) 4397 /* It's okay to discard the const when free_rev is set, because 4398 * we know we allocated it in this function. 4399 */ 4400 free ((char *)rev); 4401 return 0; 4402 } 4403 4404 /* Next, we look at this file's hardlinks field, and see whether 4405 it is linked to any other file that has been checked out. 4406 If so, we don't do anything else -- just link it to that file. 4407 4408 If we are checking out a file to a pipe or temporary storage, 4409 none of this should matter. Hence the `workfile != NULL' 4410 wrapper around the whole thing. -twp */ 4411 4412 if (workfile != NULL) 4413 { 4414 List *links = vers->hardlinks; 4415 if (links != NULL) 4416 { 4417 Node *uptodate_link; 4418 4419 /* For each file in the hardlinks field, check to see 4420 if it exists, and if so, if it has been checked out 4421 this iteration. When walklist returns, uptodate_link 4422 should point to a hardlist node representing a file 4423 in `links' which has recently been checked out, or 4424 NULL if no file in `links' has yet been checked out. */ 4425 4426 uptodate_link = NULL; 4427 (void) walklist (links, find_checkedout_proc, &uptodate_link); 4428 dellist (&links); 4429 4430 /* If we've found a file that `workfile' is supposed to be 4431 linked to, and it has been checked out since CVS was 4432 invoked, then simply link workfile to that file and return. 4433 4434 If one of these conditions is not met, then 4435 workfile is the first one in its hardlink group to 4436 be checked out, and we must continue with a full 4437 checkout. */ 4438 4439 if (uptodate_link != NULL) 4440 { 4441 struct hardlink_info *hlinfo = uptodate_link->data; 4442 4443 if (link (uptodate_link->key, workfile) < 0) 4444 error (1, errno, "cannot link %s to %s", 4445 workfile, uptodate_link->key); 4446 hlinfo->checked_out = 1; /* probably unnecessary */ 4447 if (free_value) 4448 free (value); 4449 if (free_rev) 4450 /* It's okay to discard the const when free_rev is set, 4451 * because we know we allocated it in this function. 4452 */ 4453 free ((char *)rev); 4454 return 0; 4455 } 4456 } 4457 } 4458 4459 info = findnode (vers->other_delta, "owner"); 4460 if (info != NULL) 4461 { 4462 change_rcs_owner_or_group = 1; 4463 rcs_owner = (uid_t) strtoul (info->data, NULL, 10); 4464 } 4465 info = findnode (vers->other_delta, "group"); 4466 if (info != NULL) 4467 { 4468 change_rcs_owner_or_group = 1; 4469 rcs_group = (gid_t) strtoul (info->data, NULL, 10); 4470 } 4471 info = findnode (vers->other_delta, "permissions"); 4472 if (info != NULL) 4473 { 4474 change_rcs_mode = 1; 4475 rcs_mode = (mode_t) strtoul (info->data, NULL, 8); 4476 } 4477 info = findnode (vers->other_delta, "special"); 4478 if (info != NULL) 4479 { 4480 /* If the size of `devtype' changes, fix the sscanf call also */ 4481 char devtype[16]; 4482 4483 if (sscanf (info->data, "%15s %lu", 4484 devtype, &devnum_long) < 2) 4485 error (1, 0, "%s:%s has bad `special' newphrase %s", 4486 workfile, vers->version, (char *)info->data); 4487 devnum = devnum_long; 4488 if (STREQ (devtype, "character")) 4489 special_file = S_IFCHR; 4490 else if (STREQ (devtype, "block")) 4491 special_file = S_IFBLK; 4492 else 4493 error (0, 0, "%s is a special file of unsupported type `%s'", 4494 workfile, (char *)info->data); 4495 } 4496 } 4497#endif /* PRESERVE_PERMISSIONS_SUPPORT */ 4498 4499 if (expand != KFLAG_O && expand != KFLAG_B) 4500 { 4501 char *newvalue; 4502 4503 /* Don't fetch the delta node again if we already have it. */ 4504 if (vp == NULL) 4505 { 4506 vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); 4507 if (vp == NULL) 4508 error (1, 0, "internal error: no revision information for %s", 4509 rev == NULL ? rcs->head : rev); 4510 } 4511 4512 expand_keywords (rcs, vp->data, nametag, log, loglen, 4513 expand, value, len, &newvalue, &len); 4514 4515 if (newvalue != value) 4516 { 4517 if (free_value) 4518 free (value); 4519 value = newvalue; 4520 free_value = 1; 4521 } 4522 } 4523 4524 if (free_rev) 4525 /* It's okay to discard the const when free_rev is set, because 4526 * we know we allocated it in this function. 4527 */ 4528 free ((char *)rev); 4529 4530 if (log != NULL) 4531 { 4532 free (log); 4533 log = NULL; 4534 } 4535 4536 if (pfn != NULL) 4537 { 4538#ifdef PRESERVE_PERMISSIONS_SUPPORT 4539 if (special_file) 4540 error (1, 0, "special file %s cannot be piped to anything", 4541 rcs->path); 4542#endif 4543 /* The PFN interface is very simple to implement right now, as 4544 we always have the entire file in memory. */ 4545 if (len != 0) 4546 pfn (callerdat, value, len); 4547 } 4548#ifdef PRESERVE_PERMISSIONS_SUPPORT 4549 else if (special_file) 4550 { 4551# ifdef HAVE_MKNOD 4552 char *dest; 4553 4554 /* Can send either to WORKFILE or to SOUT, as long as SOUT is 4555 not RUN_TTY. */ 4556 dest = workfile; 4557 if (dest == NULL) 4558 { 4559 if (sout == RUN_TTY) 4560 error (1, 0, "special file %s cannot be written to stdout", 4561 rcs->path); 4562 dest = sout; 4563 } 4564 4565 /* Unlink `dest', just in case. It's okay if this provokes a 4566 ENOENT error. */ 4567 if (CVS_UNLINK (dest) < 0 && existence_error (errno)) 4568 error (1, errno, "cannot remove %s", dest); 4569 if (mknod (dest, special_file, devnum) < 0) 4570 error (1, errno, "could not create special file %s", 4571 dest); 4572# else 4573 error (1, 0, 4574"cannot create %s: unable to create special files on this system", 4575workfile); 4576# endif 4577 } 4578#endif 4579 else 4580 { 4581 /* Not a special file: write to WORKFILE or SOUT. */ 4582 if (workfile == NULL) 4583 { 4584 if (sout == RUN_TTY) 4585 ofp = stdout; 4586 else 4587 { 4588 /* Symbolic links should be removed before replacement, so that 4589 `fopen' doesn't follow the link and open the wrong file. */ 4590 if (islink (sout)) 4591 if (unlink_file (sout) < 0) 4592 error (1, errno, "cannot remove %s", sout); 4593 ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w"); 4594 if (ofp == NULL) 4595 error (1, errno, "cannot open %s", sout); 4596 } 4597 } 4598 else 4599 { 4600 /* Output is supposed to go to WORKFILE, so we should open that 4601 file. Symbolic links should be removed first (see above). */ 4602 if (islink (workfile)) 4603 if (unlink_file (workfile) < 0) 4604 error (1, errno, "cannot remove %s", workfile); 4605 4606 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4607 4608 /* If the open failed because the existing workfile was not 4609 writable, try to chmod the file and retry the open. */ 4610 if (ofp == NULL && errno == EACCES 4611 && isfile (workfile) && !iswritable (workfile)) 4612 { 4613 xchmod (workfile, 1); 4614 ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); 4615 } 4616 4617 if (ofp == NULL) 4618 { 4619 error (0, errno, "cannot open %s", workfile); 4620 if (free_value) 4621 free (value); 4622 return 1; 4623 } 4624 } 4625 4626 if (workfile == NULL && sout == RUN_TTY) 4627 { 4628 if (expand == KFLAG_B) 4629 cvs_output_binary (value, len); 4630 else 4631 { 4632 /* cvs_output requires the caller to check for zero 4633 length. */ 4634 if (len > 0) 4635 cvs_output (value, len); 4636 } 4637 } 4638 else 4639 { 4640 /* NT 4.0 is said to have trouble writing 2099999 bytes 4641 (for example) in a single fwrite. So break it down 4642 (there is no need to be writing that much at once 4643 anyway; it is possible that LARGEST_FWRITE should be 4644 somewhat larger for good performance, but for testing I 4645 want to start with a small value until/unless a bigger 4646 one proves useful). */ 4647#define LARGEST_FWRITE 8192 4648 size_t nleft = len; 4649 size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE); 4650 char *p = value; 4651 4652 while (nleft > 0) 4653 { 4654 if (fwrite (p, 1, nstep, ofp) != nstep) 4655 { 4656 error (0, errno, "cannot write %s", 4657 (workfile != NULL 4658 ? workfile 4659 : (sout != RUN_TTY ? sout : "stdout"))); 4660 if (free_value) 4661 free (value); 4662 return 1; 4663 } 4664 p += nstep; 4665 nleft -= nstep; 4666 if (nleft < nstep) 4667 nstep = nleft; 4668 } 4669 } 4670 } 4671 4672 if (free_value) 4673 free (value); 4674 4675 if (workfile != NULL) 4676 { 4677 int ret; 4678 4679#ifdef PRESERVE_PERMISSIONS_SUPPORT 4680 if (!special_file && fclose (ofp) < 0) 4681 { 4682 error (0, errno, "cannot close %s", workfile); 4683 return 1; 4684 } 4685 4686 if (change_rcs_owner_or_group) 4687 { 4688 if (chown (workfile, rcs_owner, rcs_group) < 0) 4689 error (0, errno, "could not change owner or group of %s", 4690 workfile); 4691 } 4692 4693 ret = chmod (workfile, 4694 change_rcs_mode 4695 ? rcs_mode 4696 : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4697#else 4698 if (fclose (ofp) < 0) 4699 { 4700 error (0, errno, "cannot close %s", workfile); 4701 return 1; 4702 } 4703 4704 ret = chmod (workfile, 4705 sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); 4706#endif 4707 if (ret < 0) 4708 { 4709 error (0, errno, "cannot change mode of file %s", 4710 workfile); 4711 } 4712 } 4713 else if (sout != RUN_TTY) 4714 { 4715 if ( 4716#ifdef PRESERVE_PERMISSIONS_SUPPORT 4717 !special_file && 4718#endif 4719 fclose (ofp) < 0) 4720 { 4721 error (0, errno, "cannot close %s", sout); 4722 return 1; 4723 } 4724 } 4725 4726#ifdef PRESERVE_PERMISSIONS_SUPPORT 4727 /* If we are in the business of preserving hardlinks, then 4728 mark this file as having been checked out. */ 4729 if (preserve_perms && workfile != NULL) 4730 update_hardlink_info (workfile); 4731#endif 4732 4733 return 0; 4734} 4735 4736static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs)); 4737 4738/* Find the delta currently locked by the user. From the `ci' man page: 4739 4740 "If rev is omitted, ci tries to derive the new revision 4741 number from the caller's last lock. If the caller has 4742 locked the tip revision of a branch, the new revision is 4743 appended to that branch. The new revision number is 4744 obtained by incrementing the tip revision number. If the 4745 caller locked a non-tip revision, a new branch is started 4746 at that revision by incrementing the highest branch number 4747 at that revision. The default initial branch and level 4748 numbers are 1. 4749 4750 If rev is omitted and the caller has no lock, but owns the 4751 file and locking is not set to strict, then the revision 4752 is appended to the default branch (normally the trunk; see 4753 the -b option of rcs(1))." 4754 4755 RCS_findlock_or_tip finds the unique revision locked by the caller 4756 and returns its delta node. If the caller has not locked any 4757 revisions (and is permitted to commit to an unlocked delta, as 4758 described above), return the tip of the default branch. */ 4759 4760static RCSVers * 4761RCS_findlock_or_tip (rcs) 4762 RCSNode *rcs; 4763{ 4764 char *user = getcaller(); 4765 Node *lock, *p; 4766 List *locklist; 4767 char *defaultrev = NULL; 4768 4769 /* Find unique delta locked by caller. This code is very similar 4770 to the code in RCS_unlock -- perhaps it could be abstracted 4771 into a RCS_findlock function. */ 4772 locklist = RCS_getlocks (rcs); 4773 lock = NULL; 4774 for (p = locklist->list->next; p != locklist->list; p = p->next) 4775 { 4776 if (STREQ (p->data, user)) 4777 { 4778 if (lock != NULL) 4779 { 4780 error (0, 0, "\ 4781%s: multiple revisions locked by %s; please specify one", rcs->path, user); 4782 return NULL; 4783 } 4784 lock = p; 4785 } 4786 } 4787 4788 if (lock != NULL) 4789 { 4790 /* Found an old lock, but check that the revision still exists. */ 4791 p = findnode (rcs->versions, lock->key); 4792 if (p == NULL) 4793 { 4794 error (0, 0, "%s: can't unlock nonexistent revision %s", 4795 rcs->path, 4796 lock->key); 4797 return NULL; 4798 } 4799 return p->data; 4800 } 4801 4802 /* No existing lock. The RCS rule is that this is an error unless 4803 locking is nonstrict AND the file is owned by the current 4804 user. Trying to determine the latter is a portability nightmare 4805 in the face of NT, VMS, AFS, and other systems with non-unix-like 4806 ideas of users and owners. In the case of CVS, we should never get 4807 here (as long as the traditional behavior of making sure to call 4808 RCS_lock persists). Anyway, we skip the RCS error checks 4809 and just return the default branch or head. The reasoning is that 4810 those error checks are to make users lock before a checkin, and we do 4811 that in other ways if at all anyway (e.g. rcslock.pl). */ 4812 4813 defaultrev = RCS_getbranch (rcs, rcs->branch, 0); 4814 p = findnode (rcs->versions, defaultrev); 4815 if (defaultrev != NULL) 4816 free (defaultrev); 4817 if (!p) 4818 { 4819 error (0, 0, "RCS file `%s' does not contain its default revision.", 4820 rcs->path); 4821 return NULL; 4822 } 4823 4824 return p->data; 4825} 4826 4827/* Revision number string, R, must contain a `.'. 4828 Return a newly-malloc'd copy of the prefix of R up 4829 to but not including the final `.'. */ 4830 4831static char * 4832truncate_revnum (r) 4833 const char *r; 4834{ 4835 size_t len; 4836 char *new_r; 4837 char *dot = strrchr (r, '.'); 4838 4839 assert (dot); 4840 len = dot - r; 4841 new_r = xmalloc (len + 1); 4842 memcpy (new_r, r, len); 4843 *(new_r + len) = '\0'; 4844 return new_r; 4845} 4846 4847/* Revision number string, R, must contain a `.'. 4848 R must be writable. Replace the rightmost `.' in R with 4849 the NUL byte and return a pointer to that NUL byte. */ 4850 4851static char * 4852truncate_revnum_in_place (r) 4853 char *r; 4854{ 4855 char *dot = strrchr (r, '.'); 4856 assert (dot); 4857 *dot = '\0'; 4858 return dot; 4859} 4860 4861/* Revision number strings, R and S, must each contain a `.'. 4862 R and S must be writable and must have the same number of dots. 4863 Truncate R and S for the comparison, then restored them to their 4864 original state. 4865 Return the result (see compare_revnums) of comparing R and S 4866 ignoring differences in any component after the rightmost `.'. */ 4867 4868static int 4869compare_truncated_revnums (r, s) 4870 char *r; 4871 char *s; 4872{ 4873 char *r_dot = truncate_revnum_in_place (r); 4874 char *s_dot = truncate_revnum_in_place (s); 4875 int cmp; 4876 4877 assert (numdots (r) == numdots (s)); 4878 4879 cmp = compare_revnums (r, s); 4880 4881 *r_dot = '.'; 4882 *s_dot = '.'; 4883 4884 return cmp; 4885} 4886 4887/* Return a malloc'd copy of the string representing the highest branch 4888 number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL. 4889 FIXME: isn't the max rev always the last one? 4890 If so, we don't even need a loop. */ 4891 4892static char *max_rev PROTO ((const RCSVers *)); 4893 4894static char * 4895max_rev (branchnode) 4896 const RCSVers *branchnode; 4897{ 4898 Node *head; 4899 Node *bp; 4900 char *max; 4901 4902 if (branchnode->branches == NULL) 4903 { 4904 return NULL; 4905 } 4906 4907 max = NULL; 4908 head = branchnode->branches->list; 4909 for (bp = head->next; bp != head; bp = bp->next) 4910 { 4911 if (max == NULL || compare_truncated_revnums (max, bp->key) < 0) 4912 { 4913 max = bp->key; 4914 } 4915 } 4916 assert (max); 4917 4918 return truncate_revnum (max); 4919} 4920 4921/* Create BRANCH in RCS's delta tree. BRANCH may be either a branch 4922 number or a revision number. In the former case, create the branch 4923 with the specified number; in the latter case, create a new branch 4924 rooted at node BRANCH with a higher branch number than any others. 4925 Return the number of the tip node on the new branch. */ 4926 4927static char * 4928RCS_addbranch (rcs, branch) 4929 RCSNode *rcs; 4930 const char *branch; 4931{ 4932 char *branchpoint, *newrevnum; 4933 Node *nodep, *bp; 4934 Node *marker; 4935 RCSVers *branchnode; 4936 4937 assert (branch); 4938 4939 /* Append to end by default. */ 4940 marker = NULL; 4941 4942 branchpoint = xstrdup (branch); 4943 if ((numdots (branchpoint) & 1) == 0) 4944 { 4945 truncate_revnum_in_place (branchpoint); 4946 } 4947 4948 /* Find the branch rooted at BRANCHPOINT. */ 4949 nodep = findnode (rcs->versions, branchpoint); 4950 if (nodep == NULL) 4951 { 4952 error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint); 4953 free (branchpoint); 4954 return NULL; 4955 } 4956 free (branchpoint); 4957 branchnode = nodep->data; 4958 4959 /* If BRANCH was a full branch number, make sure it is higher than MAX. */ 4960 if ((numdots (branch) & 1) == 1) 4961 { 4962 if (branchnode->branches == NULL) 4963 { 4964 /* We have to create the first branch on this node, which means 4965 appending ".2" to the revision number. */ 4966 newrevnum = (char *) xmalloc (strlen (branch) + 3); 4967 strcpy (newrevnum, branch); 4968 strcat (newrevnum, ".2"); 4969 } 4970 else 4971 { 4972 char *max = max_rev (branchnode); 4973 assert (max); 4974 newrevnum = increment_revnum (max); 4975 free (max); 4976 } 4977 } 4978 else 4979 { 4980 newrevnum = xstrdup (branch); 4981 4982 if (branchnode->branches != NULL) 4983 { 4984 Node *head; 4985 Node *bp; 4986 4987 /* Find the position of this new branch in the sorted list 4988 of branches. */ 4989 head = branchnode->branches->list; 4990 for (bp = head->next; bp != head; bp = bp->next) 4991 { 4992 char *dot; 4993 int found_pos; 4994 4995 /* The existing list must be sorted on increasing revnum. */ 4996 assert (bp->next == head 4997 || compare_truncated_revnums (bp->key, 4998 bp->next->key) < 0); 4999 dot = truncate_revnum_in_place (bp->key); 5000 found_pos = (compare_revnums (branch, bp->key) < 0); 5001 *dot = '.'; 5002 5003 if (found_pos) 5004 { 5005 break; 5006 } 5007 } 5008 marker = bp; 5009 } 5010 } 5011 5012 newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3); 5013 strcat (newrevnum, ".1"); 5014 5015 /* Add this new revision number to BRANCHPOINT's branches list. */ 5016 if (branchnode->branches == NULL) 5017 branchnode->branches = getlist(); 5018 bp = getnode(); 5019 bp->key = xstrdup (newrevnum); 5020 5021 /* Append to the end of the list by default, that is, just before 5022 the header node, `list'. */ 5023 if (marker == NULL) 5024 marker = branchnode->branches->list; 5025 5026 { 5027 int fail; 5028 fail = insert_before (branchnode->branches, marker, bp); 5029 assert (!fail); 5030 } 5031 5032 return newrevnum; 5033} 5034 5035/* Check in to RCSFILE with revision REV (which must be greater than 5036 the largest revision) and message MESSAGE (which is checked for 5037 legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. 5038 If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & 5039 RCS_FLAGS_MODTIME, use the working file's modification time for the 5040 checkin time. WORKFILE is the working file to check in from, or 5041 NULL to use the usual RCS rules for deriving it from the RCSFILE. 5042 If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file; 5043 unlinking the working file is standard RCS behavior, but is rarely 5044 appropriate for CVS. 5045 5046 This function should almost exactly mimic the behavior of `rcs ci'. The 5047 principal point of difference is the support here for preserving file 5048 ownership and permissions in the delta nodes. This is not a clean 5049 solution -- precisely because it diverges from RCS's behavior -- but 5050 it doesn't seem feasible to do this anywhere else in the code. [-twp] 5051 5052 Return value is -1 for error (and errno is set to indicate the 5053 error), positive for error (and an error message has been printed), 5054 or zero for success. */ 5055 5056int 5057RCS_checkin (rcs, workfile_in, message, rev, citime, flags) 5058 RCSNode *rcs; 5059 const char *workfile_in; 5060 const char *message; 5061 const char *rev; 5062 time_t citime; 5063 int flags; 5064{ 5065 RCSVers *delta, *commitpt; 5066 Deltatext *dtext; 5067 Node *nodep; 5068 char *tmpfile, *changefile; 5069 int dargc = 0; 5070 size_t darg_allocated = 0; 5071 char **dargv = NULL; 5072 size_t bufsize; 5073 int status, checkin_quiet; 5074 struct tm *ftm; 5075 time_t modtime; 5076 int adding_branch = 0; 5077 char *workfile = xstrdup (workfile_in); 5078#ifdef PRESERVE_PERMISSIONS_SUPPORT 5079 struct stat sb; 5080#endif 5081 5082 commitpt = NULL; 5083 5084 if (rcs->flags & PARTIAL) 5085 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5086 5087 /* Get basename of working file. Is there a library function to 5088 do this? I couldn't find one. -twp */ 5089 if (workfile == NULL) 5090 { 5091 char *p; 5092 int extlen = strlen (RCSEXT); 5093 assert (rcs->path); 5094 workfile = xstrdup (last_component (rcs->path)); 5095 p = workfile + (strlen (workfile) - extlen); 5096 assert (strncmp (p, RCSEXT, extlen) == 0); 5097 *p = '\0'; 5098 } 5099 5100 /* If the filename is a symbolic link, follow it and replace it 5101 with the destination of the link. We need to do this before 5102 calling rcs_internal_lockfile, or else we won't put the lock in 5103 the right place. */ 5104 resolve_symlink (&(rcs->path)); 5105 5106 checkin_quiet = flags & RCS_FLAGS_QUIET; 5107 if (!checkin_quiet) 5108 { 5109 cvs_output (rcs->path, 0); 5110 cvs_output (" <-- ", 7); 5111 cvs_output (workfile, 0); 5112 cvs_output ("\n", 1); 5113 } 5114 5115 /* Create new delta node. */ 5116 delta = (RCSVers *) xmalloc (sizeof (RCSVers)); 5117 memset (delta, 0, sizeof (RCSVers)); 5118 delta->author = xstrdup (getcaller ()); 5119 if (flags & RCS_FLAGS_MODTIME) 5120 { 5121 struct stat ws; 5122 if (stat (workfile, &ws) < 0) 5123 { 5124 error (1, errno, "cannot stat %s", workfile); 5125 } 5126 modtime = ws.st_mtime; 5127 } 5128 else if (flags & RCS_FLAGS_USETIME) 5129 modtime = citime; 5130 else 5131 (void) time (&modtime); 5132 ftm = gmtime (&modtime); 5133 delta->date = (char *) xmalloc (MAXDATELEN); 5134 (void) sprintf (delta->date, DATEFORM, 5135 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 5136 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 5137 ftm->tm_min, ftm->tm_sec); 5138 if (flags & RCS_FLAGS_DEAD) 5139 { 5140 delta->state = xstrdup (RCSDEAD); 5141 delta->dead = 1; 5142 } 5143 else 5144 delta->state = xstrdup ("Exp"); 5145 5146#ifdef PRESERVE_PERMISSIONS_SUPPORT 5147 /* If permissions should be preserved on this project, then 5148 save the permission info. */ 5149 if (preserve_perms) 5150 { 5151 Node *np; 5152 char buf[64]; /* static buffer should be safe: see usage. -twp */ 5153 5154 delta->other_delta = getlist(); 5155 5156 if (CVS_LSTAT (workfile, &sb) < 0) 5157 error (1, errno, "cannot lstat %s", workfile); 5158 5159 if (S_ISLNK (sb.st_mode)) 5160 { 5161 np = getnode(); 5162 np->type = RCSFIELD; 5163 np->key = xstrdup ("symlink"); 5164 np->data = xreadlink (workfile); 5165 addnode (delta->other_delta, np); 5166 } 5167 else 5168 { 5169 (void) sprintf (buf, "%u", sb.st_uid); 5170 np = getnode(); 5171 np->type = RCSFIELD; 5172 np->key = xstrdup ("owner"); 5173 np->data = xstrdup (buf); 5174 addnode (delta->other_delta, np); 5175 5176 (void) sprintf (buf, "%u", sb.st_gid); 5177 np = getnode(); 5178 np->type = RCSFIELD; 5179 np->key = xstrdup ("group"); 5180 np->data = xstrdup (buf); 5181 addnode (delta->other_delta, np); 5182 5183 (void) sprintf (buf, "%o", sb.st_mode & 07777); 5184 np = getnode(); 5185 np->type = RCSFIELD; 5186 np->key = xstrdup ("permissions"); 5187 np->data = xstrdup (buf); 5188 addnode (delta->other_delta, np); 5189 5190 /* Save device number. */ 5191 switch (sb.st_mode & S_IFMT) 5192 { 5193 case S_IFREG: break; 5194 case S_IFCHR: 5195 case S_IFBLK: 5196# ifdef HAVE_STRUCT_STAT_ST_RDEV 5197 np = getnode(); 5198 np->type = RCSFIELD; 5199 np->key = xstrdup ("special"); 5200 sprintf (buf, "%s %lu", 5201 ((sb.st_mode & S_IFMT) == S_IFCHR 5202 ? "character" : "block"), 5203 (unsigned long) sb.st_rdev); 5204 np->data = xstrdup (buf); 5205 addnode (delta->other_delta, np); 5206# else 5207 error (0, 0, 5208"can't preserve %s: unable to save device files on this system", 5209workfile); 5210# endif 5211 break; 5212 5213 default: 5214 error (0, 0, "special file %s has unknown type", workfile); 5215 } 5216 5217 /* Save hardlinks. */ 5218 delta->hardlinks = list_linked_files_on_disk (workfile); 5219 } 5220 } 5221#endif 5222 5223 /* Create a new deltatext node. */ 5224 dtext = (Deltatext *) xmalloc (sizeof (Deltatext)); 5225 memset (dtext, 0, sizeof (Deltatext)); 5226 5227 dtext->log = make_message_rcslegal (message); 5228 5229 /* If the delta tree is empty, then there's nothing to link the 5230 new delta into. So make a new delta tree, snarf the working 5231 file contents, and just write the new RCS file. */ 5232 if (rcs->head == NULL) 5233 { 5234 char *newrev; 5235 FILE *fout; 5236 5237 /* Figure out what the first revision number should be. */ 5238 if (rev == NULL || *rev == '\0') 5239 newrev = xstrdup ("1.1"); 5240 else if (numdots (rev) == 0) 5241 { 5242 newrev = (char *) xmalloc (strlen (rev) + 3); 5243 strcpy (newrev, rev); 5244 strcat (newrev, ".1"); 5245 } 5246 else 5247 newrev = xstrdup (rev); 5248 5249 /* Don't need to xstrdup NEWREV because it's already dynamic, and 5250 not used for anything else. (Don't need to free it, either.) */ 5251 rcs->head = newrev; 5252 delta->version = xstrdup (newrev); 5253 nodep = getnode(); 5254 nodep->type = RCSVERS; 5255 nodep->delproc = rcsvers_delproc; 5256 nodep->data = delta; 5257 nodep->key = delta->version; 5258 (void) addnode (rcs->versions, nodep); 5259 5260 dtext->version = xstrdup (newrev); 5261 bufsize = 0; 5262#ifdef PRESERVE_PERMISSIONS_SUPPORT 5263 if (preserve_perms && !S_ISREG (sb.st_mode)) 5264 /* Pretend file is empty. */ 5265 bufsize = 0; 5266 else 5267#endif 5268 get_file (workfile, workfile, 5269 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5270 &dtext->text, &bufsize, &dtext->len); 5271 5272 if (!checkin_quiet) 5273 { 5274 cvs_output ("initial revision: ", 0); 5275 cvs_output (rcs->head, 0); 5276 cvs_output ("\n", 1); 5277 } 5278 5279 /* We are probably about to invalidate any cached file. */ 5280 rcsbuf_cache_close (); 5281 5282 fout = rcs_internal_lockfile (rcs->path); 5283 RCS_putadmin (rcs, fout); 5284 RCS_putdtree (rcs, rcs->head, fout); 5285 RCS_putdesc (rcs, fout); 5286 rcs->delta_pos = ftell (fout); 5287 if (rcs->delta_pos == -1) 5288 error (1, errno, "cannot ftell for %s", rcs->path); 5289 putdeltatext (fout, dtext); 5290 rcs_internal_unlockfile (fout, rcs->path); 5291 5292 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5293 { 5294 if (unlink_file (workfile) < 0) 5295 /* FIXME-update-dir: message does not include update_dir. */ 5296 error (0, errno, "cannot remove %s", workfile); 5297 } 5298 5299 if (!checkin_quiet) 5300 cvs_output ("done\n", 5); 5301 5302 status = 0; 5303 goto checkin_done; 5304 } 5305 5306 /* Derive a new revision number. From the `ci' man page: 5307 5308 "If rev is a revision number, it must be higher than the 5309 latest one on the branch to which rev belongs, or must 5310 start a new branch. 5311 5312 If rev is a branch rather than a revision number, the new 5313 revision is appended to that branch. The level number is 5314 obtained by incrementing the tip revision number of that 5315 branch. If rev indicates a non-existing branch, that 5316 branch is created with the initial revision numbered 5317 rev.1." 5318 5319 RCS_findlock_or_tip handles the case where REV is omitted. 5320 RCS 5.7 also permits REV to be "$" or to begin with a dot, but 5321 we do not address those cases -- every routine that calls 5322 RCS_checkin passes it a numeric revision. */ 5323 5324 if (rev == NULL || *rev == '\0') 5325 { 5326 /* Figure out where the commit point is by looking for locks. 5327 If the commit point is at the tip of a branch (or is the 5328 head of the delta tree), then increment its revision number 5329 to obtain the new revnum. Otherwise, start a new 5330 branch. */ 5331 commitpt = RCS_findlock_or_tip (rcs); 5332 if (commitpt == NULL) 5333 { 5334 status = 1; 5335 goto checkin_done; 5336 } 5337 else if (commitpt->next == NULL 5338 || STREQ (commitpt->version, rcs->head)) 5339 delta->version = increment_revnum (commitpt->version); 5340 else 5341 delta->version = RCS_addbranch (rcs, commitpt->version); 5342 } 5343 else 5344 { 5345 /* REV is either a revision number or a branch number. Find the 5346 tip of the target branch. */ 5347 char *branch, *tip, *newrev, *p; 5348 int dots, isrevnum; 5349 5350 assert (isdigit ((unsigned char) *rev)); 5351 5352 newrev = xstrdup (rev); 5353 dots = numdots (newrev); 5354 isrevnum = dots & 1; 5355 5356 branch = xstrdup (rev); 5357 if (isrevnum) 5358 { 5359 p = strrchr (branch, '.'); 5360 *p = '\0'; 5361 } 5362 5363 /* Find the tip of the target branch. If we got a one- or two-digit 5364 revision number, this will be the head of the tree. Exception: 5365 if rev is a single-field revision equal to the branch number of 5366 the trunk (usually "1") then we want to treat it like an ordinary 5367 branch revision. */ 5368 if (dots == 0) 5369 { 5370 tip = xstrdup (rcs->head); 5371 assert (tip != NULL); 5372 if (atoi (tip) != atoi (branch)) 5373 { 5374 newrev = (char *) xrealloc (newrev, strlen (newrev) + 3); 5375 strcat (newrev, ".1"); 5376 dots = isrevnum = 1; 5377 } 5378 } 5379 else if (dots == 1) 5380 tip = xstrdup (rcs->head); 5381 else 5382 tip = RCS_getbranch (rcs, branch, 1); 5383 5384 /* If the branch does not exist, and we were supplied an exact 5385 revision number, signal an error. Otherwise, if we were 5386 given only a branch number, create it and set COMMITPT to 5387 the branch point. */ 5388 if (tip == NULL) 5389 { 5390 if (isrevnum) 5391 { 5392 error (0, 0, "%s: can't find branch point %s", 5393 rcs->path, branch); 5394 free (branch); 5395 free (newrev); 5396 status = 1; 5397 goto checkin_done; 5398 } 5399 delta->version = RCS_addbranch (rcs, branch); 5400 if (!delta->version) 5401 { 5402 free (branch); 5403 free (newrev); 5404 status = 1; 5405 goto checkin_done; 5406 } 5407 adding_branch = 1; 5408 p = strrchr (branch, '.'); 5409 *p = '\0'; 5410 tip = xstrdup (branch); 5411 } 5412 else 5413 { 5414 if (isrevnum) 5415 { 5416 /* NEWREV must be higher than TIP. */ 5417 if (compare_revnums (tip, newrev) >= 0) 5418 { 5419 error (0, 0, 5420 "%s: revision %s too low; must be higher than %s", 5421 rcs->path, 5422 newrev, tip); 5423 free (branch); 5424 free (newrev); 5425 free (tip); 5426 status = 1; 5427 goto checkin_done; 5428 } 5429 delta->version = xstrdup (newrev); 5430 } 5431 else 5432 /* Just increment the tip number to get the new revision. */ 5433 delta->version = increment_revnum (tip); 5434 } 5435 5436 nodep = findnode (rcs->versions, tip); 5437 commitpt = nodep->data; 5438 5439 free (branch); 5440 free (newrev); 5441 free (tip); 5442 } 5443 5444 assert (delta->version != NULL); 5445 5446 /* If COMMITPT is locked by us, break the lock. If it's locked 5447 by someone else, signal an error. */ 5448 nodep = findnode (RCS_getlocks (rcs), commitpt->version); 5449 if (nodep != NULL) 5450 { 5451 if (! STREQ (nodep->data, delta->author)) 5452 { 5453 /* If we are adding a branch, then leave the old lock around. 5454 That is sensible in the sense that when adding a branch, 5455 we don't need to use the lock to tell us where to check 5456 in. It is fishy in the sense that if it is our own lock, 5457 we break it. However, this is the RCS 5.7 behavior (at 5458 the end of addbranch in ci.c in RCS 5.7, it calls 5459 removelock only if it is our own lock, not someone 5460 else's). */ 5461 5462 if (!adding_branch) 5463 { 5464 error (0, 0, "%s: revision %s locked by %s", 5465 rcs->path, 5466 nodep->key, (char *)nodep->data); 5467 status = 1; 5468 goto checkin_done; 5469 } 5470 } 5471 else 5472 delnode (nodep); 5473 } 5474 5475 dtext->version = xstrdup (delta->version); 5476 5477 /* Obtain the change text for the new delta. If DELTA is to be the 5478 new head of the tree, then its change text should be the contents 5479 of the working file, and LEAFNODE's change text should be a diff. 5480 Else, DELTA's change text should be a diff between LEAFNODE and 5481 the working file. */ 5482 5483 tmpfile = cvs_temp_name(); 5484 status = RCS_checkout (rcs, NULL, commitpt->version, NULL, 5485 ((rcs->expand != NULL 5486 && STREQ (rcs->expand, "b")) 5487 ? "-kb" 5488 : "-ko"), 5489 tmpfile, 5490 (RCSCHECKOUTPROC)0, NULL); 5491 if (status != 0) 5492 error (1, 0, 5493 "could not check out revision %s of `%s'", 5494 commitpt->version, rcs->path); 5495 5496 bufsize = 0; 5497 changefile = cvs_temp_name(); 5498 5499 /* Diff options should include --binary if the RCS file has -kb set 5500 in its `expand' field. */ 5501 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); 5502 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); 5503 if (rcs->expand && STREQ (rcs->expand, "b")) 5504 run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary"); 5505 5506 if (STREQ (commitpt->version, rcs->head) && 5507 numdots (delta->version) == 1) 5508 { 5509 /* If this revision is being inserted on the trunk, the change text 5510 for the new delta should be the contents of the working file ... */ 5511 bufsize = 0; 5512#ifdef PRESERVE_PERMISSIONS_SUPPORT 5513 if (preserve_perms && !S_ISREG (sb.st_mode)) 5514 /* Pretend file is empty. */ 5515 ; 5516 else 5517#endif 5518 get_file (workfile, workfile, 5519 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5520 &dtext->text, &bufsize, &dtext->len); 5521 5522 /* ... and the change text for the old delta should be a diff. */ 5523 commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext)); 5524 memset (commitpt->text, 0, sizeof (Deltatext)); 5525 5526 bufsize = 0; 5527 switch (diff_exec (workfile, tmpfile, NULL, NULL, 5528 dargc, dargv, changefile)) 5529 { 5530 case 0: 5531 case 1: 5532 break; 5533 case -1: 5534 /* FIXME-update-dir: message does not include update_dir. */ 5535 error (1, errno, "error diffing %s", workfile); 5536 break; 5537 default: 5538 /* FIXME-update-dir: message does not include update_dir. */ 5539 error (1, 0, "error diffing %s", workfile); 5540 break; 5541 } 5542 5543 /* OK, the text file case here is really dumb. Logically 5544 speaking we want diff to read the files in text mode, 5545 convert them to the canonical form found in RCS files 5546 (which, we hope at least, is independent of OS--always 5547 bare linefeeds), and then work with change texts in that 5548 format. However, diff_exec both generates change 5549 texts and produces output for user purposes (e.g. patch.c), 5550 and there is no way to distinguish between the two cases. 5551 So we actually implement the text file case by writing the 5552 change text as a text file, then reading it as a text file. 5553 This should cause no harm, but doesn't strike me as 5554 immensely clean. */ 5555 get_file (changefile, changefile, 5556 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5557 &commitpt->text->text, &bufsize, &commitpt->text->len); 5558 5559 /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE 5560 was empty and that there are no differences between revisions. 5561 In that event, we want to force RCS_rewrite to write an empty 5562 string for COMMITPT's change text. Leaving the change text 5563 field set NULL won't work, since that means "preserve the original 5564 change text for this delta." */ 5565 if (commitpt->text->text == NULL) 5566 { 5567 commitpt->text->text = xstrdup (""); 5568 commitpt->text->len = 0; 5569 } 5570 } 5571 else 5572 { 5573 /* This file is not being inserted at the head, but on a side 5574 branch somewhere. Make a diff from the previous revision 5575 to the working file. */ 5576 switch (diff_exec (tmpfile, workfile, NULL, NULL, 5577 dargc, dargv, changefile)) 5578 { 5579 case 0: 5580 case 1: 5581 break; 5582 case -1: 5583 /* FIXME-update-dir: message does not include update_dir. */ 5584 error (1, errno, "error diffing %s", workfile); 5585 break; 5586 default: 5587 /* FIXME-update-dir: message does not include update_dir. */ 5588 error (1, 0, "error diffing %s", workfile); 5589 break; 5590 } 5591 /* See the comment above, at the other get_file invocation, 5592 regarding binary vs. text. */ 5593 get_file (changefile, changefile, 5594 rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", 5595 &dtext->text, &bufsize, 5596 &dtext->len); 5597 if (dtext->text == NULL) 5598 { 5599 dtext->text = xstrdup (""); 5600 dtext->len = 0; 5601 } 5602 } 5603 5604 run_arg_free_p (dargc, dargv); 5605 free (dargv); 5606 5607 /* Update DELTA linkage. It is important not to do this before 5608 the very end of RCS_checkin; if an error arises that forces 5609 us to abort checking in, we must not have malformed deltas 5610 partially linked into the tree. 5611 5612 If DELTA and COMMITPT are on different branches, do nothing -- 5613 DELTA is linked to the tree through COMMITPT->BRANCHES, and we 5614 don't want to change `next' pointers. 5615 5616 Otherwise, if the nodes are both on the trunk, link DELTA to 5617 COMMITPT; otherwise, link COMMITPT to DELTA. */ 5618 5619 if (numdots (commitpt->version) == numdots (delta->version)) 5620 { 5621 if (STREQ (commitpt->version, rcs->head)) 5622 { 5623 delta->next = rcs->head; 5624 rcs->head = xstrdup (delta->version); 5625 } 5626 else 5627 commitpt->next = xstrdup (delta->version); 5628 } 5629 5630 /* Add DELTA to RCS->VERSIONS. */ 5631 if (rcs->versions == NULL) 5632 rcs->versions = getlist(); 5633 nodep = getnode(); 5634 nodep->type = RCSVERS; 5635 nodep->delproc = rcsvers_delproc; 5636 nodep->data = delta; 5637 nodep->key = delta->version; 5638 (void) addnode (rcs->versions, nodep); 5639 5640 /* Write the new RCS file, inserting the new delta at COMMITPT. */ 5641 if (!checkin_quiet) 5642 { 5643 cvs_output ("new revision: ", 14); 5644 cvs_output (delta->version, 0); 5645 cvs_output ("; previous revision: ", 21); 5646 cvs_output (commitpt->version, 0); 5647 cvs_output ("\n", 1); 5648 } 5649 5650 RCS_rewrite (rcs, dtext, commitpt->version); 5651 5652 if ((flags & RCS_FLAGS_KEEPFILE) == 0) 5653 { 5654 if (unlink_file (workfile) < 0) 5655 /* FIXME-update-dir: message does not include update_dir. */ 5656 error (1, errno, "cannot remove %s", workfile); 5657 } 5658 if (unlink_file (tmpfile) < 0) 5659 error (0, errno, "cannot remove %s", tmpfile); 5660 free (tmpfile); 5661 if (unlink_file (changefile) < 0) 5662 error (0, errno, "cannot remove %s", changefile); 5663 free (changefile); 5664 5665 if (!checkin_quiet) 5666 cvs_output ("done\n", 5); 5667 5668 checkin_done: 5669 free (workfile); 5670 5671 if (commitpt != NULL && commitpt->text != NULL) 5672 { 5673 freedeltatext (commitpt->text); 5674 commitpt->text = NULL; 5675 } 5676 5677 freedeltatext (dtext); 5678 if (status != 0) 5679 { 5680 /* If delta has not been added to a List, then freeing the Node key 5681 * won't free delta->version. 5682 */ 5683 if (delta->version) free (delta->version); 5684 free_rcsvers_contents (delta); 5685 } 5686 5687 return status; 5688} 5689 5690 5691 5692/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */ 5693struct cmp_file_data 5694{ 5695 const char *filename; 5696 FILE *fp; 5697 int different; 5698}; 5699 5700/* Compare the contents of revision REV1 of RCS file RCS with the 5701 contents of REV2 if given, otherwise, compare with the contents of 5702 the file FILENAME. OPTIONS is a string for the keyword 5703 expansion options. Return 0 if the contents of the revision are 5704 the same as the contents of the file, 1 if they are different. */ 5705int 5706RCS_cmp_file (rcs, rev1, rev1_cache, rev2, options, filename) 5707 RCSNode *rcs; 5708 const char *rev1; 5709 char **rev1_cache; 5710 const char *rev2; 5711 const char *options; 5712 const char *filename; 5713{ 5714 int binary; 5715 5716 if (options != NULL && options[0] != '\0') 5717 binary = STREQ (options, "-kb"); 5718 else 5719 { 5720 char *expand; 5721 5722 expand = RCS_getexpand (rcs); 5723 if (expand != NULL && STREQ (expand, "b")) 5724 binary = 1; 5725 else 5726 binary = 0; 5727 } 5728 5729#ifdef PRESERVE_PERMISSIONS_SUPPORT 5730 /* If CVS is to deal properly with special files (when 5731 PreservePermissions is on), the best way is to check out the 5732 revision to a temporary file and call `xcmp' on the two disk 5733 files. xcmp needs to handle non-regular files properly anyway, 5734 so calling it simplifies RCS_cmp_file. We *could* just yank 5735 the delta node out of the version tree and look for device 5736 numbers, but writing to disk and calling xcmp is a better 5737 abstraction (therefore probably more robust). -twp */ 5738 5739 if (preserve_perms) 5740 { 5741 char *tmp; 5742 int retcode; 5743 5744 tmp = cvs_temp_name(); 5745 retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL); 5746 if (retcode != 0) 5747 return 1; 5748 5749 retcode = xcmp (tmp, filename); 5750 if (CVS_UNLINK (tmp) < 0) 5751 error (0, errno, "cannot remove %s", tmp); 5752 free (tmp); 5753 return retcode; 5754 } 5755 else 5756#endif 5757 { 5758 FILE *fp; 5759 struct cmp_file_data data; 5760 const char *use_file1; 5761 char *tmpfile = NULL; 5762 5763 if (rev2 != NULL) 5764 { 5765 /* Open & cache rev1 */ 5766 tmpfile = cvs_temp_name(); 5767 if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile, 5768 (RCSCHECKOUTPROC)0, NULL)) 5769 error (1, errno, 5770 "cannot check out revision %s of %s", 5771 rev1, rcs->path); 5772 use_file1 = tmpfile; 5773 if (rev1_cache != NULL) 5774 *rev1_cache = tmpfile; 5775 } 5776 else 5777 use_file1 = filename; 5778 5779 fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r"); 5780 if (fp == NULL) 5781 /* FIXME-update-dir: should include update_dir in message. */ 5782 error (1, errno, "cannot open file %s for comparing", use_file1); 5783 5784 data.filename = use_file1; 5785 data.fp = fp; 5786 data.different = 0; 5787 5788 if (RCS_checkout (rcs, (char *)NULL, rev2 ? rev2 : rev1, 5789 (char *)NULL, options, RUN_TTY, cmp_file_buffer, 5790 (void *)&data )) 5791 error (1, errno, 5792 "cannot check out revision %s of %s", 5793 rev2 ? rev2 : rev1, rcs->path); 5794 5795 /* If we have not yet found a difference, make sure that we are at 5796 the end of the file. */ 5797 if (!data.different) 5798 { 5799 if (getc (fp) != EOF) 5800 data.different = 1; 5801 } 5802 5803 fclose (fp); 5804 if (rev1_cache == NULL && tmpfile) 5805 { 5806 if (CVS_UNLINK (tmpfile ) < 0) 5807 error (0, errno, "cannot remove %s", tmpfile); 5808 free (tmpfile); 5809 } 5810 5811 return data.different; 5812 } 5813} 5814 5815 5816 5817/* This is a subroutine of RCS_cmp_file. It is passed to 5818 RCS_checkout. */ 5819#define CMP_BUF_SIZE (8 * 1024) 5820 5821static void 5822cmp_file_buffer (callerdat, buffer, len) 5823 void *callerdat; 5824 const char *buffer; 5825 size_t len; 5826{ 5827 struct cmp_file_data *data = (struct cmp_file_data *)callerdat; 5828 char *filebuf; 5829 5830 /* If we've already found a difference, we don't need to check 5831 further. */ 5832 if (data->different) 5833 return; 5834 5835 filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len); 5836 5837 while (len > 0) 5838 { 5839 size_t checklen; 5840 5841 checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len; 5842 if (fread (filebuf, 1, checklen, data->fp) != checklen) 5843 { 5844 if (ferror (data->fp)) 5845 error (1, errno, "cannot read file %s for comparing", 5846 data->filename); 5847 data->different = 1; 5848 free (filebuf); 5849 return; 5850 } 5851 5852 if (memcmp (filebuf, buffer, checklen) != 0) 5853 { 5854 data->different = 1; 5855 free (filebuf); 5856 return; 5857 } 5858 5859 buffer += checklen; 5860 len -= checklen; 5861 } 5862 5863 free (filebuf); 5864} 5865 5866 5867 5868/* For RCS file RCS, make symbolic tag TAG point to revision REV. 5869 This validates that TAG is OK for a user to use. Return value is 5870 -1 for error (and errno is set to indicate the error), positive for 5871 error (and an error message has been printed), or zero for success. */ 5872 5873int 5874RCS_settag (rcs, tag, rev) 5875 RCSNode *rcs; 5876 const char *tag; 5877 const char *rev; 5878{ 5879 List *symbols; 5880 Node *node; 5881 5882 if (rcs->flags & PARTIAL) 5883 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5884 5885 /* FIXME: This check should be moved to RCS_check_tag. There is no 5886 reason for it to be here. */ 5887 if (STREQ (tag, TAG_BASE) 5888 || STREQ (tag, TAG_HEAD)) 5889 { 5890 /* Print the name of the tag might be considered redundant 5891 with the caller, which also prints it. Perhaps this helps 5892 clarify why the tag name is considered reserved, I don't 5893 know. */ 5894 error (0, 0, "Attempt to add reserved tag name %s", tag); 5895 return 1; 5896 } 5897 5898 /* A revision number of NULL means use the head or default branch. 5899 If rev is not NULL, it may be a symbolic tag or branch number; 5900 expand it to the correct numeric revision or branch head. */ 5901 if (rev == NULL) 5902 rev = rcs->branch ? rcs->branch : rcs->head; 5903 5904 /* At this point rcs->symbol_data may not have been parsed. 5905 Calling RCS_symbols will force it to be parsed into a list 5906 which we can easily manipulate. */ 5907 symbols = RCS_symbols (rcs); 5908 if (symbols == NULL) 5909 { 5910 symbols = getlist (); 5911 rcs->symbols = symbols; 5912 } 5913 node = findnode (symbols, tag); 5914 if (node != NULL) 5915 { 5916 free (node->data); 5917 node->data = xstrdup (rev); 5918 } 5919 else 5920 { 5921 node = getnode (); 5922 node->key = xstrdup (tag); 5923 node->data = xstrdup (rev); 5924 (void) addnode_at_front (symbols, node); 5925 } 5926 5927 return 0; 5928} 5929 5930/* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if 5931 the tag was found (and removed), or 1 if it was not present. (In 5932 either case, the tag will no longer be in RCS->SYMBOLS.) */ 5933 5934int 5935RCS_deltag (rcs, tag) 5936 RCSNode *rcs; 5937 const char *tag; 5938{ 5939 List *symbols; 5940 Node *node; 5941 if (rcs->flags & PARTIAL) 5942 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5943 5944 symbols = RCS_symbols (rcs); 5945 if (symbols == NULL) 5946 return 1; 5947 5948 node = findnode (symbols, tag); 5949 if (node == NULL) 5950 return 1; 5951 5952 delnode (node); 5953 5954 return 0; 5955} 5956 5957/* Set the default branch of RCS to REV. */ 5958 5959int 5960RCS_setbranch (rcs, rev) 5961 RCSNode *rcs; 5962 const char *rev; 5963{ 5964 if (rcs->flags & PARTIAL) 5965 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 5966 5967 if (rev && ! *rev) 5968 rev = NULL; 5969 5970 if (rev == NULL && rcs->branch == NULL) 5971 return 0; 5972 if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch)) 5973 return 0; 5974 5975 if (rcs->branch != NULL) 5976 free (rcs->branch); 5977 rcs->branch = xstrdup (rev); 5978 5979 return 0; 5980} 5981 5982/* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME: 5983 Most of the callers only call us because RCS_checkin still tends to 5984 like a lock (a relic of old behavior inherited from the RCS ci 5985 program). If we clean this up, only "cvs admin -l" will still need 5986 to call RCS_lock. */ 5987 5988/* FIXME-twp: if a lock owned by someone else is broken, should this 5989 send mail to the lock owner? Prompt user? It seems like such an 5990 obscure situation for CVS as almost not worth worrying much 5991 about. */ 5992 5993int 5994RCS_lock (rcs, rev, lock_quiet) 5995 RCSNode *rcs; 5996 const char *rev; 5997 int lock_quiet; 5998{ 5999 List *locks; 6000 Node *p; 6001 char *user; 6002 char *xrev = NULL; 6003 6004 if (rcs->flags & PARTIAL) 6005 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6006 6007 locks = RCS_getlocks (rcs); 6008 if (locks == NULL) 6009 locks = rcs->locks = getlist(); 6010 user = getcaller(); 6011 6012 /* A revision number of NULL means lock the head or default branch. */ 6013 if (rev == NULL) 6014 xrev = RCS_head (rcs); 6015 else 6016 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); 6017 6018 /* Make sure that the desired revision exists. Technically, 6019 we can update the locks list without even checking this, 6020 but RCS 5.7 did this. And it can't hurt. */ 6021 if (xrev == NULL || findnode (rcs->versions, xrev) == NULL) 6022 { 6023 if (!lock_quiet) 6024 error (0, 0, "%s: revision %s absent", rcs->path, rev); 6025 free (xrev); 6026 return 1; 6027 } 6028 6029 /* Is this rev already locked? */ 6030 p = findnode (locks, xrev); 6031 if (p != NULL) 6032 { 6033 if (STREQ (p->data, user)) 6034 { 6035 /* We already own the lock on this revision, so do nothing. */ 6036 free (xrev); 6037 return 0; 6038 } 6039 6040#if 0 6041 /* Well, first of all, "rev" below should be "xrev" to avoid 6042 core dumps. But more importantly, should we really be 6043 breaking the lock unconditionally? What CVS 1.9 does (via 6044 RCS) is to prompt "Revision 1.1 is already locked by fred. 6045 Do you want to break the lock? [ny](n): ". Well, we don't 6046 want to interact with the user (certainly not at the 6047 server/protocol level, and probably not in the command-line 6048 client), but isn't it more sensible to give an error and 6049 let the user run "cvs admin -u" if they want to break the 6050 lock? */ 6051 6052 /* Break the lock. */ 6053 if (!lock_quiet) 6054 { 6055 cvs_output (rev, 0); 6056 cvs_output (" unlocked\n", 0); 6057 } 6058 delnode (p); 6059#else 6060 error (1, 0, "Revision %s is already locked by %s", xrev, (char *)p->data); 6061#endif 6062 } 6063 6064 /* Create a new lock. */ 6065 p = getnode(); 6066 p->key = xrev; /* already xstrdupped */ 6067 p->data = xstrdup (getcaller()); 6068 (void) addnode_at_front (locks, p); 6069 6070 if (!lock_quiet) 6071 { 6072 cvs_output (xrev, 0); 6073 cvs_output (" locked\n", 0); 6074 } 6075 6076 return 0; 6077} 6078 6079/* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME: 6080 Like RCS_lock, this can become a no-op if we do the checkin 6081 ourselves. 6082 6083 If REV is not null and is locked by someone else, break their 6084 lock and notify them. It is an open issue whether RCS_unlock 6085 queries the user about whether or not to break the lock. */ 6086 6087int 6088RCS_unlock (rcs, rev, unlock_quiet) 6089 RCSNode *rcs; 6090 char *rev; 6091 int unlock_quiet; 6092{ 6093 Node *lock; 6094 List *locks; 6095 char *user; 6096 char *xrev = NULL; 6097 6098 user = getcaller(); 6099 if (rcs->flags & PARTIAL) 6100 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6101 6102 /* If rev is NULL, unlock the revision held by the caller; if more 6103 than one, make the user specify the revision explicitly. This 6104 differs from RCS which unlocks the latest revision (first in 6105 rcs->locks) held by the caller. */ 6106 if (rev == NULL) 6107 { 6108 Node *p; 6109 6110 /* No-ops: attempts to unlock an empty tree or an unlocked file. */ 6111 if (rcs->head == NULL) 6112 { 6113 if (!unlock_quiet) 6114 cvs_outerr ("can't unlock an empty tree\n", 0); 6115 return 0; 6116 } 6117 6118 locks = RCS_getlocks (rcs); 6119 if (locks == NULL) 6120 { 6121 if (!unlock_quiet) 6122 cvs_outerr ("No locks are set.\n", 0); 6123 return 0; 6124 } 6125 6126 lock = NULL; 6127 for (p = locks->list->next; p != locks->list; p = p->next) 6128 { 6129 if (STREQ (p->data, user)) 6130 { 6131 if (lock != NULL) 6132 { 6133 if (!unlock_quiet) 6134 error (0, 0, "\ 6135%s: multiple revisions locked by %s; please specify one", rcs->path, user); 6136 return 1; 6137 } 6138 lock = p; 6139 } 6140 } 6141 if (lock == NULL) 6142 { 6143 if (!unlock_quiet) 6144 error (0, 0, "No locks are set for %s.\n", user); 6145 return 0; /* no lock found, ergo nothing to do */ 6146 } 6147 xrev = xstrdup (lock->key); 6148 } 6149 else 6150 { 6151 xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); 6152 if (xrev == NULL) 6153 { 6154 error (0, 0, "%s: revision %s absent", rcs->path, rev); 6155 return 1; 6156 } 6157 } 6158 6159 lock = findnode (RCS_getlocks (rcs), xrev); 6160 if (lock == NULL) 6161 { 6162 /* This revision isn't locked. */ 6163 free (xrev); 6164 return 0; 6165 } 6166 6167 if (! STREQ (lock->data, user)) 6168 { 6169 /* If the revision is locked by someone else, notify 6170 them. Note that this shouldn't ever happen if RCS_unlock 6171 is called with a NULL revision, since that means "whatever 6172 revision is currently locked by the caller." */ 6173 char *repos, *workfile; 6174 if (!unlock_quiet) 6175 error (0, 0, "\ 6176%s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data); 6177 repos = xstrdup (rcs->path); 6178 workfile = strrchr (repos, '/'); 6179 *workfile++ = '\0'; 6180 notify_do ('C', workfile, user, NULL, NULL, repos); 6181 free (repos); 6182 } 6183 6184 delnode (lock); 6185 if (!unlock_quiet) 6186 { 6187 cvs_output (xrev, 0); 6188 cvs_output (" unlocked\n", 0); 6189 } 6190 6191 free (xrev); 6192 return 0; 6193} 6194 6195/* Add USER to the access list of RCS. Do nothing if already present. 6196 FIXME-twp: check syntax of USER to make sure it's a valid id. */ 6197 6198void 6199RCS_addaccess (rcs, user) 6200 RCSNode *rcs; 6201 char *user; 6202{ 6203 char *access, *a; 6204 6205 if (rcs->flags & PARTIAL) 6206 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6207 6208 if (rcs->access == NULL) 6209 rcs->access = xstrdup (user); 6210 else 6211 { 6212 access = xstrdup (rcs->access); 6213 for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " ")) 6214 { 6215 if (STREQ (a, user)) 6216 { 6217 free (access); 6218 return; 6219 } 6220 } 6221 free (access); 6222 rcs->access = (char *) xrealloc 6223 (rcs->access, strlen (rcs->access) + strlen (user) + 2); 6224 strcat (rcs->access, " "); 6225 strcat (rcs->access, user); 6226 } 6227} 6228 6229/* Remove USER from the access list of RCS. */ 6230 6231void 6232RCS_delaccess (rcs, user) 6233 RCSNode *rcs; 6234 char *user; 6235{ 6236 char *p, *s; 6237 int ulen; 6238 6239 if (rcs->flags & PARTIAL) 6240 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6241 6242 if (rcs->access == NULL) 6243 return; 6244 6245 if (user == NULL) 6246 { 6247 free (rcs->access); 6248 rcs->access = NULL; 6249 return; 6250 } 6251 6252 p = rcs->access; 6253 ulen = strlen (user); 6254 while (p != NULL) 6255 { 6256 if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' ')) 6257 break; 6258 p = strchr (p, ' '); 6259 if (p != NULL) 6260 ++p; 6261 } 6262 6263 if (p == NULL) 6264 return; 6265 6266 s = p + ulen; 6267 while (*s != '\0') 6268 *p++ = *s++; 6269 *p = '\0'; 6270} 6271 6272char * 6273RCS_getaccess (rcs) 6274 RCSNode *rcs; 6275{ 6276 if (rcs->flags & PARTIAL) 6277 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6278 6279 return rcs->access; 6280} 6281 6282static int findtag PROTO ((Node *, void *)); 6283 6284/* Return a nonzero value if the revision specified by ARG is found. */ 6285 6286static int 6287findtag (node, arg) 6288 Node *node; 6289 void *arg; 6290{ 6291 char *rev = (char *)arg; 6292 6293 if (STREQ (node->data, rev)) 6294 return 1; 6295 else 6296 return 0; 6297} 6298 6299static int findmagictag PROTO ((Node *, void *)); 6300 6301/* Return a nonzero value if a magic tag rooted at ARG is found. */ 6302 6303static int 6304findmagictag (node, arg) 6305 Node *node; 6306 void *arg; 6307{ 6308 char *rev = (char *)arg; 6309 size_t len = strlen (rev); 6310 6311 if (strncmp (node->data, rev, len) == 0 && 6312 strncmp ((char *)node->data + len, ".0.", 3) == 0) 6313 return 1; 6314 else 6315 return 0; 6316} 6317 6318/* Delete revisions between REV1 and REV2. The changes between the two 6319 revisions must be collapsed, and the result stored in the revision 6320 immediately preceding the lower one. Return 0 for successful completion, 6321 1 otherwise. 6322 6323 Solution: check out the revision preceding REV1 and the revision 6324 following REV2. Use call_diff to find aggregate diffs between 6325 these two revisions, and replace the delta text for the latter one 6326 with the new aggregate diff. Alternatively, we could write a 6327 function that takes two change texts and combines them to produce a 6328 new change text, without checking out any revs or calling diff. It 6329 would be hairy, but so, so cool. 6330 6331 If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to 6332 delete that revision as well (cvs admin -o tag1:tag2). If clear, 6333 delete up to but not including that revision (cvs admin -o tag1::tag2). 6334 This does not affect TAG1 or TAG2 being NULL; the meaning of the start 6335 point in ::tag2 and :tag2 is the same and likewise for end points. */ 6336 6337int 6338RCS_delete_revs (rcs, tag1, tag2, inclusive) 6339 RCSNode *rcs; 6340 char *tag1; 6341 char *tag2; 6342 int inclusive; 6343{ 6344 char *next; 6345 Node *nodep; 6346 RCSVers *revp = NULL; 6347 RCSVers *beforep; 6348 int status, found; 6349 int save_noexec; 6350 6351 char *branchpoint = NULL; 6352 char *rev1 = NULL; 6353 char *rev2 = NULL; 6354 int rev1_inclusive = inclusive; 6355 int rev2_inclusive = inclusive; 6356 char *before = NULL; 6357 char *after = NULL; 6358 char *beforefile = NULL; 6359 char *afterfile = NULL; 6360 char *outfile = NULL; 6361 6362 if (tag1 == NULL && tag2 == NULL) 6363 return 0; 6364 6365 /* Assume error status until everything is finished. */ 6366 status = 1; 6367 6368 /* Make sure both revisions exist. */ 6369 if (tag1 != NULL) 6370 { 6371 rev1 = RCS_gettag (rcs, tag1, 1, NULL); 6372 if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL) 6373 { 6374 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1); 6375 goto delrev_done; 6376 } 6377 } 6378 if (tag2 != NULL) 6379 { 6380 rev2 = RCS_gettag (rcs, tag2, 1, NULL); 6381 if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL) 6382 { 6383 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2); 6384 goto delrev_done; 6385 } 6386 } 6387 6388 /* If rev1 is on the trunk and rev2 is NULL, rev2 should be 6389 RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch 6390 instead.) We need to check this special case early, in order 6391 to make sure that rev1 and rev2 get ordered correctly. */ 6392 if (rev2 == NULL && numdots (rev1) == 1) 6393 { 6394 rev2 = xstrdup (rcs->head); 6395 rev2_inclusive = 1; 6396 } 6397 6398 if (rev2 == NULL) 6399 rev2_inclusive = 1; 6400 6401 if (rev1 != NULL && rev2 != NULL) 6402 { 6403 /* A range consisting of a branch number means the latest revision 6404 on that branch. */ 6405 if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2)) 6406 { 6407 char *tmp = RCS_getbranch (rcs, rev1, 0); 6408 free (rev1); 6409 free (rev2); 6410 rev1 = rev2 = tmp; 6411 } 6412 else 6413 { 6414 /* Make sure REV1 and REV2 are ordered correctly (in the 6415 same order as the next field). For revisions on the 6416 trunk, REV1 should be higher than REV2; for branches, 6417 REV1 should be lower. */ 6418 /* Shouldn't we just be giving an error in the case where 6419 the user specifies the revisions in the wrong order 6420 (that is, always swap on the trunk, never swap on a 6421 branch, in the non-error cases)? It is not at all 6422 clear to me that users who specify -o 1.4:1.2 really 6423 meant to type -o 1.2:1.4, and the out of order usage 6424 has never been documented, either by cvs.texinfo or 6425 rcs(1). */ 6426 char *temp; 6427 int temp_inclusive; 6428 if (numdots (rev1) == 1) 6429 { 6430 if (compare_revnums (rev1, rev2) <= 0) 6431 { 6432 temp = rev2; 6433 rev2 = rev1; 6434 rev1 = temp; 6435 6436 temp_inclusive = rev2_inclusive; 6437 rev2_inclusive = rev1_inclusive; 6438 rev1_inclusive = temp_inclusive; 6439 } 6440 } 6441 else if (compare_revnums (rev1, rev2) > 0) 6442 { 6443 temp = rev2; 6444 rev2 = rev1; 6445 rev1 = temp; 6446 6447 temp_inclusive = rev2_inclusive; 6448 rev2_inclusive = rev1_inclusive; 6449 rev1_inclusive = temp_inclusive; 6450 } 6451 } 6452 } 6453 6454 /* Basically the same thing; make sure that the ordering is what we 6455 need. */ 6456 if (rev1 == NULL) 6457 { 6458 assert (rev2 != NULL); 6459 if (numdots (rev2) == 1) 6460 { 6461 /* Swap rev1 and rev2. */ 6462 int temp_inclusive; 6463 6464 rev1 = rev2; 6465 rev2 = NULL; 6466 6467 temp_inclusive = rev2_inclusive; 6468 rev2_inclusive = rev1_inclusive; 6469 rev1_inclusive = temp_inclusive; 6470 } 6471 } 6472 6473 /* Put the revision number preceding the first one to delete into 6474 BEFORE (where "preceding" means according to the next field). 6475 If the first revision to delete is the first revision on its 6476 branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk 6477 at which the branch is rooted. If the first revision to delete 6478 is the head revision of the trunk, set BEFORE to NULL. 6479 6480 Note that because BEFORE may not be on the same branch as REV1, 6481 it is not very handy for navigating the revision tree. It's 6482 most useful just for checking out the revision preceding REV1. */ 6483 before = NULL; 6484 branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2); 6485 if (rev1 == NULL) 6486 { 6487 rev1 = xstrdup (branchpoint); 6488 if (numdots (branchpoint) > 1) 6489 { 6490 char *bp; 6491 bp = strrchr (branchpoint, '.'); 6492 while (*--bp != '.') 6493 ; 6494 *bp = '\0'; 6495 /* Note that this is exclusive, always, because the inclusive 6496 flag doesn't affect the meaning when rev1 == NULL. */ 6497 before = xstrdup (branchpoint); 6498 *bp = '.'; 6499 } 6500 } 6501 else if (! STREQ (rev1, branchpoint)) 6502 { 6503 /* Walk deltas from BRANCHPOINT on, looking for REV1. */ 6504 nodep = findnode (rcs->versions, branchpoint); 6505 revp = nodep->data; 6506 while (revp->next != NULL && ! STREQ (revp->next, rev1)) 6507 { 6508 revp = nodep->data; 6509 nodep = findnode (rcs->versions, revp->next); 6510 } 6511 if (revp->next == NULL) 6512 { 6513 error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1); 6514 goto delrev_done; 6515 } 6516 if (rev1_inclusive) 6517 before = xstrdup (revp->version); 6518 else 6519 { 6520 before = rev1; 6521 nodep = findnode (rcs->versions, before); 6522 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6523 } 6524 } 6525 else if (!rev1_inclusive) 6526 { 6527 before = rev1; 6528 nodep = findnode (rcs->versions, before); 6529 rev1 = xstrdup (((RCSVers *)nodep->data)->next); 6530 } 6531 else if (numdots (branchpoint) > 1) 6532 { 6533 /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1". 6534 Set before to "1.3". */ 6535 char *bp; 6536 bp = strrchr (branchpoint, '.'); 6537 while (*--bp != '.') 6538 ; 6539 *bp = '\0'; 6540 before = xstrdup (branchpoint); 6541 *bp = '.'; 6542 } 6543 6544 /* If any revision between REV1 and REV2 is locked or is a branch point, 6545 we can't delete that revision and must abort. */ 6546 after = NULL; 6547 next = rev1; 6548 found = 0; 6549 while (!found && next != NULL) 6550 { 6551 nodep = findnode (rcs->versions, next); 6552 revp = nodep->data; 6553 6554 if (rev2 != NULL) 6555 found = STREQ (revp->version, rev2); 6556 next = revp->next; 6557 6558 if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL) 6559 { 6560 if (findnode (RCS_getlocks (rcs), revp->version)) 6561 { 6562 error (0, 0, "%s: can't remove locked revision %s", 6563 rcs->path, 6564 revp->version); 6565 goto delrev_done; 6566 } 6567 if (revp->branches != NULL) 6568 { 6569 error (0, 0, "%s: can't remove branch point %s", 6570 rcs->path, 6571 revp->version); 6572 goto delrev_done; 6573 } 6574 6575 /* Doing this only for the :: syntax is for compatibility. 6576 See cvs.texinfo for somewhat more discussion. */ 6577 if (!inclusive && 6578 (walklist (RCS_symbols (rcs), findtag, revp->version) || 6579 walklist (RCS_symbols (rcs), findmagictag, revp->version))) 6580 { 6581 /* We don't print which file this happens to on the theory 6582 that the caller will print the name of the file in a 6583 more useful fashion (fullname not rcs->path). */ 6584 error (0, 0, "cannot remove revision %s because it has tags", 6585 revp->version); 6586 goto delrev_done; 6587 } 6588 6589 /* It's misleading to print the `deleting revision' output 6590 here, since we may not actually delete these revisions. 6591 But that's how RCS does it. Bleah. Someday this should be 6592 moved to the point where the revs are actually marked for 6593 deletion. -twp */ 6594 cvs_output ("deleting revision ", 0); 6595 cvs_output (revp->version, 0); 6596 cvs_output ("\n", 1); 6597 } 6598 } 6599 6600 if (rev2 == NULL) 6601 ; 6602 else if (found) 6603 { 6604 if (rev2_inclusive) 6605 after = xstrdup (next); 6606 else 6607 after = xstrdup (revp->version); 6608 } 6609 else if (!inclusive) 6610 { 6611 /* In the case of an empty range, for example 1.2::1.2 or 6612 1.2::1.3, we want to just do nothing. */ 6613 status = 0; 6614 goto delrev_done; 6615 } 6616 else 6617 { 6618 /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL. 6619 Are those cases really impossible? */ 6620 assert (tag1 != NULL); 6621 assert (tag2 != NULL); 6622 6623 error (0, 0, "%s: invalid revision range %s:%s", rcs->path, 6624 tag1, tag2); 6625 goto delrev_done; 6626 } 6627 6628 if (after == NULL && before == NULL) 6629 { 6630 /* The user is trying to delete all revisions. While an 6631 RCS file without revisions makes sense to RCS (e.g. the 6632 state after "rcs -i"), CVS has never been able to cope with 6633 it. So at least for now we just make this an error. 6634 6635 We don't include rcs->path in the message since "cvs admin" 6636 already printed "RCS file:" and the name. */ 6637 error (1, 0, "attempt to delete all revisions"); 6638 } 6639 6640 /* The conditionals at this point get really hairy. Here is the 6641 general idea: 6642 6643 IF before != NULL and after == NULL 6644 THEN don't check out any revisions, just delete them 6645 IF before == NULL and after != NULL 6646 THEN only check out after's revision, and use it for the new deltatext 6647 ELSE 6648 check out both revisions and diff -n them. This could use 6649 RCS_exec_rcsdiff with some changes, like being able 6650 to suppress diagnostic messages and to direct output. */ 6651 6652 if (after != NULL) 6653 { 6654 char *diffbuf; 6655 size_t bufsize, len; 6656 6657#if defined (WOE32) && !defined (__CYGWIN32__) 6658 /* FIXME: This is an awful kludge, but at least until I have 6659 time to work on it a little more and test it, I'd rather 6660 give a fatal error than corrupt the file. I think that we 6661 need to use "-kb" and "--binary" and "rb" to get_file 6662 (probably can do it always, not just for binary files, if 6663 we are consistent between the RCS_checkout and the diff). */ 6664 { 6665 char *expand = RCS_getexpand (rcs); 6666 if (expand != NULL && STREQ (expand, "b")) 6667 error (1, 0, 6668 "admin -o not implemented yet for binary on this system"); 6669 } 6670#endif /* WOE32 */ 6671 6672 afterfile = cvs_temp_name(); 6673 status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile, 6674 (RCSCHECKOUTPROC)0, NULL); 6675 if (status > 0) 6676 goto delrev_done; 6677 6678 if (before == NULL) 6679 { 6680 /* We are deleting revisions from the head of the tree, 6681 so must create a new head. */ 6682 diffbuf = NULL; 6683 bufsize = 0; 6684 get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len); 6685 6686 save_noexec = noexec; 6687 noexec = 0; 6688 if (unlink_file (afterfile) < 0) 6689 error (0, errno, "cannot remove %s", afterfile); 6690 noexec = save_noexec; 6691 6692 free (afterfile); 6693 afterfile = NULL; 6694 6695 free (rcs->head); 6696 rcs->head = xstrdup (after); 6697 } 6698 else 6699 { 6700 int dargc = 0; 6701 size_t darg_allocated = 0; 6702 char **dargv = NULL; 6703 6704 beforefile = cvs_temp_name(); 6705 status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile, 6706 (RCSCHECKOUTPROC)0, NULL); 6707 if (status > 0) 6708 goto delrev_done; 6709 6710 outfile = cvs_temp_name(); 6711 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); 6712 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); 6713 status = diff_exec (beforefile, afterfile, NULL, NULL, 6714 dargc, dargv, outfile); 6715 run_arg_free_p (dargc, dargv); 6716 free (dargv); 6717 6718 if (status == 2) 6719 { 6720 /* Not sure we need this message; will diff_exec already 6721 have printed an error? */ 6722 error (0, 0, "%s: could not diff", rcs->path); 6723 status = 1; 6724 goto delrev_done; 6725 } 6726 6727 diffbuf = NULL; 6728 bufsize = 0; 6729 get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len); 6730 } 6731 6732 /* Save the new change text in after's delta node. */ 6733 nodep = findnode (rcs->versions, after); 6734 revp = nodep->data; 6735 6736 assert (revp->text == NULL); 6737 6738 revp->text = (Deltatext *) xmalloc (sizeof (Deltatext)); 6739 memset ((Deltatext *) revp->text, 0, sizeof (Deltatext)); 6740 revp->text->version = xstrdup (revp->version); 6741 revp->text->text = diffbuf; 6742 revp->text->len = len; 6743 6744 /* If DIFFBUF is NULL, it means that OUTFILE is empty and that 6745 there are no differences between the two revisions. In that 6746 case, we want to force RCS_copydeltas to write an empty string 6747 for the new change text (leaving the text field set NULL 6748 means "preserve the original change text for this delta," so 6749 we don't want that). */ 6750 if (revp->text->text == NULL) 6751 revp->text->text = xstrdup (""); 6752 } 6753 6754 /* Walk through the revisions (again) to mark each one as 6755 outdated. (FIXME: would it be safe to use the `dead' field for 6756 this? Doubtful.) */ 6757 for (next = rev1; 6758 next != NULL && (after == NULL || ! STREQ (next, after)); 6759 next = revp->next) 6760 { 6761 nodep = findnode (rcs->versions, next); 6762 revp = nodep->data; 6763 revp->outdated = 1; 6764 } 6765 6766 /* Update delta links. If BEFORE == NULL, we're changing the 6767 head of the tree and don't need to update any `next' links. */ 6768 if (before != NULL) 6769 { 6770 /* If REV1 is the first node on its branch, then BEFORE is its 6771 root node (on the trunk) and we have to update its branches 6772 list. Otherwise, BEFORE is on the same branch as AFTER, and 6773 we can just change BEFORE's `next' field to point to AFTER. 6774 (This should be safe: since findnode manages its lists via 6775 the `hashnext' and `hashprev' fields, rather than `next' and 6776 `prev', mucking with `next' and `prev' should not corrupt the 6777 delta tree's internal structure. Much. -twp) */ 6778 6779 if (rev1 == NULL) 6780 /* beforep's ->next field already should be equal to after, 6781 which I think is always NULL in this case. */ 6782 ; 6783 else if (STREQ (rev1, branchpoint)) 6784 { 6785 nodep = findnode (rcs->versions, before); 6786 revp = nodep->data; 6787 nodep = revp->branches->list->next; 6788 while (nodep != revp->branches->list && 6789 ! STREQ (nodep->key, rev1)) 6790 nodep = nodep->next; 6791 assert (nodep != revp->branches->list); 6792 if (after == NULL) 6793 delnode (nodep); 6794 else 6795 { 6796 free (nodep->key); 6797 nodep->key = xstrdup (after); 6798 } 6799 } 6800 else 6801 { 6802 nodep = findnode (rcs->versions, before); 6803 beforep = nodep->data; 6804 free (beforep->next); 6805 beforep->next = xstrdup (after); 6806 } 6807 } 6808 6809 status = 0; 6810 6811 delrev_done: 6812 if (rev1 != NULL) 6813 free (rev1); 6814 if (rev2 && rev2 != rev1) 6815 free (rev2); 6816 if (branchpoint != NULL) 6817 free (branchpoint); 6818 if (before != NULL) 6819 free (before); 6820 if (after != NULL) 6821 free (after); 6822 6823 save_noexec = noexec; 6824 noexec = 0; 6825 if (beforefile != NULL) 6826 { 6827 if (unlink_file (beforefile) < 0) 6828 error (0, errno, "cannot remove %s", beforefile); 6829 free (beforefile); 6830 } 6831 if (afterfile != NULL) 6832 { 6833 if (unlink_file (afterfile) < 0) 6834 error (0, errno, "cannot remove %s", afterfile); 6835 free (afterfile); 6836 } 6837 if (outfile != NULL) 6838 { 6839 if (unlink_file (outfile) < 0) 6840 error (0, errno, "cannot remove %s", outfile); 6841 free (outfile); 6842 } 6843 noexec = save_noexec; 6844 6845 return status; 6846} 6847 6848/* 6849 * TRUE if there exists a symbolic tag "tag" in file. 6850 */ 6851int 6852RCS_exist_tag (rcs, tag) 6853 RCSNode *rcs; 6854 char *tag; 6855{ 6856 6857 assert (rcs != NULL); 6858 6859 if (findnode (RCS_symbols (rcs), tag)) 6860 return 1; 6861 return 0; 6862 6863} 6864 6865/* 6866 * TRUE if RCS revision number "rev" exists. 6867 * This includes magic branch revisions, not found in rcs->versions, 6868 * but only in rcs->symbols, requiring a list walk to find them. 6869 * Take advantage of list walk callback function already used by 6870 * RCS_delete_revs, above. 6871 */ 6872int 6873RCS_exist_rev (rcs, rev) 6874 RCSNode *rcs; 6875 char *rev; 6876{ 6877 6878 assert (rcs != NULL); 6879 6880 if (rcs->flags & PARTIAL) 6881 RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); 6882 6883 if (findnode(rcs->versions, rev) != 0) 6884 return 1; 6885 6886 if (walklist (RCS_symbols(rcs), findtag, rev) != 0) 6887 return 1; 6888 6889 return 0; 6890 6891} 6892 6893 6894/* RCS_deltas and friends. Processing of the deltas in RCS files. */ 6895 6896struct line 6897{ 6898 /* Text of this line. Part of the same malloc'd block as the struct 6899 line itself (we probably should use the "struct hack" (char text[1]) 6900 and save ourselves sizeof (char *) bytes). Does not include \n; 6901 instead has_newline indicates the presence or absence of \n. */ 6902 char *text; 6903 /* Length of this line, not counting \n if has_newline is true. */ 6904 size_t len; 6905 /* Version in which it was introduced. */ 6906 RCSVers *vers; 6907 /* Nonzero if this line ends with \n. This will always be true 6908 except possibly for the last line. */ 6909 int has_newline; 6910 /* Number of pointers to this struct line. */ 6911 int refcount; 6912}; 6913 6914struct linevector 6915{ 6916 /* How many lines in use for this linevector? */ 6917 unsigned int nlines; 6918 /* How many lines allocated for this linevector? */ 6919 unsigned int lines_alloced; 6920 /* Pointer to array containing a pointer to each line. */ 6921 struct line **vector; 6922}; 6923 6924static void linevector_init PROTO ((struct linevector *)); 6925 6926/* Initialize *VEC to be a linevector with no lines. */ 6927static void 6928linevector_init (vec) 6929 struct linevector *vec; 6930{ 6931 vec->lines_alloced = 0; 6932 vec->nlines = 0; 6933 vec->vector = NULL; 6934} 6935 6936static int linevector_add PROTO ((struct linevector *vec, const char *text, 6937 size_t len, RCSVers *vers, 6938 unsigned int pos)); 6939 6940/* Given some text TEXT, add each of its lines to VEC before line POS 6941 (where line 0 is the first line). The last line in TEXT may or may 6942 not be \n terminated. 6943 Set the version for each of the new lines to VERS. This 6944 function returns non-zero for success. It returns zero if the line 6945 number is out of range. 6946 6947 Each of the lines in TEXT are copied to space which is managed with 6948 the linevector (and freed by linevector_free). So the caller doesn't 6949 need to keep TEXT around after the call to this function. */ 6950static int 6951linevector_add (vec, text, len, vers, pos) 6952 struct linevector *vec; 6953 const char *text; 6954 size_t len; 6955 RCSVers *vers; 6956 unsigned int pos; 6957{ 6958 const char *textend; 6959 unsigned int i; 6960 unsigned int nnew; 6961 const char *p; 6962 const char *nextline_text; 6963 size_t nextline_len; 6964 int nextline_newline; 6965 struct line *q; 6966 6967 if (len == 0) 6968 return 1; 6969 6970 textend = text + len; 6971 6972 /* Count the number of lines we will need to add. */ 6973 nnew = 1; 6974 for (p = text; p < textend; ++p) 6975 if (*p == '\n' && p + 1 < textend) 6976 ++nnew; 6977 6978 /* Expand VEC->VECTOR if needed. */ 6979 if (vec->nlines + nnew >= vec->lines_alloced) 6980 { 6981 if (vec->lines_alloced == 0) 6982 vec->lines_alloced = 10; 6983 while (vec->nlines + nnew >= vec->lines_alloced) 6984 vec->lines_alloced *= 2; 6985 vec->vector = xrealloc (vec->vector, 6986 vec->lines_alloced * sizeof (*vec->vector)); 6987 } 6988 6989 /* Make room for the new lines in VEC->VECTOR. */ 6990 for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i) 6991 vec->vector[i] = vec->vector[i - nnew]; 6992 6993 if (pos > vec->nlines) 6994 return 0; 6995 6996 /* Actually add the lines, to VEC->VECTOR. */ 6997 i = pos; 6998 nextline_text = text; 6999 nextline_newline = 0; 7000 for (p = text; p < textend; ++p) 7001 if (*p == '\n') 7002 { 7003 nextline_newline = 1; 7004 if (p + 1 == textend) 7005 /* If there are no characters beyond the last newline, we 7006 don't consider it another line. */ 7007 break; 7008 nextline_len = p - nextline_text; 7009 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); 7010 q->vers = vers; 7011 q->text = (char *)q + sizeof (struct line); 7012 q->len = nextline_len; 7013 q->has_newline = nextline_newline; 7014 q->refcount = 1; 7015 memcpy (q->text, nextline_text, nextline_len); 7016 vec->vector[i++] = q; 7017 7018 nextline_text = (char *)p + 1; 7019 nextline_newline = 0; 7020 } 7021 nextline_len = p - nextline_text; 7022 q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); 7023 q->vers = vers; 7024 q->text = (char *)q + sizeof (struct line); 7025 q->len = nextline_len; 7026 q->has_newline = nextline_newline; 7027 q->refcount = 1; 7028 memcpy (q->text, nextline_text, nextline_len); 7029 vec->vector[i] = q; 7030 7031 vec->nlines += nnew; 7032 7033 return 1; 7034} 7035 7036static void linevector_copy PROTO ((struct linevector *, struct linevector *)); 7037 7038/* Copy FROM to TO, copying the vectors but not the lines pointed to. */ 7039static void 7040linevector_copy (to, from) 7041 struct linevector *to; 7042 struct linevector *from; 7043{ 7044 unsigned int ln; 7045 7046 for (ln = 0; ln < to->nlines; ++ln) 7047 { 7048 if (--to->vector[ln]->refcount == 0) 7049 free (to->vector[ln]); 7050 } 7051 if (from->nlines > to->lines_alloced) 7052 { 7053 if (to->lines_alloced == 0) 7054 to->lines_alloced = 10; 7055 while (from->nlines > to->lines_alloced) 7056 to->lines_alloced *= 2; 7057 to->vector = (struct line **) 7058 xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector)); 7059 } 7060 memcpy (to->vector, from->vector, 7061 from->nlines * sizeof (*to->vector)); 7062 to->nlines = from->nlines; 7063 for (ln = 0; ln < to->nlines; ++ln) 7064 ++to->vector[ln]->refcount; 7065} 7066 7067static void linevector_free PROTO ((struct linevector *)); 7068 7069/* Free storage associated with linevector. */ 7070static void 7071linevector_free (vec) 7072 struct linevector *vec; 7073{ 7074 unsigned int ln; 7075 7076 if (vec->vector != NULL) 7077 { 7078 for (ln = 0; ln < vec->nlines; ++ln) 7079 if (vec->vector[ln] && --vec->vector[ln]->refcount == 0) 7080 free (vec->vector[ln]); 7081 7082 free (vec->vector); 7083 } 7084} 7085 7086static char *month_printname PROTO ((char *)); 7087 7088/* Given a textual string giving the month (1-12), terminated with any 7089 character not recognized by atoi, return the 3 character name to 7090 print it with. I do not think it is a good idea to change these 7091 strings based on the locale; they are standard abbreviations (for 7092 example in rfc822 mail messages) which should be widely understood. 7093 Returns a pointer into static readonly storage. */ 7094static char * 7095month_printname (month) 7096 char *month; 7097{ 7098 static const char *const months[] = 7099 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 7100 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 7101 int mnum; 7102 7103 mnum = atoi (month); 7104 if (mnum < 1 || mnum > 12) 7105 return "???"; 7106 return (char *)months[mnum - 1]; 7107} 7108 7109static int 7110apply_rcs_changes PROTO ((struct linevector *, const char *, size_t, 7111 const char *, RCSVers *, RCSVers *)); 7112 7113/* Apply changes to the line vector LINES. DIFFBUF is a buffer of 7114 * length DIFFLEN holding the change text from an RCS file (the output 7115 * of diff -n). NAME is used in error messages. The VERS field of 7116 * any line added is set to ADDVERS. The VERS field of any line 7117 * deleted is set to DELVERS, unless DELVERS is NULL, in which case 7118 * the VERS field of deleted lines is unchanged. 7119 * 7120 * RETURNS 7121 * Non-zero if the change text is applied successfully to ORIG_LINES. 7122 * 7123 * If the change text does not appear to apply to ORIG_LINES (e.g., a 7124 * line number is invalid), this function will return zero and ORIG_LINES 7125 * will remain unmolested. 7126 * 7127 * ERRORS 7128 * If the change text is improperly formatted (e.g., it is not the output 7129 * of diff -n), the function calls error with a status of 1, causing the 7130 * program to exit. 7131 */ 7132static int 7133apply_rcs_changes (orig_lines, diffbuf, difflen, name, addvers, delvers) 7134 struct linevector *orig_lines; 7135 const char *diffbuf; 7136 size_t difflen; 7137 const char *name; 7138 RCSVers *addvers; 7139 RCSVers *delvers; 7140{ 7141 const char *p; 7142 const char *q; 7143 int op; 7144 /* The RCS format throws us for a loop in that the deltafrags (if 7145 we define a deltafrag as an add or a delete) need to be applied 7146 in reverse order. So we stick them into a linked list. */ 7147 struct deltafrag { 7148 enum {FRAG_ADD, FRAG_DELETE} type; 7149 unsigned long pos; 7150 unsigned long nlines; 7151 const char *new_lines; 7152 size_t len; 7153 struct deltafrag *next; 7154 }; 7155 struct deltafrag *dfhead; 7156 struct deltafrag **dftail; 7157 struct deltafrag *df; 7158 unsigned long numlines, lastmodline, offset; 7159 struct linevector lines; 7160 int err; 7161 7162 dfhead = NULL; 7163 dftail = &dfhead; 7164 numlines = orig_lines->nlines; /* start with init # of lines */ 7165 for (p = diffbuf; p != NULL && p < diffbuf + difflen; ) 7166 { 7167 op = *p++; 7168 if (op != 'a' && op != 'd') 7169 /* Can't just skip over the deltafrag, because the value 7170 of op determines the syntax. */ 7171 error (1, 0, "unrecognized operation '\\x%x' in %s", 7172 op, name); 7173 *dftail = df = xmalloc (sizeof *df); 7174 *(dftail = &df->next) = NULL; 7175 7176 df->pos = strtoul (p, (char **) &q, 10); 7177 7178 if (p == q) 7179 error (1, 0, "number expected in %s", name); 7180 p = q; 7181 if (*p++ != ' ') 7182 error (1, 0, "space expected in %s", name); 7183 df->nlines = strtoul (p, (char **) &q, 10); 7184 if (p == q) 7185 error (1, 0, "number expected in %s", name); 7186 p = q; 7187 if (*p++ != '\012') 7188 error (1, 0, "linefeed expected in %s", name); 7189 7190 if (op == 'a') 7191 { 7192 unsigned int i; 7193 7194 df->type = FRAG_ADD; 7195 i = df->nlines; 7196 /* The text we want is the number of lines specified, or 7197 until the end of the value, whichever comes first (it 7198 will be the former except in the case where we are 7199 adding a line which does not end in newline). */ 7200 for (q = p; i != 0; ++q) 7201 if (*q == '\n') 7202 --i; 7203 else if (q == diffbuf + difflen) 7204 { 7205 if (i != 1) 7206 error (1, 0, "premature end of change in %s", name); 7207 else 7208 break; 7209 } 7210 7211 /* Stash away a pointer to the text we are adding. */ 7212 df->new_lines = p; 7213 df->len = q - p; 7214 7215 p = q; 7216 numlines += df->nlines; 7217 } 7218 else 7219 { 7220 /* Correct for the fact that line numbers in RCS files 7221 start with 1. */ 7222 --df->pos; 7223 7224 assert (op == 'd'); 7225 df->type = FRAG_DELETE; 7226 numlines -= df->nlines; 7227 } 7228 } 7229 7230 /* New temp data structure to hold new org before 7231 copy back into original structure. */ 7232 lines.nlines = lines.lines_alloced = numlines; 7233 lines.vector = xmalloc (numlines * sizeof *lines.vector); 7234 7235 /* We changed the list order to first to last -- so the 7236 list never gets larger than the size numlines. */ 7237 lastmodline = 0; 7238 7239 /* offset created when adding/removing lines 7240 between new and original structure */ 7241 offset = 0; 7242 err = 0; 7243 for (df = dfhead; df != NULL; ) 7244 { 7245 unsigned int ln; 7246 unsigned long deltaend; 7247 7248 if (df->pos > orig_lines->nlines) 7249 err = 1; 7250 7251 /* On error, just free the rest of the list. */ 7252 if (!err) 7253 { 7254 /* Here we need to get to the line where the next insert will 7255 begin, which is DF->pos in ORIG_LINES. We will fill up to 7256 DF->pos - OFFSET in LINES with original items. */ 7257 for (deltaend = df->pos - offset; 7258 lastmodline < deltaend; 7259 lastmodline++) 7260 { 7261 /* we need to copy from the orig structure into new one */ 7262 lines.vector[lastmodline] = 7263 orig_lines->vector[lastmodline + offset]; 7264 lines.vector[lastmodline]->refcount++; 7265 } 7266 7267 switch (df->type) 7268 { 7269 case FRAG_ADD: 7270 { 7271 const char *textend, *p; 7272 const char *nextline_text; 7273 struct line *q; 7274 int nextline_newline; 7275 size_t nextline_len; 7276 7277 textend = df->new_lines + df->len; 7278 nextline_newline = 0; 7279 nextline_text = df->new_lines; 7280 for (p = df->new_lines; p < textend; ++p) 7281 { 7282 if (*p == '\n') 7283 { 7284 nextline_newline = 1; 7285 if (p + 1 == textend) 7286 { 7287 /* If there are no characters beyond the 7288 last newline, we don't consider it 7289 another line. */ 7290 break; 7291 } 7292 7293 nextline_len = p - nextline_text; 7294 q = xmalloc (sizeof *q + nextline_len); 7295 q->vers = addvers; 7296 q->text = (char *)(q + 1); 7297 q->len = nextline_len; 7298 q->has_newline = nextline_newline; 7299 q->refcount = 1; 7300 memcpy (q->text, nextline_text, nextline_len); 7301 lines.vector[lastmodline++] = q; 7302 offset--; 7303 7304 nextline_text = (char *)p + 1; 7305 nextline_newline = 0; 7306 } 7307 } 7308 nextline_len = p - nextline_text; 7309 q = xmalloc (sizeof *q + nextline_len); 7310 q->vers = addvers; 7311 q->text = (char *)(q + 1); 7312 q->len = nextline_len; 7313 q->has_newline = nextline_newline; 7314 q->refcount = 1; 7315 memcpy (q->text, nextline_text, nextline_len); 7316 lines.vector[lastmodline++] = q; 7317 7318 /* For each line we add the offset between the #'s 7319 decreases. */ 7320 offset--; 7321 break; 7322 } 7323 7324 case FRAG_DELETE: 7325 /* we are removing this many lines from the source. */ 7326 offset += df->nlines; 7327 7328 if (df->pos + df->nlines > orig_lines->nlines) 7329 err = 1; 7330 else if (delvers) 7331 for (ln = df->pos; ln < df->pos + df->nlines; ++ln) 7332 if (orig_lines->vector[ln]->refcount > 1) 7333 /* Annotate needs this but, since the original 7334 * vector is disposed of before returning from 7335 * this function, we only need keep track if 7336 * there are multiple references. 7337 */ 7338 orig_lines->vector[ln]->vers = delvers; 7339 break; 7340 } 7341 } 7342 7343 df = df->next; 7344 free (dfhead); 7345 dfhead = df; 7346 } 7347 7348 if (err) 7349 { 7350 /* No reason to try and move a half-mutated and known invalid 7351 * text into the output buffer. 7352 */ 7353 linevector_free (&lines); 7354 } 7355 else 7356 { 7357 /* add the rest of the remaining lines to the data vector */ 7358 for (; lastmodline < numlines; lastmodline++) 7359 { 7360 /* we need to copy from the orig structure into new one */ 7361 lines.vector[lastmodline] = orig_lines->vector[lastmodline 7362 + offset]; 7363 lines.vector[lastmodline]->refcount++; 7364 } 7365 7366 /* Move the lines vector to the original structure for output, 7367 * first deleting the old. 7368 */ 7369 linevector_free (orig_lines); 7370 orig_lines->vector = lines.vector; 7371 orig_lines->lines_alloced = numlines; 7372 orig_lines->nlines = lines.nlines; 7373 } 7374 7375 return !err; 7376} 7377 7378/* Apply an RCS change text to a buffer. The function name starts 7379 with rcs rather than RCS because this does not take an RCSNode 7380 argument. NAME is used in error messages. TEXTBUF is the text 7381 buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are 7382 the change buffer and size. The new buffer is returned in *RETBUF 7383 and *RETLEN. The new buffer is allocated by xmalloc. 7384 7385 Return 1 for success. On failure, call error and return 0. */ 7386 7387int 7388rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen) 7389 const char *name; 7390 char *textbuf; 7391 size_t textlen; 7392 const char *diffbuf; 7393 size_t difflen; 7394 char **retbuf; 7395 size_t *retlen; 7396{ 7397 struct linevector lines; 7398 int ret; 7399 7400 *retbuf = NULL; 7401 *retlen = 0; 7402 7403 linevector_init (&lines); 7404 7405 if (! linevector_add (&lines, textbuf, textlen, NULL, 0)) 7406 error (1, 0, "cannot initialize line vector"); 7407 7408 if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL)) 7409 { 7410 error (0, 0, "invalid change text in %s", name); 7411 ret = 0; 7412 } 7413 else 7414 { 7415 char *p; 7416 size_t n; 7417 unsigned int ln; 7418 7419 n = 0; 7420 for (ln = 0; ln < lines.nlines; ++ln) 7421 /* 1 for \n */ 7422 n += lines.vector[ln]->len + 1; 7423 7424 p = xmalloc (n); 7425 *retbuf = p; 7426 7427 for (ln = 0; ln < lines.nlines; ++ln) 7428 { 7429 memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len); 7430 p += lines.vector[ln]->len; 7431 if (lines.vector[ln]->has_newline) 7432 *p++ = '\n'; 7433 } 7434 7435 *retlen = p - *retbuf; 7436 assert (*retlen <= n); 7437 7438 ret = 1; 7439 } 7440 7441 linevector_free (&lines); 7442 7443 return ret; 7444} 7445 7446/* Walk the deltas in RCS to get to revision VERSION. 7447 7448 If OP is RCS_ANNOTATE, then write annotations using cvs_output. 7449 7450 If OP is RCS_FETCH, then put the contents of VERSION into a 7451 newly-malloc'd array and put a pointer to it in *TEXT. Each line 7452 is \n terminated; the caller is responsible for converting text 7453 files if desired. The total length is put in *LEN. 7454 7455 If FP is non-NULL, it should be a file descriptor open to the file 7456 RCS with file position pointing to the deltas. We close the file 7457 when we are done. 7458 7459 If LOG is non-NULL, then *LOG is set to the log message of VERSION, 7460 and *LOGLEN is set to the length of the log message. 7461 7462 On error, give a fatal error. */ 7463 7464void 7465RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen) 7466 RCSNode *rcs; 7467 FILE *fp; 7468 struct rcsbuffer *rcsbuf; 7469 const char *version; 7470 enum rcs_delta_op op; 7471 char **text; 7472 size_t *len; 7473 char **log; 7474 size_t *loglen; 7475{ 7476 struct rcsbuffer rcsbuf_local; 7477 char *branchversion; 7478 char *cpversion; 7479 char *key; 7480 char *value; 7481 size_t vallen; 7482 RCSVers *vers; 7483 RCSVers *prev_vers; 7484 RCSVers *trunk_vers; 7485 char *next; 7486 int ishead, isnext, isversion, onbranch; 7487 Node *node; 7488 struct linevector headlines; 7489 struct linevector curlines; 7490 struct linevector trunklines; 7491 int foundhead; 7492 7493 assert (version); 7494 7495 if (fp == NULL) 7496 { 7497 rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local); 7498 rcsbuf = &rcsbuf_local; 7499 } 7500 7501 assert (rcsbuf); 7502 7503 if (log) *log = NULL; 7504 7505 ishead = 1; 7506 vers = NULL; 7507 prev_vers = NULL; 7508 trunk_vers = NULL; 7509 next = NULL; 7510 onbranch = 0; 7511 foundhead = 0; 7512 7513 linevector_init (&curlines); 7514 linevector_init (&headlines); 7515 linevector_init (&trunklines); 7516 7517 /* We set BRANCHVERSION to the version we are currently looking 7518 for. Initially, this is the version on the trunk from which 7519 VERSION branches off. If VERSION is not a branch, then 7520 BRANCHVERSION is just VERSION. */ 7521 branchversion = xstrdup (version); 7522 cpversion = strchr (branchversion, '.'); 7523 if (cpversion != NULL) 7524 cpversion = strchr (cpversion + 1, '.'); 7525 if (cpversion != NULL) 7526 *cpversion = '\0'; 7527 7528 do { 7529 if (! rcsbuf_getrevnum (rcsbuf, &key)) 7530 error (1, 0, "unexpected EOF reading RCS file %s", rcs->path); 7531 7532 /* look up the revision */ 7533 node = findnode (rcs->versions, key); 7534 if (!node) 7535 error (1, 0, 7536 "Delta text %s without revision information in `%s'.", 7537 key, rcs->path); 7538 7539 if (next != NULL && ! STREQ (next, key)) 7540 { 7541 /* This is not the next version we need. It is a branch 7542 version which we want to ignore. */ 7543 isnext = 0; 7544 isversion = 0; 7545 } 7546 else 7547 { 7548 isnext = 1; 7549 7550 /* Stash the previous version. */ 7551 prev_vers = vers; 7552 7553 vers = node->data; 7554 next = vers->next; 7555 7556 /* Compare key and trunkversion now, because key points to 7557 storage controlled by rcsbuf_getkey. */ 7558 if (STREQ (branchversion, key)) 7559 isversion = 1; 7560 else 7561 isversion = 0; 7562 } 7563 7564 while (1) 7565 { 7566 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7567 error (1, 0, "%s does not appear to be a valid rcs file", 7568 rcs->path); 7569 7570 if (log != NULL 7571 && isversion 7572 && STREQ (key, "log") 7573 && STREQ (branchversion, version)) 7574 { 7575 if (*log != NULL) 7576 { 7577 error (0, 0, "Duplicate `log' keyword in RCS file (`%s').", 7578 rcs->path); 7579 free (*log); 7580 } 7581 *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen); 7582 } 7583 7584 if (STREQ (key, "text")) 7585 { 7586 rcsbuf_valpolish (rcsbuf, value, 0, &vallen); 7587 if (ishead) 7588 { 7589 if (! linevector_add (&curlines, value, vallen, NULL, 0)) 7590 error (1, 0, "invalid rcs file %s", rcs->path); 7591 7592 ishead = 0; 7593 } 7594 else if (isnext) 7595 { 7596 if (! apply_rcs_changes (&curlines, value, vallen, 7597 rcs->path, 7598 onbranch ? vers : NULL, 7599 onbranch ? NULL : prev_vers)) 7600 error (1, 0, "invalid change text in %s", rcs->path); 7601 } 7602 break; 7603 } 7604 } 7605 7606 if (isversion) 7607 { 7608 /* This is either the version we want, or it is the 7609 branchpoint to the version we want. */ 7610 if (STREQ (branchversion, version)) 7611 { 7612 /* This is the version we want. */ 7613 linevector_copy (&headlines, &curlines); 7614 foundhead = 1; 7615 if (onbranch) 7616 { 7617 /* We have found this version by tracking up a 7618 branch. Restore back to the lines we saved 7619 when we left the trunk, and continue tracking 7620 down the trunk. */ 7621 onbranch = 0; 7622 vers = trunk_vers; 7623 next = vers->next; 7624 linevector_copy (&curlines, &trunklines); 7625 } 7626 } 7627 else 7628 { 7629 Node *p; 7630 7631 /* We need to look up the branch. */ 7632 onbranch = 1; 7633 7634 if (numdots (branchversion) < 2) 7635 { 7636 unsigned int ln; 7637 7638 /* We are leaving the trunk; save the current 7639 lines so that we can restore them when we 7640 continue tracking down the trunk. */ 7641 trunk_vers = vers; 7642 linevector_copy (&trunklines, &curlines); 7643 7644 /* Reset the version information we have 7645 accumulated so far. It only applies to the 7646 changes from the head to this version. */ 7647 for (ln = 0; ln < curlines.nlines; ++ln) 7648 curlines.vector[ln]->vers = NULL; 7649 } 7650 7651 /* The next version we want is the entry on 7652 VERS->branches which matches this branch. For 7653 example, suppose VERSION is 1.21.4.3 and 7654 BRANCHVERSION was 1.21. Then we look for an entry 7655 starting with "1.21.4" and we'll put it (probably 7656 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by 7657 two dots (in this example, to 1.21.4.3). */ 7658 7659 if (vers->branches == NULL) 7660 error (1, 0, "missing expected branches in %s", 7661 rcs->path); 7662 if (!cpversion) 7663 error (1, 0, "Invalid revision number in `%s'.", 7664 rcs->path); 7665 *cpversion = '.'; 7666 ++cpversion; 7667 cpversion = strchr (cpversion, '.'); 7668 if (cpversion == NULL) 7669 error (1, 0, "version number confusion in %s", 7670 rcs->path); 7671 for (p = vers->branches->list->next; 7672 p != vers->branches->list; 7673 p = p->next) 7674 if (strncmp (p->key, branchversion, 7675 cpversion - branchversion) == 0) 7676 break; 7677 if (p == vers->branches->list) 7678 error (1, 0, "missing expected branch in %s", 7679 rcs->path); 7680 7681 next = p->key; 7682 7683 cpversion = strchr (cpversion + 1, '.'); 7684 if (cpversion != NULL) 7685 *cpversion = '\0'; 7686 } 7687 } 7688 if (op == RCS_FETCH && foundhead) 7689 break; 7690 } while (next != NULL); 7691 7692 free (branchversion); 7693 7694 rcsbuf_cache (rcs, rcsbuf); 7695 7696 if (! foundhead) 7697 error (1, 0, "could not find desired version %s in %s", 7698 version, rcs->path); 7699 7700 /* Now print out or return the data we have just computed. */ 7701 switch (op) 7702 { 7703 case RCS_ANNOTATE: 7704 { 7705 unsigned int ln; 7706 7707 for (ln = 0; ln < headlines.nlines; ++ln) 7708 { 7709 char *buf; 7710 /* Period which separates year from month in date. */ 7711 char *ym; 7712 /* Period which separates month from day in date. */ 7713 char *md; 7714 RCSVers *prvers; 7715 7716 prvers = headlines.vector[ln]->vers; 7717 if (prvers == NULL) 7718 prvers = vers; 7719 7720 buf = xmalloc (strlen (prvers->version) + 24); 7721 sprintf (buf, "%-12s (%-8.8s ", 7722 prvers->version, 7723 prvers->author); 7724 cvs_output (buf, 0); 7725 free (buf); 7726 7727 /* Now output the date. */ 7728 ym = strchr (prvers->date, '.'); 7729 if (ym == NULL) 7730 { 7731 /* ??- is an ANSI trigraph. The ANSI way to 7732 avoid it is \? but some pre ANSI compilers 7733 complain about the unrecognized escape 7734 sequence. Of course string concatenation 7735 ("??" "-???") is also an ANSI-ism. Testing 7736 __STDC__ seems to be a can of worms, since 7737 compilers do all kinds of things with it. */ 7738 cvs_output ("??", 0); 7739 cvs_output ("-???", 0); 7740 cvs_output ("-??", 0); 7741 } 7742 else 7743 { 7744 md = strchr (ym + 1, '.'); 7745 if (md == NULL) 7746 cvs_output ("??", 0); 7747 else 7748 cvs_output (md + 1, 2); 7749 7750 cvs_output ("-", 1); 7751 cvs_output (month_printname (ym + 1), 0); 7752 cvs_output ("-", 1); 7753 /* Only output the last two digits of the year. Our output 7754 lines are long enough as it is without printing the 7755 century. */ 7756 cvs_output (ym - 2, 2); 7757 } 7758 cvs_output ("): ", 0); 7759 if (headlines.vector[ln]->len != 0) 7760 cvs_output (headlines.vector[ln]->text, 7761 headlines.vector[ln]->len); 7762 cvs_output ("\n", 1); 7763 } 7764 } 7765 break; 7766 case RCS_FETCH: 7767 { 7768 char *p; 7769 size_t n; 7770 unsigned int ln; 7771 7772 assert (text != NULL); 7773 assert (len != NULL); 7774 7775 n = 0; 7776 for (ln = 0; ln < headlines.nlines; ++ln) 7777 /* 1 for \n */ 7778 n += headlines.vector[ln]->len + 1; 7779 p = xmalloc (n); 7780 *text = p; 7781 for (ln = 0; ln < headlines.nlines; ++ln) 7782 { 7783 memcpy (p, headlines.vector[ln]->text, 7784 headlines.vector[ln]->len); 7785 p += headlines.vector[ln]->len; 7786 if (headlines.vector[ln]->has_newline) 7787 *p++ = '\n'; 7788 } 7789 *len = p - *text; 7790 assert (*len <= n); 7791 } 7792 break; 7793 } 7794 7795 linevector_free (&curlines); 7796 linevector_free (&headlines); 7797 linevector_free (&trunklines); 7798 7799 return; 7800} 7801 7802/* Read the information for a single delta from the RCS buffer RCSBUF, 7803 whose name is RCSFILE. *KEYP and *VALP are either NULL, or the 7804 first key/value pair to read, as set by rcsbuf_getkey. Return NULL 7805 if there are no more deltas. Store the key/value pair which 7806 terminated the read in *KEYP and *VALP. */ 7807 7808static RCSVers * 7809getdelta (rcsbuf, rcsfile, keyp, valp) 7810 struct rcsbuffer *rcsbuf; 7811 char *rcsfile; 7812 char **keyp; 7813 char **valp; 7814{ 7815 RCSVers *vnode; 7816 char *key, *value, *cp; 7817 Node *kv; 7818 7819 /* Get revision number if it wasn't passed in. This uses 7820 rcsbuf_getkey because it doesn't croak when encountering 7821 unexpected input. As a result, we have to play unholy games 7822 with `key' and `value'. */ 7823 if (*keyp != NULL) 7824 { 7825 key = *keyp; 7826 value = *valp; 7827 } 7828 else 7829 { 7830 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7831 error (1, 0, "%s: unexpected EOF", rcsfile); 7832 } 7833 7834 /* Make sure that it is a revision number and not a cabbage 7835 or something. */ 7836 for (cp = key; 7837 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7838 cp++) 7839 /* do nothing */ ; 7840 /* Note that when comparing with RCSDATE, we are not massaging 7841 VALUE from the string found in the RCS file. This is OK since 7842 we know exactly what to expect. */ 7843 if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0) 7844 { 7845 *keyp = key; 7846 *valp = value; 7847 return NULL; 7848 } 7849 7850 vnode = (RCSVers *) xmalloc (sizeof (RCSVers)); 7851 memset (vnode, 0, sizeof (RCSVers)); 7852 7853 vnode->version = xstrdup (key); 7854 7855 /* Grab the value of the date from value. Note that we are not 7856 massaging VALUE from the string found in the RCS file. */ 7857 cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */ 7858 while (whitespace (*cp)) /* take space off front of value */ 7859 cp++; 7860 7861 vnode->date = xstrdup (cp); 7862 7863 /* Get author field. */ 7864 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7865 { 7866 error (1, 0, "unexpected end of file reading %s", rcsfile); 7867 } 7868 if (! STREQ (key, "author")) 7869 error (1, 0, "\ 7870unable to parse %s; `author' not in the expected place", rcsfile); 7871 vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7872 7873 /* Get state field. */ 7874 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7875 { 7876 error (1, 0, "unexpected end of file reading %s", rcsfile); 7877 } 7878 if (! STREQ (key, "state")) 7879 error (1, 0, "\ 7880unable to parse %s; `state' not in the expected place", rcsfile); 7881 vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7882 /* The value is optional, according to rcsfile(5). */ 7883 if (value != NULL && STREQ (value, RCSDEAD)) 7884 { 7885 vnode->dead = 1; 7886 } 7887 7888 /* Note that "branches" and "next" are in fact mandatory, according 7889 to doc/RCSFILES. */ 7890 7891 /* fill in the branch list (if any branches exist) */ 7892 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7893 { 7894 error (1, 0, "unexpected end of file reading %s", rcsfile); 7895 } 7896 if (STREQ (key, RCSDESC)) 7897 { 7898 *keyp = key; 7899 *valp = value; 7900 /* Probably could/should be a fatal error. */ 7901 error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile); 7902 return vnode; 7903 } 7904 if (value != (char *) NULL) 7905 { 7906 vnode->branches = getlist (); 7907 /* Note that we are not massaging VALUE from the string found 7908 in the RCS file. */ 7909 do_branches (vnode->branches, value); 7910 } 7911 7912 /* fill in the next field if there is a next revision */ 7913 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7914 { 7915 error (1, 0, "unexpected end of file reading %s", rcsfile); 7916 } 7917 if (STREQ (key, RCSDESC)) 7918 { 7919 *keyp = key; 7920 *valp = value; 7921 /* Probably could/should be a fatal error. */ 7922 error (0, 0, "warning: 'next' keyword missing from %s", rcsfile); 7923 return vnode; 7924 } 7925 if (value != (char *) NULL) 7926 vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 7927 7928 /* 7929 * XXX - this is where we put the symbolic link stuff??? 7930 * (into newphrases in the deltas). 7931 */ 7932 while (1) 7933 { 7934 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 7935 error (1, 0, "unexpected end of file reading %s", rcsfile); 7936 7937 /* The `desc' keyword is the end of the deltas. */ 7938 if (strcmp (key, RCSDESC) == 0) 7939 break; 7940 7941#ifdef PRESERVE_PERMISSIONS_SUPPORT 7942 7943 /* The `hardlinks' value is a group of words, which must 7944 be parsed separately and added as a list to vnode->hardlinks. */ 7945 if (strcmp (key, "hardlinks") == 0) 7946 { 7947 char *word; 7948 7949 vnode->hardlinks = getlist(); 7950 while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) 7951 { 7952 Node *n = getnode(); 7953 n->key = word; 7954 addnode (vnode->hardlinks, n); 7955 } 7956 continue; 7957 } 7958#endif 7959 7960 /* Enable use of repositories created by certain obsolete 7961 versions of CVS. This code should remain indefinately; 7962 there is no procedure for converting old repositories, and 7963 checking for it is harmless. */ 7964 if (STREQ (key, RCSDEAD)) 7965 { 7966 vnode->dead = 1; 7967 if (vnode->state != NULL) 7968 free (vnode->state); 7969 vnode->state = xstrdup (RCSDEAD); 7970 continue; 7971 } 7972 /* if we have a new revision number, we're done with this delta */ 7973 for (cp = key; 7974 (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; 7975 cp++) 7976 /* do nothing */ ; 7977 /* Note that when comparing with RCSDATE, we are not massaging 7978 VALUE from the string found in the RCS file. This is OK 7979 since we know exactly what to expect. */ 7980 if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) 7981 break; 7982 7983 /* At this point, key and value represent a user-defined field 7984 in the delta node. */ 7985 if (vnode->other_delta == NULL) 7986 vnode->other_delta = getlist (); 7987 kv = getnode (); 7988 kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 7989 kv->key = xstrdup (key); 7990 kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, 7991 (size_t *) NULL); 7992 if (addnode (vnode->other_delta, kv) != 0) 7993 { 7994 /* Complaining about duplicate keys in newphrases seems 7995 questionable, in that we don't know what they mean and 7996 doc/RCSFILES has no prohibition on several newphrases 7997 with the same key. But we can't store more than one as 7998 long as we store them in a List *. */ 7999 error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", 8000 key, rcsfile); 8001 freenode (kv); 8002 } 8003 } 8004 8005 /* Return the key which caused us to fail back to the caller. */ 8006 *keyp = key; 8007 *valp = value; 8008 8009 return vnode; 8010} 8011 8012static void 8013freedeltatext (d) 8014 Deltatext *d; 8015{ 8016 if (d->version != NULL) 8017 free (d->version); 8018 if (d->log != NULL) 8019 free (d->log); 8020 if (d->text != NULL) 8021 free (d->text); 8022 if (d->other != (List *) NULL) 8023 dellist (&d->other); 8024 free (d); 8025} 8026 8027static Deltatext * 8028RCS_getdeltatext (rcs, fp, rcsbuf) 8029 RCSNode *rcs; 8030 FILE *fp; 8031 struct rcsbuffer *rcsbuf; 8032{ 8033 char *num; 8034 char *key, *value; 8035 Node *p; 8036 Deltatext *d; 8037 8038 /* Get the revision number. */ 8039 if (! rcsbuf_getrevnum (rcsbuf, &num)) 8040 { 8041 /* If num == NULL, it means we reached EOF naturally. That's 8042 fine. */ 8043 if (num == NULL) 8044 return NULL; 8045 else 8046 error (1, 0, "%s: unexpected EOF", rcs->path); 8047 } 8048 8049 p = findnode (rcs->versions, num); 8050 if (!p) 8051 error (1, 0, 8052 "Delta text %s without revision information in `%s'.", 8053 num, rcs->path); 8054 8055 d = (Deltatext *) xmalloc (sizeof (Deltatext)); 8056 d->version = xstrdup (num); 8057 8058 /* Get the log message. */ 8059 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 8060 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); 8061 if (! STREQ (key, "log")) 8062 error (1, 0, "%s, delta %s: expected `log', got `%s'", 8063 rcs->path, num, key); 8064 d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); 8065 8066 /* Get random newphrases. */ 8067 d->other = getlist(); 8068 while (1) 8069 { 8070 if (! rcsbuf_getkey (rcsbuf, &key, &value)) 8071 error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); 8072 8073 if (STREQ (key, "text")) 8074 break; 8075 8076 p = getnode(); 8077 p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; 8078 p->key = xstrdup (key); 8079 p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, 8080 (size_t *) NULL); 8081 if (addnode (d->other, p) < 0) 8082 { 8083 error (0, 0, "warning: %s, delta %s: duplicate field `%s'", 8084 rcs->path, num, key); 8085 } 8086 } 8087 8088 /* Get the change text. We already know that this key is `text'. */ 8089 d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len); 8090 8091 return d; 8092} 8093 8094/* RCS output functions, for writing RCS format files from RCSNode 8095 structures. 8096 8097 For most of this work, RCS 5.7 uses an `aprintf' function which aborts 8098 program upon error. Instead, these functions check the output status 8099 of the stream right before closing it, and aborts if an error condition 8100 is found. The RCS solution is probably the better one: it produces 8101 more overhead, but will produce a clearer diagnostic in the case of 8102 catastrophic error. In either case, however, the repository will probably 8103 not get corrupted. */ 8104 8105static int 8106putsymbol_proc (symnode, fparg) 8107 Node *symnode; 8108 void *fparg; 8109{ 8110 FILE *fp = (FILE *) fparg; 8111 8112 /* A fiddly optimization: this code used to just call fprintf, but 8113 in an old repository with hundreds of tags this can get called 8114 hundreds of thousands of times when doing a cvs tag. Since 8115 tagging is a relatively common operation, and using putc and 8116 fputs is just as comprehensible, the change is worthwhile. */ 8117 putc ('\n', fp); 8118 putc ('\t', fp); 8119 fputs (symnode->key, fp); 8120 putc (':', fp); 8121 fputs (symnode->data, fp); 8122 return 0; 8123} 8124 8125static int putlock_proc PROTO ((Node *, void *)); 8126 8127/* putlock_proc is like putsymbol_proc, but key and data are reversed. */ 8128 8129static int 8130putlock_proc (symnode, fp) 8131 Node *symnode; 8132 void *fp; 8133{ 8134 return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key); 8135} 8136 8137static int 8138putrcsfield_proc (node, vfp) 8139 Node *node; 8140 void *vfp; 8141{ 8142 FILE *fp = (FILE *) vfp; 8143 8144 /* Some magic keys used internally by CVS start with `;'. Skip them. */ 8145 if (node->key[0] == ';') 8146 return 0; 8147 8148 fprintf (fp, "\n%s\t", node->key); 8149 if (node->data != NULL) 8150 { 8151 /* If the field's value contains evil characters, 8152 it must be stringified. */ 8153 /* FIXME: This does not quite get it right. "7jk8f" is not a legal 8154 value for a value in a newpharse, according to doc/RCSFILES, 8155 because digits are not valid in an "id". We might do OK by 8156 always writing strings (enclosed in @@). Would be nice to 8157 explicitly mention this one way or another in doc/RCSFILES. 8158 A case where we are wrong in a much more clear-cut way is that 8159 we let through non-graphic characters such as whitespace and 8160 control characters. */ 8161 8162 if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) 8163 fputs (node->data, fp); 8164 else 8165 { 8166 putc ('@', fp); 8167 expand_at_signs (node->data, (off_t) strlen (node->data), fp); 8168 putc ('@', fp); 8169 } 8170 } 8171 8172 /* desc, log and text fields should not be terminated with semicolon; 8173 all other fields should be. */ 8174 if (! STREQ (node->key, "desc") && 8175 ! STREQ (node->key, "log") && 8176 ! STREQ (node->key, "text")) 8177 { 8178 putc (';', fp); 8179 } 8180 return 0; 8181} 8182 8183#ifdef PRESERVE_PERMISSIONS_SUPPORT 8184 8185/* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain 8186 a full pathname, but currently only basenames are stored in the RCS 8187 node. Assume that the filename includes nasty characters and 8188 @-escape it. */ 8189 8190static int 8191puthardlink_proc (node, vfp) 8192 Node *node; 8193 void *vfp; 8194{ 8195 FILE *fp = (FILE *) vfp; 8196 char *basename = strrchr (node->key, '/'); 8197 8198 if (basename == NULL) 8199 basename = node->key; 8200 else 8201 ++basename; 8202 8203 putc ('\t', fp); 8204 putc ('@', fp); 8205 (void) expand_at_signs (basename, strlen (basename), fp); 8206 putc ('@', fp); 8207 8208 return 0; 8209} 8210 8211#endif 8212 8213/* Output the admin node for RCS into stream FP. */ 8214 8215static void 8216RCS_putadmin (rcs, fp) 8217 RCSNode *rcs; 8218 FILE *fp; 8219{ 8220 fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : ""); 8221 if (rcs->branch) 8222 fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch); 8223 8224 fputs ("access", fp); 8225 if (rcs->access) 8226 { 8227 char *p, *s; 8228 s = xstrdup (rcs->access); 8229 for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t")) 8230 fprintf (fp, "\n\t%s", p); 8231 free (s); 8232 } 8233 fputs (";\n", fp); 8234 8235 fputs (RCSSYMBOLS, fp); 8236 /* If we haven't had to convert the symbols to a list yet, don't 8237 force a conversion now; just write out the string. */ 8238 if (rcs->symbols == NULL && rcs->symbols_data != NULL) 8239 { 8240 fputs ("\n\t", fp); 8241 fputs (rcs->symbols_data, fp); 8242 } 8243 else 8244 walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp); 8245 fputs (";\n", fp); 8246 8247 fputs ("locks", fp); 8248 if (rcs->locks_data) 8249 fprintf (fp, "\t%s", rcs->locks_data); 8250 else if (rcs->locks) 8251 walklist (rcs->locks, putlock_proc, (void *) fp); 8252 if (rcs->strict_locks) 8253 fprintf (fp, "; strict"); 8254 fputs (";\n", fp); 8255 8256 if (rcs->comment) 8257 { 8258 fprintf (fp, "comment\t@"); 8259 expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp); 8260 fputs ("@;\n", fp); 8261 } 8262 if (rcs->expand && ! STREQ (rcs->expand, "kv")) 8263 fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand); 8264 8265 walklist (rcs->other, putrcsfield_proc, (void *) fp); 8266 8267 putc ('\n', fp); 8268} 8269 8270static void 8271putdelta (vers, fp) 8272 RCSVers *vers; 8273 FILE *fp; 8274{ 8275 Node *bp, *start; 8276 8277 /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */ 8278 if (vers == NULL || vers->outdated) 8279 return; 8280 8281 fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", 8282 vers->version, 8283 RCSDATE, vers->date, 8284 "author", vers->author, 8285 "state", vers->state ? vers->state : ""); 8286 8287 if (vers->branches != NULL) 8288 { 8289 start = vers->branches->list; 8290 for (bp = start->next; bp != start; bp = bp->next) 8291 fprintf (fp, "\n\t%s", bp->key); 8292 } 8293 8294 fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : ""); 8295 8296 walklist (vers->other_delta, putrcsfield_proc, fp); 8297 8298#ifdef PRESERVE_PERMISSIONS_SUPPORT 8299 if (vers->hardlinks) 8300 { 8301 fprintf (fp, "\nhardlinks"); 8302 walklist (vers->hardlinks, puthardlink_proc, fp); 8303 putc (';', fp); 8304 } 8305#endif 8306 putc ('\n', fp); 8307} 8308 8309static void 8310RCS_putdtree (rcs, rev, fp) 8311 RCSNode *rcs; 8312 char *rev; 8313 FILE *fp; 8314{ 8315 RCSVers *versp; 8316 Node *p, *branch; 8317 8318 /* Previously, this function used a recursive implementation, but 8319 if the trunk has a huge number of revisions and the program 8320 stack is not big, a stack overflow could occur, so this 8321 nonrecursive version was developed to be more safe. */ 8322 Node *branchlist, *onebranch; 8323 List *branches; 8324 List *onebranchlist; 8325 8326 if (rev == NULL) 8327 return; 8328 8329 branches = getlist(); 8330 8331 for (; rev != NULL;) 8332 { 8333 /* Find the delta node for this revision. */ 8334 p = findnode (rcs->versions, rev); 8335 if (p == NULL) 8336 { 8337 error (1, 0, 8338 "error parsing repository file %s, file may be corrupt.", 8339 rcs->path); 8340 } 8341 8342 versp = p->data; 8343 8344 /* Print the delta node and go for its `next' node. This 8345 prints the trunk. If there are any branches printed on this 8346 revision, mark we have some. */ 8347 putdelta (versp, fp); 8348 /* Store branch information into branch list so to write its 8349 trunk afterwards */ 8350 if (versp->branches != NULL) 8351 { 8352 branch = getnode(); 8353 branch->data = versp->branches; 8354 8355 addnode(branches, branch); 8356 } 8357 8358 rev = versp->next; 8359 } 8360 8361 /* If there are any branches printed on this revision, 8362 print those trunks as well. */ 8363 branchlist = branches->list; 8364 for (branch = branchlist->next; 8365 branch != branchlist; 8366 branch = branch->next) 8367 { 8368 onebranchlist = (List *)(branch->data); 8369 onebranch = onebranchlist->list; 8370 for (p = onebranch->next; p != onebranch; p = p->next) 8371 RCS_putdtree (rcs, p->key, fp); 8372 8373 branch->data = NULL; /* so to prevent its freeing on dellist */ 8374 } 8375 8376 dellist(&branches); 8377} 8378 8379static void 8380RCS_putdesc (rcs, fp) 8381 RCSNode *rcs; 8382 FILE *fp; 8383{ 8384 fprintf (fp, "\n\n%s\n@", RCSDESC); 8385 if (rcs->desc != NULL) 8386 { 8387 off_t len = (off_t) strlen (rcs->desc); 8388 if (len > 0) 8389 { 8390 expand_at_signs (rcs->desc, len, fp); 8391 if (rcs->desc[len-1] != '\n') 8392 putc ('\n', fp); 8393 } 8394 } 8395 fputs ("@\n", fp); 8396} 8397 8398static void 8399putdeltatext (fp, d) 8400 FILE *fp; 8401 Deltatext *d; 8402{ 8403 fprintf (fp, "\n\n%s\nlog\n@", d->version); 8404 if (d->log != NULL) 8405 { 8406 int loglen = strlen (d->log); 8407 expand_at_signs (d->log, (off_t) loglen, fp); 8408 if (d->log[loglen-1] != '\n') 8409 putc ('\n', fp); 8410 } 8411 putc ('@', fp); 8412 8413 walklist (d->other, putrcsfield_proc, fp); 8414 8415 fputs ("\ntext\n@", fp); 8416 if (d->text != NULL) 8417 expand_at_signs (d->text, (off_t) d->len, fp); 8418 fputs ("@\n", fp); 8419} 8420 8421/* TODO: the whole mechanism for updating deltas is kludgey... more 8422 sensible would be to supply all the necessary info in a `newdeltatext' 8423 field for RCSVers nodes. -twp */ 8424 8425/* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it 8426 is a new delta text node, and should be added to the tree at the 8427 node whose revision number is INSERTPT. (Note that trunk nodes are 8428 written in decreasing order, and branch nodes are written in 8429 increasing order.) */ 8430 8431static void 8432RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt) 8433 RCSNode *rcs; 8434 FILE *fin; 8435 struct rcsbuffer *rcsbufin; 8436 FILE *fout; 8437 Deltatext *newdtext; 8438 char *insertpt; 8439{ 8440 int actions; 8441 RCSVers *dadmin; 8442 Node *np; 8443 int insertbefore, found; 8444 char *bufrest; 8445 int nls; 8446 size_t buflen; 8447 char buf[8192]; 8448 int got; 8449 8450 /* Count the number of versions for which we have to do some 8451 special operation. */ 8452 actions = walklist (rcs->versions, count_delta_actions, (void *) NULL); 8453 8454 /* Make a note of whether NEWDTEXT should be inserted 8455 before or after its INSERTPT. */ 8456 insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1); 8457 8458 while (actions != 0 || newdtext != NULL) 8459 { 8460 Deltatext *dtext; 8461 8462 dtext = RCS_getdeltatext (rcs, fin, rcsbufin); 8463 8464 /* We shouldn't hit EOF here, because that would imply that 8465 some action was not taken, or that we could not insert 8466 NEWDTEXT. */ 8467 if (dtext == NULL) 8468 error (1, 0, "internal error: EOF too early in RCS_copydeltas"); 8469 8470 found = (insertpt != NULL && STREQ (dtext->version, insertpt)); 8471 if (found && insertbefore) 8472 { 8473 putdeltatext (fout, newdtext); 8474 newdtext = NULL; 8475 insertpt = NULL; 8476 } 8477 8478 np = findnode (rcs->versions, dtext->version); 8479 if (!np) 8480 error (1, 0, 8481 "Delta text %s without revision information in `%s'.", 8482 dtext->version, rcs->path); 8483 8484 dadmin = np->data; 8485 8486 /* If this revision has been outdated, just skip it. */ 8487 if (dadmin->outdated) 8488 { 8489 freedeltatext (dtext); 8490 --actions; 8491 continue; 8492 } 8493 8494 /* Update the change text for this delta. New change text 8495 data may come from cvs admin -m, cvs admin -o, or cvs ci. */ 8496 if (dadmin->text != NULL) 8497 { 8498 if (dadmin->text->log != NULL || dadmin->text->text != NULL) 8499 --actions; 8500 if (dadmin->text->log != NULL) 8501 { 8502 free (dtext->log); 8503 dtext->log = dadmin->text->log; 8504 dadmin->text->log = NULL; 8505 } 8506 if (dadmin->text->text != NULL) 8507 { 8508 free (dtext->text); 8509 dtext->text = dadmin->text->text; 8510 dtext->len = dadmin->text->len; 8511 dadmin->text->text = NULL; 8512 } 8513 } 8514 putdeltatext (fout, dtext); 8515 freedeltatext (dtext); 8516 8517 if (found && !insertbefore) 8518 { 8519 putdeltatext (fout, newdtext); 8520 newdtext = NULL; 8521 insertpt = NULL; 8522 } 8523 } 8524 8525 /* Copy the rest of the file directly, without bothering to 8526 interpret it. The caller will handle error checking by calling 8527 ferror. 8528 8529 We just wrote a newline to the file, either in putdeltatext or 8530 in the caller. However, we may not have read the corresponding 8531 newline from the file, because rcsbuf_getkey returns as soon as 8532 it finds the end of the '@' string for the desc or text key. 8533 Therefore, we may read three newlines when we should really 8534 only write two, and we check for that case here. This is not 8535 an semantically important issue; we only do it to make our RCS 8536 files look traditional. */ 8537 8538 nls = 3; 8539 8540 rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen); 8541 if (buflen > 0) 8542 { 8543 if (bufrest[0] != '\n' 8544 || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0) 8545 { 8546 nls = 0; 8547 } 8548 else 8549 { 8550 if (buflen < 3) 8551 nls -= buflen; 8552 else 8553 { 8554 ++bufrest; 8555 --buflen; 8556 nls = 0; 8557 } 8558 } 8559 8560 fwrite (bufrest, 1, buflen, fout); 8561 } 8562 if (!rcsbufin->mmapped) 8563 { 8564 /* This bit isn't necessary when using mmap since the entire file 8565 * will already be available via the RCS buffer. Besides, the 8566 * mmap code doesn't always keep the file pointer up to date, so 8567 * this adds some data twice. 8568 */ 8569 while ((got = fread (buf, 1, sizeof buf, fin)) != 0) 8570 { 8571 if (nls > 0 8572 && got >= nls 8573 && buf[0] == '\n' 8574 && strncmp (buf, "\n\n\n", nls) == 0) 8575 { 8576 fwrite (buf + 1, 1, got - 1, fout); 8577 } 8578 else 8579 { 8580 fwrite (buf, 1, got, fout); 8581 } 8582 8583 nls = 0; 8584 } 8585 } 8586} 8587 8588/* A helper procedure for RCS_copydeltas. This is called via walklist 8589 to count the number of RCS revisions for which some special action 8590 is required. */ 8591 8592static int 8593count_delta_actions (np, ignore) 8594 Node *np; 8595 void *ignore; 8596{ 8597 RCSVers *dadmin = np->data; 8598 8599 if (dadmin->outdated) 8600 return 1; 8601 8602 if (dadmin->text != NULL 8603 && (dadmin->text->log != NULL || dadmin->text->text != NULL)) 8604 { 8605 return 1; 8606 } 8607 8608 return 0; 8609} 8610 8611/* 8612 * Clean up temporary files 8613 */ 8614RETSIGTYPE 8615rcs_cleanup () 8616{ 8617 /* Note that the checks for existence_error are because we are 8618 called from a signal handler, so we don't know whether the 8619 files got created. */ 8620 8621 /* FIXME: Do not perform buffered I/O from an interrupt handler like 8622 this (via error). However, I'm leaving the error-calling code there 8623 in the hope that on the rare occasion the error call is actually made 8624 (e.g., a fluky I/O error or permissions problem prevents the deletion 8625 of a just-created file) reentrancy won't be an issue. */ 8626 if (rcs_lockfile != NULL) 8627 { 8628 char *tmp = rcs_lockfile; 8629 rcs_lockfile = NULL; 8630 if (rcs_lockfd >= 0) 8631 { 8632 if (close (rcs_lockfd) != 0) 8633 error (0, errno, "error closing lock file %s", tmp); 8634 rcs_lockfd = -1; 8635 } 8636 if (unlink_file (tmp) < 0 8637 && !existence_error (errno)) 8638 error (0, errno, "cannot remove %s", tmp); 8639 } 8640} 8641 8642/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style 8643 locking on the specified RCSFILE: for a file called `foo,v', open 8644 for writing a file called `,foo,'. 8645 8646 Note that we what do here is quite different from what RCS does. 8647 RCS creates the ,foo, file before it reads the RCS file (if it 8648 knows that it will be writing later), so that it actually serves as 8649 a lock. We don't; instead we rely on CVS writelocks. This means 8650 that if someone is running RCS on the file at the same time they 8651 are running CVS on it, they might lose (we read the file, 8652 then RCS writes it, then we write it, clobbering the 8653 changes made by RCS). I believe the current sentiment about this 8654 is "well, don't do that". 8655 8656 A concern has been expressed about whether adopting the RCS 8657 strategy would slow us down. I don't think so, since we need to 8658 write the ,foo, file anyway (unless perhaps if O_EXCL is slower or 8659 something). 8660 8661 These do not perform quite the same function as the RCS -l option 8662 for locking files: they are intended to prevent competing RCS 8663 processes from stomping all over each other's laundry. Hence, 8664 they are `internal' locking functions. 8665 8666 If there is an error, give a fatal error; if we return we always 8667 return a non-NULL value. */ 8668 8669static FILE * 8670rcs_internal_lockfile (rcsfile) 8671 char *rcsfile; 8672{ 8673 struct stat rstat; 8674 FILE *fp; 8675 static int first_call = 1; 8676 8677 if (first_call) 8678 { 8679 first_call = 0; 8680 /* clean up if we get a signal */ 8681#ifdef SIGABRT 8682 (void) SIG_register (SIGABRT, rcs_cleanup); 8683#endif 8684#ifdef SIGHUP 8685 (void) SIG_register (SIGHUP, rcs_cleanup); 8686#endif 8687#ifdef SIGINT 8688 (void) SIG_register (SIGINT, rcs_cleanup); 8689#endif 8690#ifdef SIGQUIT 8691 (void) SIG_register (SIGQUIT, rcs_cleanup); 8692#endif 8693#ifdef SIGPIPE 8694 (void) SIG_register (SIGPIPE, rcs_cleanup); 8695#endif 8696#ifdef SIGTERM 8697 (void) SIG_register (SIGTERM, rcs_cleanup); 8698#endif 8699 } 8700 8701 /* Get the lock file name: `,file,' for RCS file `file,v'. */ 8702 assert (rcs_lockfile == NULL); 8703 assert (rcs_lockfd < 0); 8704 rcs_lockfile = rcs_lockfilename (rcsfile); 8705 8706 /* Use the existing RCS file mode, or read-only if this is a new 8707 file. (Really, this is a lie -- if this is a new file, 8708 RCS_checkin uses the permissions from the working copy. For 8709 actually creating the file, we use 0444 as a safe default mode.) */ 8710 if (stat (rcsfile, &rstat) < 0) 8711 { 8712 if (existence_error (errno)) 8713 rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH; 8714 else 8715 error (1, errno, "cannot stat %s", rcsfile); 8716 } 8717 8718 /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT 8719 guarantees an exclusive open. According to the RCS source, with 8720 NFS v2 we must also throw in O_TRUNC and use an open mask that makes 8721 the file unwriteable. For extensive justification, see the comments for 8722 rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless 8723 in the CVS case; see comment at the start of this file concerning 8724 general ,foo, file strategy. 8725 8726 There is some sentiment that with NFSv3 and such, that one can 8727 rely on O_EXCL these days. This might be true for unix (I 8728 don't really know), but I am still pretty skeptical in the case 8729 of the non-unix systems. */ 8730 rcs_lockfd = open (rcs_lockfile, 8731 OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 8732 S_IRUSR | S_IRGRP | S_IROTH); 8733 8734 if (rcs_lockfd < 0) 8735 { 8736 error (1, errno, "could not open lock file `%s'", rcs_lockfile); 8737 } 8738 8739 /* Force the file permissions, and return a stream object. */ 8740 /* Because we change the modes later, we don't worry about 8741 this in the non-HAVE_FCHMOD case. */ 8742#ifdef HAVE_FCHMOD 8743 if (fchmod (rcs_lockfd, rstat.st_mode) < 0) 8744 error (1, errno, "cannot change mode for %s", rcs_lockfile); 8745#endif 8746 fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); 8747 if (fp == NULL) 8748 error (1, errno, "cannot fdopen %s", rcs_lockfile); 8749 8750 return fp; 8751} 8752 8753static void 8754rcs_internal_unlockfile (fp, rcsfile) 8755 FILE *fp; 8756 char *rcsfile; 8757{ 8758 assert (rcs_lockfile != NULL); 8759 assert (rcs_lockfd >= 0); 8760 8761 /* Abort if we could not write everything successfully to LOCKFILE. 8762 This is not a great error-handling mechanism, but should prevent 8763 corrupting the repository. */ 8764 8765 if (ferror (fp)) 8766 /* Using errno here may well be misleanding since the most recent 8767 call that set errno may not have anything whatsoever to do with 8768 the error that set the flag, but it's better than nothing. The 8769 real solution is to check each call to fprintf rather than waiting 8770 until the end like this. */ 8771 error (1, errno, "error writing to lock file %s", rcs_lockfile); 8772 8773 /* Flush and sync the file, or the user may be told the commit completed, 8774 * while a server crash/power failure could still cause the data to be 8775 * lost. 8776 * 8777 * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs 8778 * only flushes the inode for the target file to disk, it does not 8779 * guarantee flush of the kernel buffers allocated for the ,<file>,. 8780 * Depending upon the load on the machine, the Linux kernel's flush daemon 8781 * process may not flush for a while. In the meantime the CVS transaction 8782 * could have been declared committed to the end CVS user (CVS process has 8783 * returned the final "OK"). If the machine crashes prior to syncing the 8784 * changes to disk, the committed transaction can be lost. 8785 */ 8786 if (fflush (fp) != 0) 8787 error (1, errno, "error flushing file `%s' to kernel buffers", 8788 rcs_lockfile); 8789#ifdef HAVE_FSYNC 8790 if (fsync (rcs_lockfd) < 0) 8791 error (1, errno, "error fsyncing file `%s'", rcs_lockfile); 8792#endif 8793 8794 if (fclose (fp) == EOF) 8795 error (1, errno, "error closing lock file %s", rcs_lockfile); 8796 rcs_lockfd = -1; 8797 8798 rename_file (rcs_lockfile, rcsfile); 8799 8800 { 8801 /* Use a temporary to make sure there's no interval 8802 (after rcs_lockfile has been freed but before it's set to NULL) 8803 during which the signal handler's use of rcs_lockfile would 8804 reference freed memory. */ 8805 char *tmp = rcs_lockfile; 8806 rcs_lockfile = NULL; 8807 free (tmp); 8808 } 8809} 8810 8811static char * 8812rcs_lockfilename (rcsfile) 8813 const char *rcsfile; 8814{ 8815 char *lockfile, *lockp; 8816 const char *rcsbase, *rcsp, *rcsend; 8817 int rcslen; 8818 8819 /* Create the lockfile name. */ 8820 rcslen = strlen (rcsfile); 8821 lockfile = (char *) xmalloc (rcslen + 10); 8822 rcsbase = last_component (rcsfile); 8823 rcsend = rcsfile + rcslen - sizeof(RCSEXT); 8824 for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp) 8825 *lockp++ = *rcsp; 8826 *lockp++ = ','; 8827 while (rcsp <= rcsend) 8828 *lockp++ = *rcsp++; 8829 *lockp++ = ','; 8830 *lockp = '\0'; 8831 8832 return lockfile; 8833} 8834 8835/* Rewrite an RCS file. The basic idea here is that the caller should 8836 first call RCS_reparsercsfile, then munge the data structures as 8837 desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */ 8838 8839void 8840RCS_rewrite (rcs, newdtext, insertpt) 8841 RCSNode *rcs; 8842 Deltatext *newdtext; 8843 char *insertpt; 8844{ 8845 FILE *fin, *fout; 8846 struct rcsbuffer rcsbufin; 8847 8848 assert (rcs); 8849 8850 if (noexec) 8851 return; 8852 8853 /* Make sure we're operating on an actual file and not a symlink. */ 8854 resolve_symlink (&(rcs->path)); 8855 8856 fout = rcs_internal_lockfile (rcs->path); 8857 8858 RCS_putadmin (rcs, fout); 8859 RCS_putdtree (rcs, rcs->head, fout); 8860 RCS_putdesc (rcs, fout); 8861 8862 /* Open the original RCS file and seek to the first delta text. */ 8863 rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin); 8864 8865 /* Update delta_pos to the current position in the output file. 8866 Do NOT move these statements: they must be done after fin has 8867 been positioned at the old delta_pos, but before any delta 8868 texts have been written to fout. 8869 */ 8870 rcs->delta_pos = ftell (fout); 8871 if (rcs->delta_pos == -1) 8872 error (1, errno, "cannot ftell in RCS file %s", rcs->path); 8873 8874 RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt); 8875 8876 /* We don't want to call rcsbuf_cache here, since we're about to 8877 delete the file. */ 8878 rcsbuf_close (&rcsbufin); 8879 if (ferror (fin)) 8880 /* The only case in which using errno here would be meaningful 8881 is if we happen to have left errno unmolested since the call 8882 which produced the error (e.g. fread). That is pretty 8883 fragile even if it happens to sometimes be true. The real 8884 solution is to make sure that all the code which reads 8885 from fin checks for errors itself (some does, some doesn't). */ 8886 error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path); 8887 if (fclose (fin) < 0) 8888 error (0, errno, "warning: closing RCS file `%s'", rcs->path); 8889 8890 rcs_internal_unlockfile (fout, rcs->path); 8891} 8892 8893/* Abandon changes to an RCS file. */ 8894 8895void 8896RCS_abandon (rcs) 8897 RCSNode *rcs; 8898{ 8899 free_rcsnode_contents (rcs); 8900 rcs->symbols_data = NULL; 8901 rcs->expand = NULL; 8902 rcs->access = NULL; 8903 rcs->locks_data = NULL; 8904 rcs->comment = NULL; 8905 rcs->desc = NULL; 8906 rcs->flags |= PARTIAL; 8907} 8908 8909/* 8910 * For a given file with full pathname PATH and revision number REV, 8911 * produce a file label suitable for passing to diff. The default 8912 * file label as used by RCS 5.7 looks like this: 8913 * 8914 * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM 8915 * 8916 * The date and time used are the revision's last checkin date and time. 8917 * If REV is NULL, use the working copy's mtime instead. 8918 * 8919 * /dev/null is not statted but assumed to have been created on the Epoch. 8920 * At least using the POSIX.2 definition of patch, this should cause creation 8921 * of files on platforms such as Windoze where the null IO device isn't named 8922 * /dev/null to be parsed by patch properly. 8923 */ 8924char * 8925make_file_label (path, rev, rcs) 8926 const char *path; 8927 const char *rev; 8928 RCSNode *rcs; 8929{ 8930 char datebuf[MAXDATELEN + 1]; 8931 char *label; 8932 8933 label = (char *) xmalloc (strlen (path) 8934 + (rev == NULL ? 0 : strlen (rev) + 1) 8935 + MAXDATELEN 8936 + 2); 8937 8938 if (rev) 8939 { 8940 char date[MAXDATELEN + 1]; 8941 /* revs cannot be attached to /dev/null ... duh. */ 8942 assert (strcmp(DEVNULL, path)); 8943 RCS_getrevtime (rcs, rev, datebuf, 0); 8944 (void) date_to_internet (date, datebuf); 8945 (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev); 8946 } 8947 else 8948 { 8949 struct stat sb; 8950 struct tm *wm; 8951 8952 if (strcmp(DEVNULL, path)) 8953 { 8954 const char *file = last_component (path); 8955 if (CVS_STAT (file, &sb) < 0) 8956 /* Assume that if the stat fails,then the later read for the 8957 * diff will too. 8958 */ 8959 error (1, errno, "could not get info for `%s'", path); 8960 wm = gmtime (&sb.st_mtime); 8961 } 8962 else 8963 { 8964 time_t t = 0; 8965 wm = gmtime(&t); 8966 } 8967 8968 (void) tm_to_internet (datebuf, wm); 8969 (void) sprintf (label, "-L%s\t%s", path, datebuf); 8970 } 8971 return label; 8972} 8973 8974void 8975RCS_setlocalid (arg) 8976 const char *arg; 8977{ 8978 char *copy, *next, *key; 8979 8980 copy = xstrdup(arg); 8981 next = copy; 8982 key = strtok(next, "="); 8983 8984 keywords[KEYWORD_LOCALID].string = xstrdup(key); 8985 keywords[KEYWORD_LOCALID].len = strlen(key); 8986 keywords[KEYWORD_LOCALID].expandit = 1; 8987 8988 /* options? */ 8989 while (key = strtok(NULL, ",")) { 8990 if (!strcmp(key, keywords[KEYWORD_ID].string)) 8991 keyword_local = KEYWORD_ID; 8992 else if (!strcmp(key, keywords[KEYWORD_HEADER].string)) 8993 keyword_local = KEYWORD_HEADER; 8994 else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string)) 8995 keyword_local = KEYWORD_CVSHEADER; 8996 else 8997 error(1, 0, "Unknown LocalId mode: %s", key); 8998 } 8999 free(copy); 9000} 9001 9002void 9003RCS_setincexc (arg) 9004 const char *arg; 9005{ 9006 char *key; 9007 char *copy, *next; 9008 int include = 0; 9009 struct rcs_keyword *keyword; 9010 9011 copy = xstrdup(arg); 9012 next = copy; 9013 switch (*next++) { 9014 case 'e': 9015 include = 0; 9016 break; 9017 case 'i': 9018 include = 1; 9019 break; 9020 default: 9021 free(copy); 9022 return; 9023 } 9024 9025 if (include) 9026 for (keyword = keywords; keyword->string != NULL; keyword++) 9027 { 9028 keyword->expandit = 0; 9029 } 9030 9031 key = strtok(next, ","); 9032 while (key) { 9033 for (keyword = keywords; keyword->string != NULL; keyword++) { 9034 if (strcmp (keyword->string, key) == 0) 9035 keyword->expandit = include; 9036 } 9037 key = strtok(NULL, ","); 9038 } 9039 free(copy); 9040 return; 9041} 9042 9043#define ATTIC "/" CVSATTIC 9044static char * 9045getfullCVSname(CVSname, pathstore) 9046 char *CVSname, **pathstore; 9047{ 9048 if (current_parsed_root->directory) { 9049 int rootlen; 9050 char *c = NULL; 9051 int alen = sizeof(ATTIC) - 1; 9052 9053 *pathstore = xstrdup(CVSname); 9054 if ((c = strrchr(*pathstore, '/')) != NULL) { 9055 if (c - *pathstore >= alen) { 9056 if (!strncmp(c - alen, ATTIC, alen)) { 9057 while (*c != '\0') { 9058 *(c - alen) = *c; 9059 c++; 9060 } 9061 *(c - alen) = '\0'; 9062 } 9063 } 9064 } 9065 9066 rootlen = strlen(current_parsed_root->directory); 9067 if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) && 9068 (*pathstore)[rootlen] == '/') 9069 CVSname = (*pathstore + rootlen + 1); 9070 else 9071 CVSname = (*pathstore); 9072 } 9073 return CVSname; 9074} 9075