2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
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.
15 * "commit" commits the present version to the RCS repository, AFTER
16 * having done a test on conflicts.
18 * The call is: cvs commit [options] files...
28 static Dtype
check_direntproc (void *callerdat
, const char *dir
,
29 const char *repos
, const char *update_dir
,
31 static int check_fileproc (void *callerdat
, struct file_info
*finfo
);
32 static int check_filesdoneproc (void *callerdat
, int err
, const char *repos
,
33 const char *update_dir
, List
*entries
);
34 static int checkaddfile (const char *file
, const char *repository
,
35 const char *tag
, const char *options
,
37 static Dtype
commit_direntproc (void *callerdat
, const char *dir
,
38 const char *repos
, const char *update_dir
,
40 static int commit_dirleaveproc (void *callerdat
, const char *dir
, int err
,
41 const char *update_dir
, List
*entries
);
42 static int commit_fileproc (void *callerdat
, struct file_info
*finfo
);
43 static int commit_filesdoneproc (void *callerdat
, int err
,
44 const char *repository
,
45 const char *update_dir
, List
*entries
);
46 static int finaladd (struct file_info
*finfo
, char *revision
, char *tag
,
48 static int findmaxrev (Node
* p
, void *closure
);
49 static int lock_RCS (const char *user
, RCSNode
*rcs
, const char *rev
,
50 const char *repository
);
51 static int precommit_list_to_args_proc (Node
* p
, void *closure
);
52 static int precommit_proc (const char *repository
, const char *filter
,
54 static int remove_file (struct file_info
*finfo
, char *tag
,
56 static void fixaddfile (const char *rcs
);
57 static void fixbranch (RCSNode
*, char *branch
);
58 static void unlockrcs (RCSNode
*rcs
);
59 static void ci_delproc (Node
*p
);
60 static void masterlist_delproc (Node
*p
);
64 Ctype status
; /* as returned from Classify_File() */
65 char *rev
; /* a numeric rev, if we know it */
66 char *tag
; /* any sticky tag, or -r option */
67 char *options
; /* Any sticky -k option */
71 List
*ulist
; /* list for Update_Logfile */
72 List
*cilist
; /* list with commit_info structs */
75 static int check_valid_edit
= 0;
76 static int force_ci
= 0;
77 static int got_message
;
79 static char *saved_tag
;
80 static char *write_dirtag
;
81 static int write_dirnonbranch
;
84 static char *saved_message
;
85 static time_t last_register_time
;
87 static const char *const commit_usage
[] =
89 "Usage: %s %s [-cRlf] [-m msg | -F logfile] [-r rev] files...\n",
90 " -c Check for valid edits before committing.\n",
91 " -R Process directories recursively.\n",
92 " -l Local directory only (not recursive).\n",
93 " -f Force the file to be committed; disables recursion.\n",
94 " -F logfile Read the log message from file.\n",
95 " -m msg Log message.\n",
96 " -r rev Commit to this branch or trunk revision.\n",
97 "(Specify the --help global option for a list of other help options)\n",
101 #ifdef CLIENT_SUPPORT
102 /* Identify a file which needs "? foo" or a Questionable request. */
105 /* The two fields for the Directory request. */
112 struct question
*next
;
121 /* This is used from dirent to filesdone time, for each directory,
122 to make a list of files we have already seen. */
125 /* Linked list of files which need "? foo" or a Questionable request. */
126 struct question
*questionables
;
128 /* Only good within functions called from the filesdoneproc. Stores
129 the repository (pointer into storage managed by the recursion
131 const char *repository
;
133 /* Non-zero if we should force the commit. This is enabled by
134 either -f or -r options, unlike force_ci which is just -f. */
141 find_dirent_proc (void *callerdat
, const char *dir
, const char *repository
,
142 const char *update_dir
, List
*entries
)
144 struct find_data
*find_data
= callerdat
;
146 /* This check seems to slowly be creeping throughout CVS (update
147 and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
148 is that it (or some variant thereof) should go in all the
149 dirent procs. Unless someone has some better idea... */
153 /* initialize the ignore list for this directory */
154 find_data
->ignlist
= getlist ();
156 /* Print the same warm fuzzy as in check_direntproc, since that
157 code will never be run during client/server operation and we
158 want the messages to match. */
160 error (0, 0, "Examining %s", update_dir
);
167 /* Here as a static until we get around to fixing ignore_files to pass
168 it along as an argument. */
169 static struct find_data
*find_data_static
;
174 find_ignproc (const char *file
, const char *dir
)
178 p
= xmalloc (sizeof (struct question
));
179 p
->dir
= xstrdup (dir
);
180 p
->repos
= xstrdup (find_data_static
->repository
);
181 p
->file
= xstrdup (file
);
182 p
->next
= find_data_static
->questionables
;
183 find_data_static
->questionables
= p
;
189 find_filesdoneproc (void *callerdat
, int err
, const char *repository
,
190 const char *update_dir
, List
*entries
)
192 struct find_data
*find_data
= callerdat
;
193 find_data
->repository
= repository
;
195 /* if this directory has an ignore list, process it then free it */
196 if (find_data
->ignlist
)
198 find_data_static
= find_data
;
199 ignore_files (find_data
->ignlist
, entries
, update_dir
, find_ignproc
);
200 dellist (&find_data
->ignlist
);
203 find_data
->repository
= NULL
;
210 /* Machinery to find out what is modified, added, and removed. It is
211 possible this should be broken out into a new client_classify function;
212 merging it with classify_file is almost sure to be a mess, though,
213 because classify_file has all kinds of repository processing. */
215 find_fileproc (void *callerdat
, struct file_info
*finfo
)
218 enum classify_type status
;
220 struct find_data
*args
= callerdat
;
221 struct logfile_info
*data
;
222 struct file_info xfinfo
;
224 /* if this directory has an ignore list, add this file to it */
231 p
->key
= xstrdup (finfo
->file
);
232 if (addnode (args
->ignlist
, p
) != 0)
237 xfinfo
.repository
= NULL
;
240 vers
= Version_TS (&xfinfo
, NULL
, saved_tag
, NULL
, 0, 0);
241 if (vers
->vn_user
== NULL
)
243 if (vers
->ts_user
== NULL
)
244 error (0, 0, "nothing known about `%s'", finfo
->fullname
);
246 error (0, 0, "use `%s add' to create an entry for `%s'",
247 program_name
, finfo
->fullname
);
251 if (vers
->vn_user
[0] == '-')
253 if (vers
->ts_user
!= NULL
)
256 "`%s' should be removed and is still there (or is back"
257 " again)", finfo
->fullname
);
264 else if (strcmp (vers
->vn_user
, "0") == 0)
266 if (vers
->ts_user
== NULL
)
268 /* This happens when one has `cvs add'ed a file, but it no
269 longer exists in the working directory at commit time.
270 FIXME: What classify_file does in this case is print
271 "new-born %s has disappeared" and removes the entry.
272 We probably should do the same. */
274 error (0, 0, "warning: new-born %s has disappeared",
276 status
= T_REMOVE_ENTRY
;
281 else if (vers
->ts_user
== NULL
)
283 /* FIXME: What classify_file does in this case is print
284 "%s was lost". We probably should do the same. */
288 else if (vers
->ts_rcs
!= NULL
289 && (args
->force
|| strcmp (vers
->ts_user
, vers
->ts_rcs
) != 0))
290 /* If we are forcing commits, pretend that the file is
295 /* This covers unmodified files, as well as a variety of other
296 cases. FIXME: we probably should be printing a message and
297 returning 1 for many of those cases (but I'm not sure
298 exactly which ones). */
304 node
->key
= xstrdup (finfo
->fullname
);
306 data
= xmalloc (sizeof (struct logfile_info
));
308 data
->tag
= xstrdup (vers
->tag
);
309 data
->rev_old
= data
->rev_new
= NULL
;
312 node
->delproc
= update_delproc
;
314 (void)addnode (args
->ulist
, node
);
325 copy_ulist (Node
*node
, void *data
)
327 struct find_data
*args
= data
;
328 args
->argv
[args
->argc
++] = node
->key
;
331 #endif /* CLIENT_SUPPORT */
335 #ifdef SERVER_SUPPORT
336 # define COMMIT_OPTIONS "+cnlRm:fF:r:"
337 #else /* !SERVER_SUPPORT */
338 # define COMMIT_OPTIONS "+clRm:fF:r:"
339 #endif /* SERVER_SUPPORT */
341 commit (int argc
, char **argv
)
348 usage (commit_usage
);
352 * For log purposes, do not allow "root" to commit files. If you look
353 * like root, but are really logged in as a non-root user, it's OK.
355 /* FIXME: Shouldn't this check be much more closely related to the
356 readonly user stuff (CVSROOT/readers, &c). That is, why should
357 root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
358 /* Who we are on the client side doesn't affect logging. */
359 if (geteuid () == (uid_t
) 0 && !current_parsed_root
->isremote
)
363 if ((pw
= getpwnam (getcaller ())) == NULL
)
365 "your apparent username (%s) is unknown to this system",
367 if (pw
->pw_uid
== (uid_t
) 0)
368 error (1, 0, "'root' is not allowed to commit files");
370 #endif /* CVS_BADROOT */
373 while ((c
= getopt (argc
, argv
, COMMIT_OPTIONS
)) != -1)
378 check_valid_edit
= 1;
380 #ifdef SERVER_SUPPORT
382 /* Silently ignore -n for compatibility with old
386 #endif /* SERVER_SUPPORT */
388 #ifdef FORCE_USE_EDITOR
395 free (saved_message
);
396 saved_message
= NULL
;
399 saved_message
= xstrdup (optarg
);
404 saved_tag
= xstrdup (optarg
);
414 check_valid_edit
= 0;
415 local
= 1; /* also disable recursion */
418 #ifdef FORCE_USE_EDITOR
427 usage (commit_usage
);
434 /* numeric specified revision means we ignore sticky tags... */
435 if (saved_tag
&& isdigit ((unsigned char) *saved_tag
))
437 char *p
= saved_tag
+ strlen (saved_tag
);
439 /* strip trailing dots and leading zeros */
440 while (*--p
== '.') ;
442 while (saved_tag
[0] == '0' && isdigit ((unsigned char) saved_tag
[1]))
446 /* Check if the user passed -m, but wanted -F */
451 fd
= open(saved_message
, O_RDONLY
);
452 /* valid fd -> possibly wrong flag? */
456 size_t line_alloced
= 0;
462 printf("The message you passed exists as a file\n");
463 printf("a)bort, c)ontinue, treat as f)ile name\n");
464 printf("Action: (abort) ");
466 line_len
= getline(&line
, &line_alloced
, stdin
);
469 error(0, errno
, "cannot read from stdin");
470 error(1, 0, "aborting");
472 else if (line_len
== 0 || *line
== '\n' || *line
== 'a' || *line
== 'A')
474 error(1, 0, "aborted by user");
476 else if (*line
== 'c' || *line
== 'C')
480 else if (*line
== 'f' || *line
== 'F')
483 * We are leaking the memory for the file name,
484 * but who really cares?
486 logfile
= saved_message
;
487 saved_message
= NULL
;
490 printf("Unknown input\n");
498 /* some checks related to the "-F logfile" option */
501 size_t size
= 0, len
;
504 error (1, 0, "cannot specify both a message and a log file");
506 get_file (logfile
, logfile
, "r", &saved_message
, &size
, &len
);
509 #ifdef CLIENT_SUPPORT
510 if (current_parsed_root
->isremote
)
512 struct find_data find_args
;
516 find_args
.ulist
= getlist ();
518 find_args
.questionables
= NULL
;
519 find_args
.ignlist
= NULL
;
520 find_args
.repository
= NULL
;
522 /* It is possible that only a numeric tag should set this.
523 I haven't really thought about it much.
524 Anyway, I suspect that setting it unnecessarily only causes
525 a little unneeded network traffic. */
526 find_args
.force
= force_ci
|| saved_tag
!= NULL
;
528 err
= start_recursion
529 (find_fileproc
, find_filesdoneproc
, find_dirent_proc
, NULL
,
530 &find_args
, argc
, argv
, local
, W_LOCAL
, 0, CVS_LOCK_NONE
,
533 error (1, 0, "correct above errors first!");
535 if (find_args
.argc
== 0)
537 /* Nothing to commit. Exit now without contacting the
538 server (note that this means that we won't print "?
539 foo" for files which merit it, because we don't know
540 what is in the CVSROOT/cvsignore file). */
541 dellist (&find_args
.ulist
);
545 /* Now we keep track of which files we actually are going to
546 operate on, and only work with those files in the future.
547 This saves time--we don't want to search the file system
548 of the working directory twice. */
549 if (size_overflow_p (xtimes (find_args
.argc
, sizeof (char **))))
554 find_args
.argv
= xnmalloc (find_args
.argc
, sizeof (char **));
556 walklist (find_args
.ulist
, copy_ulist
, &find_args
);
558 /* Do this before calling do_editor; don't ask for a log
559 message if we can't talk to the server. But do it after we
560 have made the checks that we can locally (to more quickly
561 catch syntax errors, the case where no files are modified,
562 added or removed, etc.).
564 On the other hand, calling start_server before do_editor
565 means that we chew up server resources the whole time that
566 the user has the editor open (hours or days if the user
567 forgets about it), which seems dubious. */
571 * We do this once, not once for each directory as in normal CVS.
572 * The protocol is designed this way. This is a feature.
575 do_editor (".", &saved_message
, NULL
, find_args
.ulist
);
577 /* We always send some sort of message, even if empty. */
578 option_with_arg ("-m", saved_message
? saved_message
: "");
580 /* OK, now process all the questionable files we have been saving
586 p
= find_args
.questionables
;
589 if (ign_inhibit_server
|| !supported_request ("Questionable"))
591 cvs_output ("? ", 2);
592 if (p
->dir
[0] != '\0')
594 cvs_output (p
->dir
, 0);
597 cvs_output (p
->file
, 0);
598 cvs_output ("\n", 1);
602 /* This used to send the Directory line of its own accord,
603 * but skipped some of the other processing like checking
604 * for whether the server would accept "Relative-directory"
605 * requests. Relying on send_a_repository() to do this
606 * picks up these checks but also:
608 * 1. Causes the "Directory" request to be sent only once
610 * 2. Causes the global TOPLEVEL_REPOS to be set.
611 * 3. Causes "Static-directory" and "Sticky" requests
612 * to sometimes be sent.
614 * (1) is almost certainly a plus. (2) & (3) may or may
615 * not be useful sometimes, and will ocassionally cause a
616 * little extra network traffic. The additional network
617 * traffic is probably already saved several times over and
618 * certainly cancelled out via the multiple "Directory"
619 * request suppression of (1).
621 send_a_repository (p
->dir
, p
->repos
, p
->dir
);
623 send_to_server ("Questionable ", 0);
624 send_to_server (p
->file
, 0);
625 send_to_server ("\012", 1);
638 if (check_valid_edit
)
642 option_with_arg ("-r", saved_tag
);
645 /* FIXME: This whole find_args.force/SEND_FORCE business is a
646 kludge. It would seem to be a server bug that we have to
647 say that files are modified when they are not. This makes
648 "cvs commit -r 2" across a whole bunch of files a very slow
649 operation (and it isn't documented in cvsclient.texi). I
650 haven't looked at the server code carefully enough to be
651 _sure_ why this is needed, but if it is because the "ci"
652 program, which we used to call, wanted the file to exist,
653 then it would be relatively simple to fix in the server. */
654 send_files (find_args
.argc
, find_args
.argv
, local
, 0,
655 find_args
.force
? SEND_FORCE
: 0);
657 /* Sending only the names of the files which were modified, added,
658 or removed means that the server will only do an up-to-date
659 check on those files. This is different from local CVS and
660 previous versions of client/server CVS, but it probably is a Good
661 Thing, or at least Not Such A Bad Thing. */
662 send_file_names (find_args
.argc
, find_args
.argv
, 0);
663 free (find_args
.argv
);
664 dellist (&find_args
.ulist
);
666 send_to_server ("ci\012", 0);
667 err
= get_responses_and_close ();
668 if (err
!= 0 && use_editor
&& saved_message
!= NULL
)
670 /* If there was an error, don't nuke the user's carefully
671 constructed prose. This is something of a kludge; a better
672 solution is probably more along the lines of #150 in TODO
673 (doing a second up-to-date check before accepting the
674 log message has also been suggested, but that seems kind of
675 iffy because the real up-to-date check could still fail,
676 another error could occur, &c. Also, a second check would
677 slow things down). */
682 fp
= cvs_temp_file (&fname
);
684 error (1, 0, "cannot create temporary file %s", fname
);
685 if (fwrite (saved_message
, 1, strlen (saved_message
), fp
)
686 != strlen (saved_message
))
687 error (1, errno
, "cannot write temporary file %s", fname
);
689 error (0, errno
, "cannot close temporary file %s", fname
);
690 error (0, 0, "saving log message in %s", fname
);
697 if (saved_tag
!= NULL
)
698 tag_check_valid (saved_tag
, argc
, argv
, local
, aflag
, "", false);
700 /* XXX - this is not the perfect check for this */
702 write_dirtag
= saved_tag
;
706 lock_tree_promotably (argc
, argv
, local
, W_LOCAL
, aflag
);
709 * Set up the master update list and hard link list
713 #ifdef PRESERVE_PERMISSIONS_SUPPORT
716 hardlist
= getlist ();
719 * We need to save the working directory so that
720 * check_fileproc can construct a full pathname for each file.
722 working_dir
= xgetcwd ();
727 * Run the recursion processor to verify the files are all up-to-date
729 err
= start_recursion (check_fileproc
, check_filesdoneproc
,
730 check_direntproc
, NULL
, NULL
, argc
, argv
, local
,
731 W_LOCAL
, aflag
, CVS_LOCK_NONE
, NULL
, 1, NULL
);
733 error (1, 0, "correct above errors first!");
736 * Run the recursion processor to commit the files
738 write_dirnonbranch
= 0;
740 err
= start_recursion (commit_fileproc
, commit_filesdoneproc
,
741 commit_direntproc
, commit_dirleaveproc
, NULL
,
742 argc
, argv
, local
, W_LOCAL
, aflag
,
743 CVS_LOCK_WRITE
, NULL
, 1, NULL
);
746 * Unlock all the dirs and clean up
751 /* see if we need to sleep before returning to avoid time-stamp races */
752 if (!server_active
&& last_register_time
)
754 sleep_past (last_register_time
);
762 /* This routine determines the status of a given file and retrieves
763 the version information that is associated with that file. */
767 classify_file_internal (struct file_info
*finfo
, Vers_TS
**vers
)
769 int save_noexec
, save_quiet
, save_really_quiet
;
772 /* FIXME: Do we need to save quiet as well as really_quiet? Last
773 time I glanced at Classify_File I only saw it looking at really_quiet
775 save_noexec
= noexec
;
777 save_really_quiet
= really_quiet
;
778 noexec
= quiet
= really_quiet
= 1;
780 /* handle specified numeric revision specially */
781 if (saved_tag
&& isdigit ((unsigned char) *saved_tag
))
783 /* If the tag is for the trunk, make sure we're at the head */
784 if (numdots (saved_tag
) < 2)
786 status
= Classify_File (finfo
, NULL
, NULL
,
787 NULL
, 1, aflag
, vers
, 0);
788 if (status
== T_UPTODATE
|| status
== T_MODIFIED
||
794 xstatus
= Classify_File (finfo
, saved_tag
, NULL
,
795 NULL
, 1, aflag
, vers
, 0);
796 if (xstatus
== T_REMOVE_ENTRY
)
798 else if (status
== T_MODIFIED
&& xstatus
== T_CONFLICT
)
809 * The revision is off the main trunk; make sure we're
810 * up-to-date with the head of the specified branch.
812 xtag
= xstrdup (saved_tag
);
813 if ((numdots (xtag
) & 1) != 0)
815 cp
= strrchr (xtag
, '.');
818 status
= Classify_File (finfo
, xtag
, NULL
,
819 NULL
, 1, aflag
, vers
, 0);
820 if ((status
== T_REMOVE_ENTRY
|| status
== T_CONFLICT
)
821 && (cp
= strrchr (xtag
, '.')) != NULL
)
823 /* pluck one more dot off the revision */
826 status
= Classify_File (finfo
, xtag
, NULL
,
827 NULL
, 1, aflag
, vers
, 0);
828 if (status
== T_UPTODATE
|| status
== T_REMOVE_ENTRY
)
831 /* now, muck with vers to make the tag correct */
833 (*vers
)->tag
= xstrdup (saved_tag
);
838 status
= Classify_File (finfo
, saved_tag
, NULL
, NULL
, 1, 0, vers
, 0);
839 noexec
= save_noexec
;
841 really_quiet
= save_really_quiet
;
849 * Check to see if a file is ok to commit and make sure all files are
854 check_fileproc (void *callerdat
, struct file_info
*finfo
)
859 List
*ulist
, *cilist
;
861 struct commit_info
*ci
;
862 struct logfile_info
*li
;
865 size_t cvsroot_len
= strlen (current_parsed_root
->directory
);
867 if (!finfo
->repository
)
869 error (0, 0, "nothing known about `%s'", finfo
->fullname
);
873 if (strncmp (finfo
->repository
, current_parsed_root
->directory
,
875 && ISSLASH (finfo
->repository
[cvsroot_len
])
876 && strncmp (finfo
->repository
+ cvsroot_len
+ 1,
878 sizeof (CVSROOTADM
) - 1) == 0
879 && ISSLASH (finfo
->repository
[cvsroot_len
+ sizeof (CVSROOTADM
)])
880 && strcmp (finfo
->repository
+ cvsroot_len
+ sizeof (CVSROOTADM
) + 1,
883 error (1, 0, "cannot check in to %s", finfo
->repository
);
885 status
= classify_file_internal (finfo
, &vers
);
888 * If the force-commit option is enabled, and the file in question
889 * appears to be up-to-date, just make it look modified so that
890 * it will be committed.
892 if (force_ci
&& status
== T_UPTODATE
)
901 error (0, 0, "Up-to-date check failed for `%s'", finfo
->fullname
);
911 * some quick sanity checks; if no numeric -r option specified:
912 * - can't have a sticky date
913 * - can't have a sticky tag that is not a branch
915 * - if status is T_REMOVED, file must not exist and its entry
916 * can't have a numeric sticky tag.
917 * - if status is T_ADDED, rcs file must not exist unless on
918 * a branch or head is dead
919 * - if status is T_ADDED, can't have a non-trunk numeric rev
920 * - if status is T_MODIFIED and a Conflict marker exists, don't
921 * allow the commit if timestamp is identical or if we find
922 * an RCS_MERGE_PAT in the file.
924 if (!saved_tag
|| !isdigit ((unsigned char) *saved_tag
))
929 "cannot commit with sticky date for file `%s'",
933 if (status
== T_MODIFIED
&& vers
->tag
&&
934 !RCS_isbranch (finfo
->rcs
, vers
->tag
))
937 "sticky tag `%s' for file `%s' is not a branch",
938 vers
->tag
, finfo
->fullname
);
942 if (status
== T_CONFLICT
&& !force_ci
)
945 "file `%s' had a conflict and has not been modified",
949 if (status
== T_MODIFIED
&& !force_ci
&& file_has_markers (finfo
))
951 /* Make this a warning, not an error, because we have
952 no way of knowing whether the "conflict indicators"
953 are really from a conflict or whether they are part
954 of the document itself (cvs.texinfo and sanity.sh in
955 CVS itself, for example, tend to want to have strings
956 like ">>>>>>>" at the start of a line). Making people
957 kludge this the way they need to kludge keyword
958 expansion seems undesirable. And it is worse than
959 keyword expansion, because there is no -ko
963 warning: file `%s' seems to still contain conflict indicators",
967 if (status
== T_REMOVED
)
969 if (vers
->ts_user
!= NULL
)
972 "`%s' should be removed and is still there (or is"
973 " back again)", finfo
->fullname
);
977 if (vers
->tag
&& isdigit ((unsigned char) *vers
->tag
))
979 /* Remove also tries to forbid this, but we should check
980 here. I'm only _sure_ about somewhat obscure cases
981 (hacking the Entries file, using an old version of
982 CVS for the remove and a new one for the commit), but
983 there might be other cases. */
985 "cannot remove file `%s' which has a numeric sticky"
986 " tag of `%s'", finfo
->fullname
, vers
->tag
);
991 if (status
== T_ADDED
)
993 if (vers
->tag
== NULL
)
995 if (finfo
->rcs
!= NULL
&&
996 !RCS_isdead (finfo
->rcs
, finfo
->rcs
->head
))
999 "cannot add file `%s' when RCS file `%s' already exists",
1000 finfo
->fullname
, finfo
->rcs
->path
);
1004 else if (isdigit ((unsigned char) *vers
->tag
) &&
1005 numdots (vers
->tag
) > 1)
1008 "cannot add file `%s' with revision `%s'; must be on trunk",
1009 finfo
->fullname
, vers
->tag
);
1014 /* done with consistency checks; now, to get on with the commit */
1015 if (finfo
->update_dir
[0] == '\0')
1018 xdir
= finfo
->update_dir
;
1019 if ((p
= findnode (mulist
, xdir
)) != NULL
)
1021 ulist
= ((struct master_lists
*) p
->data
)->ulist
;
1022 cilist
= ((struct master_lists
*) p
->data
)->cilist
;
1026 struct master_lists
*ml
;
1028 ml
= xmalloc (sizeof (struct master_lists
));
1029 ulist
= ml
->ulist
= getlist ();
1030 cilist
= ml
->cilist
= getlist ();
1033 p
->key
= xstrdup (xdir
);
1036 p
->delproc
= masterlist_delproc
;
1037 (void) addnode (mulist
, p
);
1040 /* first do ulist, then cilist */
1042 p
->key
= xstrdup (finfo
->file
);
1044 p
->delproc
= update_delproc
;
1045 li
= xmalloc (sizeof (struct logfile_info
));
1048 if (check_valid_edit
)
1050 char *editors
= NULL
;
1053 editors
= fileattr_get0 (finfo
->file
, "_editors");
1054 if (editors
!= NULL
)
1056 char *caller
= getcaller ();
1064 p
= strchr (p
, '>');
1070 if (strcmp (caller
, p0
) == 0)
1074 p
= strchr (p
+ 1, ',');
1083 if (strcmp (caller
, p0
) == 0)
1092 if (check_valid_edit
&& editor
== NULL
)
1094 error (0, 0, "Valid edit does not exist for %s",
1096 freevers_ts (&vers
);
1100 li
->tag
= xstrdup (vers
->tag
);
1101 li
->rev_old
= xstrdup (vers
->vn_rcs
);
1104 (void) addnode (ulist
, p
);
1107 p
->key
= xstrdup (finfo
->file
);
1109 p
->delproc
= ci_delproc
;
1110 ci
= xmalloc (sizeof (struct commit_info
));
1111 ci
->status
= status
;
1113 if (isdigit ((unsigned char) *vers
->tag
))
1114 ci
->rev
= xstrdup (vers
->tag
);
1116 ci
->rev
= RCS_whatbranch (finfo
->rcs
, vers
->tag
);
1119 ci
->tag
= xstrdup (vers
->tag
);
1120 ci
->options
= xstrdup (vers
->options
);
1122 (void) addnode (cilist
, p
);
1124 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1127 /* Add this file to hardlist, indexed on its inode. When
1128 we are done, we can find out what files are hardlinked
1129 to a given file by looking up its inode in hardlist. */
1132 struct hardlink_info
*hlinfo
;
1134 /* Get the full pathname of the current file. */
1135 fullpath
= Xasprintf ("%s/%s", working_dir
, finfo
->fullname
);
1137 /* To permit following links in subdirectories, files
1138 are keyed on finfo->fullname, not on finfo->name. */
1139 linkp
= lookup_file_by_inode (fullpath
);
1141 /* If linkp is NULL, the file doesn't exist... maybe
1142 we're doing a remove operation? */
1145 /* Create a new hardlink_info node, which will record
1146 the current file's status and the links listed in its
1147 `hardlinks' delta field. We will append this
1148 hardlink_info node to the appropriate hardlist entry. */
1149 hlinfo
= xmalloc (sizeof (struct hardlink_info
));
1150 hlinfo
->status
= status
;
1151 linkp
->data
= hlinfo
;
1160 error (0, 0, "nothing known about `%s'", finfo
->fullname
);
1165 error (0, 0, "CVS internal error: unknown status %d", status
);
1173 freevers_ts (&vers
);
1180 * By default, return the code that tells do_recursion to examine all
1185 check_direntproc (void *callerdat
, const char *dir
, const char *repos
,
1186 const char *update_dir
, List
*entries
)
1192 error (0, 0, "Examining %s", update_dir
);
1200 * Walklist proc to generate an arg list from the line in commitinfo
1203 precommit_list_to_args_proc (p
, closure
)
1207 struct format_cmdline_walklist_closure
*c
= closure
;
1208 struct logfile_info
*li
;
1214 if (p
->data
== NULL
) return 1;
1218 /* foreach requested attribute */
1225 if (li
->type
== T_ADDED
1226 || li
->type
== T_MODIFIED
1227 || li
->type
== T_REMOVED
)
1234 "Unknown format character or not a list attribute: %c",
1239 /* copy the attribute into an argument */
1242 arg
= cmdlineescape (c
->quotes
, arg
);
1246 arg
= cmdlinequote ('"', arg
);
1249 expand_string (c
->buf
, c
->length
, doff
+ strlen (arg
));
1251 strncpy (d
, arg
, strlen (arg
));
1255 /* and always put the extra space on. we'll have to back up a char
1256 * when we're done, but that seems most efficient
1259 expand_string (c
->buf
, c
->length
, doff
+ 1);
1263 /* correct our original pointer into the buff */
1271 * Callback proc for pre-commit checking
1274 precommit_proc (const char *repository
, const char *filter
, void *closure
)
1276 char *newfilter
= NULL
;
1278 const char *srepos
= Short_Repository (repository
);
1279 List
*ulist
= closure
;
1281 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1282 if (!strchr (filter
, '%'))
1285 "warning: commitinfo line contains no format strings:\n"
1287 "Appending defaults (\" %%r/%%p %%s\"), but please be aware that this usage is\n"
1288 "deprecated.", filter
);
1289 newfilter
= Xasprintf ("%s %%r/%%p %%s", filter
);
1292 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1295 * Cast any NULL arguments as appropriate pointers as this is an
1296 * stdarg function and we need to be certain the caller gets what
1299 cmdline
= format_cmdline (
1300 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1302 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1304 "c", "s", cvs_cmd_name
,
1305 #ifdef SERVER_SUPPORT
1306 "R", "s", referrer
? referrer
->original
: "NONE",
1307 #endif /* SERVER_SUPPORT */
1309 "r", "s", current_parsed_root
->directory
,
1310 "s", ",", ulist
, precommit_list_to_args_proc
,
1314 if (newfilter
) free (newfilter
);
1316 if (!cmdline
|| !strlen (cmdline
))
1318 if (cmdline
) free (cmdline
);
1319 error (0, 0, "precommit proc resolved to the empty string!");
1323 run_setup (cmdline
);
1326 return run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
, RUN_NORMAL
| RUN_REALLY
);
1332 * Run the pre-commit checks for the dir
1336 check_filesdoneproc (void *callerdat
, int err
, const char *repos
,
1337 const char *update_dir
, List
*entries
)
1343 /* find the update list for this dir */
1344 p
= findnode (mulist
, update_dir
);
1346 saved_ulist
= ((struct master_lists
*) p
->data
)->ulist
;
1350 /* skip the checks if there's nothing to do */
1351 if (saved_ulist
== NULL
|| saved_ulist
->list
->next
== saved_ulist
->list
)
1354 /* run any pre-commit checks */
1355 n
= Parse_Info (CVSROOTADM_COMMITINFO
, repos
, precommit_proc
, PIOPT_ALL
,
1359 error (0, 0, "Pre-commit check failed");
1369 * Do the work of committing a file
1372 static char *sbranch
;
1376 commit_fileproc (void *callerdat
, struct file_info
*finfo
)
1380 List
*ulist
, *cilist
;
1381 struct commit_info
*ci
;
1383 /* Keep track of whether write_dirtag is a branch tag.
1384 Note that if it is a branch tag in some files and a nonbranch tag
1385 in others, treat it as a nonbranch tag. It is possible that case
1386 should elicit a warning or an error. */
1387 if (write_dirtag
!= NULL
1388 && finfo
->rcs
!= NULL
)
1390 char *rev
= RCS_getversion (finfo
->rcs
, write_dirtag
, NULL
, 1, NULL
);
1392 && !RCS_nodeisbranch (finfo
->rcs
, write_dirtag
))
1393 write_dirnonbranch
= 1;
1398 if (finfo
->update_dir
[0] == '\0')
1399 p
= findnode (mulist
, ".");
1401 p
= findnode (mulist
, finfo
->update_dir
);
1404 * if p is null, there were file type command line args which were
1405 * all up-to-date so nothing really needs to be done
1409 ulist
= ((struct master_lists
*) p
->data
)->ulist
;
1410 cilist
= ((struct master_lists
*) p
->data
)->cilist
;
1413 * At this point, we should have the commit message unless we were called
1414 * with files as args from the command line. In that latter case, we
1415 * need to get the commit message ourselves
1420 if (!server_active
&& use_editor
)
1421 do_editor (finfo
->update_dir
, &saved_message
,
1422 finfo
->repository
, ulist
);
1423 do_verify (&saved_message
, finfo
->repository
, ulist
);
1426 p
= findnode (cilist
, finfo
->file
);
1431 if (ci
->status
== T_MODIFIED
)
1433 if (finfo
->rcs
== NULL
)
1434 error (1, 0, "internal error: no parsed RCS file");
1435 if (lock_RCS (finfo
->file
, finfo
->rcs
, ci
->rev
,
1436 finfo
->repository
) != 0)
1438 unlockrcs (finfo
->rcs
);
1443 else if (ci
->status
== T_ADDED
)
1445 if (checkaddfile (finfo
->file
, finfo
->repository
, ci
->tag
, ci
->options
,
1448 if (finfo
->rcs
!= NULL
)
1449 fixaddfile (finfo
->rcs
->path
);
1454 /* adding files with a tag, now means adding them on a branch.
1455 Since the branch test was done in check_fileproc for
1456 modified files, we need to stub it in again here. */
1460 /* If numeric, it is on the trunk; check_fileproc enforced
1462 && !isdigit ((unsigned char) ci
->tag
[0]))
1464 if (finfo
->rcs
== NULL
)
1465 error (1, 0, "internal error: no parsed RCS file");
1468 ci
->rev
= RCS_whatbranch (finfo
->rcs
, ci
->tag
);
1469 err
= Checkin ('A', finfo
, ci
->rev
,
1470 ci
->tag
, ci
->options
, saved_message
);
1473 unlockrcs (finfo
->rcs
);
1474 fixbranch (finfo
->rcs
, sbranch
);
1477 (void) time (&last_register_time
);
1479 ci
->status
= T_UPTODATE
;
1484 * Add the file for real
1486 if (ci
->status
== T_ADDED
)
1490 if (ci
->rev
== NULL
)
1492 /* find the max major rev number in this directory */
1494 (void) walklist (finfo
->entries
, findmaxrev
, NULL
);
1495 if (finfo
->rcs
->head
)
1497 /* resurrecting: include dead revision */
1498 int thisrev
= atoi (finfo
->rcs
->head
);
1499 if (thisrev
> maxrev
)
1504 xrev
= Xasprintf ("%d", maxrev
);
1507 /* XXX - an added file with symbolic -r should add tag as well */
1508 err
= finaladd (finfo
, ci
->rev
? ci
->rev
: xrev
, ci
->tag
, ci
->options
);
1512 else if (ci
->status
== T_MODIFIED
)
1514 err
= Checkin ('M', finfo
, ci
->rev
, ci
->tag
,
1515 ci
->options
, saved_message
);
1517 (void) time (&last_register_time
);
1521 unlockrcs (finfo
->rcs
);
1522 fixbranch (finfo
->rcs
, sbranch
);
1525 else if (ci
->status
== T_REMOVED
)
1527 err
= remove_file (finfo
, ci
->tag
, saved_message
);
1528 #ifdef SERVER_SUPPORT
1531 server_scratch_entry_only ();
1532 server_updated (finfo
,
1535 /* Doesn't matter, it won't get checked. */
1545 /* Clearly this is right for T_MODIFIED. I haven't thought so much
1546 about T_ADDED or T_REMOVED. */
1547 notify_do ('C', finfo
->file
, finfo
->update_dir
, getcaller (), NULL
, NULL
,
1553 /* on failure, remove the file from ulist */
1554 p
= findnode (ulist
, finfo
->file
);
1560 /* On success, retrieve the new version number of the file and
1561 copy it into the log information (see logmsg.c
1562 (logfile_write) for more details). We should only update
1563 the version number for files that have been added or
1564 modified but not removed since classify_file_internal
1565 will return the version number of a file even after it has
1566 been removed from the archive, which is not the behavior we
1567 want for our commitlog messages; we want the old version
1568 number and then "NONE." */
1570 if (ci
->status
!= T_REMOVED
)
1572 p
= findnode (ulist
, finfo
->file
);
1576 struct logfile_info
*li
;
1578 (void) classify_file_internal (finfo
, &vers
);
1580 li
->rev_new
= xstrdup (vers
->vn_rcs
);
1581 freevers_ts (&vers
);
1585 if (SIG_inCrSect ())
1594 * Log the commit and clean up the update list
1598 commit_filesdoneproc (void *callerdat
, int err
, const char *repository
,
1599 const char *update_dir
, List
*entries
)
1604 assert (repository
);
1606 p
= findnode (mulist
, update_dir
);
1610 ulist
= ((struct master_lists
*) p
->data
)->ulist
;
1614 /* Build the administrative files if necessary. */
1618 if (strncmp (current_parsed_root
->directory
, repository
,
1619 strlen (current_parsed_root
->directory
)) != 0)
1621 "internal error: repository (%s) doesn't begin with root (%s)",
1622 repository
, current_parsed_root
->directory
);
1623 p
= repository
+ strlen (current_parsed_root
->directory
);
1626 if (strcmp ("CVSROOT", p
) == 0
1627 /* Check for subdirectories because people may want to create
1628 subdirectories and list files therein in checkoutlist. */
1629 || strncmp ("CVSROOT/", p
, strlen ("CVSROOT/")) == 0
1632 /* "Database" might a little bit grandiose and/or vague,
1633 but "checked-out copies of administrative files, unless
1634 in the case of modules and you are using ndbm in which
1635 case modules.{pag,dir,db}" is verbose and excessively
1636 focused on how the database is implemented. */
1638 /* mkmodules requires the absolute name of the CVSROOT directory.
1639 Remove anything after the `CVSROOT' component -- this is
1640 necessary when committing in a subdirectory of CVSROOT. */
1641 char *admin_dir
= xstrdup (repository
);
1642 int cvsrootlen
= strlen ("CVSROOT");
1643 assert (admin_dir
[p
- repository
+ cvsrootlen
] == '\0'
1644 || admin_dir
[p
- repository
+ cvsrootlen
] == '/');
1645 admin_dir
[p
- repository
+ cvsrootlen
] = '\0';
1649 cvs_output (program_name
, 0);
1650 cvs_output (" ", 1);
1651 cvs_output (cvs_cmd_name
, 0);
1652 cvs_output (": Rebuilding administrative file database\n", 0);
1654 mkmodules (admin_dir
);
1656 WriteTemplate (".", 1, repository
);
1660 /* FIXME: This used to be above the block above. The advantage of being
1661 * here is that it is not called until after all possible writes from this
1662 * process are complete. The disadvantage is that a fatal error during
1663 * update of CVSROOT can prevent the loginfo script from being called.
1665 * A more general solution I have been considering is calling a generic
1666 * "postwrite" hook from the remove write lock routine.
1668 Update_Logfile (repository
, saved_message
, NULL
, ulist
);
1676 * Get the log message for a dir
1680 commit_direntproc (void *callerdat
, const char *dir
, const char *repos
,
1681 const char *update_dir
, List
*entries
)
1690 /* find the update list for this dir */
1691 p
= findnode (mulist
, update_dir
);
1693 ulist
= ((struct master_lists
*) p
->data
)->ulist
;
1697 /* skip the files as an optimization */
1698 if (ulist
== NULL
|| ulist
->list
->next
== ulist
->list
)
1699 return R_SKIP_FILES
;
1701 /* get commit message */
1703 real_repos
= Name_Repository (dir
, update_dir
);
1704 if (!server_active
&& use_editor
)
1705 do_editor (update_dir
, &saved_message
, real_repos
, ulist
);
1706 do_verify (&saved_message
, real_repos
, ulist
);
1714 * Process the post-commit proc if necessary
1718 commit_dirleaveproc (void *callerdat
, const char *dir
, int err
,
1719 const char *update_dir
, List
*entries
)
1721 /* update the per-directory tag info */
1722 /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly
1723 mentions commit -r being sticky, but apparently in the context of
1724 this being a confusing feature! */
1725 if (err
== 0 && write_dirtag
!= NULL
)
1727 char *repos
= Name_Repository (NULL
, update_dir
);
1728 WriteTag (NULL
, write_dirtag
, NULL
, write_dirnonbranch
,
1739 * find the maximum major rev number in an entries file
1742 findmaxrev (Node
*p
, void *closure
)
1745 Entnode
*entdata
= p
->data
;
1747 if (entdata
->type
!= ENT_FILE
)
1749 thisrev
= atoi (entdata
->version
);
1750 if (thisrev
> maxrev
)
1756 * Actually remove a file by moving it to the attic
1757 * XXX - if removing a ,v file that is a relative symbolic link to
1758 * another ,v file, we probably should add a ".." component to the
1759 * link to keep it relative after we move it into the attic.
1761 Return value is 0 on success, or >0 on error (in which case we have
1762 printed an error message). */
1764 remove_file (struct file_info
*finfo
, char *tag
, char *message
)
1781 if (finfo
->rcs
== NULL
)
1782 error (1, 0, "internal error: no parsed RCS file");
1785 if (tag
&& !(branch
= RCS_nodeisbranch (finfo
->rcs
, tag
)))
1787 /* a symbolic tag is specified; just remove the tag from the file */
1788 if ((retcode
= RCS_deltag (finfo
->rcs
, tag
)) != 0)
1791 error (0, retcode
== -1 ? errno
: 0,
1792 "failed to remove tag `%s' from `%s'", tag
,
1796 RCS_rewrite (finfo
->rcs
, NULL
, NULL
);
1797 Scratch_Entry (finfo
->entries
, finfo
->file
);
1801 /* we are removing the file from either the head or a branch */
1802 /* commit a new, dead revision. */
1810 rev
= RCS_whatbranch (finfo
->rcs
, tag
);
1813 error (0, 0, "cannot find branch \"%s\".", tag
);
1817 branchname
= RCS_getbranch (finfo
->rcs
, rev
, 1);
1818 if (branchname
== NULL
)
1820 /* no revision exists on this branch. use the previous
1821 revision but do not lock. */
1822 corev
= RCS_gettag (finfo
->rcs
, tag
, 1, NULL
);
1823 prev_rev
= xstrdup (corev
);
1827 corev
= xstrdup (rev
);
1828 prev_rev
= xstrdup (branchname
);
1832 } else /* Not a branch */
1834 /* Get current head revision of file. */
1835 prev_rev
= RCS_head (finfo
->rcs
);
1838 /* if removing without a tag or a branch, then make sure the default
1839 branch is the trunk. */
1840 if (!tag
&& !branch
)
1842 if (RCS_setbranch (finfo
->rcs
, NULL
) != 0)
1844 error (0, 0, "cannot change branch to default for %s",
1848 RCS_rewrite (finfo
->rcs
, NULL
, NULL
);
1851 /* check something out. Generally this is the head. If we have a
1852 particular rev, then name it. */
1853 retcode
= RCS_checkout (finfo
->rcs
, finfo
->file
, rev
? corev
: NULL
,
1854 NULL
, NULL
, RUN_TTY
, NULL
, NULL
);
1858 "failed to check out `%s'", finfo
->fullname
);
1862 /* Except when we are creating a branch, lock the revision so that
1863 we can check in the new revision. */
1866 if (RCS_lock (finfo
->rcs
, rev
? corev
: NULL
, 1) == 0)
1867 RCS_rewrite (finfo
->rcs
, NULL
, NULL
);
1873 retcode
= RCS_checkin (finfo
->rcs
, NULL
, finfo
->file
, message
,
1874 rev
, 0, RCS_FLAGS_DEAD
| RCS_FLAGS_QUIET
);
1878 error (0, retcode
== -1 ? errno
: 0,
1879 "failed to commit dead revision for `%s'", finfo
->fullname
);
1882 /* At this point, the file has been committed as removed. We should
1883 probably tell the history file about it */
1884 history_write ('R', NULL
, finfo
->rcs
->head
, finfo
->file
, finfo
->repository
);
1889 old_path
= xstrdup (finfo
->rcs
->path
);
1891 RCS_setattic (finfo
->rcs
, 1);
1893 /* Print message that file was removed. */
1896 cvs_output (old_path
, 0);
1897 cvs_output (" <-- ", 0);
1898 if (finfo
->update_dir
&& strlen (finfo
->update_dir
))
1900 cvs_output (finfo
->update_dir
, 0);
1901 cvs_output ("/", 1);
1903 cvs_output (finfo
->file
, 0);
1904 cvs_output ("\nnew revision: delete; previous revision: ", 0);
1905 cvs_output (prev_rev
, 0);
1906 cvs_output ("\n", 0);
1913 Scratch_Entry (finfo
->entries
, finfo
->file
);
1920 * Do the actual checkin for added files
1923 finaladd (struct file_info
*finfo
, char *rev
, char *tag
, char *options
)
1927 ret
= Checkin ('A', finfo
, rev
, tag
, options
, saved_message
);
1930 char *tmp
= Xasprintf ("%s/%s%s", CVSADM
, finfo
->file
, CVSEXT_LOG
);
1931 if (unlink_file (tmp
) < 0
1932 && !existence_error (errno
))
1933 error (0, errno
, "cannot remove %s", tmp
);
1936 else if (finfo
->rcs
!= NULL
)
1937 fixaddfile (finfo
->rcs
->path
);
1939 (void) time (&last_register_time
);
1947 * Unlock an rcs file
1950 unlockrcs (RCSNode
*rcs
)
1954 if ((retcode
= RCS_unlock (rcs
, NULL
, 1)) != 0)
1955 error (retcode
== -1 ? 1 : 0, retcode
== -1 ? errno
: 0,
1956 "could not unlock %s", rcs
->path
);
1958 RCS_rewrite (rcs
, NULL
, NULL
);
1964 * remove a partially added file. if we can parse it, leave it alone.
1966 * FIXME: Every caller that calls this function can access finfo->rcs (the
1967 * parsed RCSNode data), so we should be able to detect that the file needs
1968 * to be removed without reparsing the file as we do below.
1971 fixaddfile (const char *rcs
)
1974 int save_really_quiet
;
1976 save_really_quiet
= really_quiet
;
1978 if ((rcsfile
= RCS_parsercsfile (rcs
)) == NULL
)
1980 if (unlink_file (rcs
) < 0)
1981 error (0, errno
, "cannot remove %s", rcs
);
1984 freercsnode (&rcsfile
);
1985 really_quiet
= save_really_quiet
;
1991 * put the branch back on an rcs file
1994 fixbranch (RCSNode
*rcs
, char *branch
)
2000 if ((retcode
= RCS_setbranch (rcs
, branch
)) != 0)
2001 error (retcode
== -1 ? 1 : 0, retcode
== -1 ? errno
: 0,
2002 "cannot restore branch to %s for %s", branch
, rcs
->path
);
2003 RCS_rewrite (rcs
, NULL
, NULL
);
2010 * do the initial part of a file add for the named file. if adding
2011 * with a tag, put the file in the Attic and point the symbolic tag
2012 * at the committed revision.
2015 * file The name of the file in the workspace.
2016 * repository The repository directory to expect to find FILE,v in.
2017 * tag The name or rev num of the branch being added to, if any.
2018 * options Any RCS keyword expansion options specified by the user.
2019 * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
2020 * exists in the repository. If this is NULL, assume the file
2021 * does not yet exist.
2025 * 1 on errors, after printing any appropriate error messages.
2028 * This function will return an error when any of the following functions do:
2033 * RCS_parse (called to verify the newly created archive file)
2038 checkaddfile (const char *file
, const char *repository
, const char *tag
,
2039 const char *options
, RCSNode
**rcsnode
)
2043 int newfile
= 0; /* Set to 1 if we created a new RCS archive. */
2045 int adding_on_branch
;
2047 assert (rcsnode
!= NULL
);
2049 /* Callers expect to be able to use either "" or NULL to mean the
2050 default keyword expansion. */
2051 if (options
!= NULL
&& options
[0] == '\0')
2053 if (options
!= NULL
)
2054 assert (options
[0] == '-' && options
[1] == 'k');
2056 /* If numeric, it is on the trunk; check_fileproc enforced
2058 adding_on_branch
= tag
!= NULL
&& !isdigit ((unsigned char) tag
[0]);
2060 if (*rcsnode
== NULL
)
2064 size_t descalloc
= 0;
2068 if (adding_on_branch
)
2071 rcsname
= xmalloc (strlen (repository
)
2076 (void) sprintf (rcsname
, "%s/%s", repository
, CVSATTIC
);
2077 omask
= umask (cvsumask
);
2078 if (CVS_MKDIR (rcsname
, 0777) != 0 && errno
!= EEXIST
)
2079 error (1, errno
, "cannot make directory `%s'", rcsname
);
2080 (void) umask (omask
);
2081 (void) sprintf (rcsname
,
2089 rcsname
= Xasprintf ("%s/%s%s", repository
, file
, RCSEXT
);
2091 /* this is the first time we have ever seen this file; create
2093 fname
= Xasprintf ("%s/%s%s", CVSADM
, file
, CVSEXT_LOG
);
2094 /* If the file does not exist, no big deal. In particular, the
2095 server does not (yet at least) create CVSEXT_LOG files. */
2097 /* FIXME: Should be including update_dir in the appropriate
2099 get_file (fname
, fname
, "r", &desc
, &descalloc
, &desclen
);
2102 /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
2103 end of the log message if the message is nonempty.
2104 Do it. RCS also deletes certain whitespace, in cleanlogmsg,
2105 which we don't try to do here. */
2108 expand_string (&desc
, &descalloc
, desclen
+ 1);
2109 desc
[desclen
++] = '\012';
2112 /* Set RCS keyword expansion options. */
2113 if (options
!= NULL
)
2118 if (add_rcs_file (NULL
, rcsname
, file
, NULL
, opt
,
2119 NULL
, NULL
, 0, NULL
,
2120 desc
, desclen
, NULL
, 0) != 0)
2122 if (rcsname
!= NULL
)
2126 rcs
= RCS_parsercsfile (rcsname
);
2128 if (rcsname
!= NULL
)
2136 /* file has existed in the past. Prepare to resurrect. */
2142 oldexpand
= RCS_getexpand (rcs
);
2143 if ((oldexpand
!= NULL
2145 && strcmp (options
+ 2, oldexpand
) != 0)
2146 || (oldexpand
== NULL
&& options
!= NULL
))
2148 /* We tell the user about this, because it means that the
2149 old revisions will no longer retrieve the way that they
2151 error (0, 0, "changing keyword expansion mode to %s", options
);
2152 RCS_setexpand (rcs
, options
+ 2);
2155 if (!adding_on_branch
)
2157 /* We are adding on the trunk, so move the file out of the
2159 if (!(rcs
->flags
& INATTIC
))
2161 error (0, 0, "warning: expected %s to be in Attic",
2165 /* Begin a critical section around the code that spans the
2166 first commit on the trunk of a file that's already been
2167 committed on a branch. */
2170 if (RCS_setattic (rcs
, 0))
2176 rev
= RCS_getversion (rcs
, tag
, NULL
, 1, NULL
);
2178 if (lock_RCS (file
, rcs
, rev
, repository
))
2180 error (0, 0, "cannot lock revision %s in `%s'.",
2181 rev
? rev
: tag
? tag
: "HEAD", rcs
->path
);
2191 /* when adding a file for the first time, and using a tag, we need
2192 to create a dead revision on the trunk. */
2193 if (adding_on_branch
)
2201 /* move the new file out of the way. */
2202 fname
= Xasprintf ("%s/%s%s", CVSADM
, CVSPREFIX
, file
);
2203 rename_file (file
, fname
);
2205 /* Create empty FILE. Can't use copy_file with a DEVNULL
2206 argument -- copy_file now ignores device files. */
2207 fp
= fopen (file
, "w");
2209 error (1, errno
, "cannot open %s for writing", file
);
2210 if (fclose (fp
) < 0)
2211 error (0, errno
, "cannot close %s", file
);
2213 tmp
= Xasprintf ("file %s was initially added on branch %s.",
2215 /* commit a dead revision. */
2216 retcode
= RCS_checkin (rcs
, NULL
, NULL
, tmp
, NULL
, 0,
2217 RCS_FLAGS_DEAD
| RCS_FLAGS_QUIET
);
2221 error (retcode
== -1 ? 1 : 0, retcode
== -1 ? errno
: 0,
2222 "could not create initial dead revision %s", rcs
->path
);
2227 /* put the new file back where it was */
2228 rename_file (fname
, file
);
2231 /* double-check that the file was written correctly */
2233 rcs
= RCS_parse (file
, repository
);
2236 error (0, 0, "could not read %s", rcs
->path
);
2241 /* and lock it once again. */
2242 if (lock_RCS (file
, rcs
, NULL
, repository
))
2244 error (0, 0, "cannot lock initial revision in `%s'.",
2250 /* when adding with a tag, we need to stub a branch, if it
2251 doesn't already exist. */
2252 if (!RCS_nodeisbranch (rcs
, tag
))
2254 /* branch does not exist. Stub it. */
2258 time_t headtime
= -1;
2264 fixbranch (rcs
, sbranch
);
2266 head
= RCS_getversion (rcs
, NULL
, NULL
, 0, NULL
);
2268 error (1, 0, "No head revision in archive file `%s'.",
2270 magicrev
= RCS_magicrev (rcs
, head
);
2272 /* If this is not a new branch, then we will want a dead
2273 version created before this one. */
2275 headtime
= RCS_getrevtime (rcs
, head
, 0, 0);
2277 retcode
= RCS_settag (rcs
, tag
, magicrev
);
2278 RCS_rewrite (rcs
, NULL
, NULL
);
2285 error (retcode
== -1 ? 1 : 0, retcode
== -1 ? errno
: 0,
2286 "could not stub branch %s for %s", tag
, rcs
->path
);
2289 /* We need to add a dead version here to avoid -rtag -Dtime
2290 checkout problems between when the head version was
2292 if (!newfile
&& headtime
!= -1)
2294 /* move the new file out of the way. */
2295 fname
= Xasprintf ("%s/%s%s", CVSADM
, CVSPREFIX
, file
);
2296 rename_file (file
, fname
);
2298 /* Create empty FILE. Can't use copy_file with a DEVNULL
2299 argument -- copy_file now ignores device files. */
2300 fp
= fopen (file
, "w");
2302 error (1, errno
, "cannot open %s for writing", file
);
2303 if (fclose (fp
) < 0)
2304 error (0, errno
, "cannot close %s", file
);
2306 /* As we will be hacking the delta date, put the time
2307 this was added into the log message. */
2310 tmp
= Xasprintf ("file %s was added on branch %s on %d-%02d-%02d %02d:%02d:%02d +0000",
2312 ct
->tm_year
+ (ct
->tm_year
< 100 ? 0 : 1900),
2313 ct
->tm_mon
+ 1, ct
->tm_mday
,
2314 ct
->tm_hour
, ct
->tm_min
, ct
->tm_sec
);
2316 /* commit a dead revision. */
2317 revnum
= RCS_whatbranch (rcs
, tag
);
2318 retcode
= RCS_checkin (rcs
, NULL
, NULL
, tmp
, revnum
, headtime
,
2327 error (retcode
== -1 ? 1 : 0, retcode
== -1 ? errno
: 0,
2328 "could not created dead stub %s for %s", tag
,
2333 /* put the new file back where it was */
2334 rename_file (fname
, file
);
2337 /* double-check that the file was written correctly */
2339 rcs
= RCS_parse (file
, repository
);
2342 error (0, 0, "could not read %s", rcs
->path
);
2350 /* lock the branch. (stubbed branches need not be locked.) */
2351 if (lock_RCS (file
, rcs
, NULL
, repository
))
2353 error (0, 0, "cannot lock head revision in `%s'.", rcs
->path
);
2358 if (*rcsnode
!= rcs
)
2360 freercsnode (rcsnode
);
2365 fileattr_newfile (file
);
2367 /* At this point, we used to set the file mode of the RCS file
2368 based on the mode of the file in the working directory. If we
2369 are creating the RCS file for the first time, add_rcs_file does
2370 this already. If we are re-adding the file, then perhaps it is
2371 consistent to preserve the old file mode, just as we preserve
2372 the old keyword expansion mode.
2374 If we decide that we should change the modes, then we can't do
2375 it here anyhow. At this point, the RCS file may be owned by
2376 somebody else, so a chmod will fail. We need to instead do the
2377 chmod after rewriting it.
2379 FIXME: In general, I think the file mode (and the keyword
2380 expansion mode) should be associated with a particular revision
2381 of the file, so that it is possible to have different revisions
2382 of a file have different modes. */
2387 if (retval
!= 0 && SIG_inCrSect ())
2395 * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
2396 * couldn't. If the RCS file currently has a branch as the head, we must
2397 * move the head back to the trunk before locking the file, and be sure to
2398 * put the branch back as the head if there are any errors.
2401 lock_RCS (const char *user
, RCSNode
*rcs
, const char *rev
,
2402 const char *repository
)
2404 char *branch
= NULL
;
2408 * For a specified, numeric revision of the form "1" or "1.1", (or when
2409 * no revision is specified ""), definitely move the branch to the trunk
2410 * before locking the RCS file.
2412 * The assumption is that if there is more than one revision on the trunk,
2413 * the head points to the trunk, not a branch... and as such, it's not
2414 * necessary to move the head in this case.
2417 || (rev
&& isdigit ((unsigned char) *rev
) && numdots (rev
) < 2))
2419 branch
= xstrdup (rcs
->branch
);
2422 if (RCS_setbranch (rcs
, NULL
) != 0)
2424 error (0, 0, "cannot change branch to default for %s",
2431 err
= RCS_lock (rcs
, NULL
, 1);
2435 RCS_lock (rcs
, rev
, 1);
2438 /* We used to call RCS_rewrite here, and that might seem
2439 appropriate in order to write out the locked revision
2440 information. However, such a call would actually serve no
2441 purpose. CVS locks will prevent any interference from other
2442 CVS processes. The comment above rcs_internal_lockfile
2443 explains that it is already unsafe to use RCS and CVS
2444 simultaneously. It follows that writing out the locked
2445 revision information here would add no additional security.
2447 If we ever do care about it, the proper fix is to create the
2448 RCS lock file before calling this function, and maintain it
2449 until the checkin is complete.
2451 The call to RCS_lock is still required at present, since in
2452 some cases RCS_checkin will determine which revision to check
2453 in by looking for a lock. FIXME: This is rather roundabout,
2454 and a more straightforward approach would probably be easier to
2459 if (sbranch
!= NULL
)
2465 /* try to restore the branch if we can on error */
2467 fixbranch (rcs
, branch
);
2477 * free an UPDATE node's data
2480 update_delproc (Node
*p
)
2482 struct logfile_info
*li
= p
->data
;
2494 * Free the commit_info structure in p.
2497 ci_delproc (Node
*p
)
2499 struct commit_info
*ci
= p
->data
;
2511 * Free the commit_info structure in p.
2514 masterlist_delproc (Node
*p
)
2516 struct master_lists
*ml
= p
->data
;
2518 dellist (&ml
->ulist
);
2519 dellist (&ml
->cilist
);