/contrib/cvs/src/import.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1653 lines · 1268 code · 130 blank · 255 comment · 315 complexity · 8ecc8e99959a6ed3afa37f1bf00c8e1e 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. * "import" checks in the vendor release located in the current directory into
  14. * the CVS source repository. The CVS vendor branch support is utilized.
  15. *
  16. * At least three arguments are expected to follow the options:
  17. * repository Where the source belongs relative to the CVSROOT
  18. * VendorTag Vendor's major tag
  19. * VendorReleTag Tag for this particular release
  20. *
  21. * Additional arguments specify more Vendor Release Tags.
  22. */
  23. #include "cvs.h"
  24. #include "savecwd.h"
  25. #include <assert.h>
  26. static char *get_comment PROTO((const char *user));
  27. static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
  28. char *vers));
  29. static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
  30. char *targv[]));
  31. static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]));
  32. static int import_descend_dir PROTO((char *message, char *dir, char *vtag,
  33. int targc, char *targv[]));
  34. static int process_import_file PROTO((char *message, char *vfile, char *vtag,
  35. int targc, char *targv[]));
  36. static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc,
  37. char *targv[], int inattic));
  38. static void add_log PROTO((int ch, char *fname));
  39. static int repos_len;
  40. static char *vhead;
  41. static char *vbranch;
  42. static FILE *logfp;
  43. static char *repository;
  44. static int conflicts;
  45. static int use_file_modtime;
  46. static char *keyword_opt = NULL;
  47. static const char *const import_usage[] =
  48. {
  49. "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n",
  50. " [-W spec] repository vendor-tag release-tags...\n",
  51. "\t-d\tUse the file's modification time as the time of import.\n",
  52. "\t-k sub\tSet default RCS keyword substitution mode.\n",
  53. "\t-I ign\tMore files to ignore (! to reset).\n",
  54. "\t-b bra\tVendor branch id.\n",
  55. "\t-m msg\tLog message.\n",
  56. "\t-W spec\tWrappers specification line.\n",
  57. "(Specify the --help global option for a list of other help options)\n",
  58. NULL
  59. };
  60. int
  61. import (argc, argv)
  62. int argc;
  63. char **argv;
  64. {
  65. char *message = NULL;
  66. char *tmpfile;
  67. char *cp;
  68. int i, c, msglen, err;
  69. List *ulist;
  70. Node *p;
  71. struct logfile_info *li;
  72. if (argc == -1)
  73. usage (import_usage);
  74. ign_setup ();
  75. wrap_setup ();
  76. vbranch = xstrdup (CVSBRANCH);
  77. optind = 0;
  78. while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1)
  79. {
  80. switch (c)
  81. {
  82. case 'Q':
  83. case 'q':
  84. /* The CVS 1.5 client sends these options (in addition to
  85. Global_option requests), so we must ignore them. */
  86. if (!server_active)
  87. error (1, 0,
  88. "-q or -Q must be specified before \"%s\"",
  89. cvs_cmd_name);
  90. break;
  91. case 'd':
  92. if (server_active)
  93. {
  94. /* CVS 1.10 and older clients will send this, but it
  95. doesn't do any good. So tell the user we can't
  96. cope, rather than silently losing. */
  97. error (0, 0,
  98. "warning: not setting the time of import from the file");
  99. error (0, 0, "due to client limitations");
  100. }
  101. use_file_modtime = 1;
  102. break;
  103. case 'b':
  104. free (vbranch);
  105. vbranch = xstrdup (optarg);
  106. break;
  107. case 'm':
  108. #ifdef FORCE_USE_EDITOR
  109. use_editor = 1;
  110. #else
  111. use_editor = 0;
  112. #endif
  113. if (message) free (message);
  114. message = xstrdup(optarg);
  115. break;
  116. case 'I':
  117. ign_add (optarg, 0);
  118. break;
  119. case 'k':
  120. /* RCS_check_kflag returns strings of the form -kxx. We
  121. only use it for validation, so we can free the value
  122. as soon as it is returned. */
  123. free (RCS_check_kflag (optarg));
  124. keyword_opt = optarg;
  125. break;
  126. case 'W':
  127. wrap_add (optarg, 0);
  128. break;
  129. case '?':
  130. default:
  131. usage (import_usage);
  132. break;
  133. }
  134. }
  135. argc -= optind;
  136. argv += optind;
  137. if (argc < 3)
  138. usage (import_usage);
  139. /* This is for handling the Checkin-time request. It might seem a
  140. bit odd to enable the use_file_modtime code even in the case
  141. where Checkin-time was not sent for a particular file. The
  142. effect is that we use the time of upload, rather than the time
  143. when we call RCS_checkin. Since those times are both during
  144. CVS's run, that seems OK, and it is easier to implement than
  145. putting the "was Checkin-time sent" flag in CVS/Entries or some
  146. such place. */
  147. if (server_active)
  148. use_file_modtime = 1;
  149. /* Don't allow "CVS" as any directory in module path.
  150. *
  151. * Could abstract this to valid_module_path, but I don't think we'll need
  152. * to call it from anywhere else.
  153. */
  154. /* for each "CVS" in path... */
  155. cp = argv[0];
  156. while ((cp = strstr(cp, "CVS")) != NULL)
  157. {
  158. if ( /* /^CVS/ OR m#/CVS#... */
  159. (cp == argv[0] || ISDIRSEP(*(cp-1)))
  160. /* ...AND /CVS$/ OR m#CVS/# */
  161. && (*(cp+3) == '\0' || ISDIRSEP(*(cp+3)))
  162. )
  163. {
  164. error (0, 0,
  165. "The word `CVS' is reserved by CVS and may not be used");
  166. error (1, 0, "as a directory in a path or as a file name.");
  167. }
  168. cp += 3;
  169. }
  170. for (i = 1; i < argc; i++) /* check the tags for validity */
  171. {
  172. int j;
  173. RCS_check_tag (argv[i]);
  174. for (j = 1; j < i; j++)
  175. if (strcmp (argv[j], argv[i]) == 0)
  176. error (1, 0, "tag `%s' was specified more than once", argv[i]);
  177. }
  178. /* XXX - this should be a module, not just a pathname */
  179. if (!isabsolute (argv[0]) && pathname_levels (argv[0]) == 0)
  180. {
  181. if (current_parsed_root == NULL)
  182. {
  183. error (0, 0, "missing CVSROOT environment variable\n");
  184. error (1, 0, "Set it or specify the '-d' option to %s.",
  185. program_name);
  186. }
  187. repository = xmalloc (strlen (current_parsed_root->directory)
  188. + strlen (argv[0])
  189. + 2);
  190. (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]);
  191. repos_len = strlen (current_parsed_root->directory);
  192. }
  193. else
  194. {
  195. /* It is somewhere between a security hole and "unexpected" to
  196. let the client start mucking around outside the cvsroot
  197. (wouldn't get the right CVSROOT configuration, &c). */
  198. error (1, 0, "directory %s not relative within the repository",
  199. argv[0]);
  200. }
  201. /*
  202. * Consistency checks on the specified vendor branch. It must be
  203. * composed of only numbers and dots ('.'). Also, for now we only
  204. * support branching to a single level, so the specified vendor branch
  205. * must only have two dots in it (like "1.1.1").
  206. */
  207. {
  208. regex_t pat;
  209. int ret = regcomp (&pat, "^[1-9][0-9]*\\.[1-9][0-9]*\\.[1-9][0-9]*$",
  210. REG_EXTENDED);
  211. assert (!ret);
  212. if (regexec (&pat, vbranch, 0, NULL, 0))
  213. {
  214. error (1, 0,
  215. "Only numeric branch specifications with two dots are\n"
  216. "supported by import, not `%s'. For example: `1.1.1'.",
  217. vbranch);
  218. }
  219. regfree (&pat);
  220. }
  221. /* Set vhead to the branch's parent. */
  222. vhead = xstrdup (vbranch);
  223. cp = strrchr (vhead, '.');
  224. *cp = '\0';
  225. #ifdef CLIENT_SUPPORT
  226. if (current_parsed_root->isremote)
  227. {
  228. /* For rationale behind calling start_server before do_editor, see
  229. commit.c */
  230. start_server ();
  231. }
  232. #endif
  233. if (!server_active && use_editor)
  234. {
  235. do_editor ((char *) NULL, &message,
  236. current_parsed_root->isremote ? (char *) NULL : repository,
  237. (List *) NULL);
  238. }
  239. do_verify (&message, repository);
  240. msglen = message == NULL ? 0 : strlen (message);
  241. if (msglen == 0 || message[msglen - 1] != '\n')
  242. {
  243. char *nm = xmalloc (msglen + 2);
  244. *nm = '\0';
  245. if (message != NULL)
  246. {
  247. (void) strcpy (nm, message);
  248. free (message);
  249. }
  250. (void) strcat (nm + msglen, "\n");
  251. message = nm;
  252. }
  253. #ifdef CLIENT_SUPPORT
  254. if (current_parsed_root->isremote)
  255. {
  256. int err;
  257. if (vbranch[0] != '\0')
  258. option_with_arg ("-b", vbranch);
  259. option_with_arg ("-m", message ? message : "");
  260. if (keyword_opt != NULL)
  261. option_with_arg ("-k", keyword_opt);
  262. /* The only ignore processing which takes place on the server side
  263. is the CVSROOT/cvsignore file. But if the user specified -I !,
  264. the documented behavior is to not process said file. */
  265. if (ign_inhibit_server)
  266. {
  267. send_arg ("-I");
  268. send_arg ("!");
  269. }
  270. wrap_send ();
  271. {
  272. int i;
  273. for (i = 0; i < argc; ++i)
  274. send_arg (argv[i]);
  275. }
  276. logfp = stdin;
  277. client_import_setup (repository);
  278. err = import_descend (message, argv[1], argc - 2, argv + 2);
  279. client_import_done ();
  280. if (message)
  281. free (message);
  282. free (repository);
  283. free (vbranch);
  284. free (vhead);
  285. send_to_server ("import\012", 0);
  286. err += get_responses_and_close ();
  287. return err;
  288. }
  289. #endif
  290. if (!safe_location ( NULL ))
  291. {
  292. error (1, 0, "attempt to import the repository");
  293. }
  294. /*
  295. * Make all newly created directories writable. Should really use a more
  296. * sophisticated security mechanism here.
  297. */
  298. (void) umask (cvsumask);
  299. make_directories (repository);
  300. /* Create the logfile that will be logged upon completion */
  301. if ((logfp = cvs_temp_file (&tmpfile)) == NULL)
  302. error (1, errno, "cannot create temporary file `%s'",
  303. tmpfile ? tmpfile : "(null)");
  304. /* On systems where we can unlink an open file, do so, so it will go
  305. away no matter how we exit. FIXME-maybe: Should be checking for
  306. errors but I'm not sure which error(s) we get if we are on a system
  307. where one can't unlink open files. */
  308. (void) CVS_UNLINK (tmpfile);
  309. (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
  310. (void) fprintf (logfp, "Release Tags:\t");
  311. for (i = 2; i < argc; i++)
  312. (void) fprintf (logfp, "%s\n\t\t", argv[i]);
  313. (void) fprintf (logfp, "\n");
  314. /* Just Do It. */
  315. err = import_descend (message, argv[1], argc - 2, argv + 2);
  316. if (conflicts)
  317. {
  318. if (!really_quiet)
  319. {
  320. char buf[20];
  321. cvs_output_tagged ("+importmergecmd", NULL);
  322. cvs_output_tagged ("newline", NULL);
  323. sprintf (buf, "%d", conflicts);
  324. cvs_output_tagged ("conflicts", buf);
  325. cvs_output_tagged ("text", " conflicts created by this import.");
  326. cvs_output_tagged ("newline", NULL);
  327. cvs_output_tagged ("text",
  328. "Use the following command to help the merge:");
  329. cvs_output_tagged ("newline", NULL);
  330. cvs_output_tagged ("newline", NULL);
  331. cvs_output_tagged ("text", "\t");
  332. cvs_output_tagged ("text", program_name);
  333. if (CVSroot_cmdline != NULL)
  334. {
  335. cvs_output_tagged ("text", " -d ");
  336. cvs_output_tagged ("text", CVSroot_cmdline);
  337. }
  338. cvs_output_tagged ("text", " checkout -j");
  339. cvs_output_tagged ("mergetag1", "<prev_rel_tag>");
  340. cvs_output_tagged ("text", " -j");
  341. cvs_output_tagged ("mergetag2", argv[2]);
  342. cvs_output_tagged ("text", " ");
  343. cvs_output_tagged ("repository", argv[0]);
  344. cvs_output_tagged ("newline", NULL);
  345. cvs_output_tagged ("newline", NULL);
  346. cvs_output_tagged ("-importmergecmd", NULL);
  347. }
  348. /* FIXME: I'm not sure whether we need to put this information
  349. into the loginfo. If we do, then note that it does not
  350. report any required -d option. There is no particularly
  351. clean way to tell the server about the -d option used by
  352. the client. */
  353. (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
  354. conflicts);
  355. (void) fprintf (logfp,
  356. "Use the following command to help the merge:\n\n");
  357. (void) fprintf (logfp, "\t%s checkout ", program_name);
  358. (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
  359. argv[1], argv[1], argv[0]);
  360. }
  361. else
  362. {
  363. if (!really_quiet)
  364. cvs_output ("\nNo conflicts created by this import\n\n", 0);
  365. (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
  366. }
  367. /*
  368. * Write out the logfile and clean up.
  369. */
  370. ulist = getlist ();
  371. p = getnode ();
  372. p->type = UPDATE;
  373. p->delproc = update_delproc;
  374. p->key = xstrdup ("- Imported sources");
  375. li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
  376. li->type = T_TITLE;
  377. li->tag = xstrdup (vbranch);
  378. li->rev_old = li->rev_new = NULL;
  379. p->data = li;
  380. (void) addnode (ulist, p);
  381. Update_Logfile (repository, message, logfp, ulist);
  382. dellist (&ulist);
  383. if (fclose (logfp) < 0)
  384. error (0, errno, "error closing %s", tmpfile);
  385. /* Make sure the temporary file goes away, even on systems that don't let
  386. you delete a file that's in use. */
  387. if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
  388. error (0, errno, "cannot remove %s", tmpfile);
  389. free (tmpfile);
  390. if (message)
  391. free (message);
  392. free (repository);
  393. free (vbranch);
  394. free (vhead);
  395. return (err);
  396. }
  397. /* Process all the files in ".", then descend into other directories.
  398. Returns 0 for success, or >0 on error (in which case a message
  399. will have been printed). */
  400. static int
  401. import_descend (message, vtag, targc, targv)
  402. char *message;
  403. char *vtag;
  404. int targc;
  405. char *targv[];
  406. {
  407. DIR *dirp;
  408. struct dirent *dp;
  409. int err = 0;
  410. List *dirlist = NULL;
  411. /* first, load up any per-directory ignore lists */
  412. ign_add_file (CVSDOTIGNORE, 1);
  413. wrap_add_file (CVSDOTWRAPPER, 1);
  414. if (!current_parsed_root->isremote)
  415. lock_dir_for_write (repository);
  416. if ((dirp = CVS_OPENDIR (".")) == NULL)
  417. {
  418. error (0, errno, "cannot open directory");
  419. err++;
  420. }
  421. else
  422. {
  423. errno = 0;
  424. while ((dp = CVS_READDIR (dirp)) != NULL)
  425. {
  426. if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
  427. goto one_more_time_boys;
  428. /* CVS directories are created in the temp directory by
  429. server.c because it doesn't special-case import. So
  430. don't print a message about them, regardless of -I!. */
  431. if (server_active && strcmp (dp->d_name, CVSADM) == 0)
  432. goto one_more_time_boys;
  433. if (ign_name (dp->d_name))
  434. {
  435. add_log ('I', dp->d_name);
  436. goto one_more_time_boys;
  437. }
  438. if (
  439. #ifdef DT_DIR
  440. (dp->d_type == DT_DIR
  441. || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name)))
  442. #else
  443. isdir (dp->d_name)
  444. #endif
  445. && !wrap_name_has (dp->d_name, WRAP_TOCVS)
  446. )
  447. {
  448. Node *n;
  449. if (dirlist == NULL)
  450. dirlist = getlist();
  451. n = getnode();
  452. n->key = xstrdup (dp->d_name);
  453. addnode(dirlist, n);
  454. }
  455. else if (
  456. #ifdef DT_DIR
  457. dp->d_type == DT_LNK
  458. || (dp->d_type == DT_UNKNOWN && islink (dp->d_name))
  459. #else
  460. islink (dp->d_name)
  461. #endif
  462. )
  463. {
  464. add_log ('L', dp->d_name);
  465. err++;
  466. }
  467. else
  468. {
  469. #ifdef CLIENT_SUPPORT
  470. if (current_parsed_root->isremote)
  471. err += client_process_import_file (message, dp->d_name,
  472. vtag, targc, targv,
  473. repository,
  474. keyword_opt != NULL &&
  475. keyword_opt[0] == 'b',
  476. use_file_modtime);
  477. else
  478. #endif
  479. err += process_import_file (message, dp->d_name,
  480. vtag, targc, targv);
  481. }
  482. one_more_time_boys:
  483. errno = 0;
  484. }
  485. if (errno != 0)
  486. {
  487. error (0, errno, "cannot read directory");
  488. ++err;
  489. }
  490. (void) CVS_CLOSEDIR (dirp);
  491. }
  492. if (!current_parsed_root->isremote)
  493. Lock_Cleanup ();
  494. if (dirlist != NULL)
  495. {
  496. Node *head, *p;
  497. head = dirlist->list;
  498. for (p = head->next; p != head; p = p->next)
  499. {
  500. err += import_descend_dir (message, p->key, vtag, targc, targv);
  501. }
  502. dellist(&dirlist);
  503. }
  504. return (err);
  505. }
  506. /*
  507. * Process the argument import file.
  508. */
  509. static int
  510. process_import_file (message, vfile, vtag, targc, targv)
  511. char *message;
  512. char *vfile;
  513. char *vtag;
  514. int targc;
  515. char *targv[];
  516. {
  517. char *rcs;
  518. int inattic = 0;
  519. rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT)
  520. + 5);
  521. (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
  522. if (!isfile (rcs))
  523. {
  524. char *attic_name;
  525. attic_name = xmalloc (strlen (repository) + strlen (vfile) +
  526. sizeof (CVSATTIC) + sizeof (RCSEXT) + 10);
  527. (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
  528. vfile, RCSEXT);
  529. if (!isfile (attic_name))
  530. {
  531. int retval;
  532. char *free_opt = NULL;
  533. char *our_opt = keyword_opt;
  534. free (attic_name);
  535. /*
  536. * A new import source file; it doesn't exist as a ,v within the
  537. * repository nor in the Attic -- create it anew.
  538. */
  539. add_log ('N', vfile);
  540. #ifdef SERVER_SUPPORT
  541. /* The most reliable information on whether the file is binary
  542. is what the client told us. That is because if the client had
  543. the wrong idea about binaryness, it corrupted the file, so
  544. we might as well believe the client. */
  545. if (server_active)
  546. {
  547. Node *node;
  548. List *entries;
  549. /* Reading all the entries for each file is fairly silly, and
  550. probably slow. But I am too lazy at the moment to do
  551. anything else. */
  552. entries = Entries_Open (0, NULL);
  553. node = findnode_fn (entries, vfile);
  554. if (node != NULL)
  555. {
  556. Entnode *entdata = node->data;
  557. if (entdata->type == ENT_FILE)
  558. {
  559. assert (entdata->options[0] == '-'
  560. && entdata->options[1] == 'k');
  561. our_opt = xstrdup (entdata->options + 2);
  562. free_opt = our_opt;
  563. }
  564. }
  565. Entries_Close (entries);
  566. }
  567. #endif
  568. retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
  569. vbranch, vtag, targc, targv,
  570. NULL, 0, logfp);
  571. if (free_opt != NULL)
  572. free (free_opt);
  573. free (rcs);
  574. return retval;
  575. }
  576. free (attic_name);
  577. inattic = 1;
  578. }
  579. free (rcs);
  580. /*
  581. * an rcs file exists. have to do things the official, slow, way.
  582. */
  583. return (update_rcs_file (message, vfile, vtag, targc, targv, inattic));
  584. }
  585. /*
  586. * The RCS file exists; update it by adding the new import file to the
  587. * (possibly already existing) vendor branch.
  588. */
  589. static int
  590. update_rcs_file (message, vfile, vtag, targc, targv, inattic)
  591. char *message;
  592. char *vfile;
  593. char *vtag;
  594. int targc;
  595. char *targv[];
  596. int inattic;
  597. {
  598. Vers_TS *vers;
  599. int letter;
  600. char *tocvsPath;
  601. char *expand;
  602. struct file_info finfo;
  603. memset (&finfo, 0, sizeof finfo);
  604. finfo.file = vfile;
  605. /* Not used, so don't worry about it. */
  606. finfo.update_dir = NULL;
  607. finfo.fullname = finfo.file;
  608. finfo.repository = repository;
  609. finfo.entries = NULL;
  610. finfo.rcs = NULL;
  611. vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL,
  612. 1, 0);
  613. if (vers->vn_rcs != NULL
  614. && !RCS_isdead(vers->srcfile, vers->vn_rcs))
  615. {
  616. int different;
  617. /*
  618. * The rcs file does have a revision on the vendor branch. Compare
  619. * this revision with the import file; if they match exactly, there
  620. * is no need to install the new import file as a new revision to the
  621. * branch. Just tag the revision with the new import tags.
  622. *
  623. * This is to try to cut down the number of "C" conflict messages for
  624. * locally modified import source files.
  625. */
  626. tocvsPath = wrap_tocvs_process_file (vfile);
  627. /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is
  628. not NULL? */
  629. expand = vers->srcfile->expand != NULL &&
  630. vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko";
  631. different = RCS_cmp_file( vers->srcfile, vers->vn_rcs, (char **)NULL,
  632. (char *)NULL, expand, vfile );
  633. if (tocvsPath)
  634. if (unlink_file_dir (tocvsPath) < 0)
  635. error (0, errno, "cannot remove %s", tocvsPath);
  636. if (!different)
  637. {
  638. int retval = 0;
  639. /*
  640. * The two files are identical. Just update the tags, print the
  641. * "U", signifying that the file has changed, but needs no
  642. * attention, and we're done.
  643. */
  644. if (add_tags (vers->srcfile, vfile, vtag, targc, targv))
  645. retval = 1;
  646. add_log ('U', vfile);
  647. freevers_ts (&vers);
  648. return (retval);
  649. }
  650. }
  651. /* We may have failed to parse the RCS file; check just in case */
  652. if (vers->srcfile == NULL ||
  653. add_rev (message, vers->srcfile, vfile, vers->vn_rcs) ||
  654. add_tags (vers->srcfile, vfile, vtag, targc, targv))
  655. {
  656. freevers_ts (&vers);
  657. return (1);
  658. }
  659. if (vers->srcfile->branch == NULL || inattic ||
  660. strcmp (vers->srcfile->branch, vbranch) != 0)
  661. {
  662. conflicts++;
  663. letter = 'C';
  664. }
  665. else
  666. letter = 'U';
  667. add_log (letter, vfile);
  668. freevers_ts (&vers);
  669. return (0);
  670. }
  671. /*
  672. * Add the revision to the vendor branch
  673. */
  674. static int
  675. add_rev (message, rcs, vfile, vers)
  676. char *message;
  677. RCSNode *rcs;
  678. char *vfile;
  679. char *vers;
  680. {
  681. int locked, status, ierrno;
  682. char *tocvsPath;
  683. if (noexec)
  684. return (0);
  685. locked = 0;
  686. if (vers != NULL)
  687. {
  688. /* Before RCS_lock existed, we were directing stdout, as well as
  689. stderr, from the RCS command, to DEVNULL. I wouldn't guess that
  690. was necessary, but I don't know for sure. */
  691. /* Earlier versions of this function printed a `fork failed' error
  692. when RCS_lock returned an error code. That's not appropriate
  693. now that RCS_lock is librarified, but should the error text be
  694. preserved? */
  695. if (RCS_lock (rcs, vbranch, 1) != 0)
  696. return 1;
  697. locked = 1;
  698. RCS_rewrite (rcs, NULL, NULL);
  699. }
  700. tocvsPath = wrap_tocvs_process_file (vfile);
  701. status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
  702. message, vbranch, 0,
  703. (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
  704. | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
  705. ierrno = errno;
  706. if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
  707. error (0, errno, "cannot remove %s", tocvsPath);
  708. if (status)
  709. {
  710. if (!noexec)
  711. {
  712. fperrmsg (logfp, 0, status == -1 ? ierrno : 0,
  713. "ERROR: Check-in of %s failed", rcs->path);
  714. error (0, status == -1 ? ierrno : 0,
  715. "ERROR: Check-in of %s failed", rcs->path);
  716. }
  717. if (locked)
  718. {
  719. (void) RCS_unlock(rcs, vbranch, 0);
  720. RCS_rewrite (rcs, NULL, NULL);
  721. }
  722. return (1);
  723. }
  724. return (0);
  725. }
  726. /*
  727. * Add the vendor branch tag and all the specified import release tags to the
  728. * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
  729. * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
  730. * 1.1.1.2, ...).
  731. */
  732. static int
  733. add_tags (rcs, vfile, vtag, targc, targv)
  734. RCSNode *rcs;
  735. char *vfile;
  736. char *vtag;
  737. int targc;
  738. char *targv[];
  739. {
  740. int i, ierrno;
  741. Vers_TS *vers;
  742. int retcode = 0;
  743. struct file_info finfo;
  744. if (noexec)
  745. return (0);
  746. if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0)
  747. {
  748. ierrno = errno;
  749. fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
  750. "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
  751. error (0, retcode == -1 ? ierrno : 0,
  752. "ERROR: Failed to set tag %s in %s", vtag, rcs->path);
  753. return (1);
  754. }
  755. RCS_rewrite (rcs, NULL, NULL);
  756. memset (&finfo, 0, sizeof finfo);
  757. finfo.file = vfile;
  758. /* Not used, so don't worry about it. */
  759. finfo.update_dir = NULL;
  760. finfo.fullname = finfo.file;
  761. finfo.repository = repository;
  762. finfo.entries = NULL;
  763. finfo.rcs = NULL;
  764. vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
  765. for (i = 0; i < targc; i++)
  766. {
  767. if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
  768. RCS_rewrite (rcs, NULL, NULL);
  769. else
  770. {
  771. ierrno = errno;
  772. fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0,
  773. "WARNING: Couldn't add tag %s to %s", targv[i],
  774. rcs->path);
  775. error (0, retcode == -1 ? ierrno : 0,
  776. "WARNING: Couldn't add tag %s to %s", targv[i],
  777. rcs->path);
  778. }
  779. }
  780. freevers_ts (&vers);
  781. return (0);
  782. }
  783. /*
  784. * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
  785. */
  786. struct compair
  787. {
  788. char *suffix, *comlead;
  789. };
  790. static const struct compair comtable[] =
  791. {
  792. /*
  793. * comtable pairs each filename suffix with a comment leader. The comment
  794. * leader is placed before each line generated by the $Log keyword. This
  795. * table is used to guess the proper comment leader from the working file's
  796. * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
  797. * languages without multiline comments; for others they are optional.
  798. *
  799. * I believe that the comment leader is unused if you are using RCS 5.7, which
  800. * decides what leader to use based on the text surrounding the $Log keyword
  801. * rather than a specified comment leader.
  802. */
  803. {"a", "-- "}, /* Ada */
  804. {"ada", "-- "},
  805. {"adb", "-- "},
  806. {"asm", ";; "}, /* assembler (MS-DOS) */
  807. {"ads", "-- "}, /* Ada */
  808. {"bas", "' "}, /* Visual Basic code */
  809. {"bat", ":: "}, /* batch (MS-DOS) */
  810. {"body", "-- "}, /* Ada */
  811. {"c", " * "}, /* C */
  812. {"c++", "// "}, /* C++ in all its infinite guises */
  813. {"cc", "// "},
  814. {"cpp", "// "},
  815. {"cxx", "// "},
  816. {"m", "// "}, /* Objective-C */
  817. {"cl", ";;; "}, /* Common Lisp */
  818. {"cmd", ":: "}, /* command (OS/2) */
  819. {"cmf", "c "}, /* CM Fortran */
  820. {"cs", " * "}, /* C* */
  821. {"csh", "# "}, /* shell */
  822. {"dlg", " * "}, /* MS Windows dialog file */
  823. {"e", "# "}, /* efl */
  824. {"epsf", "% "}, /* encapsulated postscript */
  825. {"epsi", "% "}, /* encapsulated postscript */
  826. {"el", "; "}, /* Emacs Lisp */
  827. {"f", "c "}, /* Fortran */
  828. {"for", "c "},
  829. {"frm", "' "}, /* Visual Basic form */
  830. {"h", " * "}, /* C-header */
  831. {"hh", "// "}, /* C++ header */
  832. {"hpp", "// "},
  833. {"hxx", "// "},
  834. {"in", "# "}, /* for Makefile.in */
  835. {"l", " * "}, /* lex (conflict between lex and
  836. * franzlisp) */
  837. {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11,
  838. * VMS, etc) */
  839. {"mak", "# "}, /* makefile, e.g. Visual C++ */
  840. {"me", ".\\\" "}, /* me-macros t/nroff */
  841. {"ml", "; "}, /* mocklisp */
  842. {"mm", ".\\\" "}, /* mm-macros t/nroff */
  843. {"ms", ".\\\" "}, /* ms-macros t/nroff */
  844. {"man", ".\\\" "}, /* man-macros t/nroff */
  845. {"1", ".\\\" "}, /* feeble attempt at man pages... */
  846. {"2", ".\\\" "},
  847. {"3", ".\\\" "},
  848. {"4", ".\\\" "},
  849. {"5", ".\\\" "},
  850. {"6", ".\\\" "},
  851. {"7", ".\\\" "},
  852. {"8", ".\\\" "},
  853. {"9", ".\\\" "},
  854. {"p", " * "}, /* pascal */
  855. {"pas", " * "},
  856. {"pl", "# "}, /* perl (conflict with Prolog) */
  857. {"ps", "% "}, /* postscript */
  858. {"psw", "% "}, /* postscript wrap */
  859. {"pswm", "% "}, /* postscript wrap */
  860. {"r", "# "}, /* ratfor */
  861. {"rc", " * "}, /* Microsoft Windows resource file */
  862. {"red", "% "}, /* psl/rlisp */
  863. #ifdef sparc
  864. {"s", "! "}, /* assembler */
  865. #endif
  866. #ifdef mc68000
  867. {"s", "| "}, /* assembler */
  868. #endif
  869. #ifdef pdp11
  870. {"s", "/ "}, /* assembler */
  871. #endif
  872. #ifdef vax
  873. {"s", "# "}, /* assembler */
  874. #endif
  875. #ifdef __ksr__
  876. {"s", "# "}, /* assembler */
  877. {"S", "# "}, /* Macro assembler */
  878. #endif
  879. {"sh", "# "}, /* shell */
  880. {"sl", "% "}, /* psl */
  881. {"spec", "-- "}, /* Ada */
  882. {"tex", "% "}, /* tex */
  883. {"y", " * "}, /* yacc */
  884. {"ye", " * "}, /* yacc-efl */
  885. {"yr", " * "}, /* yacc-ratfor */
  886. {"", "# "}, /* default for empty suffix */
  887. {NULL, "# "} /* default for unknown suffix; */
  888. /* must always be last */
  889. };
  890. static char *
  891. get_comment (user)
  892. const char *user;
  893. {
  894. char *cp, *suffix;
  895. char *suffix_path;
  896. int i;
  897. char *retval;
  898. suffix_path = xmalloc (strlen (user) + 5);
  899. cp = strrchr (user, '.');
  900. if (cp != NULL)
  901. {
  902. cp++;
  903. /*
  904. * Convert to lower-case, since we are not concerned about the
  905. * case-ness of the suffix.
  906. */
  907. (void) strcpy (suffix_path, cp);
  908. for (cp = suffix_path; *cp; cp++)
  909. if (isupper ((unsigned char) *cp))
  910. *cp = tolower (*cp);
  911. suffix = suffix_path;
  912. }
  913. else
  914. suffix = ""; /* will use the default */
  915. for (i = 0;; i++)
  916. {
  917. if (comtable[i].suffix == NULL)
  918. {
  919. /* Default. Note we'll always hit this case before we
  920. ever return NULL. */
  921. retval = comtable[i].comlead;
  922. break;
  923. }
  924. if (strcmp (suffix, comtable[i].suffix) == 0)
  925. {
  926. retval = comtable[i].comlead;
  927. break;
  928. }
  929. }
  930. free (suffix_path);
  931. return retval;
  932. }
  933. /* Create a new RCS file from scratch.
  934. This probably should be moved to rcs.c now that it is called from
  935. places outside import.c.
  936. Return value is 0 for success, or nonzero for failure (in which
  937. case an error message will have already been printed). */
  938. int
  939. add_rcs_file (message, rcs, user, add_vhead, key_opt,
  940. add_vbranch, vtag, targc, targv,
  941. desctext, desclen, add_logfp)
  942. /* Log message for the addition. Not used if add_vhead == NULL. */
  943. const char *message;
  944. /* Filename of the RCS file to create. */
  945. const char *rcs;
  946. /* Filename of the file to serve as the contents of the initial
  947. revision. Even if add_vhead is NULL, we use this to determine
  948. the modes to give the new RCS file. */
  949. const char *user;
  950. /* Revision number of head that we are adding. Normally 1.1 but
  951. could be another revision as long as ADD_VBRANCH is a branch
  952. from it. If NULL, then just add an empty file without any
  953. revisions (similar to the one created by "rcs -i"). */
  954. const char *add_vhead;
  955. /* Keyword expansion mode, e.g., "b" for binary. NULL means the
  956. default behavior. */
  957. const char *key_opt;
  958. /* Vendor branch to import to, or NULL if none. If non-NULL, then
  959. vtag should also be non-NULL. */
  960. const char *add_vbranch;
  961. const char *vtag;
  962. int targc;
  963. char *targv[];
  964. /* If non-NULL, description for the file. If NULL, the description
  965. will be empty. */
  966. const char *desctext;
  967. size_t desclen;
  968. /* Write errors to here as well as via error (), or NULL if we should
  969. use only error (). */
  970. FILE *add_logfp;
  971. {
  972. FILE *fprcs, *fpuser;
  973. struct stat sb;
  974. struct tm *ftm;
  975. time_t now;
  976. char altdate1[MAXDATELEN];
  977. char *author;
  978. int i, ierrno, err = 0;
  979. mode_t mode;
  980. char *tocvsPath;
  981. const char *userfile;
  982. char *free_opt = NULL;
  983. mode_t file_type;
  984. if (noexec)
  985. return (0);
  986. /* Note that as the code stands now, the -k option overrides any
  987. settings in wrappers (whether CVSROOT/cvswrappers, -W, or
  988. whatever). Some have suggested this should be the other way
  989. around. As far as I know the documentation doesn't say one way
  990. or the other. Before making a change of this sort, should think
  991. about what is best, document it (in cvs.texinfo and NEWS), &c. */
  992. if (key_opt == NULL)
  993. {
  994. if (wrap_name_has (user, WRAP_RCSOPTION))
  995. {
  996. key_opt = free_opt = wrap_rcsoption (user, 0);
  997. }
  998. }
  999. tocvsPath = wrap_tocvs_process_file (user);
  1000. userfile = (tocvsPath == NULL ? user : tocvsPath);
  1001. /* Opening in text mode is probably never the right thing for the
  1002. server (because the protocol encodes text files in a fashion
  1003. which does not depend on what the client or server OS is, as
  1004. documented in cvsclient.texi), but as long as the server just
  1005. runs on unix it is a moot point. */
  1006. /* If PreservePermissions is set, then make sure that the file
  1007. is a plain file before trying to open it. Longstanding (although
  1008. often unpopular) CVS behavior has been to follow symlinks, so we
  1009. maintain that behavior if PreservePermissions is not on.
  1010. NOTE: this error message used to be `cannot fstat', but is now
  1011. `cannot lstat'. I don't see a way around this, since we must
  1012. stat the file before opening it. -twp */
  1013. if (CVS_LSTAT (userfile, &sb) < 0)
  1014. {
  1015. /* not fatal, continue import */
  1016. if (add_logfp != NULL)
  1017. fperrmsg (add_logfp, 0, errno,
  1018. "ERROR: cannot lstat file %s", userfile);
  1019. error (0, errno, "cannot lstat file %s", userfile);
  1020. goto read_error;
  1021. }
  1022. file_type = sb.st_mode & S_IFMT;
  1023. fpuser = NULL;
  1024. if (!preserve_perms || file_type == S_IFREG)
  1025. {
  1026. fpuser = CVS_FOPEN (userfile,
  1027. ((key_opt != NULL && strcmp (key_opt, "b") == 0)
  1028. ? "rb"
  1029. : "r")
  1030. );
  1031. if (fpuser == NULL)
  1032. {
  1033. /* not fatal, continue import */
  1034. if (add_logfp != NULL)
  1035. fperrmsg (add_logfp, 0, errno,
  1036. "ERROR: cannot read file %s", userfile);
  1037. error (0, errno, "ERROR: cannot read file %s", userfile);
  1038. goto read_error;
  1039. }
  1040. }
  1041. fprcs = CVS_FOPEN (rcs, "w+b");
  1042. if (fprcs == NULL)
  1043. {
  1044. ierrno = errno;
  1045. goto write_error_noclose;
  1046. }
  1047. /*
  1048. * putadmin()
  1049. */
  1050. if (add_vhead != NULL)
  1051. {
  1052. if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
  1053. goto write_error;
  1054. }
  1055. else
  1056. {
  1057. if (fprintf (fprcs, "head ;\012") < 0)
  1058. goto write_error;
  1059. }
  1060. if (add_vbranch != NULL)
  1061. {
  1062. if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
  1063. goto write_error;
  1064. }
  1065. if (fprintf (fprcs, "access ;\012") < 0 ||
  1066. fprintf (fprcs, "symbols ") < 0)
  1067. {
  1068. goto write_error;
  1069. }
  1070. for (i = targc - 1; i >= 0; i--)
  1071. {
  1072. /* RCS writes the symbols backwards */
  1073. assert (add_vbranch != NULL);
  1074. if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0)
  1075. goto write_error;
  1076. }
  1077. if (add_vbranch != NULL)
  1078. {
  1079. if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0)
  1080. goto write_error;
  1081. }
  1082. if (fprintf (fprcs, ";\012") < 0)
  1083. goto write_error;
  1084. if (fprintf (fprcs, "locks ; strict;\012") < 0 ||
  1085. /* XXX - make sure @@ processing works in the RCS file */
  1086. fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
  1087. {
  1088. goto write_error;
  1089. }
  1090. if (key_opt != NULL && strcmp (key_opt, "kv") != 0)
  1091. {
  1092. if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0)
  1093. {
  1094. goto write_error;
  1095. }
  1096. }
  1097. if (fprintf (fprcs, "\012") < 0)
  1098. goto write_error;
  1099. /* Write the revision(s), with the date and author and so on
  1100. (that is "delta" rather than "deltatext" from rcsfile(5)). */
  1101. if (add_vhead != NULL)
  1102. {
  1103. if (use_file_modtime)
  1104. now = sb.st_mtime;
  1105. else
  1106. (void) time (&now);
  1107. ftm = gmtime (&now);
  1108. (void) sprintf (altdate1, DATEFORM,
  1109. ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
  1110. ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
  1111. ftm->tm_min, ftm->tm_sec);
  1112. author = getcaller ();
  1113. if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
  1114. fprintf (fprcs, "date %s; author %s; state Exp;\012",
  1115. altdate1, author) < 0)
  1116. goto write_error;
  1117. if (fprintf (fprcs, "branches") < 0)
  1118. goto write_error;
  1119. if (add_vbranch != NULL)
  1120. {
  1121. if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
  1122. goto write_error;
  1123. }
  1124. if (fprintf (fprcs, ";\012") < 0)
  1125. goto write_error;
  1126. if (fprintf (fprcs, "next ;\012") < 0)
  1127. goto write_error;
  1128. #ifdef PRESERVE_PERMISSIONS_SUPPORT
  1129. /* Store initial permissions if necessary. */
  1130. if (preserve_perms)
  1131. {
  1132. if (file_type == S_IFLNK)
  1133. {
  1134. char *link = xreadlink (userfile);
  1135. if (fprintf (fprcs, "symlink\t@") < 0 ||
  1136. expand_at_signs (link, strlen (link), fprcs) < 0 ||
  1137. fprintf (fprcs, "@;\012") < 0)
  1138. goto write_error;
  1139. free (link);
  1140. }
  1141. else
  1142. {
  1143. if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
  1144. goto write_error;
  1145. if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
  1146. goto write_error;
  1147. if (fprintf (fprcs, "permissions\t%o;\012",
  1148. sb.st_mode & 07777) < 0)
  1149. goto write_error;
  1150. switch (file_type)
  1151. {
  1152. case S_IFREG: break;
  1153. case S_IFCHR:
  1154. case S_IFBLK:
  1155. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  1156. if (fprintf (fprcs, "special\t%s %lu;\012",
  1157. (file_type == S_IFCHR
  1158. ? "character"
  1159. : "block"),
  1160. (unsigned long) sb.st_rdev) < 0)
  1161. goto write_error;
  1162. #else
  1163. error (0, 0,
  1164. "can't import %s: unable to import device files on this system",
  1165. userfile);
  1166. #endif
  1167. break;
  1168. default:
  1169. error (0, 0,
  1170. "can't import %s: unknown kind of special file",
  1171. userfile);
  1172. }
  1173. }
  1174. }
  1175. #endif
  1176. if (add_vbranch != NULL)
  1177. {
  1178. if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
  1179. fprintf (fprcs, "date %s; author %s; state Exp;\012",
  1180. altdate1, author) < 0 ||
  1181. fprintf (fprcs, "branches ;\012") < 0 ||
  1182. fprintf (fprcs, "next ;\012") < 0)
  1183. goto write_error;
  1184. #ifdef PRESERVE_PERMISSIONS_SUPPORT
  1185. /* Store initial permissions if necessary. */
  1186. if (preserve_perms)
  1187. {
  1188. if (file_type == S_IFLNK)
  1189. {
  1190. char *link = xreadlink (userfile);
  1191. if (fprintf (fprcs, "symlink\t@") < 0 ||
  1192. expand_at_signs (link, strlen (link), fprcs) < 0 ||
  1193. fprintf (fprcs, "@;\012") < 0)
  1194. goto write_error;
  1195. free (link);
  1196. }
  1197. else
  1198. {
  1199. if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
  1200. fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
  1201. fprintf (fprcs, "permissions\t%o;\012",
  1202. sb.st_mode & 07777) < 0)
  1203. goto write_error;
  1204. switch (file_type)
  1205. {
  1206. case S_IFREG: break;
  1207. case S_IFCHR:
  1208. case S_IFBLK:
  1209. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  1210. if (fprintf (fprcs, "special\t%s %lu;\012",
  1211. (file_type == S_IFCHR
  1212. ? "character"
  1213. : "block"),
  1214. (unsigned long) sb.st_rdev) < 0)
  1215. goto write_error;
  1216. #else
  1217. error (0, 0,
  1218. "can't import %s: unable to import device files on this system",
  1219. userfile);
  1220. #endif
  1221. break;
  1222. default:
  1223. error (0, 0,
  1224. "cannot import %s: special file of unknown type",
  1225. userfile);
  1226. }
  1227. }
  1228. }
  1229. #endif
  1230. if (fprintf (fprcs, "\012") < 0)
  1231. goto write_error;
  1232. }
  1233. }
  1234. /* Now write the description (possibly empty). */
  1235. if (fprintf (fprcs, "\012desc\012") < 0 ||
  1236. fprintf (fprcs, "@") < 0)
  1237. goto write_error;
  1238. if (desctext != NULL)
  1239. {
  1240. /* The use of off_t not size_t for the second argument is very
  1241. strange, since we are dealing with something which definitely
  1242. fits in memory. */
  1243. if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
  1244. goto write_error;
  1245. }
  1246. if (fprintf (fprcs, "@\012\012\012") < 0)
  1247. goto write_error;
  1248. /* Now write the log messages and contents for the revision(s) (that
  1249. is, "deltatext" rather than "delta" from rcsfile(5)). */
  1250. if (add_vhead != NULL)
  1251. {
  1252. if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
  1253. fprintf (fprcs, "log\012@") < 0)
  1254. goto write_error;
  1255. if (add_vbranch != NULL)
  1256. {
  1257. /* We are going to put the log message in the revision on the
  1258. branch. So putting it here too seems kind of redundant, I
  1259. guess (and that is what CVS has always done, anyway). */
  1260. if (fprintf (fprcs, "Initial revision\012") < 0)
  1261. goto write_error;
  1262. }
  1263. else
  1264. {
  1265. if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
  1266. goto write_error;
  1267. }
  1268. if (fprintf (fprcs, "@\012") < 0 ||
  1269. fprintf (fprcs, "text\012@") < 0)
  1270. {
  1271. goto write_error;
  1272. }
  1273. /* Now copy over the contents of the file, expanding at signs.
  1274. If preserve_perms is set, do this only for regular files. */
  1275. if (!preserve_perms || file_type == S_IFREG)
  1276. {
  1277. char buf[8192];
  1278. unsigned int len;
  1279. while (1)
  1280. {
  1281. len = fread (buf, 1, sizeof buf, fpuser);
  1282. if (len == 0)
  1283. {
  1284. if (ferror (fpuser))
  1285. error (1, errno, "cannot read file %s for copying",
  1286. user);
  1287. break;
  1288. }
  1289. if (expand_at_signs (buf, len, fprcs) < 0)
  1290. goto write_error;
  1291. }
  1292. }
  1293. if (fprintf (fprcs, "@\012\012") < 0)
  1294. goto write_error;
  1295. if (add_vbranch != NULL)
  1296. {
  1297. if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
  1298. fprintf (fprcs, "log\012@") < 0 ||
  1299. expand_at_signs (message,
  1300. (off_t) strlen (message), fprcs) < 0 ||
  1301. fprintf (fprcs, "@\012text\012") < 0 ||
  1302. fprintf (fprcs, "@@\012") < 0)
  1303. goto write_error;
  1304. }
  1305. }
  1306. if (fclose (fprcs) == EOF)
  1307. {
  1308. ierrno = errno;
  1309. goto write_error_noclose;
  1310. }
  1311. /* Close fpuser only if we opened it to begin with. */
  1312. if (fpuser != NULL)
  1313. {
  1314. if (fclose (fpuser) < 0)
  1315. error (0, errno, "cannot close %s", user);
  1316. }
  1317. /*
  1318. * Fix the modes on the RCS files. The user modes of the original
  1319. * user file are propagated to the group and other modes as allowed
  1320. * by the repository umask, except that all write permissions are
  1321. * turned off.
  1322. */
  1323. mode = (sb.st_mode |
  1324. (sb.st_mode & S_IRWXU) >> 3 |
  1325. (sb.st_mode & S_IRWXU) >> 6) &
  1326. ~cvsumask &
  1327. ~(S_IWRITE | S_IWGRP | S_IWOTH);
  1328. if (chmod (rcs, mode) < 0)
  1329. {
  1330. ierrno = errno;
  1331. if (add_logfp != NULL)
  1332. fperrmsg (add_logfp, 0, ierrno,
  1333. "WARNING: cannot change mode of file %s", rcs);
  1334. error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
  1335. err++;
  1336. }
  1337. if (tocvsPath)
  1338. if (unlink_file_dir (tocvsPath) < 0)
  1339. error (0, errno, "cannot remove %s", tocvsPath);
  1340. if (free_opt != NULL)
  1341. free (free_opt);
  1342. return (err);
  1343. write_error:
  1344. ierrno = errno;
  1345. if (fclose (fprcs) < 0)
  1346. error (0, errno, "cannot close %s", rcs);
  1347. write_error_noclose:
  1348. if (fclose (fpuser) < 0)
  1349. error (0, errno, "cannot close %s", user);
  1350. if (add_logfp != NULL)
  1351. fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
  1352. error (0, ierrno, "ERROR: cannot write file %s", rcs);
  1353. if (ierrno == ENOSPC)
  1354. {
  1355. if (CVS_UNLINK (rcs) < 0)
  1356. error (0, errno, "cannot remove %s", rcs);
  1357. if (add_logfp != NULL)
  1358. fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting");
  1359. error (1, 0, "ERROR: out of space - aborting");
  1360. }
  1361. read_error:
  1362. if (tocvsPath)
  1363. if (unlink_file_dir (tocvsPath) < 0)
  1364. error (0, errno, "cannot remove %s", tocvsPath);
  1365. if (free_opt != NULL)
  1366. free (free_opt);
  1367. return (err + 1);
  1368. }
  1369. /*
  1370. * Write SIZE bytes at BUF to FP, expanding @ signs into double @
  1371. * signs. If an error occurs, return a negative value and set errno
  1372. * to indicate the error. If not, return a nonnegative value.
  1373. */
  1374. int
  1375. expand_at_signs (buf, size, fp)
  1376. const char *buf;
  1377. off_t size;
  1378. FILE *fp;
  1379. {
  1380. register const char *cp, *next;
  1381. cp = buf;
  1382. while ((next = memchr (cp, '@', size)) != NULL)
  1383. {
  1384. size_t len = ++next - cp;
  1385. if (fwrite (cp, 1, len, fp) != len)
  1386. return EOF;
  1387. if (putc ('@', fp) == EOF)
  1388. return EOF;
  1389. cp = next;
  1390. size -= len;
  1391. }
  1392. if (fwrite (cp, 1, size, fp) != size)
  1393. return EOF;
  1394. return 1;
  1395. }
  1396. /*
  1397. * Write an update message to (potentially) the screen and the log file.
  1398. */
  1399. static void
  1400. add_log (ch, fname)
  1401. int ch;
  1402. char *fname;
  1403. {
  1404. if (!really_quiet) /* write to terminal */
  1405. {
  1406. char buf[2];
  1407. buf[0] = ch;
  1408. buf[1] = ' ';
  1409. cvs_output (buf, 2);
  1410. if (repos_len)
  1411. {
  1412. cvs_output (repository + repos_len + 1, 0);
  1413. cvs_output ("/", 1);
  1414. }
  1415. else if (repository[0] != '\0')
  1416. {
  1417. cvs_output (repository, 0);
  1418. cvs_output ("/", 1);
  1419. }
  1420. cvs_output (fname, 0);
  1421. cvs_output ("\n", 1);
  1422. }
  1423. if (repos_len) /* write to logfile */
  1424. (void) fprintf (logfp, "%c %s/%s\n", ch,
  1425. repository + repos_len + 1, fname);
  1426. else if (repository[0])
  1427. (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
  1428. else
  1429. (void) fprintf (logfp, "%c %s\n", ch, fname);
  1430. }
  1431. /*
  1432. * This is the recursive function that walks the argument directory looking
  1433. * for sub-directories that have CVS administration files in them and updates
  1434. * them recursively.
  1435. *
  1436. * Note that we do not follow symbolic links here, which is a feature!
  1437. */
  1438. static int
  1439. import_descend_dir (message, dir, vtag, targc, targv)
  1440. char *message;
  1441. char *dir;
  1442. char *vtag;
  1443. int targc;
  1444. char *targv[];
  1445. {
  1446. struct saved_cwd cwd;
  1447. char *cp;
  1448. int ierrno, err;
  1449. char *rcs = NULL;
  1450. if (islink (dir))
  1451. return (0);
  1452. if (save_cwd (&cwd))
  1453. {
  1454. fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory");
  1455. return (1);
  1456. }
  1457. /* Concatenate DIR to the end of REPOSITORY. */
  1458. if (repository[0] == '\0')
  1459. {
  1460. char *new = xstrdup (dir);
  1461. free (repository);
  1462. repository = new;
  1463. }
  1464. else
  1465. {
  1466. char *new = xmalloc (strlen (repository) + strlen (dir) + 10);
  1467. strcpy (new, repository);
  1468. (void) strcat (new, "/");
  1469. (void) strcat (new, dir);
  1470. free (repository);
  1471. repository = new;
  1472. }
  1473. if (!quiet && !current_parsed_root->isremote)
  1474. error (0, 0, "Importing %s", repository);
  1475. if ( CVS_CHDIR (dir) < 0)
  1476. {
  1477. ierrno = errno;
  1478. fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", dir);
  1479. error (0, ierrno, "ERROR: cannot chdir to %s", dir);
  1480. err = 1;
  1481. goto out;
  1482. }
  1483. if (!current_parsed_root->isremote && !isdir (repository))
  1484. {
  1485. rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5);
  1486. (void) sprintf (rcs, "%s%s", repository, RCSEXT);
  1487. if (isfile (repository) || isfile(rcs))
  1488. {
  1489. fperrmsg (logfp, 0, 0,
  1490. "ERROR: %s is a file, should be a directory!",
  1491. repository);
  1492. error (0, 0, "ERROR: %s is a file, should be a directory!",
  1493. repository);
  1494. err = 1;
  1495. goto out;
  1496. }
  1497. if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0)
  1498. {
  1499. ierrno = errno;
  1500. fperrmsg (logfp, 0, ierrno,
  1501. "ERROR: cannot mkdir %s -- not added", repository);
  1502. error (0, ierrno,
  1503. "ERROR: cannot mkdir %s -- not added", repository);
  1504. err = 1;
  1505. goto out;
  1506. }
  1507. }
  1508. err = import_descend (message, vtag, targc, targv);
  1509. out:
  1510. if (rcs != NULL)
  1511. free (rcs);
  1512. if ((cp = strrchr (repository, '/')) != NULL)
  1513. *cp = '\0';
  1514. else
  1515. repository[0] = '\0';
  1516. if (restore_cwd (&cwd, NULL))
  1517. error_exit ();
  1518. free_cwd (&cwd);
  1519. return (err);
  1520. }