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