xref: /openbsd/gnu/usr.bin/cvs/src/checkin.c (revision 5e617892)
11e72d8d2Sderaadt /*
21e72d8d2Sderaadt  * Copyright (c) 1992, Brian Berliner and Jeff Polk
31e72d8d2Sderaadt  * Copyright (c) 1989-1992, Brian Berliner
41e72d8d2Sderaadt  *
51e72d8d2Sderaadt  * You may distribute under the terms of the GNU General Public License as
62286d8edStholo  * specified in the README file that comes with the CVS source distribution.
71e72d8d2Sderaadt  *
81e72d8d2Sderaadt  * Check In
91e72d8d2Sderaadt  *
101e72d8d2Sderaadt  * Does a very careful checkin of the file "user", and tries not to spoil its
111e72d8d2Sderaadt  * modification time (to avoid needless recompilations). When RCS ID keywords
121e72d8d2Sderaadt  * get expanded on checkout, however, the modification time is updated and
131e72d8d2Sderaadt  * there is no good way to get around this.
141e72d8d2Sderaadt  *
151e72d8d2Sderaadt  * Returns non-zero on error.
161e72d8d2Sderaadt  */
171e72d8d2Sderaadt 
181e72d8d2Sderaadt #include "cvs.h"
1913571821Stholo #include "fileattr.h"
2013571821Stholo #include "edit.h"
211e72d8d2Sderaadt 
221e72d8d2Sderaadt int
Checkin(type,finfo,rcs,rev,tag,options,message)2350bf276cStholo Checkin (type, finfo, rcs, rev, tag, options, message)
241e72d8d2Sderaadt     int type;
2550bf276cStholo     struct file_info *finfo;
261e72d8d2Sderaadt     char *rcs;
271e72d8d2Sderaadt     char *rev;
281e72d8d2Sderaadt     char *tag;
291e72d8d2Sderaadt     char *options;
301e72d8d2Sderaadt     char *message;
311e72d8d2Sderaadt {
321e72d8d2Sderaadt     Vers_TS *vers;
331e72d8d2Sderaadt     int set_time;
341e72d8d2Sderaadt     char *tocvsPath = NULL;
351e72d8d2Sderaadt 
36780d15dfStholo     /* Hmm.  This message goes to stdout and the "foo,v  <--  foo"
37780d15dfStholo        message from "ci" goes to stderr.  This doesn't make a whole
38780d15dfStholo        lot of sense, but making everything go to stdout can only be
39780d15dfStholo        gracefully achieved once RCS_checkin is librarified.  */
40780d15dfStholo     cvs_output ("Checking in ", 0);
41780d15dfStholo     cvs_output (finfo->fullname, 0);
42780d15dfStholo     cvs_output (";\n", 0);
43780d15dfStholo 
442770ece5Stholo     tocvsPath = wrap_tocvs_process_file (finfo->file);
451e72d8d2Sderaadt     if (!noexec)
461e72d8d2Sderaadt     {
471e72d8d2Sderaadt         if (tocvsPath)
481e72d8d2Sderaadt 	{
4950bf276cStholo 	    if (unlink_file_dir (finfo->file) < 0)
5013571821Stholo 		if (! existence_error (errno))
5150bf276cStholo 		    error (1, errno, "cannot remove %s", finfo->fullname);
52*5e617892Stholo 	    rename_file (tocvsPath, finfo->file);
531e72d8d2Sderaadt 	}
541e72d8d2Sderaadt     }
551e72d8d2Sderaadt 
562286d8edStholo     if (finfo->rcs == NULL)
572286d8edStholo 	finfo->rcs = RCS_parse (finfo->file, finfo->repository);
582286d8edStholo 
59*5e617892Stholo     switch (RCS_checkin (finfo->rcs, NULL, message, rev, RCS_FLAGS_KEEPFILE))
601e72d8d2Sderaadt     {
611e72d8d2Sderaadt 	case 0:			/* everything normal */
621e72d8d2Sderaadt 
63*5e617892Stholo 	    /* The checkin succeeded.  If checking the file out again
64*5e617892Stholo                would not cause any changes, we are done.  Otherwise,
65*5e617892Stholo                we need to check out the file, which will change the
66*5e617892Stholo                modification time of the file.
67*5e617892Stholo 
68*5e617892Stholo 	       The only way checking out the file could cause any
69*5e617892Stholo 	       changes is if the file contains RCS keywords.  So we if
70*5e617892Stholo 	       we are not expanding RCS keywords, we are done.  */
711e72d8d2Sderaadt 
721e72d8d2Sderaadt 	    if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
731e72d8d2Sderaadt 		options[0] = '\0';
74c26070a5Stholo 
75*5e617892Stholo 	    /* FIXME: If PreservePermissions is on, RCS_cmp_file is
76*5e617892Stholo                going to call RCS_checkout into a temporary file
77*5e617892Stholo                anyhow.  In that case, it would be more efficient to
78*5e617892Stholo                call RCS_checkout here, compare the resulting files
79*5e617892Stholo                using xcmp, and rename if necessary.  I think this
80*5e617892Stholo                should be fixed in RCS_cmp_file.  */
81*5e617892Stholo 	    if ((! preserve_perms
82*5e617892Stholo 		 && options != NULL
83*5e617892Stholo 		 && (strcmp (options, "-ko") == 0
84*5e617892Stholo 		     || strcmp (options, "-kb") == 0))
85*5e617892Stholo 		|| RCS_cmp_file (finfo->rcs, rev, options, finfo->file) == 0)
861e72d8d2Sderaadt 	    {
87*5e617892Stholo 		/* The existing file is correct.  We don't have to do
88*5e617892Stholo                    anything.  */
891e72d8d2Sderaadt 		set_time = 0;
901e72d8d2Sderaadt 	    }
911e72d8d2Sderaadt 	    else
921e72d8d2Sderaadt 	    {
93*5e617892Stholo 		/* The existing file is incorrect.  We need to check
94*5e617892Stholo                    out the correct file contents.  */
95*5e617892Stholo 		if (RCS_checkout (finfo->rcs, finfo->file, rev, (char *) NULL,
96*5e617892Stholo 				  options, RUN_TTY, (RCSCHECKOUTPROC) NULL,
97*5e617892Stholo 				  (void *) NULL) != 0)
98*5e617892Stholo 		    error (1, 0, "failed when checking out new copy of %s",
99*5e617892Stholo 			   finfo->fullname);
100*5e617892Stholo 		xchmod (finfo->file, 1);
1011e72d8d2Sderaadt 		set_time = 1;
1021e72d8d2Sderaadt 	    }
1031e72d8d2Sderaadt 
10450bf276cStholo 	    wrap_fromcvs_process_file (finfo->file);
1051e72d8d2Sderaadt 
1061e72d8d2Sderaadt 	    /*
1071e72d8d2Sderaadt 	     * If we want read-only files, muck the permissions here, before
1081e72d8d2Sderaadt 	     * getting the file time-stamp.
1091e72d8d2Sderaadt 	     */
1102286d8edStholo 	    if (!cvswrite || fileattr_get (finfo->file, "_watched"))
11150bf276cStholo 		xchmod (finfo->file, 0);
1121e72d8d2Sderaadt 
11350bf276cStholo 	    /* Re-register with the new data.  */
11450bf276cStholo 	    vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
1151e72d8d2Sderaadt 	    if (strcmp (vers->options, "-V4") == 0)
1161e72d8d2Sderaadt 		vers->options[0] = '\0';
11750bf276cStholo 	    Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
1181e72d8d2Sderaadt 		      vers->options, vers->tag, vers->date, (char *) 0);
11950bf276cStholo 	    history_write (type, NULL, vers->vn_rcs,
12050bf276cStholo 			   finfo->file, finfo->repository);
1211e72d8d2Sderaadt 
1221e72d8d2Sderaadt 	    if (tocvsPath)
1231e72d8d2Sderaadt 		if (unlink_file_dir (tocvsPath) < 0)
1241e72d8d2Sderaadt 		    error (0, errno, "cannot remove %s", tocvsPath);
1251e72d8d2Sderaadt 
1261e72d8d2Sderaadt 	    break;
1271e72d8d2Sderaadt 
1281e72d8d2Sderaadt 	case -1:			/* fork failed */
1291e72d8d2Sderaadt 	    if (tocvsPath)
1301e72d8d2Sderaadt 		if (unlink_file_dir (tocvsPath) < 0)
1311e72d8d2Sderaadt 		    error (0, errno, "cannot remove %s", tocvsPath);
1321e72d8d2Sderaadt 
1331e72d8d2Sderaadt 	    if (!noexec)
1341e72d8d2Sderaadt 		error (1, errno, "could not check in %s -- fork failed",
13550bf276cStholo 		       finfo->fullname);
1361e72d8d2Sderaadt 	    return (1);
1371e72d8d2Sderaadt 
1381e72d8d2Sderaadt 	default:			/* ci failed */
1391e72d8d2Sderaadt 
140*5e617892Stholo 	    /* The checkin failed, for some unknown reason, so we
141*5e617892Stholo 	       print an error, and return an error.  We assume that
142*5e617892Stholo 	       the original file has not been touched.  */
1431e72d8d2Sderaadt 	    if (tocvsPath)
1441e72d8d2Sderaadt 		if (unlink_file_dir (tocvsPath) < 0)
1451e72d8d2Sderaadt 		    error (0, errno, "cannot remove %s", tocvsPath);
1461e72d8d2Sderaadt 
1471e72d8d2Sderaadt 	    if (!noexec)
14850bf276cStholo 		error (0, 0, "could not check in %s", finfo->fullname);
1491e72d8d2Sderaadt 	    return (1);
1501e72d8d2Sderaadt     }
1511e72d8d2Sderaadt 
1521e72d8d2Sderaadt     /*
1531e72d8d2Sderaadt      * When checking in a specific revision, we may have locked the wrong
1541e72d8d2Sderaadt      * branch, so to be sure, we do an extra unlock here before
1551e72d8d2Sderaadt      * returning.
1561e72d8d2Sderaadt      */
1571e72d8d2Sderaadt     if (rev)
1581e72d8d2Sderaadt     {
15950bf276cStholo 	(void) RCS_unlock (finfo->rcs, NULL, 1);
1602286d8edStholo 	RCS_rewrite (finfo->rcs, NULL, NULL);
1611e72d8d2Sderaadt     }
1621e72d8d2Sderaadt 
1631e72d8d2Sderaadt #ifdef SERVER_SUPPORT
1641e72d8d2Sderaadt     if (server_active)
1651e72d8d2Sderaadt     {
1661e72d8d2Sderaadt 	if (set_time)
1671e72d8d2Sderaadt 	    /* Need to update the checked out file on the client side.  */
16850bf276cStholo 	    server_updated (finfo, vers, SERVER_UPDATED,
169*5e617892Stholo 			    (mode_t) -1, (unsigned char *) NULL,
170*5e617892Stholo 			    (struct buffer *) NULL);
1711e72d8d2Sderaadt 	else
17250bf276cStholo 	    server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
1731e72d8d2Sderaadt     }
17413571821Stholo     else
1751e72d8d2Sderaadt #endif
17650bf276cStholo 	mark_up_to_date (finfo->file);
1771e72d8d2Sderaadt 
17850bf276cStholo     freevers_ts (&vers);
1791e72d8d2Sderaadt     return (0);
1801e72d8d2Sderaadt }
181