/contrib/cvs/src/tag.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1465 lines · 1075 code · 150 blank · 240 comment · 256 complexity · 44c027368495479d80158c2f7607cf3b MD5 · raw file

  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. * Tag and Rtag
  14. *
  15. * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
  16. * Tag uses the checked out revision in the current directory, rtag uses
  17. * the modules database, if necessary.
  18. *
  19. * $FreeBSD$
  20. */
  21. #include "cvs.h"
  22. #include "savecwd.h"
  23. static int rtag_proc PROTO((int argc, char **argv, char *xwhere,
  24. char *mwhere, char *mfile, int shorten,
  25. int local_specified, char *mname, char *msg));
  26. static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  27. static int check_filesdoneproc PROTO ((void *callerdat, int err,
  28. const char *repos,
  29. const char *update_dir,
  30. List *entries));
  31. static int pretag_proc PROTO((const char *repository, const char *filter));
  32. static void masterlist_delproc PROTO((Node *p));
  33. static void tag_delproc PROTO((Node *p));
  34. static int pretag_list_proc PROTO((Node *p, void *closure));
  35. static Dtype tag_dirproc PROTO ((void *callerdat, const char *dir,
  36. const char *repos, const char *update_dir,
  37. List *entries));
  38. static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  39. static int rtag_delete PROTO((RCSNode *rcsfile));
  40. static int tag_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  41. static char *numtag; /* specific revision to tag */
  42. static int numtag_validated = 0;
  43. static char *date = NULL;
  44. static char *symtag; /* tag to add or delete */
  45. static int delete_flag; /* adding a tag by default */
  46. static int branch_mode; /* make an automagic "branch" tag */
  47. static int disturb_branch_tags = 0; /* allow -F,-d to disturb branch tags */
  48. static int force_tag_match = 1; /* force tag to match by default */
  49. static int force_tag_move; /* don't force tag to move by default */
  50. static int check_uptodate; /* no uptodate-check by default */
  51. static int attic_too; /* remove tag from Attic files */
  52. static int is_rtag;
  53. struct tag_info
  54. {
  55. Ctype status;
  56. char *rev;
  57. char *tag;
  58. char *options;
  59. };
  60. struct master_lists
  61. {
  62. List *tlist;
  63. };
  64. static List *mtlist;
  65. static List *tlist;
  66. static const char rtag_opts[] = "+aBbdFflnQqRr:D:";
  67. static const char *const rtag_usage[] =
  68. {
  69. "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n",
  70. "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
  71. "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
  72. "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
  73. "\t-d\tDelete the given tag.\n",
  74. "\t-F\tMove tag if it already exists.\n",
  75. "\t-f\tForce a head revision match if tag/date not found.\n",
  76. "\t-l\tLocal directory only, not recursive.\n",
  77. "\t-n\tNo execution of 'tag program'.\n",
  78. "\t-R\tProcess directories recursively.\n",
  79. "\t-r rev\tExisting revision/tag.\n",
  80. "\t-D\tExisting date.\n",
  81. "(Specify the --help global option for a list of other help options)\n",
  82. NULL
  83. };
  84. static const char tag_opts[] = "+BbcdFflQqRr:D:";
  85. static const char *const tag_usage[] =
  86. {
  87. "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n",
  88. "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
  89. "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
  90. "\t-c\tCheck that working files are unmodified.\n",
  91. "\t-d\tDelete the given tag.\n",
  92. "\t-F\tMove tag if it already exists.\n",
  93. "\t-f\tForce a head revision match if tag/date not found.\n",
  94. "\t-l\tLocal directory only, not recursive.\n",
  95. "\t-R\tProcess directories recursively.\n",
  96. "\t-r rev\tExisting revision/tag.\n",
  97. "\t-D\tExisting date.\n",
  98. "(Specify the --help global option for a list of other help options)\n",
  99. NULL
  100. };
  101. int
  102. cvstag (argc, argv)
  103. int argc;
  104. char **argv;
  105. {
  106. int local = 0; /* recursive by default */
  107. int c;
  108. int err = 0;
  109. int run_module_prog = 1;
  110. is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0);
  111. if (argc == -1)
  112. usage (is_rtag ? rtag_usage : tag_usage);
  113. optind = 0;
  114. while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1)
  115. {
  116. switch (c)
  117. {
  118. case 'a':
  119. attic_too = 1;
  120. break;
  121. case 'b':
  122. branch_mode = 1;
  123. break;
  124. case 'B':
  125. disturb_branch_tags = 1;
  126. break;
  127. case 'c':
  128. check_uptodate = 1;
  129. break;
  130. case 'd':
  131. delete_flag = 1;
  132. break;
  133. case 'F':
  134. force_tag_move = 1;
  135. break;
  136. case 'f':
  137. force_tag_match = 0;
  138. break;
  139. case 'l':
  140. local = 1;
  141. break;
  142. case 'n':
  143. run_module_prog = 0;
  144. break;
  145. case 'Q':
  146. case 'q':
  147. /* The CVS 1.5 client sends these options (in addition to
  148. Global_option requests), so we must ignore them. */
  149. if (!server_active)
  150. error (1, 0,
  151. "-q or -Q must be specified before \"%s\"",
  152. cvs_cmd_name);
  153. break;
  154. case 'R':
  155. local = 0;
  156. break;
  157. case 'r':
  158. numtag = optarg;
  159. break;
  160. case 'D':
  161. if (date)
  162. free (date);
  163. date = Make_Date (optarg);
  164. break;
  165. case '?':
  166. default:
  167. usage (is_rtag ? rtag_usage : tag_usage);
  168. break;
  169. }
  170. }
  171. argc -= optind;
  172. argv += optind;
  173. if (argc < (is_rtag ? 2 : 1))
  174. usage (is_rtag ? rtag_usage : tag_usage);
  175. symtag = argv[0];
  176. argc--;
  177. argv++;
  178. if (date && numtag)
  179. error (1, 0, "-r and -D options are mutually exclusive");
  180. if (delete_flag && branch_mode)
  181. error (0, 0, "warning: -b ignored with -d options");
  182. RCS_check_tag (symtag);
  183. #ifdef CLIENT_SUPPORT
  184. if (current_parsed_root->isremote)
  185. {
  186. /* We're the client side. Fire up the remote server. */
  187. start_server ();
  188. ign_setup ();
  189. if (attic_too)
  190. send_arg("-a");
  191. if (branch_mode)
  192. send_arg("-b");
  193. if (disturb_branch_tags)
  194. send_arg("-B");
  195. if (check_uptodate)
  196. send_arg("-c");
  197. if (delete_flag)
  198. send_arg("-d");
  199. if (force_tag_move)
  200. send_arg("-F");
  201. if (!force_tag_match)
  202. send_arg ("-f");
  203. if (local)
  204. send_arg("-l");
  205. if (!run_module_prog)
  206. send_arg("-n");
  207. if (numtag)
  208. option_with_arg ("-r", numtag);
  209. if (date)
  210. client_senddate (date);
  211. send_arg ("--");
  212. send_arg (symtag);
  213. if (is_rtag)
  214. {
  215. int i;
  216. for (i = 0; i < argc; ++i)
  217. send_arg (argv[i]);
  218. send_to_server ("rtag\012", 0);
  219. }
  220. else
  221. {
  222. send_files (argc, argv, local, 0,
  223. /* I think the -c case is like "cvs status", in
  224. which we really better be correct rather than
  225. being fast; it is just too confusing otherwise. */
  226. check_uptodate ? 0 : SEND_NO_CONTENTS);
  227. send_file_names (argc, argv, SEND_EXPAND_WILD);
  228. send_to_server ("tag\012", 0);
  229. }
  230. return get_responses_and_close ();
  231. }
  232. #endif
  233. if (is_rtag)
  234. {
  235. DBM *db;
  236. int i;
  237. db = open_module ();
  238. for (i = 0; i < argc; i++)
  239. {
  240. /* XXX last arg should be repository, but doesn't make sense here */
  241. history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
  242. (date ? date : "A"))), symtag, argv[i], "");
  243. err += do_module (db, argv[i], TAG,
  244. delete_flag ? "Untagging" : "Tagging",
  245. rtag_proc, (char *) NULL, 0, local, run_module_prog,
  246. 0, symtag);
  247. }
  248. close_module (db);
  249. }
  250. else
  251. {
  252. err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
  253. NULL);
  254. }
  255. return (err);
  256. }
  257. /*
  258. * callback proc for doing the real work of tagging
  259. */
  260. /* ARGSUSED */
  261. static int
  262. rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
  263. mname, msg)
  264. int argc;
  265. char **argv;
  266. char *xwhere;
  267. char *mwhere;
  268. char *mfile;
  269. int shorten;
  270. int local_specified;
  271. char *mname;
  272. char *msg;
  273. {
  274. /* Begin section which is identical to patch_proc--should this
  275. be abstracted out somehow? */
  276. char *myargv[2];
  277. int err = 0;
  278. int which;
  279. char *repository;
  280. char *where;
  281. if (is_rtag)
  282. {
  283. repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0])
  284. + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
  285. (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
  286. where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1)
  287. + 1);
  288. (void) strcpy (where, argv[0]);
  289. /* if mfile isn't null, we need to set up to do only part of the module */
  290. if (mfile != NULL)
  291. {
  292. char *cp;
  293. char *path;
  294. /* if the portion of the module is a path, put the dir part on repos */
  295. if ((cp = strrchr (mfile, '/')) != NULL)
  296. {
  297. *cp = '\0';
  298. (void) strcat (repository, "/");
  299. (void) strcat (repository, mfile);
  300. (void) strcat (where, "/");
  301. (void) strcat (where, mfile);
  302. mfile = cp + 1;
  303. }
  304. /* take care of the rest */
  305. path = xmalloc (strlen (repository) + strlen (mfile) + 5);
  306. (void) sprintf (path, "%s/%s", repository, mfile);
  307. if (isdir (path))
  308. {
  309. /* directory means repository gets the dir tacked on */
  310. (void) strcpy (repository, path);
  311. (void) strcat (where, "/");
  312. (void) strcat (where, mfile);
  313. }
  314. else
  315. {
  316. myargv[0] = argv[0];
  317. myargv[1] = mfile;
  318. argc = 2;
  319. argv = myargv;
  320. }
  321. free (path);
  322. }
  323. /* cd to the starting repository */
  324. if ( CVS_CHDIR (repository) < 0)
  325. {
  326. error (0, errno, "cannot chdir to %s", repository);
  327. free (repository);
  328. free (where);
  329. return (1);
  330. }
  331. /* End section which is identical to patch_proc. */
  332. if (delete_flag || force_tag_move || attic_too || numtag)
  333. which = W_REPOS | W_ATTIC;
  334. else
  335. which = W_REPOS;
  336. }
  337. else
  338. {
  339. where = NULL;
  340. which = W_LOCAL;
  341. repository = "";
  342. }
  343. if (numtag != NULL && !numtag_validated)
  344. {
  345. tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0, repository);
  346. numtag_validated = 1;
  347. }
  348. /* check to make sure they are authorized to tag all the
  349. specified files in the repository */
  350. mtlist = getlist();
  351. err = start_recursion (check_fileproc, check_filesdoneproc,
  352. (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
  353. argc - 1, argv + 1, local_specified, which, 0,
  354. CVS_LOCK_READ, where, 1, repository);
  355. if (err)
  356. {
  357. error (1, 0, "correct the above errors first!");
  358. }
  359. /* It would be nice to provide consistency with respect to
  360. commits; however CVS lacks the infrastructure to do that (see
  361. Concurrency in cvs.texinfo and comment in do_recursion). */
  362. /* start the recursion processor */
  363. err = start_recursion (is_rtag ? rtag_fileproc : tag_fileproc,
  364. (FILESDONEPROC) NULL, tag_dirproc,
  365. (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1,
  366. local_specified, which, 0, CVS_LOCK_WRITE, where, 1,
  367. repository);
  368. if ( which & W_REPOS ) free ( repository );
  369. dellist (&mtlist);
  370. if (where != NULL)
  371. free (where);
  372. return (err);
  373. }
  374. /* check file that is to be tagged */
  375. /* All we do here is add it to our list */
  376. static int
  377. check_fileproc (callerdat, finfo)
  378. void *callerdat;
  379. struct file_info *finfo;
  380. {
  381. const char *xdir;
  382. Node *p;
  383. Vers_TS *vers;
  384. if (check_uptodate)
  385. {
  386. switch (Classify_File (finfo, (char *) NULL, (char *) NULL,
  387. (char *) NULL, 1, 0, &vers, 0))
  388. {
  389. case T_UPTODATE:
  390. case T_CHECKOUT:
  391. case T_PATCH:
  392. case T_REMOVE_ENTRY:
  393. break;
  394. case T_UNKNOWN:
  395. case T_CONFLICT:
  396. case T_NEEDS_MERGE:
  397. case T_MODIFIED:
  398. case T_ADDED:
  399. case T_REMOVED:
  400. default:
  401. error (0, 0, "%s is locally modified", finfo->fullname);
  402. freevers_ts (&vers);
  403. return (1);
  404. }
  405. }
  406. else
  407. vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
  408. if (finfo->update_dir[0] == '\0')
  409. xdir = ".";
  410. else
  411. xdir = finfo->update_dir;
  412. if ((p = findnode (mtlist, xdir)) != NULL)
  413. {
  414. tlist = ((struct master_lists *) p->data)->tlist;
  415. }
  416. else
  417. {
  418. struct master_lists *ml;
  419. tlist = getlist ();
  420. p = getnode ();
  421. p->key = xstrdup (xdir);
  422. p->type = UPDATE;
  423. ml = (struct master_lists *)
  424. xmalloc (sizeof (struct master_lists));
  425. ml->tlist = tlist;
  426. p->data = ml;
  427. p->delproc = masterlist_delproc;
  428. (void) addnode (mtlist, p);
  429. }
  430. /* do tlist */
  431. p = getnode ();
  432. p->key = xstrdup (finfo->file);
  433. p->type = UPDATE;
  434. p->delproc = tag_delproc;
  435. if (vers->srcfile == NULL)
  436. {
  437. if (!really_quiet)
  438. error (0, 0, "nothing known about %s", finfo->file);
  439. freevers_ts (&vers);
  440. freenode (p);
  441. return (1);
  442. }
  443. /* Here we duplicate the calculation in tag_fileproc about which
  444. version we are going to tag. There probably are some subtle races
  445. (e.g. numtag is "foo" which gets moved between here and
  446. tag_fileproc). */
  447. if (!is_rtag && numtag == NULL && date == NULL)
  448. p->data = xstrdup (vers->vn_user);
  449. else
  450. p->data = RCS_getversion (vers->srcfile, numtag, date,
  451. force_tag_match, NULL);
  452. if (p->data != NULL)
  453. {
  454. int addit = 1;
  455. char *oversion;
  456. oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
  457. (int *) NULL);
  458. if (oversion == NULL)
  459. {
  460. if (delete_flag)
  461. {
  462. /* Deleting a tag which did not exist is a noop and
  463. should not be logged. */
  464. addit = 0;
  465. }
  466. }
  467. else if (delete_flag)
  468. {
  469. free (p->data);
  470. p->data = xstrdup (oversion);
  471. }
  472. else if (strcmp(oversion, p->data) == 0)
  473. {
  474. addit = 0;
  475. }
  476. else if (!force_tag_move)
  477. {
  478. addit = 0;
  479. }
  480. if (oversion != NULL)
  481. {
  482. free(oversion);
  483. }
  484. if (!addit)
  485. {
  486. free(p->data);
  487. p->data = NULL;
  488. }
  489. }
  490. freevers_ts (&vers);
  491. (void) addnode (tlist, p);
  492. return (0);
  493. }
  494. static int
  495. check_filesdoneproc (callerdat, err, repos, update_dir, entries)
  496. void *callerdat;
  497. int err;
  498. const char *repos;
  499. const char *update_dir;
  500. List *entries;
  501. {
  502. int n;
  503. Node *p;
  504. p = findnode(mtlist, update_dir);
  505. if (p != NULL)
  506. {
  507. tlist = ((struct master_lists *) p->data)->tlist;
  508. }
  509. else
  510. {
  511. tlist = (List *) NULL;
  512. }
  513. if ((tlist == NULL) || (tlist->list->next == tlist->list))
  514. {
  515. return (err);
  516. }
  517. if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0)
  518. {
  519. error (0, 0, "Pre-tag check failed");
  520. err += n;
  521. }
  522. return (err);
  523. }
  524. static int
  525. pretag_proc (repository, filter)
  526. const char *repository;
  527. const char *filter;
  528. {
  529. if (filter[0] == '/')
  530. {
  531. char *s, *cp;
  532. s = xstrdup(filter);
  533. for (cp=s; *cp; cp++)
  534. {
  535. if (isspace ((unsigned char) *cp))
  536. {
  537. *cp = '\0';
  538. break;
  539. }
  540. }
  541. if (!isfile(s))
  542. {
  543. error (0, errno, "cannot find pre-tag filter '%s'", s);
  544. free(s);
  545. return (1);
  546. }
  547. free(s);
  548. }
  549. run_setup (filter);
  550. run_arg (symtag);
  551. run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add");
  552. run_arg (repository);
  553. walklist(tlist, pretag_list_proc, NULL);
  554. return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL));
  555. }
  556. static void
  557. masterlist_delproc(p)
  558. Node *p;
  559. {
  560. struct master_lists *ml = p->data;
  561. dellist(&ml->tlist);
  562. free(ml);
  563. return;
  564. }
  565. static void
  566. tag_delproc(p)
  567. Node *p;
  568. {
  569. if (p->data != NULL)
  570. {
  571. free(p->data);
  572. p->data = NULL;
  573. }
  574. return;
  575. }
  576. static int
  577. pretag_list_proc(p, closure)
  578. Node *p;
  579. void *closure;
  580. {
  581. if (p->data != NULL)
  582. {
  583. run_arg(p->key);
  584. run_arg(p->data);
  585. }
  586. return (0);
  587. }
  588. /*
  589. * Called to rtag a particular file, as appropriate with the options that were
  590. * set above.
  591. */
  592. /* ARGSUSED */
  593. static int
  594. rtag_fileproc (callerdat, finfo)
  595. void *callerdat;
  596. struct file_info *finfo;
  597. {
  598. RCSNode *rcsfile;
  599. char *version, *rev;
  600. int retcode = 0;
  601. /* find the parsed RCS data */
  602. if ((rcsfile = finfo->rcs) == NULL)
  603. return (1);
  604. /*
  605. * For tagging an RCS file which is a symbolic link, you'd best be
  606. * running with RCS 5.6, since it knows how to handle symbolic links
  607. * correctly without breaking your link!
  608. */
  609. if (delete_flag)
  610. return (rtag_delete (rcsfile));
  611. /*
  612. * If we get here, we are adding a tag. But, if -a was specified, we
  613. * need to check to see if a -r or -D option was specified. If neither
  614. * was specified and the file is in the Attic, remove the tag.
  615. */
  616. if (attic_too && (!numtag && !date))
  617. {
  618. if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
  619. return (rtag_delete (rcsfile));
  620. }
  621. version = RCS_getversion (rcsfile, numtag, date, force_tag_match,
  622. (int *) NULL);
  623. if (version == NULL)
  624. {
  625. /* If -a specified, clean up any old tags */
  626. if (attic_too)
  627. (void) rtag_delete (rcsfile);
  628. if (!quiet && !force_tag_match)
  629. {
  630. error (0, 0, "cannot find tag `%s' in `%s'",
  631. numtag ? numtag : "head", rcsfile->path);
  632. return (1);
  633. }
  634. return (0);
  635. }
  636. if (numtag
  637. && isdigit ((unsigned char) *numtag)
  638. && strcmp (numtag, version) != 0)
  639. {
  640. /*
  641. * We didn't find a match for the numeric tag that was specified, but
  642. * that's OK. just pass the numeric tag on to rcs, to be tagged as
  643. * specified. Could get here if one tried to tag "1.1.1" and there
  644. * was a 1.1.1 branch with some head revision. In this case, we want
  645. * the tag to reference "1.1.1" and not the revision at the head of
  646. * the branch. Use a symbolic tag for that.
  647. */
  648. rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
  649. retcode = RCS_settag(rcsfile, symtag, numtag);
  650. if (retcode == 0)
  651. RCS_rewrite (rcsfile, NULL, NULL);
  652. }
  653. else
  654. {
  655. char *oversion;
  656. /*
  657. * As an enhancement for the case where a tag is being re-applied to
  658. * a large body of a module, make one extra call to RCS_getversion to
  659. * see if the tag is already set in the RCS file. If so, check to
  660. * see if it needs to be moved. If not, do nothing. This will
  661. * likely save a lot of time when simply moving the tag to the
  662. * "current" head revisions of a module -- which I have found to be a
  663. * typical tagging operation.
  664. */
  665. rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
  666. oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
  667. (int *) NULL);
  668. if (oversion != NULL)
  669. {
  670. int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
  671. /*
  672. * if versions the same and neither old or new are branches don't
  673. * have to do anything
  674. */
  675. if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
  676. {
  677. free (oversion);
  678. free (version);
  679. return (0);
  680. }
  681. if (!force_tag_move)
  682. {
  683. /* we're NOT going to move the tag */
  684. (void) printf ("W %s", finfo->fullname);
  685. (void) printf (" : %s already exists on %s %s",
  686. symtag, isbranch ? "branch" : "version",
  687. oversion);
  688. (void) printf (" : NOT MOVING tag to %s %s\n",
  689. branch_mode ? "branch" : "version", rev);
  690. free (oversion);
  691. free (version);
  692. if (branch_mode) free(rev);
  693. return (0);
  694. }
  695. else /* force_tag_move is set and... */
  696. if ((isbranch && !disturb_branch_tags) ||
  697. (!isbranch && disturb_branch_tags))
  698. {
  699. error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
  700. finfo->fullname,
  701. isbranch ? "branch" : "non-branch",
  702. symtag, oversion, rev,
  703. isbranch ? "" : " due to `-B' option");
  704. if (branch_mode) free(rev);
  705. free (oversion);
  706. free (version);
  707. return (0);
  708. }
  709. free (oversion);
  710. }
  711. retcode = RCS_settag(rcsfile, symtag, rev);
  712. if (retcode == 0)
  713. RCS_rewrite (rcsfile, NULL, NULL);
  714. }
  715. if (retcode != 0)
  716. {
  717. error (1, retcode == -1 ? errno : 0,
  718. "failed to set tag `%s' to revision `%s' in `%s'",
  719. symtag, rev, rcsfile->path);
  720. if (branch_mode)
  721. free (rev);
  722. free (version);
  723. return (1);
  724. }
  725. if (branch_mode)
  726. free (rev);
  727. free (version);
  728. return (0);
  729. }
  730. /*
  731. * If -d is specified, "force_tag_match" is set, so that this call to
  732. * RCS_getversion() will return a NULL version string if the symbolic
  733. * tag does not exist in the RCS file.
  734. *
  735. * If the -r flag was used, numtag is set, and we only delete the
  736. * symtag from files that have numtag.
  737. *
  738. * This is done here because it's MUCH faster than just blindly calling
  739. * "rcs" to remove the tag... trust me.
  740. */
  741. static int
  742. rtag_delete (rcsfile)
  743. RCSNode *rcsfile;
  744. {
  745. char *version;
  746. int retcode, isbranch;
  747. if (numtag)
  748. {
  749. version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1,
  750. (int *) NULL);
  751. if (version == NULL)
  752. return (0);
  753. free (version);
  754. }
  755. version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1,
  756. (int *) NULL);
  757. if (version == NULL)
  758. return (0);
  759. free (version);
  760. isbranch = RCS_nodeisbranch (rcsfile, symtag);
  761. if ((isbranch && !disturb_branch_tags) ||
  762. (!isbranch && disturb_branch_tags))
  763. {
  764. if (!quiet)
  765. error(0, 0,
  766. "Not removing %s tag `%s' from `%s'%s.",
  767. isbranch ? "branch" : "non-branch",
  768. symtag, rcsfile->path,
  769. isbranch ? "" : " due to `-B' option");
  770. return (1);
  771. }
  772. if ((retcode = RCS_deltag(rcsfile, symtag)) != 0)
  773. {
  774. if (!quiet)
  775. error (0, retcode == -1 ? errno : 0,
  776. "failed to remove tag `%s' from `%s'", symtag,
  777. rcsfile->path);
  778. return (1);
  779. }
  780. RCS_rewrite (rcsfile, NULL, NULL);
  781. return (0);
  782. }
  783. /*
  784. * Called to tag a particular file (the currently checked out version is
  785. * tagged with the specified tag - or the specified tag is deleted).
  786. */
  787. /* ARGSUSED */
  788. static int
  789. tag_fileproc (callerdat, finfo)
  790. void *callerdat;
  791. struct file_info *finfo;
  792. {
  793. char *version, *oversion;
  794. char *nversion = NULL;
  795. char *rev;
  796. Vers_TS *vers;
  797. int retcode = 0;
  798. int retval = 0;
  799. vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
  800. if ((numtag != NULL) || (date != NULL))
  801. {
  802. nversion = RCS_getversion(vers->srcfile,
  803. numtag,
  804. date,
  805. force_tag_match,
  806. (int *) NULL);
  807. if (nversion == NULL)
  808. goto free_vars_and_return;
  809. }
  810. if (delete_flag)
  811. {
  812. int isbranch;
  813. /*
  814. * If -d is specified, "force_tag_match" is set, so that this call to
  815. * RCS_getversion() will return a NULL version string if the symbolic
  816. * tag does not exist in the RCS file.
  817. *
  818. * This is done here because it's MUCH faster than just blindly calling
  819. * "rcs" to remove the tag... trust me.
  820. */
  821. version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
  822. (int *) NULL);
  823. if (version == NULL || vers->srcfile == NULL)
  824. goto free_vars_and_return;
  825. free (version);
  826. isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
  827. if ((isbranch && !disturb_branch_tags) ||
  828. (!isbranch && disturb_branch_tags))
  829. {
  830. if (!quiet)
  831. error(0, 0,
  832. "Not removing %s tag `%s' from `%s'%s.",
  833. isbranch ? "branch" : "non-branch",
  834. symtag, vers->srcfile->path,
  835. isbranch ? "" : " due to `-B' option");
  836. retval = 1;
  837. goto free_vars_and_return;
  838. }
  839. if ((retcode = RCS_deltag(vers->srcfile, symtag)) != 0)
  840. {
  841. if (!quiet)
  842. error (0, retcode == -1 ? errno : 0,
  843. "failed to remove tag %s from %s", symtag,
  844. vers->srcfile->path);
  845. retval = 1;
  846. goto free_vars_and_return;
  847. }
  848. RCS_rewrite (vers->srcfile, NULL, NULL);
  849. /* warm fuzzies */
  850. if (!really_quiet)
  851. {
  852. cvs_output ("D ", 2);
  853. cvs_output (finfo->fullname, 0);
  854. cvs_output ("\n", 1);
  855. }
  856. goto free_vars_and_return;
  857. }
  858. /*
  859. * If we are adding a tag, we need to know which version we have checked
  860. * out and we'll tag that version.
  861. */
  862. if (nversion == NULL)
  863. {
  864. version = vers->vn_user;
  865. }
  866. else
  867. {
  868. version = nversion;
  869. }
  870. if (version == NULL)
  871. {
  872. goto free_vars_and_return;
  873. }
  874. else if (strcmp (version, "0") == 0)
  875. {
  876. if (!quiet)
  877. error (0, 0, "couldn't tag added but un-commited file `%s'", finfo->file);
  878. goto free_vars_and_return;
  879. }
  880. else if (version[0] == '-')
  881. {
  882. if (!quiet)
  883. error (0, 0, "skipping removed but un-commited file `%s'", finfo->file);
  884. goto free_vars_and_return;
  885. }
  886. else if (vers->srcfile == NULL)
  887. {
  888. if (!quiet)
  889. error (0, 0, "cannot find revision control file for `%s'", finfo->file);
  890. goto free_vars_and_return;
  891. }
  892. /*
  893. * As an enhancement for the case where a tag is being re-applied to a
  894. * large number of files, make one extra call to RCS_getversion to see
  895. * if the tag is already set in the RCS file. If so, check to see if it
  896. * needs to be moved. If not, do nothing. This will likely save a lot of
  897. * time when simply moving the tag to the "current" head revisions of a
  898. * module -- which I have found to be a typical tagging operation.
  899. */
  900. rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
  901. oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1,
  902. (int *) NULL);
  903. if (oversion != NULL)
  904. {
  905. int isbranch = RCS_nodeisbranch (finfo->rcs, symtag);
  906. /*
  907. * if versions the same and neither old or new are branches don't have
  908. * to do anything
  909. */
  910. if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
  911. {
  912. free (oversion);
  913. if (branch_mode)
  914. free (rev);
  915. goto free_vars_and_return;
  916. }
  917. if (!force_tag_move)
  918. {
  919. /* we're NOT going to move the tag */
  920. cvs_output ("W ", 2);
  921. cvs_output (finfo->fullname, 0);
  922. cvs_output (" : ", 0);
  923. cvs_output (symtag, 0);
  924. cvs_output (" already exists on ", 0);
  925. cvs_output (isbranch ? "branch" : "version", 0);
  926. cvs_output (" ", 0);
  927. cvs_output (oversion, 0);
  928. cvs_output (" : NOT MOVING tag to ", 0);
  929. cvs_output (branch_mode ? "branch" : "version", 0);
  930. cvs_output (" ", 0);
  931. cvs_output (rev, 0);
  932. cvs_output ("\n", 1);
  933. free (oversion);
  934. if (branch_mode)
  935. free (rev);
  936. goto free_vars_and_return;
  937. }
  938. else /* force_tag_move == 1 and... */
  939. if ((isbranch && !disturb_branch_tags) ||
  940. (!isbranch && disturb_branch_tags))
  941. {
  942. error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.",
  943. finfo->fullname,
  944. isbranch ? "branch" : "non-branch",
  945. symtag, oversion, rev,
  946. isbranch ? "" : " due to `-B' option");
  947. free (oversion);
  948. if (branch_mode)
  949. free (rev);
  950. goto free_vars_and_return;
  951. }
  952. free (oversion);
  953. }
  954. if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0)
  955. {
  956. error (1, retcode == -1 ? errno : 0,
  957. "failed to set tag %s to revision %s in %s",
  958. symtag, rev, vers->srcfile->path);
  959. if (branch_mode)
  960. free (rev);
  961. retval = 1;
  962. goto free_vars_and_return;
  963. }
  964. if (branch_mode)
  965. free (rev);
  966. RCS_rewrite (vers->srcfile, NULL, NULL);
  967. /* more warm fuzzies */
  968. if (!really_quiet)
  969. {
  970. cvs_output ("T ", 2);
  971. cvs_output (finfo->fullname, 0);
  972. cvs_output ("\n", 1);
  973. }
  974. free_vars_and_return:
  975. if (nversion != NULL)
  976. free (nversion);
  977. freevers_ts (&vers);
  978. return (retval);
  979. }
  980. /*
  981. * Print a warm fuzzy message
  982. */
  983. /* ARGSUSED */
  984. static Dtype
  985. tag_dirproc (callerdat, dir, repos, update_dir, entries)
  986. void *callerdat;
  987. const char *dir;
  988. const char *repos;
  989. const char *update_dir;
  990. List *entries;
  991. {
  992. if (ignore_directory (update_dir))
  993. {
  994. /* print the warm fuzzy message */
  995. if (!quiet)
  996. error (0, 0, "Ignoring %s", update_dir);
  997. return R_SKIP_ALL;
  998. }
  999. if (!quiet)
  1000. error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging", update_dir);
  1001. return (R_PROCESS);
  1002. }
  1003. /* Code relating to the val-tags file. Note that this file has no way
  1004. of knowing when a tag has been deleted. The problem is that there
  1005. is no way of knowing whether a tag still exists somewhere, when we
  1006. delete it some places. Using per-directory val-tags files (in
  1007. CVSREP) might be better, but that might slow down the process of
  1008. verifying that a tag is correct (maybe not, for the likely cases,
  1009. if carefully done), and/or be harder to implement correctly. */
  1010. struct val_args {
  1011. char *name;
  1012. int found;
  1013. };
  1014. static int val_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  1015. static int
  1016. val_fileproc (callerdat, finfo)
  1017. void *callerdat;
  1018. struct file_info *finfo;
  1019. {
  1020. RCSNode *rcsdata;
  1021. struct val_args *args = (struct val_args *)callerdat;
  1022. char *tag;
  1023. if ((rcsdata = finfo->rcs) == NULL)
  1024. /* Not sure this can happen, after all we passed only
  1025. W_REPOS | W_ATTIC. */
  1026. return 0;
  1027. tag = RCS_gettag (rcsdata, args->name, 1, (int *) NULL);
  1028. if (tag != NULL)
  1029. {
  1030. /* FIXME: should find out a way to stop the search at this point. */
  1031. args->found = 1;
  1032. free (tag);
  1033. }
  1034. return 0;
  1035. }
  1036. /* This routine determines whether a tag appears in CVSROOT/val-tags.
  1037. *
  1038. * The val-tags file will be open read-only when IDB is NULL. Since writes to
  1039. * val-tags always append to it, the lack of locking is okay. The worst case
  1040. * race condition might misinterpret a partially written "foobar" matched, for
  1041. * instance, a request for "f", "foo", of "foob". Such a mismatch would be
  1042. * caught harmlessly later.
  1043. *
  1044. * Before CVS adds a tag to val-tags, it will lock val-tags for write and
  1045. * verify that the tag is still not present to avoid adding it twice.
  1046. *
  1047. * NOTES
  1048. * This function expects its parent to handle any necessary locking of the
  1049. * val-tags file.
  1050. *
  1051. * INPUTS
  1052. * idb When this value is NULL, the val-tags file is opened in
  1053. * in read-only mode. When present, the val-tags file is opened
  1054. * in read-write mode and the DBM handle is stored in *IDB.
  1055. * name The tag to search for.
  1056. *
  1057. * OUTPUTS
  1058. * *idb The val-tags file opened for read/write, or NULL if it couldn't
  1059. * be opened.
  1060. *
  1061. * ERRORS
  1062. * Exits with an error message if the val-tags file cannot be opened for
  1063. * read (failure to open val-tags read/write is harmless - see below).
  1064. *
  1065. * RETURNS
  1066. * true 1. If NAME exists in val-tags.
  1067. * 2. If IDB is non-NULL and val-tags cannot be opened for write.
  1068. * This allows callers to ignore the harmless inability to
  1069. * update the val-tags cache.
  1070. * false If the file could be opened and the tag is not present.
  1071. */
  1072. static int is_in_val_tags PROTO((DBM **idb, const char *name));
  1073. static int
  1074. is_in_val_tags (idb, name)
  1075. DBM **idb;
  1076. const char *name;
  1077. {
  1078. DBM *db = NULL;
  1079. char *valtags_filename;
  1080. datum mytag;
  1081. int status;
  1082. /* Casting out const should be safe here - input datums are not
  1083. * written to by the myndbm functions.
  1084. */
  1085. mytag.dptr = (char *)name;
  1086. mytag.dsize = strlen (name);
  1087. valtags_filename = xmalloc (strlen (current_parsed_root->directory)
  1088. + sizeof CVSROOTADM
  1089. + sizeof CVSROOTADM_VALTAGS + 3);
  1090. sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory,
  1091. CVSROOTADM, CVSROOTADM_VALTAGS);
  1092. if (idb)
  1093. {
  1094. db = dbm_open (valtags_filename, O_RDWR, 0666);
  1095. if (!db)
  1096. {
  1097. mode_t omask;
  1098. if (!existence_error (errno))
  1099. {
  1100. error (0, errno, "warning: cannot open %s read/write",
  1101. valtags_filename);
  1102. *idb = NULL;
  1103. return 1;
  1104. }
  1105. omask = umask (cvsumask);
  1106. db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
  1107. umask (omask);
  1108. if (!db)
  1109. {
  1110. error (0, errno, "warning: cannot create %s",
  1111. valtags_filename);
  1112. *idb = NULL;
  1113. return 1;
  1114. }
  1115. *idb = db;
  1116. return 0;
  1117. }
  1118. *idb = db;
  1119. }
  1120. else
  1121. {
  1122. db = dbm_open (valtags_filename, O_RDONLY, 0444);
  1123. if (!db && !existence_error (errno))
  1124. error (1, errno, "cannot read %s", valtags_filename);
  1125. }
  1126. /* If the file merely fails to exist, we just keep going and create
  1127. it later if need be. */
  1128. status = 0;
  1129. if (db)
  1130. {
  1131. datum val;
  1132. val = dbm_fetch (db, mytag);
  1133. if (val.dptr != NULL)
  1134. /* Found. The tag is valid. */
  1135. status = 1;
  1136. /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */
  1137. if (!idb) dbm_close (db);
  1138. }
  1139. free (valtags_filename);
  1140. return status;
  1141. }
  1142. /* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and
  1143. * reverifies that the tag does not exist before adding it.
  1144. */
  1145. static void add_to_val_tags PROTO((const char *name));
  1146. static void
  1147. add_to_val_tags (name)
  1148. const char *name;
  1149. {
  1150. DBM *db;
  1151. datum mytag;
  1152. datum value;
  1153. if (noexec) return;
  1154. val_tags_lock (current_parsed_root->directory);
  1155. /* Check for presence again since we have a lock now. */
  1156. if (is_in_val_tags (&db, name))
  1157. {
  1158. clear_val_tags_lock ();
  1159. if (db)
  1160. dbm_close (db);
  1161. return;
  1162. }
  1163. /* Casting out const should be safe here - input datums are not
  1164. * written to by the myndbm functions.
  1165. */
  1166. mytag.dptr = (char *)name;
  1167. mytag.dsize = strlen (name);
  1168. value.dptr = "y";
  1169. value.dsize = 1;
  1170. if (dbm_store (db, mytag, value, DBM_REPLACE) < 0)
  1171. error (0, errno, "failed to store %s into val-tags", name);
  1172. dbm_close (db);
  1173. clear_val_tags_lock ();
  1174. }
  1175. static Dtype val_direntproc PROTO ((void *, const char *, const char *,
  1176. const char *, List *));
  1177. static Dtype
  1178. val_direntproc (callerdat, dir, repository, update_dir, entries)
  1179. void *callerdat;
  1180. const char *dir;
  1181. const char *repository;
  1182. const char *update_dir;
  1183. List *entries;
  1184. {
  1185. /* This is not quite right--it doesn't get right the case of "cvs
  1186. update -d -r foobar" where foobar is a tag which exists only in
  1187. files in a directory which does not exist yet, but which is
  1188. about to be created. */
  1189. if (isdir (dir))
  1190. return R_PROCESS;
  1191. return R_SKIP_ALL;
  1192. }
  1193. /* Check to see whether NAME is a valid tag. If so, return. If not
  1194. print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify
  1195. which files we will be operating on.
  1196. REPOSITORY is the repository if we need to cd into it, or NULL if
  1197. we are already there, or "" if we should do a W_LOCAL recursion.
  1198. Sorry for three cases, but the "" case is needed in case the
  1199. working directories come from diverse parts of the repository, the
  1200. NULL case avoids an unneccesary chdir, and the non-NULL, non-""
  1201. case is needed for checkout, where we don't want to chdir if the
  1202. tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any
  1203. local directory. */
  1204. void
  1205. tag_check_valid (name, argc, argv, local, aflag, repository)
  1206. char *name;
  1207. int argc;
  1208. char **argv;
  1209. int local;
  1210. int aflag;
  1211. char *repository;
  1212. {
  1213. struct val_args the_val_args;
  1214. struct saved_cwd cwd;
  1215. int which;
  1216. /* Numeric tags require only a syntactic check. */
  1217. if (isdigit ((unsigned char) name[0]))
  1218. {
  1219. char *p;
  1220. for (p = name; *p != '\0'; ++p)
  1221. {
  1222. if (!(isdigit ((unsigned char) *p) || *p == '.'))
  1223. error (1, 0, "\
  1224. Numeric tag %s contains characters other than digits and '.'", name);
  1225. }
  1226. return;
  1227. }
  1228. /* Special tags are always valid. */
  1229. if (strcmp (name, TAG_BASE) == 0
  1230. || strcmp (name, TAG_HEAD) == 0)
  1231. return;
  1232. if (readonlyfs)
  1233. return;
  1234. /* Verify that the tag is valid syntactically. Some later code once made
  1235. * assumptions about this.
  1236. */
  1237. RCS_check_tag (name);
  1238. if (is_in_val_tags (NULL, name)) return;
  1239. /* We didn't find the tag in val-tags, so look through all the RCS files
  1240. to see whether it exists there. Yes, this is expensive, but there
  1241. is no other way to cope with a tag which might have been created
  1242. by an old version of CVS, from before val-tags was invented.
  1243. Since we need this code anyway, we also use it to create
  1244. entries in val-tags in general (that is, the val-tags entry
  1245. will get created the first time the tag is used, not when the
  1246. tag is created). */
  1247. the_val_args.name = name;
  1248. the_val_args.found = 0;
  1249. which = W_REPOS | W_ATTIC;
  1250. if (repository != NULL)
  1251. {
  1252. if (repository[0] == '\0')
  1253. which |= W_LOCAL;
  1254. else
  1255. {
  1256. if (save_cwd (&cwd))
  1257. error_exit ();
  1258. if (CVS_CHDIR (repository) < 0)
  1259. error (1, errno, "cannot change to %s directory", repository);
  1260. }
  1261. }
  1262. start_recursion (val_fileproc, (FILESDONEPROC) NULL,
  1263. val_direntproc, (DIRLEAVEPROC) NULL,
  1264. (void *)&the_val_args,
  1265. argc, argv, local, which, aflag,
  1266. CVS_LOCK_READ, NULL, 1, repository);
  1267. if (repository != NULL && repository[0] != '\0')
  1268. {
  1269. if (restore_cwd (&cwd, NULL))
  1270. error_exit ();
  1271. free_cwd (&cwd);
  1272. }
  1273. if (!the_val_args.found)
  1274. error (1, 0, "no such tag %s", name);
  1275. else
  1276. /* The tags is valid but not mentioned in val-tags. Add it. */
  1277. add_to_val_tags (name);
  1278. }
  1279. /*
  1280. * Check whether a join tag is valid. This is just like
  1281. * tag_check_valid, but we must stop before the colon if there is one.
  1282. */
  1283. void
  1284. tag_check_valid_join (join_tag, argc, argv, local, aflag, repository)
  1285. char *join_tag;
  1286. int argc;
  1287. char **argv;
  1288. int local;
  1289. int aflag;
  1290. char *repository;
  1291. {
  1292. char *c, *s;
  1293. c = xstrdup (join_tag);
  1294. s = strchr (c, ':');
  1295. if (s != NULL)
  1296. {
  1297. if (isdigit ((unsigned char) join_tag[0]))
  1298. error (1, 0,
  1299. "Numeric join tag %s may not contain a date specifier",
  1300. join_tag);
  1301. *s = '\0';
  1302. /* hmmm... I think it makes sense to allow -j:<date>, but
  1303. * for now this fixes a bug where CVS just spins and spins (I
  1304. * think in the RCS code) looking for a zero length tag.
  1305. */
  1306. if (!*c)
  1307. error (1, 0,
  1308. "argument to join may not contain a date specifier without a tag");
  1309. }
  1310. tag_check_valid (c, argc, argv, local, aflag, repository);
  1311. free (c);
  1312. }