xref: /dragonfly/contrib/cvs-1.12/src/checkin.c (revision 49781055)
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  * Check In
14  *
15  * Does a very careful checkin of the file "user", and tries not to spoil its
16  * modification time (to avoid needless recompilations). When RCS ID keywords
17  * get expanded on checkout, however, the modification time is updated and
18  * there is no good way to get around this.
19  *
20  * Returns non-zero on error.
21  */
22 
23 #include "cvs.h"
24 #include "fileattr.h"
25 #include "edit.h"
26 
27 int
28 Checkin (int type, struct file_info *finfo, char *rev, char *tag,
29 	 char *options, char *message)
30 {
31     Vers_TS *vers;
32     int set_time;
33     char *tocvsPath = NULL;
34 
35     tocvsPath = wrap_tocvs_process_file (finfo->file);
36     if (!noexec)
37     {
38         if (tocvsPath)
39 	{
40 	    if (unlink_file_dir (finfo->file) < 0)
41 		if (! existence_error (errno))
42 		    error (1, errno, "cannot remove %s", finfo->fullname);
43 	    rename_file (tocvsPath, finfo->file);
44 	}
45     }
46 
47     /* There use to be a check for finfo->rcs == NULL here and then a
48      * call to RCS_parse when necessary, but Checkin() isn't called
49      * if the RCS file hasn't already been parsed in one of the
50      * check functions.
51      */
52     assert (finfo->rcs != NULL);
53 
54     switch (RCS_checkin (finfo->rcs, finfo->update_dir, finfo->file, message,
55 			 rev, 0, RCS_FLAGS_KEEPFILE))
56     {
57 	case 0:			/* everything normal */
58 
59 	    /* The checkin succeeded.  If checking the file out again
60                would not cause any changes, we are done.  Otherwise,
61                we need to check out the file, which will change the
62                modification time of the file.
63 
64 	       The only way checking out the file could cause any
65 	       changes is if the file contains RCS keywords.  So we if
66 	       we are not expanding RCS keywords, we are done.  */
67 
68 	    if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
69 		options[0] = '\0';
70 
71 	    /* FIXME: If PreservePermissions is on, RCS_cmp_file is
72                going to call RCS_checkout into a temporary file
73                anyhow.  In that case, it would be more efficient to
74                call RCS_checkout here, compare the resulting files
75                using xcmp, and rename if necessary.  I think this
76                should be fixed in RCS_cmp_file.  */
77 	    if ((1
78 #ifdef PRESERVE_PERMISSIONS_SUPPORT
79 		 !config->preserve_perms
80 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
81 		 && options
82 		 && (!strcmp (options, "-ko") || !strcmp (options, "-kb")))
83 		|| !RCS_cmp_file (finfo->rcs, rev, NULL, NULL,
84 	                          options, finfo->file))
85 	    {
86 		/* The existing file is correct.  We don't have to do
87                    anything.  */
88 		set_time = 0;
89 	    }
90 	    else
91 	    {
92 		/* The existing file is incorrect.  We need to check
93                    out the correct file contents.  */
94 		if (RCS_checkout (finfo->rcs, finfo->file, rev, NULL,
95 				  options, RUN_TTY, NULL, NULL) != 0)
96 		    error (1, 0, "failed when checking out new copy of %s",
97 			   finfo->fullname);
98 		xchmod (finfo->file, 1);
99 		set_time = 1;
100 	    }
101 
102 	    wrap_fromcvs_process_file (finfo->file);
103 
104 	    /*
105 	     * If we want read-only files, muck the permissions here, before
106 	     * getting the file time-stamp.
107 	     */
108 	    if (!cvswrite || fileattr_get (finfo->file, "_watched"))
109 		xchmod (finfo->file, 0);
110 
111 	    /* Re-register with the new data.  */
112 	    vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
113 	    if (strcmp (vers->options, "-V4") == 0)
114 		vers->options[0] = '\0';
115 	    Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
116 		      vers->options, vers->tag, vers->date, NULL);
117 	    history_write (type, NULL, vers->vn_rcs,
118 			   finfo->file, finfo->repository);
119 
120 	    if (tocvsPath)
121 		if (unlink_file_dir (tocvsPath) < 0)
122 		    error (0, errno, "cannot remove %s", tocvsPath);
123 
124 	    break;
125 
126 	case -1:			/* fork failed */
127 	    if (tocvsPath)
128 		if (unlink_file_dir (tocvsPath) < 0)
129 		    error (0, errno, "cannot remove %s", tocvsPath);
130 
131 	    if (!noexec)
132 		error (1, errno, "could not check in %s -- fork failed",
133 		       finfo->fullname);
134 	    return (1);
135 
136 	default:			/* ci failed */
137 
138 	    /* The checkin failed, for some unknown reason, so we
139 	       print an error, and return an error.  We assume that
140 	       the original file has not been touched.  */
141 	    if (tocvsPath)
142 		if (unlink_file_dir (tocvsPath) < 0)
143 		    error (0, errno, "cannot remove %s", tocvsPath);
144 
145 	    if (!noexec)
146 		error (0, 0, "could not check in %s", finfo->fullname);
147 	    return (1);
148     }
149 
150     /*
151      * When checking in a specific revision, we may have locked the wrong
152      * branch, so to be sure, we do an extra unlock here before
153      * returning.
154      */
155     if (rev)
156     {
157 	(void) RCS_unlock (finfo->rcs, NULL, 1);
158 	RCS_rewrite (finfo->rcs, NULL, NULL);
159     }
160 
161 #ifdef SERVER_SUPPORT
162     if (server_active)
163     {
164 	if (set_time)
165 	    /* Need to update the checked out file on the client side.  */
166 	    server_updated (finfo, vers, SERVER_UPDATED,
167 			    (mode_t) -1, NULL, NULL);
168 	else
169 	    server_checked_in (finfo->file, finfo->update_dir,
170 			       finfo->repository);
171     }
172     else
173 #endif
174 	mark_up_to_date (finfo->file);
175 
176     freevers_ts (&vers);
177     return 0;
178 }
179