PageRenderTime 65ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/cvs/src/commit.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2433 lines | 1644 code | 303 blank | 486 comment | 439 complexity | 6e9c8bfcd87887423de6329971706e51 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  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. * Commit Files
  14. *
  15. * "commit" commits the present version to the RCS repository, AFTER
  16. * having done a test on conflicts.
  17. *
  18. * The call is: cvs commit [options] files...
  19. *
  20. * $FreeBSD$
  21. */
  22. #include <assert.h>
  23. #include "cvs.h"
  24. #include "getline.h"
  25. #include "edit.h"
  26. #include "fileattr.h"
  27. #include "hardlink.h"
  28. static Dtype check_direntproc PROTO ((void *callerdat, const char *dir,
  29. const char *repos,
  30. const char *update_dir,
  31. List *entries));
  32. static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  33. static int check_filesdoneproc PROTO ((void *callerdat, int err,
  34. const char *repos,
  35. const char *update_dir,
  36. List *entries));
  37. static int checkaddfile PROTO((const char *file, const char *repository,
  38. const char *tag, const char *options,
  39. RCSNode **rcsnode));
  40. static Dtype commit_direntproc PROTO ((void *callerdat, const char *dir,
  41. const char *repos,
  42. const char *update_dir,
  43. List *entries));
  44. static int commit_dirleaveproc PROTO ((void *callerdat, const char *dir,
  45. int err, const char *update_dir,
  46. List *entries));
  47. static int commit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  48. static int commit_filesdoneproc PROTO ((void *callerdat, int err,
  49. const char *repository,
  50. const char *update_dir,
  51. List *entries));
  52. static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag,
  53. char *options));
  54. static int findmaxrev PROTO((Node * p, void *closure));
  55. static int lock_RCS PROTO((const char *user, RCSNode *rcs, const char *rev,
  56. const char *repository));
  57. static int precommit_list_proc PROTO((Node * p, void *closure));
  58. static int precommit_proc PROTO((const char *repository, const char *filter));
  59. static int remove_file PROTO ((struct file_info *finfo, char *tag,
  60. char *message));
  61. static void fixaddfile PROTO((const char *rcs));
  62. static void fixbranch PROTO((RCSNode *, char *branch));
  63. static void unlockrcs PROTO((RCSNode *rcs));
  64. static void ci_delproc PROTO((Node *p));
  65. static void masterlist_delproc PROTO((Node *p));
  66. struct commit_info
  67. {
  68. Ctype status; /* as returned from Classify_File() */
  69. char *rev; /* a numeric rev, if we know it */
  70. char *tag; /* any sticky tag, or -r option */
  71. char *options; /* Any sticky -k option */
  72. };
  73. struct master_lists
  74. {
  75. List *ulist; /* list for Update_Logfile */
  76. List *cilist; /* list with commit_info structs */
  77. };
  78. static int force_ci = 0;
  79. static int got_message;
  80. static int aflag;
  81. static char *saved_tag;
  82. static char *write_dirtag;
  83. static int write_dirnonbranch;
  84. static char *logfile;
  85. static List *mulist;
  86. static List *saved_ulist;
  87. static char *saved_message;
  88. static time_t last_register_time;
  89. static const char *const commit_usage[] =
  90. {
  91. "Usage: %s %s [-Rlf] [-m msg | -F logfile] [-r rev] files...\n",
  92. " -R Process directories recursively.\n",
  93. " -l Local directory only (not recursive).\n",
  94. " -f Force the file to be committed; disables recursion.\n",
  95. " -F logfile Read the log message from file.\n",
  96. " -m msg Log message.\n",
  97. " -r rev Commit to this branch or trunk revision.\n",
  98. "(Specify the --help global option for a list of other help options)\n",
  99. NULL
  100. };
  101. #ifdef CLIENT_SUPPORT
  102. /* Identify a file which needs "? foo" or a Questionable request. */
  103. struct question {
  104. /* The two fields for the Directory request. */
  105. char *dir;
  106. char *repos;
  107. /* The file name. */
  108. char *file;
  109. struct question *next;
  110. };
  111. struct find_data {
  112. List *ulist;
  113. int argc;
  114. char **argv;
  115. /* This is used from dirent to filesdone time, for each directory,
  116. to make a list of files we have already seen. */
  117. List *ignlist;
  118. /* Linked list of files which need "? foo" or a Questionable request. */
  119. struct question *questionables;
  120. /* Only good within functions called from the filesdoneproc. Stores
  121. the repository (pointer into storage managed by the recursion
  122. processor. */
  123. const char *repository;
  124. /* Non-zero if we should force the commit. This is enabled by
  125. either -f or -r options, unlike force_ci which is just -f. */
  126. int force;
  127. };
  128. static Dtype find_dirent_proc PROTO ((void *callerdat, const char *dir,
  129. const char *repository,
  130. const char *update_dir,
  131. List *entries));
  132. static Dtype
  133. find_dirent_proc (callerdat, dir, repository, update_dir, entries)
  134. void *callerdat;
  135. const char *dir;
  136. const char *repository;
  137. const char *update_dir;
  138. List *entries;
  139. {
  140. struct find_data *find_data = (struct find_data *)callerdat;
  141. /* This check seems to slowly be creeping throughout CVS (update
  142. and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
  143. is that it (or some variant thereof) should go in all the
  144. dirent procs. Unless someone has some better idea... */
  145. if (!isdir (dir))
  146. return R_SKIP_ALL;
  147. /* initialize the ignore list for this directory */
  148. find_data->ignlist = getlist ();
  149. /* Print the same warm fuzzy as in check_direntproc, since that
  150. code will never be run during client/server operation and we
  151. want the messages to match. */
  152. if (!quiet)
  153. error (0, 0, "Examining %s", update_dir);
  154. return R_PROCESS;
  155. }
  156. /* Here as a static until we get around to fixing ignore_files to pass
  157. it along as an argument. */
  158. static struct find_data *find_data_static;
  159. static void find_ignproc PROTO ((const char *, const char *));
  160. static void
  161. find_ignproc (file, dir)
  162. const char *file;
  163. const char *dir;
  164. {
  165. struct question *p;
  166. p = (struct question *) xmalloc (sizeof (struct question));
  167. p->dir = xstrdup (dir);
  168. p->repos = xstrdup (find_data_static->repository);
  169. p->file = xstrdup (file);
  170. p->next = find_data_static->questionables;
  171. find_data_static->questionables = p;
  172. }
  173. static int find_filesdoneproc PROTO ((void *callerdat, int err,
  174. const char *repository,
  175. const char *update_dir,
  176. List *entries));
  177. static int
  178. find_filesdoneproc (callerdat, err, repository, update_dir, entries)
  179. void *callerdat;
  180. int err;
  181. const char *repository;
  182. const char *update_dir;
  183. List *entries;
  184. {
  185. struct find_data *find_data = (struct find_data *)callerdat;
  186. find_data->repository = repository;
  187. /* if this directory has an ignore list, process it then free it */
  188. if (find_data->ignlist)
  189. {
  190. find_data_static = find_data;
  191. ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
  192. dellist (&find_data->ignlist);
  193. }
  194. find_data->repository = NULL;
  195. return err;
  196. }
  197. static int find_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  198. /* Machinery to find out what is modified, added, and removed. It is
  199. possible this should be broken out into a new client_classify function;
  200. merging it with classify_file is almost sure to be a mess, though,
  201. because classify_file has all kinds of repository processing. */
  202. static int
  203. find_fileproc (callerdat, finfo)
  204. void *callerdat;
  205. struct file_info *finfo;
  206. {
  207. Vers_TS *vers;
  208. enum classify_type status;
  209. Node *node;
  210. struct find_data *args = (struct find_data *)callerdat;
  211. struct logfile_info *data;
  212. struct file_info xfinfo;
  213. /* if this directory has an ignore list, add this file to it */
  214. if (args->ignlist)
  215. {
  216. Node *p;
  217. p = getnode ();
  218. p->type = FILES;
  219. p->key = xstrdup (finfo->file);
  220. if (addnode (args->ignlist, p) != 0)
  221. freenode (p);
  222. }
  223. xfinfo = *finfo;
  224. xfinfo.repository = NULL;
  225. xfinfo.rcs = NULL;
  226. vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
  227. if (vers->vn_user == NULL)
  228. {
  229. if (vers->ts_user == NULL)
  230. error (0, 0, "nothing known about `%s'", finfo->fullname);
  231. else
  232. error (0, 0, "use `%s add' to create an entry for %s",
  233. program_name, finfo->fullname);
  234. freevers_ts (&vers);
  235. return 1;
  236. }
  237. if (vers->vn_user[0] == '-')
  238. {
  239. if (vers->ts_user != NULL)
  240. {
  241. error (0, 0,
  242. "`%s' should be removed and is still there (or is back"
  243. " again)", finfo->fullname);
  244. freevers_ts (&vers);
  245. return 1;
  246. }
  247. /* else */
  248. status = T_REMOVED;
  249. }
  250. else if (strcmp (vers->vn_user, "0") == 0)
  251. {
  252. if (vers->ts_user == NULL)
  253. {
  254. /* This happens when one has `cvs add'ed a file, but it no
  255. longer exists in the working directory at commit time.
  256. FIXME: What classify_file does in this case is print
  257. "new-born %s has disappeared" and removes the entry.
  258. We probably should do the same. */
  259. if (!really_quiet)
  260. error (0, 0, "warning: new-born %s has disappeared",
  261. finfo->fullname);
  262. status = T_REMOVE_ENTRY;
  263. }
  264. else
  265. status = T_ADDED;
  266. }
  267. else if (vers->ts_user == NULL)
  268. {
  269. /* FIXME: What classify_file does in this case is print
  270. "%s was lost". We probably should do the same. */
  271. freevers_ts (&vers);
  272. return 0;
  273. }
  274. else if (vers->ts_rcs != NULL
  275. && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
  276. /* If we are forcing commits, pretend that the file is
  277. modified. */
  278. status = T_MODIFIED;
  279. else
  280. {
  281. /* This covers unmodified files, as well as a variety of other
  282. cases. FIXME: we probably should be printing a message and
  283. returning 1 for many of those cases (but I'm not sure
  284. exactly which ones). */
  285. freevers_ts (&vers);
  286. return 0;
  287. }
  288. node = getnode ();
  289. node->key = xstrdup (finfo->fullname);
  290. data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
  291. data->type = status;
  292. data->tag = xstrdup (vers->tag);
  293. data->rev_old = data->rev_new = NULL;
  294. node->type = UPDATE;
  295. node->delproc = update_delproc;
  296. node->data = data;
  297. (void)addnode (args->ulist, node);
  298. ++args->argc;
  299. freevers_ts (&vers);
  300. return 0;
  301. }
  302. static int copy_ulist PROTO ((Node *, void *));
  303. static int
  304. copy_ulist (node, data)
  305. Node *node;
  306. void *data;
  307. {
  308. struct find_data *args = (struct find_data *)data;
  309. args->argv[args->argc++] = node->key;
  310. return 0;
  311. }
  312. #endif /* CLIENT_SUPPORT */
  313. #ifdef SERVER_SUPPORT
  314. # define COMMIT_OPTIONS "+nlRm:fF:r:"
  315. #else /* !SERVER_SUPPORT */
  316. # define COMMIT_OPTIONS "+lRm:fF:r:"
  317. #endif /* SERVER_SUPPORT */
  318. int
  319. commit (argc, argv)
  320. int argc;
  321. char **argv;
  322. {
  323. int c;
  324. int err = 0;
  325. int local = 0;
  326. if (argc == -1)
  327. usage (commit_usage);
  328. #ifdef CVS_BADROOT
  329. /*
  330. * For log purposes, do not allow "root" to commit files. If you look
  331. * like root, but are really logged in as a non-root user, it's OK.
  332. */
  333. /* FIXME: Shouldn't this check be much more closely related to the
  334. readonly user stuff (CVSROOT/readers, &c). That is, why should
  335. root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
  336. /* Who we are on the client side doesn't affect logging. */
  337. if (geteuid () == (uid_t) 0 && !current_parsed_root->isremote)
  338. {
  339. struct passwd *pw;
  340. if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
  341. error (1, 0,
  342. "your apparent username (%s) is unknown to this system",
  343. getcaller ());
  344. if (pw->pw_uid == (uid_t) 0)
  345. error (1, 0, "'root' is not allowed to commit files");
  346. }
  347. #endif /* CVS_BADROOT */
  348. optind = 0;
  349. while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
  350. {
  351. switch (c)
  352. {
  353. #ifdef SERVER_SUPPORT
  354. case 'n':
  355. /* Silently ignore -n for compatibility with old
  356. * clients.
  357. */
  358. if (!server_active) error(0, 0, "the `-n' option is obsolete");
  359. break;
  360. #endif /* SERVER_SUPPORT */
  361. case 'm':
  362. #ifdef FORCE_USE_EDITOR
  363. use_editor = 1;
  364. #else
  365. use_editor = 0;
  366. #endif
  367. if (saved_message)
  368. {
  369. free (saved_message);
  370. saved_message = NULL;
  371. }
  372. saved_message = xstrdup(optarg);
  373. break;
  374. case 'r':
  375. if (saved_tag)
  376. free (saved_tag);
  377. saved_tag = xstrdup (optarg);
  378. break;
  379. case 'l':
  380. local = 1;
  381. break;
  382. case 'R':
  383. local = 0;
  384. break;
  385. case 'f':
  386. force_ci = 1;
  387. local = 1; /* also disable recursion */
  388. break;
  389. case 'F':
  390. #ifdef FORCE_USE_EDITOR
  391. use_editor = 1;
  392. #else
  393. use_editor = 0;
  394. #endif
  395. logfile = optarg;
  396. break;
  397. case '?':
  398. default:
  399. usage (commit_usage);
  400. break;
  401. }
  402. }
  403. argc -= optind;
  404. argv += optind;
  405. /* numeric specified revision means we ignore sticky tags... */
  406. if (saved_tag && isdigit ((unsigned char) *saved_tag))
  407. {
  408. char *p = saved_tag + strlen (saved_tag);
  409. aflag = 1;
  410. /* strip trailing dots and leading zeros */
  411. while (*--p == '.') ;
  412. p[1] = '\0';
  413. while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1]))
  414. ++saved_tag;
  415. }
  416. /* some checks related to the "-F logfile" option */
  417. if (logfile)
  418. {
  419. size_t size = 0, len;
  420. if (saved_message)
  421. error (1, 0, "cannot specify both a message and a log file");
  422. get_file (logfile, logfile, "r", &saved_message, &size, &len);
  423. }
  424. #ifdef CLIENT_SUPPORT
  425. if (current_parsed_root->isremote)
  426. {
  427. struct find_data find_args;
  428. ign_setup ();
  429. find_args.ulist = getlist ();
  430. find_args.argc = 0;
  431. find_args.questionables = NULL;
  432. find_args.ignlist = NULL;
  433. find_args.repository = NULL;
  434. /* It is possible that only a numeric tag should set this.
  435. I haven't really thought about it much.
  436. Anyway, I suspect that setting it unnecessarily only causes
  437. a little unneeded network traffic. */
  438. find_args.force = force_ci || saved_tag != NULL;
  439. err = start_recursion (find_fileproc, find_filesdoneproc,
  440. find_dirent_proc, (DIRLEAVEPROC) NULL,
  441. (void *)&find_args,
  442. argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
  443. (char *) NULL, 0, (char *) NULL);
  444. if (err)
  445. error (1, 0, "correct above errors first!");
  446. if (find_args.argc == 0)
  447. {
  448. /* Nothing to commit. Exit now without contacting the
  449. server (note that this means that we won't print "?
  450. foo" for files which merit it, because we don't know
  451. what is in the CVSROOT/cvsignore file). */
  452. dellist (&find_args.ulist);
  453. return 0;
  454. }
  455. /* Now we keep track of which files we actually are going to
  456. operate on, and only work with those files in the future.
  457. This saves time--we don't want to search the file system
  458. of the working directory twice. */
  459. if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
  460. {
  461. find_args.argc = 0;
  462. return 0;
  463. }
  464. find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **)));
  465. find_args.argc = 0;
  466. walklist (find_args.ulist, copy_ulist, &find_args);
  467. /* Do this before calling do_editor; don't ask for a log
  468. message if we can't talk to the server. But do it after we
  469. have made the checks that we can locally (to more quickly
  470. catch syntax errors, the case where no files are modified,
  471. added or removed, etc.).
  472. On the other hand, calling start_server before do_editor
  473. means that we chew up server resources the whole time that
  474. the user has the editor open (hours or days if the user
  475. forgets about it), which seems dubious. */
  476. start_server ();
  477. /*
  478. * We do this once, not once for each directory as in normal CVS.
  479. * The protocol is designed this way. This is a feature.
  480. */
  481. if (use_editor)
  482. do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
  483. /* We always send some sort of message, even if empty. */
  484. option_with_arg ("-m", saved_message ? saved_message : "");
  485. /* OK, now process all the questionable files we have been saving
  486. up. */
  487. {
  488. struct question *p;
  489. struct question *q;
  490. p = find_args.questionables;
  491. while (p != NULL)
  492. {
  493. if (ign_inhibit_server || !supported_request ("Questionable"))
  494. {
  495. cvs_output ("? ", 2);
  496. if (p->dir[0] != '\0')
  497. {
  498. cvs_output (p->dir, 0);
  499. cvs_output ("/", 1);
  500. }
  501. cvs_output (p->file, 0);
  502. cvs_output ("\n", 1);
  503. }
  504. else
  505. {
  506. send_to_server ("Directory ", 0);
  507. send_to_server (p->dir[0] == '\0' ? "." : p->dir, 0);
  508. send_to_server ("\012", 1);
  509. send_to_server (p->repos, 0);
  510. send_to_server ("\012", 1);
  511. send_to_server ("Questionable ", 0);
  512. send_to_server (p->file, 0);
  513. send_to_server ("\012", 1);
  514. }
  515. free (p->dir);
  516. free (p->repos);
  517. free (p->file);
  518. q = p->next;
  519. free (p);
  520. p = q;
  521. }
  522. }
  523. if (local)
  524. send_arg("-l");
  525. if (force_ci)
  526. send_arg("-f");
  527. option_with_arg ("-r", saved_tag);
  528. send_arg ("--");
  529. /* FIXME: This whole find_args.force/SEND_FORCE business is a
  530. kludge. It would seem to be a server bug that we have to
  531. say that files are modified when they are not. This makes
  532. "cvs commit -r 2" across a whole bunch of files a very slow
  533. operation (and it isn't documented in cvsclient.texi). I
  534. haven't looked at the server code carefully enough to be
  535. _sure_ why this is needed, but if it is because the "ci"
  536. program, which we used to call, wanted the file to exist,
  537. then it would be relatively simple to fix in the server. */
  538. send_files (find_args.argc, find_args.argv, local, 0,
  539. find_args.force ? SEND_FORCE : 0);
  540. /* Sending only the names of the files which were modified, added,
  541. or removed means that the server will only do an up-to-date
  542. check on those files. This is different from local CVS and
  543. previous versions of client/server CVS, but it probably is a Good
  544. Thing, or at least Not Such A Bad Thing. */
  545. send_file_names (find_args.argc, find_args.argv, 0);
  546. free (find_args.argv);
  547. dellist (&find_args.ulist);
  548. send_to_server ("ci\012", 0);
  549. err = get_responses_and_close ();
  550. if (err != 0 && use_editor && saved_message != NULL)
  551. {
  552. /* If there was an error, don't nuke the user's carefully
  553. constructed prose. This is something of a kludge; a better
  554. solution is probably more along the lines of #150 in TODO
  555. (doing a second up-to-date check before accepting the
  556. log message has also been suggested, but that seems kind of
  557. iffy because the real up-to-date check could still fail,
  558. another error could occur, &c. Also, a second check would
  559. slow things down). */
  560. char *fname;
  561. FILE *fp;
  562. fp = cvs_temp_file (&fname);
  563. if (fp == NULL)
  564. error (1, 0, "cannot create temporary file %s",
  565. fname ? fname : "(null)");
  566. if (fwrite (saved_message, 1, strlen (saved_message), fp)
  567. != strlen (saved_message))
  568. error (1, errno, "cannot write temporary file %s", fname);
  569. if (fclose (fp) < 0)
  570. error (0, errno, "cannot close temporary file %s", fname);
  571. error (0, 0, "saving log message in %s", fname);
  572. free (fname);
  573. }
  574. return err;
  575. }
  576. #endif
  577. if (saved_tag != NULL)
  578. tag_check_valid (saved_tag, argc, argv, local, aflag, "");
  579. /* XXX - this is not the perfect check for this */
  580. if (argc <= 0)
  581. write_dirtag = saved_tag;
  582. wrap_setup ();
  583. lock_tree_for_write (argc, argv, local, W_LOCAL, aflag);
  584. /*
  585. * Set up the master update list and hard link list
  586. */
  587. mulist = getlist ();
  588. #ifdef PRESERVE_PERMISSIONS_SUPPORT
  589. if (preserve_perms)
  590. {
  591. hardlist = getlist ();
  592. /*
  593. * We need to save the working directory so that
  594. * check_fileproc can construct a full pathname for each file.
  595. */
  596. working_dir = xgetwd();
  597. }
  598. #endif
  599. /*
  600. * Run the recursion processor to verify the files are all up-to-date
  601. */
  602. err = start_recursion (check_fileproc, check_filesdoneproc,
  603. check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc,
  604. argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
  605. (char *) NULL, 1, (char *) NULL);
  606. if (err)
  607. {
  608. Lock_Cleanup ();
  609. error (1, 0, "correct above errors first!");
  610. }
  611. /*
  612. * Run the recursion processor to commit the files
  613. */
  614. write_dirnonbranch = 0;
  615. if (noexec == 0)
  616. err = start_recursion (commit_fileproc, commit_filesdoneproc,
  617. commit_direntproc, commit_dirleaveproc, NULL,
  618. argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
  619. (char *) NULL, 1, (char *) NULL);
  620. /*
  621. * Unlock all the dirs and clean up
  622. */
  623. Lock_Cleanup ();
  624. dellist (&mulist);
  625. if (server_active)
  626. return err;
  627. /* see if we need to sleep before returning to avoid time-stamp races */
  628. if (last_register_time)
  629. {
  630. sleep_past (last_register_time);
  631. }
  632. return err;
  633. }
  634. /* This routine determines the status of a given file and retrieves
  635. the version information that is associated with that file. */
  636. static
  637. Ctype
  638. classify_file_internal (finfo, vers)
  639. struct file_info *finfo;
  640. Vers_TS **vers;
  641. {
  642. int save_noexec, save_quiet, save_really_quiet;
  643. Ctype status;
  644. /* FIXME: Do we need to save quiet as well as really_quiet? Last
  645. time I glanced at Classify_File I only saw it looking at really_quiet
  646. not quiet. */
  647. save_noexec = noexec;
  648. save_quiet = quiet;
  649. save_really_quiet = really_quiet;
  650. noexec = quiet = really_quiet = 1;
  651. /* handle specified numeric revision specially */
  652. if (saved_tag && isdigit ((unsigned char) *saved_tag))
  653. {
  654. /* If the tag is for the trunk, make sure we're at the head */
  655. if (numdots (saved_tag) < 2)
  656. {
  657. status = Classify_File (finfo, (char *) NULL, (char *) NULL,
  658. (char *) NULL, 1, aflag, vers, 0);
  659. if (status == T_UPTODATE || status == T_MODIFIED ||
  660. status == T_ADDED)
  661. {
  662. Ctype xstatus;
  663. freevers_ts (vers);
  664. xstatus = Classify_File (finfo, saved_tag, (char *) NULL,
  665. (char *) NULL, 1, aflag, vers, 0);
  666. if (xstatus == T_REMOVE_ENTRY)
  667. status = T_MODIFIED;
  668. else if (status == T_MODIFIED && xstatus == T_CONFLICT)
  669. status = T_MODIFIED;
  670. else
  671. status = xstatus;
  672. }
  673. }
  674. else
  675. {
  676. char *xtag, *cp;
  677. /*
  678. * The revision is off the main trunk; make sure we're
  679. * up-to-date with the head of the specified branch.
  680. */
  681. xtag = xstrdup (saved_tag);
  682. if ((numdots (xtag) & 1) != 0)
  683. {
  684. cp = strrchr (xtag, '.');
  685. *cp = '\0';
  686. }
  687. status = Classify_File (finfo, xtag, (char *) NULL,
  688. (char *) NULL, 1, aflag, vers, 0);
  689. if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
  690. && (cp = strrchr (xtag, '.')) != NULL)
  691. {
  692. /* pluck one more dot off the revision */
  693. *cp = '\0';
  694. freevers_ts (vers);
  695. status = Classify_File (finfo, xtag, (char *) NULL,
  696. (char *) NULL, 1, aflag, vers, 0);
  697. if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
  698. status = T_MODIFIED;
  699. }
  700. /* now, muck with vers to make the tag correct */
  701. free ((*vers)->tag);
  702. (*vers)->tag = xstrdup (saved_tag);
  703. free (xtag);
  704. }
  705. }
  706. else
  707. status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
  708. 1, 0, vers, 0);
  709. noexec = save_noexec;
  710. quiet = save_quiet;
  711. really_quiet = save_really_quiet;
  712. return status;
  713. }
  714. /*
  715. * Check to see if a file is ok to commit and make sure all files are
  716. * up-to-date
  717. */
  718. /* ARGSUSED */
  719. static int
  720. check_fileproc (callerdat, finfo)
  721. void *callerdat;
  722. struct file_info *finfo;
  723. {
  724. Ctype status;
  725. const char *xdir;
  726. Node *p;
  727. List *ulist, *cilist;
  728. Vers_TS *vers;
  729. struct commit_info *ci;
  730. struct logfile_info *li;
  731. size_t cvsroot_len = strlen (current_parsed_root->directory);
  732. if (!finfo->repository)
  733. {
  734. error (0, 0, "nothing known about `%s'", finfo->fullname);
  735. return 1;
  736. }
  737. if (strncmp (finfo->repository, current_parsed_root->directory,
  738. cvsroot_len) == 0
  739. && ISDIRSEP (finfo->repository[cvsroot_len])
  740. && strncmp (finfo->repository + cvsroot_len + 1,
  741. CVSROOTADM,
  742. sizeof (CVSROOTADM) - 1) == 0
  743. && ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
  744. && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
  745. CVSNULLREPOS) == 0
  746. )
  747. error (1, 0, "cannot check in to %s", finfo->repository);
  748. status = classify_file_internal (finfo, &vers);
  749. /*
  750. * If the force-commit option is enabled, and the file in question
  751. * appears to be up-to-date, just make it look modified so that
  752. * it will be committed.
  753. */
  754. if (force_ci && status == T_UPTODATE)
  755. status = T_MODIFIED;
  756. switch (status)
  757. {
  758. case T_CHECKOUT:
  759. case T_PATCH:
  760. case T_NEEDS_MERGE:
  761. case T_REMOVE_ENTRY:
  762. error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
  763. freevers_ts (&vers);
  764. return 1;
  765. case T_CONFLICT:
  766. case T_MODIFIED:
  767. case T_ADDED:
  768. case T_REMOVED:
  769. /*
  770. * some quick sanity checks; if no numeric -r option specified:
  771. * - can't have a sticky date
  772. * - can't have a sticky tag that is not a branch
  773. * Also,
  774. * - if status is T_REMOVED, file must not exist and its entry
  775. * can't have a numeric sticky tag.
  776. * - if status is T_ADDED, rcs file must not exist unless on
  777. * a branch or head is dead
  778. * - if status is T_ADDED, can't have a non-trunk numeric rev
  779. * - if status is T_MODIFIED and a Conflict marker exists, don't
  780. * allow the commit if timestamp is identical or if we find
  781. * an RCS_MERGE_PAT in the file.
  782. */
  783. if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
  784. {
  785. if (vers->date)
  786. {
  787. error (0, 0,
  788. "cannot commit with sticky date for file `%s'",
  789. finfo->fullname);
  790. freevers_ts (&vers);
  791. return 1;
  792. }
  793. if (status == T_MODIFIED && vers->tag &&
  794. !RCS_isbranch (finfo->rcs, vers->tag))
  795. {
  796. error (0, 0,
  797. "sticky tag `%s' for file `%s' is not a branch",
  798. vers->tag, finfo->fullname);
  799. freevers_ts (&vers);
  800. return 1;
  801. }
  802. }
  803. if (status == T_CONFLICT && !force_ci)
  804. {
  805. error (0, 0,
  806. "file `%s' had a conflict and has not been modified",
  807. finfo->fullname);
  808. freevers_ts (&vers);
  809. return 1;
  810. }
  811. if (status == T_MODIFIED && !force_ci && file_has_markers (finfo))
  812. {
  813. /* Make this a warning, not an error, because we have
  814. no way of knowing whether the "conflict indicators"
  815. are really from a conflict or whether they are part
  816. of the document itself (cvs.texinfo and sanity.sh in
  817. CVS itself, for example, tend to want to have strings
  818. like ">>>>>>>" at the start of a line). Making people
  819. kludge this the way they need to kludge keyword
  820. expansion seems undesirable. And it is worse than
  821. keyword expansion, because there is no -ko
  822. analogue. */
  823. error (0, 0,
  824. "\
  825. warning: file `%s' seems to still contain conflict indicators",
  826. finfo->fullname);
  827. }
  828. if (status == T_REMOVED)
  829. {
  830. if (vers->ts_user != NULL)
  831. {
  832. error (0, 0,
  833. "`%s' should be removed and is still there (or is"
  834. " back again)", finfo->fullname);
  835. freevers_ts (&vers);
  836. return 1;
  837. }
  838. if (vers->tag && isdigit ((unsigned char) *vers->tag))
  839. {
  840. /* Remove also tries to forbid this, but we should check
  841. here. I'm only _sure_ about somewhat obscure cases
  842. (hacking the Entries file, using an old version of
  843. CVS for the remove and a new one for the commit), but
  844. there might be other cases. */
  845. error (0, 0,
  846. "cannot remove file `%s' which has a numeric sticky"
  847. " tag of `%s'", finfo->fullname, vers->tag);
  848. freevers_ts (&vers);
  849. return 1;
  850. }
  851. }
  852. if (status == T_ADDED)
  853. {
  854. if (vers->tag == NULL)
  855. {
  856. if (finfo->rcs != NULL &&
  857. !RCS_isdead (finfo->rcs, finfo->rcs->head))
  858. {
  859. error (0, 0,
  860. "cannot add file `%s' when RCS file `%s' already exists",
  861. finfo->fullname, finfo->rcs->path);
  862. freevers_ts (&vers);
  863. return 1;
  864. }
  865. }
  866. else if (isdigit ((unsigned char) *vers->tag) &&
  867. numdots (vers->tag) > 1)
  868. {
  869. error (0, 0,
  870. "cannot add file `%s' with revision `%s'; must be on trunk",
  871. finfo->fullname, vers->tag);
  872. freevers_ts (&vers);
  873. return 1;
  874. }
  875. }
  876. /* done with consistency checks; now, to get on with the commit */
  877. if (finfo->update_dir[0] == '\0')
  878. xdir = ".";
  879. else
  880. xdir = finfo->update_dir;
  881. if ((p = findnode (mulist, xdir)) != NULL)
  882. {
  883. ulist = ((struct master_lists *) p->data)->ulist;
  884. cilist = ((struct master_lists *) p->data)->cilist;
  885. }
  886. else
  887. {
  888. struct master_lists *ml;
  889. ulist = getlist ();
  890. cilist = getlist ();
  891. p = getnode ();
  892. p->key = xstrdup (xdir);
  893. p->type = UPDATE;
  894. ml = (struct master_lists *)
  895. xmalloc (sizeof (struct master_lists));
  896. ml->ulist = ulist;
  897. ml->cilist = cilist;
  898. p->data = ml;
  899. p->delproc = masterlist_delproc;
  900. (void) addnode (mulist, p);
  901. }
  902. /* first do ulist, then cilist */
  903. p = getnode ();
  904. p->key = xstrdup (finfo->file);
  905. p->type = UPDATE;
  906. p->delproc = update_delproc;
  907. li = ((struct logfile_info *)
  908. xmalloc (sizeof (struct logfile_info)));
  909. li->type = status;
  910. li->tag = xstrdup (vers->tag);
  911. li->rev_old = xstrdup (vers->vn_rcs);
  912. li->rev_new = NULL;
  913. p->data = li;
  914. (void) addnode (ulist, p);
  915. p = getnode ();
  916. p->key = xstrdup (finfo->file);
  917. p->type = UPDATE;
  918. p->delproc = ci_delproc;
  919. ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
  920. ci->status = status;
  921. if (vers->tag)
  922. if (isdigit ((unsigned char) *vers->tag))
  923. ci->rev = xstrdup (vers->tag);
  924. else
  925. ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
  926. else
  927. ci->rev = (char *) NULL;
  928. ci->tag = xstrdup (vers->tag);
  929. ci->options = xstrdup(vers->options);
  930. p->data = ci;
  931. (void) addnode (cilist, p);
  932. #ifdef PRESERVE_PERMISSIONS_SUPPORT
  933. if (preserve_perms)
  934. {
  935. /* Add this file to hardlist, indexed on its inode. When
  936. we are done, we can find out what files are hardlinked
  937. to a given file by looking up its inode in hardlist. */
  938. char *fullpath;
  939. Node *linkp;
  940. struct hardlink_info *hlinfo;
  941. /* Get the full pathname of the current file. */
  942. fullpath = xmalloc (strlen(working_dir) +
  943. strlen(finfo->fullname) + 2);
  944. sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
  945. /* To permit following links in subdirectories, files
  946. are keyed on finfo->fullname, not on finfo->name. */
  947. linkp = lookup_file_by_inode (fullpath);
  948. /* If linkp is NULL, the file doesn't exist... maybe
  949. we're doing a remove operation? */
  950. if (linkp != NULL)
  951. {
  952. /* Create a new hardlink_info node, which will record
  953. the current file's status and the links listed in its
  954. `hardlinks' delta field. We will append this
  955. hardlink_info node to the appropriate hardlist entry. */
  956. hlinfo = (struct hardlink_info *)
  957. xmalloc (sizeof (struct hardlink_info));
  958. hlinfo->status = status;
  959. linkp->data = hlinfo;
  960. }
  961. }
  962. #endif
  963. break;
  964. case T_UNKNOWN:
  965. error (0, 0, "nothing known about `%s'", finfo->fullname);
  966. freevers_ts (&vers);
  967. return 1;
  968. case T_UPTODATE:
  969. break;
  970. default:
  971. error (0, 0, "CVS internal error: unknown status %d", status);
  972. break;
  973. }
  974. freevers_ts (&vers);
  975. return 0;
  976. }
  977. /*
  978. * By default, return the code that tells do_recursion to examine all
  979. * directories
  980. */
  981. /* ARGSUSED */
  982. static Dtype
  983. check_direntproc (callerdat, dir, repos, update_dir, entries)
  984. void *callerdat;
  985. const char *dir;
  986. const char *repos;
  987. const char *update_dir;
  988. List *entries;
  989. {
  990. if (!isdir (dir))
  991. return R_SKIP_ALL;
  992. if (!quiet)
  993. error (0, 0, "Examining %s", update_dir);
  994. return R_PROCESS;
  995. }
  996. /*
  997. * Walklist proc to run pre-commit checks
  998. */
  999. static int
  1000. precommit_list_proc (p, closure)
  1001. Node *p;
  1002. void *closure;
  1003. {
  1004. struct logfile_info *li = p->data;
  1005. if (li->type == T_ADDED
  1006. || li->type == T_MODIFIED
  1007. || li->type == T_REMOVED)
  1008. {
  1009. run_arg (p->key);
  1010. }
  1011. return 0;
  1012. }
  1013. /*
  1014. * Callback proc for pre-commit checking
  1015. */
  1016. static int
  1017. precommit_proc (repository, filter)
  1018. const char *repository;
  1019. const char *filter;
  1020. {
  1021. /* see if the filter is there, only if it's a full path */
  1022. if (isabsolute (filter))
  1023. {
  1024. char *s, *cp;
  1025. s = xstrdup (filter);
  1026. for (cp = s; *cp; cp++)
  1027. if (isspace ((unsigned char) *cp))
  1028. {
  1029. *cp = '\0';
  1030. break;
  1031. }
  1032. if (!isfile (s))
  1033. {
  1034. error (0, errno, "cannot find pre-commit filter `%s'", s);
  1035. free (s);
  1036. return 1; /* so it fails! */
  1037. }
  1038. free (s);
  1039. }
  1040. run_setup (filter);
  1041. run_arg (repository);
  1042. (void) walklist (saved_ulist, precommit_list_proc, NULL);
  1043. return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY);
  1044. }
  1045. /*
  1046. * Run the pre-commit checks for the dir
  1047. */
  1048. /* ARGSUSED */
  1049. static int
  1050. check_filesdoneproc (callerdat, err, repos, update_dir, entries)
  1051. void *callerdat;
  1052. int err;
  1053. const char *repos;
  1054. const char *update_dir;
  1055. List *entries;
  1056. {
  1057. int n;
  1058. Node *p;
  1059. /* find the update list for this dir */
  1060. p = findnode (mulist, update_dir);
  1061. if (p != NULL)
  1062. saved_ulist = ((struct master_lists *) p->data)->ulist;
  1063. else
  1064. saved_ulist = (List *) NULL;
  1065. /* skip the checks if there's nothing to do */
  1066. if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
  1067. return err;
  1068. /* run any pre-commit checks */
  1069. if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0)
  1070. {
  1071. error (0, 0, "Pre-commit check failed");
  1072. err += n;
  1073. }
  1074. return err;
  1075. }
  1076. /*
  1077. * Do the work of committing a file
  1078. */
  1079. static int maxrev;
  1080. static char *sbranch;
  1081. /* ARGSUSED */
  1082. static int
  1083. commit_fileproc (callerdat, finfo)
  1084. void *callerdat;
  1085. struct file_info *finfo;
  1086. {
  1087. Node *p;
  1088. int err = 0;
  1089. List *ulist, *cilist;
  1090. struct commit_info *ci;
  1091. /* Keep track of whether write_dirtag is a branch tag.
  1092. Note that if it is a branch tag in some files and a nonbranch tag
  1093. in others, treat it as a nonbranch tag. It is possible that case
  1094. should elicit a warning or an error. */
  1095. if (write_dirtag != NULL
  1096. && finfo->rcs != NULL)
  1097. {
  1098. char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
  1099. if (rev != NULL
  1100. && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
  1101. write_dirnonbranch = 1;
  1102. if (rev != NULL)
  1103. free (rev);
  1104. }
  1105. if (finfo->update_dir[0] == '\0')
  1106. p = findnode (mulist, ".");
  1107. else
  1108. p = findnode (mulist, finfo->update_dir);
  1109. /*
  1110. * if p is null, there were file type command line args which were
  1111. * all up-to-date so nothing really needs to be done
  1112. */
  1113. if (p == NULL)
  1114. return 0;
  1115. ulist = ((struct master_lists *) p->data)->ulist;
  1116. cilist = ((struct master_lists *) p->data)->cilist;
  1117. /*
  1118. * At this point, we should have the commit message unless we were called
  1119. * with files as args from the command line. In that latter case, we
  1120. * need to get the commit message ourselves
  1121. */
  1122. if (!got_message)
  1123. {
  1124. got_message = 1;
  1125. if (!server_active && use_editor)
  1126. do_editor (finfo->update_dir, &saved_message,
  1127. finfo->repository, ulist);
  1128. do_verify (&saved_message, finfo->repository);
  1129. }
  1130. p = findnode (cilist, finfo->file);
  1131. if (p == NULL)
  1132. return 0;
  1133. ci = p->data;
  1134. if (ci->status == T_MODIFIED)
  1135. {
  1136. if (finfo->rcs == NULL)
  1137. error (1, 0, "internal error: no parsed RCS file");
  1138. if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
  1139. finfo->repository) != 0)
  1140. {
  1141. unlockrcs (finfo->rcs);
  1142. err = 1;
  1143. goto out;
  1144. }
  1145. }
  1146. else if (ci->status == T_ADDED)
  1147. {
  1148. if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
  1149. &finfo->rcs) != 0)
  1150. {
  1151. if (finfo->rcs != NULL)
  1152. fixaddfile (finfo->rcs->path);
  1153. err = 1;
  1154. goto out;
  1155. }
  1156. /* adding files with a tag, now means adding them on a branch.
  1157. Since the branch test was done in check_fileproc for
  1158. modified files, we need to stub it in again here. */
  1159. if (ci->tag
  1160. /* If numeric, it is on the trunk; check_fileproc enforced
  1161. this. */
  1162. && !isdigit ((unsigned char) ci->tag[0]))
  1163. {
  1164. if (finfo->rcs == NULL)
  1165. error (1, 0, "internal error: no parsed RCS file");
  1166. if (ci->rev)
  1167. free (ci->rev);
  1168. ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
  1169. err = Checkin ('A', finfo, ci->rev,
  1170. ci->tag, ci->options, saved_message);
  1171. if (err != 0)
  1172. {
  1173. unlockrcs (finfo->rcs);
  1174. fixbranch (finfo->rcs, sbranch);
  1175. }
  1176. (void) time (&last_register_time);
  1177. ci->status = T_UPTODATE;
  1178. }
  1179. }
  1180. /*
  1181. * Add the file for real
  1182. */
  1183. if (ci->status == T_ADDED)
  1184. {
  1185. char *xrev = (char *) NULL;
  1186. if (ci->rev == NULL)
  1187. {
  1188. /* find the max major rev number in this directory */
  1189. maxrev = 0;
  1190. (void) walklist (finfo->entries, findmaxrev, NULL);
  1191. if (finfo->rcs->head) {
  1192. /* resurrecting: include dead revision */
  1193. int thisrev = atoi (finfo->rcs->head);
  1194. if (thisrev > maxrev)
  1195. maxrev = thisrev;
  1196. }
  1197. if (maxrev == 0)
  1198. maxrev = 1;
  1199. xrev = xmalloc (20);
  1200. (void) sprintf (xrev, "%d", maxrev);
  1201. }
  1202. /* XXX - an added file with symbolic -r should add tag as well */
  1203. err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
  1204. if (xrev)
  1205. free (xrev);
  1206. }
  1207. else if (ci->status == T_MODIFIED)
  1208. {
  1209. err = Checkin ('M', finfo, ci->rev, ci->tag,
  1210. ci->options, saved_message);
  1211. (void) time (&last_register_time);
  1212. if (err != 0)
  1213. {
  1214. unlockrcs (finfo->rcs);
  1215. fixbranch (finfo->rcs, sbranch);
  1216. }
  1217. }
  1218. else if (ci->status == T_REMOVED)
  1219. {
  1220. err = remove_file (finfo, ci->tag, saved_message);
  1221. #ifdef SERVER_SUPPORT
  1222. if (server_active) {
  1223. server_scratch_entry_only ();
  1224. server_updated (finfo,
  1225. NULL,
  1226. /* Doesn't matter, it won't get checked. */
  1227. SERVER_UPDATED,
  1228. (mode_t) -1,
  1229. (unsigned char *) NULL,
  1230. (struct buffer *) NULL);
  1231. }
  1232. #endif
  1233. }
  1234. /* Clearly this is right for T_MODIFIED. I haven't thought so much
  1235. about T_ADDED or T_REMOVED. */
  1236. notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository);
  1237. out:
  1238. if (err != 0)
  1239. {
  1240. /* on failure, remove the file from ulist */
  1241. p = findnode (ulist, finfo->file);
  1242. if (p)
  1243. delnode (p);
  1244. }
  1245. else
  1246. {
  1247. /* On success, retrieve the new version number of the file and
  1248. copy it into the log information (see logmsg.c
  1249. (logfile_write) for more details). We should only update
  1250. the version number for files that have been added or
  1251. modified but not removed since classify_file_internal
  1252. will return the version number of a file even after it has
  1253. been removed from the archive, which is not the behavior we
  1254. want for our commitlog messages; we want the old version
  1255. number and then "NONE." */
  1256. if (ci->status != T_REMOVED)
  1257. {
  1258. p = findnode (ulist, finfo->file);
  1259. if (p)
  1260. {
  1261. Vers_TS *vers;
  1262. struct logfile_info *li;
  1263. (void) classify_file_internal (finfo, &vers);
  1264. li = p->data;
  1265. li->rev_new = xstrdup (vers->vn_rcs);
  1266. freevers_ts (&vers);
  1267. }
  1268. }
  1269. }
  1270. if (SIG_inCrSect ())
  1271. SIG_endCrSect ();
  1272. return err;
  1273. }
  1274. /*
  1275. * Log the commit and clean up the update list
  1276. */
  1277. /* ARGSUSED */
  1278. static int
  1279. commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
  1280. void *callerdat;
  1281. int err;
  1282. const char *repository;
  1283. const char *update_dir;
  1284. List *entries;
  1285. {
  1286. Node *p;
  1287. List *ulist;
  1288. assert (repository);
  1289. p = findnode (mulist, update_dir);
  1290. if (p == NULL)
  1291. return err;
  1292. ulist = ((struct master_lists *) p->data)->ulist;
  1293. got_message = 0;
  1294. Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
  1295. /* Build the administrative files if necessary. */
  1296. {
  1297. const char *p;
  1298. if (strncmp (current_parsed_root->directory, repository,
  1299. strlen (current_parsed_root->directory)) != 0)
  1300. error (0, 0,
  1301. "internal error: repository (%s) doesn't begin with root (%s)",
  1302. repository, current_parsed_root->directory);
  1303. p = repository + strlen (current_parsed_root->directory);
  1304. if (*p == '/')
  1305. ++p;
  1306. if (strcmp ("CVSROOT", p) == 0
  1307. /* Check for subdirectories because people may want to create
  1308. subdirectories and list files therein in checkoutlist. */
  1309. || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
  1310. )
  1311. {
  1312. /* "Database" might a little bit grandiose and/or vague,
  1313. but "checked-out copies of administrative files, unless
  1314. in the case of modules and you are using ndbm in which
  1315. case modules.{pag,dir,db}" is verbose and excessively
  1316. focused on how the database is implemented. */
  1317. /* mkmodules requires the absolute name of the CVSROOT directory.
  1318. Remove anything after the `CVSROOT' component -- this is
  1319. necessary when committing in a subdirectory of CVSROOT. */
  1320. char *admin_dir = xstrdup (repository);
  1321. int cvsrootlen = strlen ("CVSROOT");
  1322. assert (admin_dir[p - repository + cvsrootlen] == '\0'
  1323. || admin_dir[p - repository + cvsrootlen] == '/');
  1324. admin_dir[p - repository + cvsrootlen] = '\0';
  1325. cvs_output (program_name, 0);
  1326. cvs_output (" ", 1);
  1327. cvs_output (cvs_cmd_name, 0);
  1328. cvs_output (": Rebuilding administrative file database\n", 0);
  1329. mkmodules (admin_dir);
  1330. free (admin_dir);
  1331. }
  1332. }
  1333. return err;
  1334. }
  1335. /*
  1336. * Get the log message for a dir
  1337. */
  1338. /* ARGSUSED */
  1339. static Dtype
  1340. commit_direntproc (callerdat, dir, repos, update_dir, entries)
  1341. void *callerdat;
  1342. const char *dir;
  1343. const char *repos;
  1344. const char *update_dir;
  1345. List *entries;
  1346. {
  1347. Node *p;
  1348. List *ulist;
  1349. char *real_repos;
  1350. if (!isdir (dir))
  1351. return R_SKIP_ALL;
  1352. /* find the update list for this dir */
  1353. p = findnode (mulist, update_dir);
  1354. if (p != NULL)
  1355. ulist = ((struct master_lists *) p->data)->ulist;
  1356. else
  1357. ulist = (List *) NULL;
  1358. /* skip the files as an optimization */
  1359. if (ulist == NULL || ulist->list->next == ulist->list)
  1360. return R_SKIP_FILES;
  1361. /* get commit message */
  1362. real_repos = Name_Repository (dir, update_dir);
  1363. got_message = 1;
  1364. if (!server_active && use_editor)
  1365. do_editor (update_dir, &saved_message, real_repos, ulist);
  1366. do_verify (&saved_message, real_repos);
  1367. free (real_repos);
  1368. return R_PROCESS;
  1369. }
  1370. /*
  1371. * Process the post-commit proc if necessary
  1372. */
  1373. /* ARGSUSED */
  1374. static int
  1375. commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
  1376. void *callerdat;
  1377. const char *dir;
  1378. int err;
  1379. const char *update_dir;
  1380. List *entries;
  1381. {
  1382. /* update the per-directory tag info */
  1383. /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly
  1384. mentions commit -r being sticky, but apparently in the context of
  1385. this being a confusing feature! */
  1386. if (err == 0 && write_dirtag != NULL)
  1387. {
  1388. char *repos = Name_Repository (NULL, update_dir);
  1389. WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
  1390. update_dir, repos);
  1391. free (repos);
  1392. }
  1393. return err;
  1394. }
  1395. /*
  1396. * find the maximum major rev number in an entries file
  1397. */
  1398. static int
  1399. findmaxrev (p, closure)
  1400. Node *p;
  1401. void *closure;
  1402. {
  1403. int thisrev;
  1404. Entnode *entdata = p->data;
  1405. if (entdata->type != ENT_FILE)
  1406. return 0;
  1407. thisrev = atoi (entdata->version);
  1408. if (thisrev > maxrev)
  1409. maxrev = thisrev;
  1410. return 0;
  1411. }
  1412. /*
  1413. * Actually remove a file by moving it to the attic
  1414. * XXX - if removing a ,v file that is a relative symbolic link to
  1415. * another ,v file, we probably should add a ".." component to the
  1416. * link to keep it relative after we move it into the attic.
  1417. Return value is 0 on success, or >0 on error (in which case we have
  1418. printed an error message). */
  1419. static int
  1420. remove_file (finfo, tag, message)
  1421. struct file_info *finfo;
  1422. char *tag;
  1423. char *message;
  1424. {
  1425. int retcode;
  1426. int branch;
  1427. int lockflag;
  1428. char *corev;
  1429. char *rev;
  1430. char *prev_rev;
  1431. char *old_path;
  1432. corev = NULL;
  1433. rev = NULL;
  1434. prev_rev = NULL;
  1435. retcode = 0;
  1436. if (finfo->rcs == NULL)
  1437. error (1, 0, "internal error: no parsed RCS file");
  1438. branch = 0;
  1439. if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
  1440. {
  1441. /* a symbolic tag is specified; just remove the tag from the file */
  1442. if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
  1443. {
  1444. if (!quiet)
  1445. error (0, retcode == -1 ? errno : 0,
  1446. "failed to remove tag `%s' from `%s'", tag,
  1447. finfo->fullname);
  1448. return 1;
  1449. }
  1450. RCS_rewrite (finfo->rcs, NULL, NULL);
  1451. Scratch_Entry (finfo->entries, finfo->file);
  1452. return 0;
  1453. }
  1454. /* we are removing the file from either the head or a branch */
  1455. /* commit a new, dead revision. */
  1456. /* Print message indicating that file is going to be removed. */
  1457. cvs_output ("Removing ", 0);
  1458. cvs_output (finfo->fullname, 0);
  1459. cvs_output (";\n", 0);
  1460. rev = NULL;
  1461. lockflag = 1;
  1462. if (branch)
  1463. {
  1464. char *branchname;
  1465. rev = RCS_whatbranch (finfo->rcs, tag);
  1466. if (rev == NULL)
  1467. {
  1468. error (0, 0, "cannot find branch \"%s\".", tag);
  1469. return 1;
  1470. }
  1471. branchname = RCS_getbranch (finfo->rcs, rev, 1);
  1472. if (branchname == NULL)
  1473. {
  1474. /* no revision exists on this branch. use the previous
  1475. revision but do not lock. */
  1476. corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL);
  1477. prev_rev = xstrdup (corev);
  1478. lockflag = 0;
  1479. } else
  1480. {
  1481. corev = xstrdup (rev);
  1482. prev_rev = xstrdup (branchname);
  1483. free (branchname);
  1484. }
  1485. } else /* Not a branch */
  1486. {
  1487. /* Get current head revision of file. */
  1488. prev_rev = RCS_head (finfo->rcs);
  1489. }
  1490. /* if removing without a tag or a branch, then make sure the default
  1491. branch is the trunk. */
  1492. if (!tag && !branch)
  1493. {
  1494. if (RCS_setbranch (finfo->rcs, NULL) != 0)
  1495. {
  1496. error (0, 0, "cannot change branch to default for %s",
  1497. finfo->fullname);
  1498. return 1;
  1499. }
  1500. RCS_rewrite (finfo->rcs, NULL, NULL);
  1501. }
  1502. /* check something out. Generally this is the head. If we have a
  1503. particular rev, then name it. */
  1504. retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
  1505. (char *) NULL, (char *) NULL, RUN_TTY,
  1506. (RCSCHECKOUTPROC) NULL, (void *) NULL);
  1507. if (retcode != 0)
  1508. {
  1509. error (0, 0,
  1510. "failed to check out `%s'", finfo->fullname);
  1511. return 1;
  1512. }
  1513. /* Except when we are creating a branch, lock the revision so that
  1514. we can check in the new revision. */
  1515. if (lockflag)
  1516. {
  1517. if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
  1518. RCS_rewrite (finfo->rcs, NULL, NULL);
  1519. }
  1520. if (corev != NULL)
  1521. free (corev);
  1522. retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev, 0,
  1523. RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
  1524. if (retcode != 0)
  1525. {
  1526. if (!quiet)
  1527. error (0, retcode == -1 ? errno : 0,
  1528. "failed to commit dead revision for `%s'", finfo->fullname);
  1529. if (prev_rev != NULL)
  1530. free (prev_rev);
  1531. return 1;
  1532. }
  1533. /* At this point, the file has been committed as removed. We should
  1534. probably tell the history file about it */
  1535. corev = rev ? RCS_getbranch (finfo->rcs, rev, 1) : RCS_head (finfo->rcs);
  1536. history_write ('R', NULL, corev, finfo->file, finfo->repository);
  1537. free (corev);
  1538. if (rev != NULL)
  1539. free (rev);
  1540. old_path = xstrdup (finfo->rcs->path);
  1541. if (!branch)
  1542. RCS_setattic (finfo->rcs, 1);
  1543. /* Print message that file was removed. */
  1544. cvs_output (old_path, 0);
  1545. cvs_output (" <-- ", 0);
  1546. cvs_output (finfo->file, 0);
  1547. cvs_output ("\nnew revision: delete; previous revision: ", 0);
  1548. cvs_output (prev_rev, 0);
  1549. cvs_output ("\ndone\n", 0);
  1550. free(prev_rev);
  1551. free (old_path);
  1552. Scratch_Entry (finfo->entries, finfo->file);
  1553. return 0;
  1554. }
  1555. /*
  1556. * Do the actual checkin for added files
  1557. */
  1558. static int
  1559. finaladd (finfo, rev, tag, options)
  1560. struct file_info *finfo;
  1561. char *rev;
  1562. char *tag;
  1563. char *options;
  1564. {
  1565. int ret;
  1566. ret = Checkin ('A', finfo, rev, tag, options, saved_message);
  1567. if (ret == 0)
  1568. {
  1569. char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
  1570. + sizeof (CVSEXT_LOG) + 10);
  1571. (void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
  1572. if (unlink_file (tmp) < 0
  1573. && !existence_error (errno))
  1574. error (0, errno, "cannot remove %s", tmp);
  1575. free (tmp);
  1576. }
  1577. else if (finfo->rcs != NULL)
  1578. fixaddfile (finfo->rcs->path);
  1579. (void) time (&last_register_time);
  1580. return ret;
  1581. }
  1582. /*
  1583. * Unlock an rcs file
  1584. */
  1585. static void
  1586. unlockrcs (rcs)
  1587. RCSNode *rcs;
  1588. {
  1589. int retcode;
  1590. if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0)
  1591. error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
  1592. "could not unlock %s", rcs->path);
  1593. else
  1594. RCS_rewrite (rcs, NULL, NULL);
  1595. }
  1596. /*
  1597. * remove a partially added file. if we can parse it, leave it alone.
  1598. *
  1599. * FIXME: Every caller that calls this function can access finfo->rcs (the
  1600. * parsed RCSNode data), so we should be able to detect that the file needs
  1601. * to be removed without reparsing the file as we do below.
  1602. */
  1603. static void
  1604. fixaddfile (rcs)
  1605. const char *rcs;
  1606. {
  1607. RCSNode *rcsfile;
  1608. int save_really_quiet;
  1609. save_really_quiet = really_quiet;
  1610. really_quiet = 1;
  1611. if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
  1612. {
  1613. if (unlink_file (rcs) < 0)
  1614. error (0, errno, "cannot remove %s", rcs);
  1615. }
  1616. else
  1617. freercsnode (&rcsfile);
  1618. really_quiet = save_really_quiet;
  1619. }
  1620. /*
  1621. * put the branch back on an rcs file
  1622. */
  1623. static void
  1624. fixbranch (rcs, branch)
  1625. RCSNode *rcs;
  1626. char *branch;
  1627. {
  1628. int retcode;
  1629. if (branch != NULL)
  1630. {
  1631. if ((retcode = RCS_setbranch (rcs, branch)) != 0)
  1632. error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
  1633. "cannot restore branch to %s for %s", branch, rcs->path);
  1634. RCS_rewrite (rcs, NULL, NULL);
  1635. }
  1636. }
  1637. /*
  1638. * do the initial part of a file add for the named file. if adding
  1639. * with a tag, put the file in the Attic and point the symbolic tag
  1640. * at the committed revision.
  1641. *
  1642. * INPUTS
  1643. * file The name of the file in the workspace.
  1644. * repository The repository directory to expect to find FILE,v in.
  1645. * tag The name or rev num of the branch being added to, if any.
  1646. * options Any RCS keyword expansion options specified by the user.
  1647. * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
  1648. * exists in the repository. If this is NULL, assume the file
  1649. * does not yet exist.
  1650. *
  1651. * RETURNS
  1652. * 0 on success.
  1653. * 1 on errors, after printing any appropriate error messages.
  1654. *
  1655. * ERRORS
  1656. * This function will return an error when any of the following functions do:
  1657. * add_rcs_file
  1658. * RCS_setattic
  1659. * lock_RCS
  1660. * RCS_checkin
  1661. * RCS_parse (called to verify the newly created archive file)
  1662. * RCS_settag
  1663. */
  1664. static int
  1665. checkaddfile (file, repository, tag, options, rcsnode)
  1666. const char *file;
  1667. const char *repository;
  1668. const char *tag;
  1669. const char *options;
  1670. RCSNode **rcsnode;
  1671. {
  1672. RCSNode *rcs;
  1673. char *fname;
  1674. int newfile = 0; /* Set to 1 if we created a new RCS archive. */
  1675. int retval = 1;
  1676. int adding_on_branch;
  1677. assert (rcsnode != NULL);
  1678. /* Callers expect to be able to use either "" or NULL to mean the
  1679. default keyword expansion. */
  1680. if (options != NULL && options[0] == '\0')
  1681. options = NULL;
  1682. if (options != NULL)
  1683. assert (options[0] == '-' && options[1] == 'k');
  1684. /* If numeric, it is on the trunk; check_fileproc enforced
  1685. this. */
  1686. adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
  1687. if (*rcsnode == NULL)
  1688. {
  1689. char *rcsname;
  1690. char *desc = NULL;
  1691. size_t descalloc = 0;
  1692. size_t desclen = 0;
  1693. const char *opt;
  1694. if ( adding_on_branch )
  1695. {
  1696. mode_t omask;
  1697. rcsname = xmalloc (strlen (repository)
  1698. + sizeof (CVSATTIC)
  1699. + strlen (file)
  1700. + sizeof (RCSEXT)
  1701. + 3);
  1702. (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC);
  1703. omask = umask ( cvsumask );
  1704. if (CVS_MKDIR (rcsname, 0777 ) != 0 && errno != EEXIST)
  1705. error (1, errno, "cannot make directory `%s'", rcsname);
  1706. (void) umask ( omask );
  1707. (void) sprintf (rcsname,
  1708. "%s/%s/%s%s",
  1709. repository,
  1710. CVSATTIC,
  1711. file,
  1712. RCSEXT);
  1713. }
  1714. else
  1715. {
  1716. rcsname = xmalloc (strlen (repository)
  1717. + strlen (file)
  1718. + sizeof (RCSEXT)
  1719. + 2);
  1720. (void) sprintf (rcsname,
  1721. "%s/%s%s",
  1722. repository,
  1723. file,
  1724. RCSEXT);
  1725. }
  1726. /* this is the first time we have ever seen this file; create
  1727. an RCS file. */
  1728. fname = xmalloc (strlen (file) + sizeof (CVSADM)
  1729. + sizeof (CVSEXT_LOG) + 10);
  1730. (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
  1731. /* If the file does not exist, no big deal. In particular, the
  1732. server does not (yet at least) create CVSEXT_LOG files. */
  1733. if (isfile (fname))
  1734. /* FIXME: Should be including update_dir in the appropriate
  1735. place here. */
  1736. get_file (fname, fname, "r", &desc, &descalloc, &desclen);
  1737. free (fname);
  1738. /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
  1739. end of the log message if the message is nonempty.
  1740. Do it. RCS also deletes certain whitespace, in cleanlogmsg,
  1741. which we don't try to do here. */
  1742. if (desclen > 0)
  1743. {
  1744. expand_string (&desc, &descalloc, desclen + 1);
  1745. desc[desclen++] = '\012';
  1746. }
  1747. /* Set RCS keyword expansion options. */
  1748. if (options != NULL)
  1749. opt = options + 2;
  1750. else
  1751. opt = NULL;
  1752. /* This message is an artifact of the time when this
  1753. was implemented via "rcs -i". It should be revised at
  1754. some point (does the "initial revision" in the message from
  1755. RCS_checkin indicate that this is a new file? Or does the
  1756. "RCS file" message serve some function?). */
  1757. cvs_output ("RCS file: ", 0);
  1758. cvs_output (rcsname, 0);
  1759. cvs_output ("\ndone\n", 0);
  1760. if (add_rcs_file (NULL, rcsname, file, NULL, opt,
  1761. NULL, NULL, 0, NULL,
  1762. desc, desclen, NULL) != 0)
  1763. {
  1764. if (rcsname != NULL)
  1765. free (rcsname);
  1766. goto out;
  1767. }
  1768. rcs = RCS_parsercsfile (rcsname);
  1769. newfile = 1;
  1770. if (rcsname != NULL)
  1771. free (rcsname);
  1772. if (desc != NULL)
  1773. free (desc);
  1774. *rcsnode = rcs;
  1775. }
  1776. else
  1777. {
  1778. /* file has existed in the past. Prepare to resurrect. */
  1779. char *rev;
  1780. char *oldexpand;
  1781. rcs = *rcsnode;
  1782. oldexpand = RCS_getexpand (rcs);
  1783. if ((oldexpand != NULL
  1784. && options != NULL
  1785. && strcmp (options + 2, oldexpand) != 0)
  1786. || (oldexpand == NULL && options != NULL))
  1787. {
  1788. /* We tell the user about this, because it means that the
  1789. old revisions will no longer retrieve the way that they
  1790. used to. */
  1791. error (0, 0, "changing keyword expansion mode to %s", options);
  1792. RCS_setexpand (rcs, options + 2);
  1793. }
  1794. if (!adding_on_branch)
  1795. {
  1796. /* We are adding on the trunk, so move the file out of the
  1797. Attic. */
  1798. if (!(rcs->flags & INATTIC))
  1799. {
  1800. error (0, 0, "warning: expected %s to be in Attic",
  1801. rcs->path);
  1802. }
  1803. /* Begin a critical section around the code that spans the
  1804. first commit on the trunk of a file that's already been
  1805. committed on a branch. */
  1806. SIG_beginCrSect ();
  1807. if (RCS_setattic (rcs, 0))
  1808. {
  1809. goto out;
  1810. }
  1811. }
  1812. rev = RCS_getversion (rcs, tag, NULL, 1, (int *) NULL);
  1813. /* and lock it */
  1814. if (lock_RCS (file, rcs, rev, repository))
  1815. {
  1816. error (0, 0, "cannot lock revision %s in `%s'.",
  1817. rev ? rev : tag ? tag : "HEAD", rcs->path);
  1818. if (rev != NULL)
  1819. free (rev);
  1820. goto out;
  1821. }
  1822. if (rev != NULL)
  1823. free (rev);
  1824. }
  1825. /* when adding a file for the first time, and using a tag, we need
  1826. to create a dead revision on the trunk. */
  1827. if (adding_on_branch)
  1828. {
  1829. if (newfile)
  1830. {
  1831. char *tmp;
  1832. FILE *fp;
  1833. int retcode;
  1834. /* move the new file out of the way. */
  1835. fname = xmalloc (strlen (file) + sizeof (CVSADM)
  1836. + sizeof (CVSPREFIX) + 10);
  1837. (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
  1838. rename_file (file, fname);
  1839. /* Create empty FILE. Can't use copy_file with a DEVNULL
  1840. argument -- copy_file now ignores device files. */
  1841. fp = fopen (file, "w");
  1842. if (fp == NULL)
  1843. error (1, errno, "cannot open %s for writing", file);
  1844. if (fclose (fp) < 0)
  1845. error (0, errno, "cannot close %s", file);
  1846. tmp = xmalloc (strlen (file) + strlen (tag) + 80);
  1847. /* commit a dead revision. */
  1848. (void) sprintf (tmp, "file %s was initially added on branch %s.",
  1849. file, tag);
  1850. retcode = RCS_checkin (rcs, NULL, tmp, NULL, 0,
  1851. RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
  1852. free (tmp);
  1853. if (retcode != 0)
  1854. {
  1855. error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
  1856. "could not create initial dead revision %s", rcs->path);
  1857. free (fname);
  1858. goto out;
  1859. }
  1860. /* put the new file back where it was */
  1861. rename_file (fname, file);
  1862. free (fname);
  1863. /* double-check that the file was written correctly */
  1864. freercsnode (&rcs);
  1865. rcs = RCS_parse (file, repository);
  1866. if (rcs == NULL)
  1867. {
  1868. error (0, 0, "could not read %s in %s", file, repository);
  1869. goto out;
  1870. }
  1871. *rcsnode = rcs;
  1872. /* and lock it once again. */
  1873. if (lock_RCS (file, rcs, NULL, repository))
  1874. {
  1875. error (0, 0, "cannot lock initial revision in `%s'.",
  1876. rcs->path);
  1877. goto out;
  1878. }
  1879. }
  1880. /* when adding with a tag, we need to stub a branch, if it
  1881. doesn't already exist. */
  1882. if (!RCS_nodeisbranch (rcs, tag))
  1883. {
  1884. /* branch does not exist. Stub it. */
  1885. char *head;
  1886. char *magicrev;
  1887. int retcode;
  1888. time_t headtime = -1;
  1889. char *revnum, *tmp;
  1890. FILE *fp;
  1891. time_t t = -1;
  1892. struct tm *ct;
  1893. fixbranch (rcs, sbranch);
  1894. head = RCS_getversion (rcs, NULL, NULL, 0, (int *) NULL);
  1895. if (!head)
  1896. error (1, 0, "No head revision in archive file `%s'.",
  1897. rcs->path);
  1898. magicrev = RCS_magicrev (rcs, head);
  1899. /* If this is not a new branch, then we will want a dead
  1900. version created before this one. */
  1901. if (!newfile)
  1902. headtime = RCS_getrevtime (rcs, head, 0, 0);
  1903. retcode = RCS_settag (rcs, tag, magicrev);
  1904. RCS_rewrite (rcs, NULL, NULL);
  1905. free (head);
  1906. free (magicrev);
  1907. if (retcode != 0)
  1908. {
  1909. error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
  1910. "could not stub branch %s for %s", tag, rcs->path);
  1911. goto out;
  1912. }
  1913. /* We need to add a dead version here to avoid -rtag -Dtime
  1914. checkout problems between when the head version was
  1915. created and now. */
  1916. if (!newfile && headtime != -1)
  1917. {
  1918. /* move the new file out of the way. */
  1919. fname = xmalloc (strlen (file) + sizeof (CVSADM)
  1920. + sizeof (CVSPREFIX) + 10);
  1921. (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
  1922. rename_file (file, fname);
  1923. /* Create empty FILE. Can't use copy_file with a DEVNULL
  1924. argument -- copy_file now ignores device files. */
  1925. fp = fopen (file, "w");
  1926. if (fp == NULL)
  1927. error (1, errno, "cannot open %s for writing", file);
  1928. if (fclose (fp) < 0)
  1929. error (0, errno, "cannot close %s", file);
  1930. /* As we will be hacking the delta date, put the time
  1931. this was added into the log message. */
  1932. t = time(NULL);
  1933. ct = gmtime(&t);
  1934. tmp = xmalloc (strlen (file) + strlen (tag) + 80);
  1935. (void) sprintf (tmp,
  1936. "file %s was added on branch %s on %d-%02d-%02d %02d:%02d:%02d +0000",
  1937. file, tag,
  1938. ct->tm_year + (ct->tm_year < 100 ? 0 : 1900),
  1939. ct->tm_mon + 1, ct->tm_mday,
  1940. ct->tm_hour, ct->tm_min, ct->tm_sec);
  1941. /* commit a dead revision. */
  1942. revnum = RCS_whatbranch (rcs, tag);
  1943. retcode = RCS_checkin (rcs, NULL, tmp, revnum, headtime,
  1944. RCS_FLAGS_DEAD |
  1945. RCS_FLAGS_QUIET |
  1946. RCS_FLAGS_USETIME);
  1947. free (revnum);
  1948. free (tmp);
  1949. if (retcode != 0)
  1950. {
  1951. error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
  1952. "could not created dead stub %s for %s", tag,
  1953. rcs->path);
  1954. goto out;
  1955. }
  1956. /* put the new file back where it was */
  1957. rename_file (fname, file);
  1958. free (fname);
  1959. /* double-check that the file was written correctly */
  1960. freercsnode (&rcs);
  1961. rcs = RCS_parse (file, repository);
  1962. if (rcs == NULL)
  1963. {
  1964. error (0, 0, "could not read %s", rcs->path);
  1965. goto out;
  1966. }
  1967. *rcsnode = rcs;
  1968. }
  1969. }
  1970. else
  1971. {
  1972. /* lock the branch. (stubbed branches need not be locked.) */
  1973. if (lock_RCS (file, rcs, NULL, repository))
  1974. {
  1975. error (0, 0, "cannot lock head revision in `%s'.", rcs->path);
  1976. goto out;
  1977. }
  1978. }
  1979. if (*rcsnode != rcs)
  1980. {
  1981. freercsnode(rcsnode);
  1982. *rcsnode = rcs;
  1983. }
  1984. }
  1985. fileattr_newfile (file);
  1986. /* At this point, we used to set the file mode of the RCS file
  1987. based on the mode of the file in the working directory. If we
  1988. are creating the RCS file for the first time, add_rcs_file does
  1989. this already. If we are re-adding the file, then perhaps it is
  1990. consistent to preserve the old file mode, just as we preserve
  1991. the old keyword expansion mode.
  1992. If we decide that we should change the modes, then we can't do
  1993. it here anyhow. At this point, the RCS file may be owned by
  1994. somebody else, so a chmod will fail. We need to instead do the
  1995. chmod after rewriting it.
  1996. FIXME: In general, I think the file mode (and the keyword
  1997. expansion mode) should be associated with a particular revision
  1998. of the file, so that it is possible to have different revisions
  1999. of a file have different modes. */
  2000. retval = 0;
  2001. out:
  2002. if (retval != 0 && SIG_inCrSect ())
  2003. SIG_endCrSect ();
  2004. return retval;
  2005. }
  2006. /*
  2007. * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
  2008. * couldn't. If the RCS file currently has a branch as the head, we must
  2009. * move the head back to the trunk before locking the file, and be sure to
  2010. * put the branch back as the head if there are any errors.
  2011. */
  2012. static int
  2013. lock_RCS (user, rcs, rev, repository)
  2014. const char *user;
  2015. RCSNode *rcs;
  2016. const char *rev;
  2017. const char *repository;
  2018. {
  2019. char *branch = NULL;
  2020. int err = 0;
  2021. /*
  2022. * For a specified, numeric revision of the form "1" or "1.1", (or when
  2023. * no revision is specified ""), definitely move the branch to the trunk
  2024. * before locking the RCS file.
  2025. *
  2026. * The assumption is that if there is more than one revision on the trunk,
  2027. * the head points to the trunk, not a branch... and as such, it's not
  2028. * necessary to move the head in this case.
  2029. */
  2030. if (rev == NULL
  2031. || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
  2032. {
  2033. branch = xstrdup (rcs->branch);
  2034. if (branch != NULL)
  2035. {
  2036. if (RCS_setbranch (rcs, NULL) != 0)
  2037. {
  2038. error (0, 0, "cannot change branch to default for %s",
  2039. rcs->path);
  2040. if (branch)
  2041. free (branch);
  2042. return 1;
  2043. }
  2044. }
  2045. err = RCS_lock (rcs, NULL, 1);
  2046. }
  2047. else
  2048. {
  2049. RCS_lock (rcs, rev, 1);
  2050. }
  2051. /* We used to call RCS_rewrite here, and that might seem
  2052. appropriate in order to write out the locked revision
  2053. information. However, such a call would actually serve no
  2054. purpose. CVS locks will prevent any interference from other
  2055. CVS processes. The comment above rcs_internal_lockfile
  2056. explains that it is already unsafe to use RCS and CVS
  2057. simultaneously. It follows that writing out the locked
  2058. revision information here would add no additional security.
  2059. If we ever do care about it, the proper fix is to create the
  2060. RCS lock file before calling this function, and maintain it
  2061. until the checkin is complete.
  2062. The call to RCS_lock is still required at present, since in
  2063. some cases RCS_checkin will determine which revision to check
  2064. in by looking for a lock. FIXME: This is rather roundabout,
  2065. and a more straightforward approach would probably be easier to
  2066. understand. */
  2067. if (err == 0)
  2068. {
  2069. if (sbranch != NULL)
  2070. free (sbranch);
  2071. sbranch = branch;
  2072. return 0;
  2073. }
  2074. /* try to restore the branch if we can on error */
  2075. if (branch != NULL)
  2076. fixbranch (rcs, branch);
  2077. if (branch)
  2078. free (branch);
  2079. return 1;
  2080. }
  2081. /*
  2082. * free an UPDATE node's data
  2083. */
  2084. void
  2085. update_delproc (p)
  2086. Node *p;
  2087. {
  2088. struct logfile_info *li = p->data;
  2089. if (li->tag)
  2090. free (li->tag);
  2091. if (li->rev_old)
  2092. free (li->rev_old);
  2093. if (li->rev_new)
  2094. free (li->rev_new);
  2095. free (li);
  2096. }
  2097. /*
  2098. * Free the commit_info structure in p.
  2099. */
  2100. static void
  2101. ci_delproc (p)
  2102. Node *p;
  2103. {
  2104. struct commit_info *ci = p->data;
  2105. if (ci->rev)
  2106. free (ci->rev);
  2107. if (ci->tag)
  2108. free (ci->tag);
  2109. if (ci->options)
  2110. free (ci->options);
  2111. free (ci);
  2112. }
  2113. /*
  2114. * Free the commit_info structure in p.
  2115. */
  2116. static void
  2117. masterlist_delproc (p)
  2118. Node *p;
  2119. {
  2120. struct master_lists *ml = p->data;
  2121. dellist (&ml->ulist);
  2122. dellist (&ml->cilist);
  2123. free (ml);
  2124. }