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