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