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