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 * Add
14 *
15 * Adds a file or directory to the RCS source repository. For a file,
16 * the entry is marked as "needing to be added" in the user's own CVS
17 * directory, and really added to the repository when it is committed.
18 * For a directory, it is added at the appropriate place in the source
19 * repository and a CVS directory is generated within the directory.
20 *
21 * The -m option is currently the only supported option. Some may wish to
22 * supply standard "rcs" options here, but I've found that this causes more
23 * trouble than anything else.
24 *
25 * The user files or directories must already exist. For a directory, it must
26 * not already have a CVS file in it.
27 *
28 * An "add" on a file that has been "remove"d but not committed will cause the
29 * file to be resurrected.
30 */
31
32 #include <assert.h>
33 #include "cvs.h"
34 #include "savecwd.h"
35 #include "fileattr.h"
36
37 static int add_directory PROTO ((struct file_info *finfo));
38 static int build_entry PROTO((const char *repository, const char *user,
39 const char *options, const char *message,
40 List * entries, const char *tag));
41
42 static const char *const add_usage[] =
43 {
44 "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
45 "\t-k rcs-kflag\tUse \"rcs-kflag\" to add the file with the specified\n",
46 "\t\t\tkflag.\n",
47 "\t-m message\tUse \"message\" for the creation log.\n",
48 "(Specify the --help global option for a list of other help options)\n",
49 NULL
50 };
51
52 int
add(argc,argv)53 add (argc, argv)
54 int argc;
55 char **argv;
56 {
57 char *message = NULL;
58 int i;
59 char *repository;
60 int c;
61 int err = 0;
62 int added_files = 0;
63 char *options = NULL;
64 List *entries;
65 Vers_TS *vers;
66 struct saved_cwd cwd;
67 /* Nonzero if we found a slash, and are thus adding files in a
68 subdirectory. */
69 int found_slash = 0;
70 size_t cvsroot_len;
71
72 if (argc == 1 || argc == -1)
73 usage (add_usage);
74
75 wrap_setup ();
76
77 /* parse args */
78 optind = 0;
79 while ((c = getopt (argc, argv, "+k:m:")) != -1)
80 {
81 switch (c)
82 {
83 case 'k':
84 if (options) free (options);
85 options = RCS_check_kflag (optarg);
86 break;
87
88 case 'm':
89 if (message) free (message);
90 message = xstrdup (optarg);
91 break;
92 case '?':
93 default:
94 usage (add_usage);
95 break;
96 }
97 }
98 argc -= optind;
99 argv += optind;
100
101 if (argc <= 0)
102 usage (add_usage);
103
104 cvsroot_len = strlen (current_parsed_root->directory);
105
106 /* First some sanity checks. I know that the CVS case is (sort of)
107 also handled by add_directory, but we need to check here so the
108 client won't get all confused in send_file_names. */
109 for (i = 0; i < argc; i++)
110 {
111 int skip_file = 0;
112
113 /* If it were up to me I'd probably make this a fatal error.
114 But some people are really fond of their "cvs add *", and
115 don't seem to object to the warnings.
116 Whatever. */
117 strip_trailing_slashes (argv[i]);
118 if (strcmp (argv[i], ".") == 0
119 || strcmp (argv[i], "..") == 0
120 || fncmp (last_component(argv[i]), CVSADM) == 0)
121 {
122 if (!quiet)
123 error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
124 skip_file = 1;
125 }
126 else
127 {
128 char *p;
129 p = argv[i];
130 while (*p != '\0')
131 {
132 if (ISDIRSEP (*p))
133 {
134 found_slash = 1;
135 break;
136 }
137 ++p;
138 }
139 }
140
141 if (skip_file)
142 {
143 int j;
144
145 /* FIXME: We don't do anything about free'ing argv[i]. But
146 the problem is that it is only sometimes allocated (see
147 cvsrc.c). */
148
149 for (j = i; j < argc - 1; ++j)
150 argv[j] = argv[j + 1];
151 --argc;
152 /* Check the new argv[i] again. */
153 --i;
154 ++err;
155 }
156 }
157
158 #ifdef CLIENT_SUPPORT
159 if (current_parsed_root->isremote)
160 {
161 int j;
162
163 if (argc == 0)
164 {
165 /* We snipped out all the arguments in the above sanity
166 check. We can just forget the whole thing (and we
167 better, because if we fired up the server and passed it
168 nothing, it would spit back a usage message). */
169 if (options)
170 free (options);
171 if (message)
172 free (message);
173 return err;
174 }
175
176 start_server ();
177 ign_setup ();
178 if (options)
179 {
180 send_arg (options);
181 free (options);
182 }
183 option_with_arg ("-m", message);
184 send_arg ("--");
185
186 /* If !found_slash, refrain from sending "Directory", for
187 CVS 1.9 compatibility. If we only tried to deal with servers
188 which are at least CVS 1.9.26 or so, we wouldn't have to
189 special-case this. */
190 if (found_slash)
191 {
192 repository = Name_Repository (NULL, NULL);
193 send_a_repository ("", repository, "");
194 free (repository);
195 }
196
197 for (j = 0; j < argc; ++j)
198 {
199 /* FIXME: Does this erroneously call Create_Admin in error
200 conditions which are only detected once the server gets its
201 hands on things? */
202 if (isdir (argv[j]))
203 {
204 char *tag;
205 char *date;
206 int nonbranch;
207 char *rcsdir;
208 char *p;
209 char *update_dir;
210 /* This is some mungeable storage into which we can point
211 with p and/or update_dir. */
212 char *filedir;
213
214 if (save_cwd (&cwd))
215 error_exit ();
216
217 filedir = xstrdup (argv[j]);
218 /* Deliberately discard the const below since we know we just
219 * allocated filedir and can do what we like with it.
220 */
221 p = (char *)last_component (filedir);
222 if (p == filedir)
223 {
224 update_dir = "";
225 }
226 else
227 {
228 p[-1] = '\0';
229 update_dir = filedir;
230 if (CVS_CHDIR (update_dir) < 0)
231 error (1, errno,
232 "could not chdir to %s", update_dir);
233 }
234
235 /* find the repository associated with our current dir */
236 repository = Name_Repository (NULL, update_dir);
237
238 /* don't add stuff to Emptydir */
239 if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
240 && ISDIRSEP (repository[cvsroot_len])
241 && strncmp (repository + cvsroot_len + 1,
242 CVSROOTADM,
243 sizeof CVSROOTADM - 1) == 0
244 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
245 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
246 CVSNULLREPOS) == 0)
247 error (1, 0, "cannot add to %s", repository);
248
249 /* before we do anything else, see if we have any
250 per-directory tags */
251 ParseTag (&tag, &date, &nonbranch);
252
253 rcsdir = xmalloc (strlen (repository) + strlen (p) + 5);
254 sprintf (rcsdir, "%s/%s", repository, p);
255
256 Create_Admin (p, argv[j], rcsdir, tag, date,
257 nonbranch, 0, 1);
258
259 if (found_slash)
260 send_a_repository ("", repository, update_dir);
261
262 if (restore_cwd (&cwd, NULL))
263 error_exit ();
264 free_cwd (&cwd);
265
266 if (tag)
267 free (tag);
268 if (date)
269 free (date);
270 free (rcsdir);
271
272 if (p == filedir)
273 Subdir_Register ((List *) NULL, (char *) NULL, argv[j]);
274 else
275 {
276 Subdir_Register ((List *) NULL, update_dir, p);
277 }
278 free (repository);
279 free (filedir);
280 }
281 }
282 send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
283 send_file_names (argc, argv, SEND_EXPAND_WILD);
284 send_to_server ("add\012", 0);
285 if (message)
286 free (message);
287 return err + get_responses_and_close ();
288 }
289 #endif
290
291 /* walk the arg list adding files/dirs */
292 for (i = 0; i < argc; i++)
293 {
294 int begin_err = err;
295 #ifdef SERVER_SUPPORT
296 int begin_added_files = added_files;
297 #endif
298 struct file_info finfo;
299 char *filename, *p;
300
301 memset (&finfo, 0, sizeof finfo);
302
303 if (save_cwd (&cwd))
304 error_exit ();
305
306 finfo.fullname = xstrdup (argv[i]);
307 filename = xstrdup (argv[i]);
308 /* We know we can discard the const below since we just allocated
309 * filename and can do as we like with it.
310 */
311 p = (char *)last_component (filename);
312 if (p == filename)
313 {
314 finfo.update_dir = "";
315 finfo.file = p;
316 }
317 else
318 {
319 p[-1] = '\0';
320 finfo.update_dir = filename;
321 finfo.file = p;
322 if (CVS_CHDIR (finfo.update_dir) < 0)
323 error (1, errno, "could not chdir to %s", finfo.update_dir);
324 }
325
326 /* Add wrappers for this directory. They exist only until
327 the next call to wrap_add_file. */
328 wrap_add_file (CVSDOTWRAPPER, 1);
329
330 finfo.rcs = NULL;
331
332 /* Find the repository associated with our current dir. */
333 repository = Name_Repository (NULL, finfo.update_dir);
334
335 /* don't add stuff to Emptydir */
336 if (strncmp (repository, current_parsed_root->directory,
337 cvsroot_len) == 0
338 && ISDIRSEP (repository[cvsroot_len])
339 && strncmp (repository + cvsroot_len + 1,
340 CVSROOTADM,
341 sizeof CVSROOTADM - 1) == 0
342 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
343 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
344 CVSNULLREPOS) == 0)
345 error (1, 0, "cannot add to %s", repository);
346
347 entries = Entries_Open (0, NULL);
348
349 finfo.repository = repository;
350 finfo.entries = entries;
351
352 /* We pass force_tag_match as 1. If the directory has a
353 sticky branch tag, and there is already an RCS file which
354 does not have that tag, then the head revision is
355 meaningless to us. */
356 vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
357
358 if (vers->vn_user == NULL)
359 {
360 /* No entry available, ts_rcs is invalid */
361 if (vers->vn_rcs == NULL)
362 {
363 /* There is no RCS file either */
364 if (vers->ts_user == NULL)
365 {
366 /* There is no user file either */
367 error (0, 0, "nothing known about %s", finfo.fullname);
368 err++;
369 }
370 else if (!isdir (finfo.file)
371 || wrap_name_has (finfo.file, WRAP_TOCVS))
372 {
373 /*
374 * See if a directory exists in the repository with
375 * the same name. If so, blow this request off.
376 */
377 char *dname = xmalloc (strlen (repository)
378 + strlen (finfo.file)
379 + 10);
380 (void) sprintf (dname, "%s/%s", repository, finfo.file);
381 if (isdir (dname))
382 {
383 error (0, 0,
384 "cannot add file `%s' since the directory",
385 finfo.fullname);
386 error (0, 0, "`%s' already exists in the repository",
387 dname);
388 error (1, 0, "illegal filename overlap");
389 }
390 free (dname);
391
392 if (vers->options == NULL || *vers->options == '\0')
393 {
394 /* No options specified on command line (or in
395 rcs file if it existed, e.g. the file exists
396 on another branch). Check for a value from
397 the wrapper stuff. */
398 if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
399 {
400 if (vers->options)
401 free (vers->options);
402 vers->options = wrap_rcsoption (finfo.file, 1);
403 }
404 }
405
406 if (vers->nonbranch)
407 {
408 error (0, 0,
409 "cannot add file on non-branch tag %s",
410 vers->tag);
411 ++err;
412 }
413 else
414 {
415 /* There is a user file, so build the entry for it */
416 if (build_entry (repository, finfo.file, vers->options,
417 message, entries, vers->tag) != 0)
418 err++;
419 else
420 {
421 added_files++;
422 if (!quiet)
423 {
424 if (vers->tag)
425 error (0, 0, "\
426 scheduling %s `%s' for addition on branch `%s'",
427 (wrap_name_has (finfo.file,
428 WRAP_TOCVS)
429 ? "wrapper"
430 : "file"),
431 finfo.fullname, vers->tag);
432 else
433 error (0, 0,
434 "scheduling %s `%s' for addition",
435 (wrap_name_has (finfo.file,
436 WRAP_TOCVS)
437 ? "wrapper"
438 : "file"),
439 finfo.fullname);
440 }
441 }
442 }
443 }
444 }
445 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
446 {
447 if (isdir (finfo.file)
448 && !wrap_name_has (finfo.file, WRAP_TOCVS))
449 {
450 error (0, 0, "\
451 the directory `%s' cannot be added because a file of the", finfo.fullname);
452 error (1, 0, "\
453 same name already exists in the repository.");
454 }
455 else
456 {
457 if (vers->nonbranch)
458 {
459 error (0, 0,
460 "cannot add file on non-branch tag %s",
461 vers->tag);
462 ++err;
463 }
464 else
465 {
466 char *timestamp = NULL;
467 if (vers->ts_user == NULL)
468 {
469 /* If this file does not exist locally, assume that
470 * the last version on the branch is being
471 * resurrected.
472 *
473 * Compute previous revision. We assume that it
474 * exists and that it is not a revision on the
475 * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We
476 * also assume that it is not dead, which seems
477 * fair since we know vers->vn_rcs is dead
478 * and we shouldn't see two dead revisions in a
479 * row.
480 */
481 char *prev = previous_rev (vers->srcfile,
482 vers->vn_rcs);
483 int status;
484 if (prev == NULL)
485 {
486 /* There is no previous revision. Either:
487 *
488 * * Revision 1.1 was dead, as when a file was
489 * inititially added on a branch,
490 *
491 * or
492 *
493 * * All previous revisions have been deleted.
494 * For instance, via `admin -o'.
495 */
496 if (!really_quiet)
497 error (0, 0,
498 "File `%s' has no previous revision to resurrect.",
499 finfo.fullname);
500 free (prev);
501 goto skip_this_file;
502 }
503 if (!quiet)
504 error (0, 0,
505 "Resurrecting file `%s' from revision %s.",
506 finfo.fullname, prev);
507 status = RCS_checkout (vers->srcfile, finfo.file,
508 prev, vers->tag,
509 vers->options, RUN_TTY,
510 NULL, NULL);
511 xchmod (finfo.file, 1);
512 if (status != 0)
513 {
514 error (0, 0, "Failed to resurrect revision %s",
515 prev);
516 err++;
517 }
518 else
519 {
520 /* I don't actually set vers->ts_user here
521 * because it would confuse server_update().
522 */
523 timestamp = time_stamp (finfo.file);
524 if (!really_quiet)
525 write_letter (&finfo, 'U');
526 }
527 free (prev);
528 }
529 if (!quiet)
530 {
531 if (vers->tag)
532 error (0, 0,
533 "file `%s' will be added on branch `%s' from version %s",
534 finfo.fullname, vers->tag,
535 vers->vn_rcs);
536 else
537 /* I'm not sure that mentioning
538 vers->vn_rcs makes any sense here; I
539 can't think of a way to word the
540 message which is not confusing. */
541 error (0, 0,
542 "Re-adding file `%s' (in place of dead revision %s).",
543 finfo.fullname, vers->vn_rcs);
544 }
545 Register (entries, finfo.file, "0",
546 timestamp ? timestamp : vers->ts_user,
547 vers->options, vers->tag, vers->date, NULL);
548 if (timestamp) free (timestamp);
549 #ifdef SERVER_SUPPORT
550 if (server_active && vers->ts_user == NULL)
551 {
552 /* If we resurrected the file from the archive, we
553 * need to tell the client about it.
554 */
555 server_updated (&finfo, vers,
556 SERVER_UPDATED,
557 (mode_t) -1, NULL, NULL);
558 /* This is kinda hacky or, at least, it renders the
559 * name "begin_added_files" obsolete, but we want
560 * the added_files to be counted without triggering
561 * the check that causes server_checked_in() to be
562 * called below since we have already called
563 * server_updated() to complete the resurrection.
564 */
565 ++begin_added_files;
566 }
567 #endif
568 ++added_files;
569 }
570 }
571 }
572 else
573 {
574 /*
575 * There is an RCS file already, so somebody else must've
576 * added it
577 */
578 error (0, 0, "%s added independently by second party",
579 finfo.fullname);
580 err++;
581 }
582 }
583 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
584 {
585
586 /*
587 * An entry for a new-born file, ts_rcs is dummy, but that is
588 * inappropriate here
589 */
590 if (!quiet)
591 error (0, 0, "%s has already been entered", finfo.fullname);
592 err++;
593 }
594 else if (vers->vn_user[0] == '-')
595 {
596 /* An entry for a removed file, ts_rcs is invalid */
597 if (vers->ts_user == NULL)
598 {
599 /* There is no user file (as it should be) */
600 if (vers->vn_rcs == NULL)
601 {
602
603 /*
604 * There is no RCS file, so somebody else must've removed
605 * it from under us
606 */
607 error (0, 0, "\
608 cannot resurrect %s; RCS file removed by second party", finfo.fullname);
609 err++;
610 }
611 else
612 {
613 int status;
614 /*
615 * There is an RCS file, so remove the "-" from the
616 * version number and restore the file
617 */
618 char *tmp = xmalloc (strlen (vers->vn_user));
619 (void) strcpy (tmp, vers->vn_user + 1);
620 (void) strcpy (vers->vn_user, tmp);
621 free(tmp);
622 status = RCS_checkout (vers->srcfile, finfo.file,
623 vers->vn_user, vers->tag,
624 vers->options, RUN_TTY,
625 NULL, NULL);
626 xchmod (finfo.file, 1);
627 if (status != 0)
628 {
629 error (0, 0, "Failed to resurrect revision %s",
630 vers->vn_user);
631 err++;
632 tmp = NULL;
633 }
634 else
635 {
636 /* I don't actually set vers->ts_user here because it
637 * would confuse server_update().
638 */
639 tmp = time_stamp (finfo.file);
640 write_letter (&finfo, 'U');
641 if (!quiet)
642 error (0, 0, "%s, version %s, resurrected",
643 finfo.fullname, vers->vn_user);
644 }
645 Register (entries, finfo.file, vers->vn_user,
646 tmp, vers->options,
647 vers->tag, vers->date, NULL);
648 if (tmp) free (tmp);
649 #ifdef SERVER_SUPPORT
650 if (server_active)
651 {
652 /* If we resurrected the file from the archive, we
653 * need to tell the client about it.
654 */
655 server_updated (&finfo, vers,
656 SERVER_UPDATED,
657 (mode_t) -1, NULL, NULL);
658 }
659 /* We don't increment added_files here because this isn't
660 * a change that needs to be committed.
661 */
662 #endif
663 }
664 }
665 else
666 {
667 /* The user file shouldn't be there */
668 error (0, 0, "\
669 %s should be removed and is still there (or is back again)", finfo.fullname);
670 err++;
671 }
672 }
673 else
674 {
675 /* A normal entry, ts_rcs is valid, so it must already be there */
676 if (!quiet)
677 error (0, 0, "%s already exists, with version number %s",
678 finfo.fullname,
679 vers->vn_user);
680 err++;
681 }
682 freevers_ts (&vers);
683
684 /* passed all the checks. Go ahead and add it if its a directory */
685 if (begin_err == err
686 && isdir (finfo.file)
687 && !wrap_name_has (finfo.file, WRAP_TOCVS))
688 {
689 err += add_directory (&finfo);
690 }
691 else
692 {
693 #ifdef SERVER_SUPPORT
694 if (server_active && begin_added_files != added_files)
695 server_checked_in (finfo.file, finfo.update_dir, repository);
696 #endif
697 }
698
699 skip_this_file:
700 free (repository);
701 Entries_Close (entries);
702
703 if (restore_cwd (&cwd, NULL))
704 error_exit ();
705 free_cwd (&cwd);
706
707 /* It's okay to discard the const to free this - we allocated this
708 * above. The const is for everybody else.
709 */
710 free ((char *) finfo.fullname);
711 free ((char *) filename);
712 }
713 if (added_files && !really_quiet)
714 error (0, 0, "use '%s commit' to add %s permanently",
715 program_name,
716 (added_files == 1) ? "this file" : "these files");
717
718 if (message)
719 free (message);
720 if (options)
721 free (options);
722
723 return err;
724 }
725
726
727
728 /*
729 * The specified user file is really a directory. So, let's make sure that
730 * it is created in the RCS source repository, and that the user's directory
731 * is updated to include a CVS directory.
732 *
733 * Returns 1 on failure, 0 on success.
734 */
735 static int
add_directory(finfo)736 add_directory (finfo)
737 struct file_info *finfo;
738 {
739 const char *repository = finfo->repository;
740 List *entries = finfo->entries;
741 const char *dir = finfo->file;
742
743 char *rcsdir = NULL;
744 struct saved_cwd cwd;
745 char *message = NULL;
746 char *tag, *date;
747 int nonbranch;
748 char *attrs;
749
750 if (strchr (dir, '/') != NULL)
751 {
752 /* "Can't happen". */
753 error (0, 0,
754 "directory %s not added; must be a direct sub-directory", dir);
755 return 1;
756 }
757 if (fncmp (dir, CVSADM) == 0)
758 {
759 error (0, 0, "cannot add a `%s' directory", CVSADM);
760 return 1;
761 }
762
763 /* before we do anything else, see if we have any per-directory tags */
764 ParseTag (&tag, &date, &nonbranch);
765
766 /* Remember the default attributes from this directory, so we can apply
767 them to the new directory. */
768 fileattr_startdir (repository);
769 attrs = fileattr_getall (NULL);
770 fileattr_free ();
771
772 /* now, remember where we were, so we can get back */
773 if (save_cwd (&cwd))
774 return 1;
775 if (CVS_CHDIR (dir) < 0)
776 {
777 error (0, errno, "cannot chdir to %s", finfo->fullname);
778 return 1;
779 }
780 if (!server_active && isfile (CVSADM))
781 {
782 error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
783 goto out;
784 }
785
786 rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5);
787 sprintf (rcsdir, "%s/%s", repository, dir);
788 if (isfile (rcsdir) && !isdir (rcsdir))
789 {
790 error (0, 0, "%s is not a directory; %s not added", rcsdir,
791 finfo->fullname);
792 goto out;
793 }
794
795 /* setup the log message */
796 message = xmalloc (strlen (rcsdir)
797 + 80
798 + (tag == NULL ? 0 : strlen (tag) + 80)
799 + (date == NULL ? 0 : strlen (date) + 80));
800 (void) sprintf (message, "Directory %s added to the repository\n",
801 rcsdir);
802 if (tag)
803 {
804 (void) strcat (message, "--> Using per-directory sticky tag `");
805 (void) strcat (message, tag);
806 (void) strcat (message, "'\n");
807 }
808 if (date)
809 {
810 (void) strcat (message, "--> Using per-directory sticky date `");
811 (void) strcat (message, date);
812 (void) strcat (message, "'\n");
813 }
814
815 if (!isdir (rcsdir))
816 {
817 mode_t omask;
818 Node *p;
819 List *ulist;
820 struct logfile_info *li;
821
822 /* There used to be some code here which would prompt for
823 whether to add the directory. The details of that code had
824 bitrotted, but more to the point it can't work
825 client/server, doesn't ask in the right way for GUIs, etc.
826 A better way of making it harder to accidentally add
827 directories would be to have to add and commit directories
828 like for files. The code was #if 0'd at least since CVS 1.5. */
829
830 if (!noexec)
831 {
832 omask = umask (cvsumask);
833 if (CVS_MKDIR (rcsdir, 0777) < 0)
834 {
835 error (0, errno, "cannot mkdir %s", rcsdir);
836 (void) umask (omask);
837 goto out;
838 }
839 (void) umask (omask);
840 }
841
842 /* Now set the default file attributes to the ones we inherited
843 from the parent directory. */
844 fileattr_startdir (rcsdir);
845 fileattr_setall (NULL, attrs);
846 fileattr_write ();
847 fileattr_free ();
848 if (attrs != NULL)
849 {
850 free (attrs);
851 attrs = NULL;
852 }
853
854 /*
855 * Set up an update list with a single title node for Update_Logfile
856 */
857 ulist = getlist ();
858 p = getnode ();
859 p->type = UPDATE;
860 p->delproc = update_delproc;
861 p->key = xstrdup ("- New directory");
862 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
863 li->type = T_TITLE;
864 li->tag = xstrdup (tag);
865 li->rev_old = li->rev_new = NULL;
866 p->data = li;
867 (void) addnode (ulist, p);
868 Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
869 dellist (&ulist);
870 }
871
872 if (!server_active)
873 Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
874 if (tag)
875 free (tag);
876 if (date)
877 free (date);
878
879 if (restore_cwd (&cwd, NULL))
880 error_exit ();
881 free_cwd (&cwd);
882
883 Subdir_Register (entries, (char *) NULL, dir);
884
885 if (!really_quiet)
886 cvs_output (message, 0);
887
888 free (rcsdir);
889 free (message);
890 if (attrs != NULL)
891 free (attrs);
892
893 return 0;
894
895 out:
896 if (restore_cwd (&cwd, NULL))
897 error_exit ();
898 free_cwd (&cwd);
899 if (message) free (message);
900 if (rcsdir != NULL)
901 free (rcsdir);
902 return 0;
903 }
904
905
906
907 /*
908 * Builds an entry for a new file and sets up "CVS/file",[pt] by
909 * interrogating the user. Returns non-zero on error.
910 */
911 static int
build_entry(repository,user,options,message,entries,tag)912 build_entry (repository, user, options, message, entries, tag)
913 const char *repository;
914 const char *user;
915 const char *options;
916 const char *message;
917 List *entries;
918 const char *tag;
919 {
920 char *fname;
921 char *line;
922 FILE *fp;
923
924 if (noexec)
925 return 0;
926
927 /*
928 * The requested log is read directly from the user and stored in the
929 * file user,t. If the "message" argument is set, use it as the
930 * initial creation log (which typically describes the file).
931 */
932 fname = xmalloc (strlen (user) + 80);
933 (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
934 fp = open_file (fname, "w+");
935 if (message && fputs (message, fp) == EOF)
936 error (1, errno, "cannot write to %s", fname);
937 if (fclose(fp) == EOF)
938 error(1, errno, "cannot close %s", fname);
939 free (fname);
940
941 /*
942 * Create the entry now, since this allows the user to interrupt us above
943 * without needing to clean anything up (well, we could clean up the
944 * ,t file, but who cares).
945 */
946 line = xmalloc (strlen (user) + 20);
947 (void) sprintf (line, "Initial %s", user);
948 Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);
949 free (line);
950 return 0;
951 }
952