xref: /dflybsd-src/contrib/cvs-1.12/src/checkin.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
386d7f5d3SJohn Marino  *
486d7f5d3SJohn Marino  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
586d7f5d3SJohn Marino  *                                  and others.
686d7f5d3SJohn Marino  *
786d7f5d3SJohn Marino  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
886d7f5d3SJohn Marino  * Portions Copyright (C) 1989-1992, Brian Berliner
986d7f5d3SJohn Marino  *
1086d7f5d3SJohn Marino  * You may distribute under the terms of the GNU General Public License as
1186d7f5d3SJohn Marino  * specified in the README file that comes with the CVS source distribution.
1286d7f5d3SJohn Marino  *
1386d7f5d3SJohn Marino  * Check In
1486d7f5d3SJohn Marino  *
1586d7f5d3SJohn Marino  * Does a very careful checkin of the file "user", and tries not to spoil its
1686d7f5d3SJohn Marino  * modification time (to avoid needless recompilations). When RCS ID keywords
1786d7f5d3SJohn Marino  * get expanded on checkout, however, the modification time is updated and
1886d7f5d3SJohn Marino  * there is no good way to get around this.
1986d7f5d3SJohn Marino  *
2086d7f5d3SJohn Marino  * Returns non-zero on error.
2186d7f5d3SJohn Marino  */
2286d7f5d3SJohn Marino 
2386d7f5d3SJohn Marino #include "cvs.h"
2486d7f5d3SJohn Marino #include "fileattr.h"
2586d7f5d3SJohn Marino #include "edit.h"
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino int
Checkin(int type,struct file_info * finfo,char * rev,char * tag,char * options,char * message)2886d7f5d3SJohn Marino Checkin (int type, struct file_info *finfo, char *rev, char *tag,
2986d7f5d3SJohn Marino 	 char *options, char *message)
3086d7f5d3SJohn Marino {
3186d7f5d3SJohn Marino     Vers_TS *vers;
3286d7f5d3SJohn Marino     int set_time;
3386d7f5d3SJohn Marino     char *tocvsPath = NULL;
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino     tocvsPath = wrap_tocvs_process_file (finfo->file);
3686d7f5d3SJohn Marino     if (!noexec)
3786d7f5d3SJohn Marino     {
3886d7f5d3SJohn Marino         if (tocvsPath)
3986d7f5d3SJohn Marino 	{
4086d7f5d3SJohn Marino 	    if (unlink_file_dir (finfo->file) < 0)
4186d7f5d3SJohn Marino 		if (! existence_error (errno))
4286d7f5d3SJohn Marino 		    error (1, errno, "cannot remove %s", finfo->fullname);
4386d7f5d3SJohn Marino 	    rename_file (tocvsPath, finfo->file);
4486d7f5d3SJohn Marino 	}
4586d7f5d3SJohn Marino     }
4686d7f5d3SJohn Marino 
4786d7f5d3SJohn Marino     /* There use to be a check for finfo->rcs == NULL here and then a
4886d7f5d3SJohn Marino      * call to RCS_parse when necessary, but Checkin() isn't called
4986d7f5d3SJohn Marino      * if the RCS file hasn't already been parsed in one of the
5086d7f5d3SJohn Marino      * check functions.
5186d7f5d3SJohn Marino      */
5286d7f5d3SJohn Marino     assert (finfo->rcs != NULL);
5386d7f5d3SJohn Marino 
5486d7f5d3SJohn Marino     switch (RCS_checkin (finfo->rcs, finfo->update_dir, finfo->file, message,
5586d7f5d3SJohn Marino 			 rev, 0, RCS_FLAGS_KEEPFILE))
5686d7f5d3SJohn Marino     {
5786d7f5d3SJohn Marino 	case 0:			/* everything normal */
5886d7f5d3SJohn Marino 
5986d7f5d3SJohn Marino 	    /* The checkin succeeded.  If checking the file out again
6086d7f5d3SJohn Marino                would not cause any changes, we are done.  Otherwise,
6186d7f5d3SJohn Marino                we need to check out the file, which will change the
6286d7f5d3SJohn Marino                modification time of the file.
6386d7f5d3SJohn Marino 
6486d7f5d3SJohn Marino 	       The only way checking out the file could cause any
6586d7f5d3SJohn Marino 	       changes is if the file contains RCS keywords.  So we if
6686d7f5d3SJohn Marino 	       we are not expanding RCS keywords, we are done.  */
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino 	    if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
6986d7f5d3SJohn Marino 		options[0] = '\0';
7086d7f5d3SJohn Marino 
7186d7f5d3SJohn Marino 	    /* FIXME: If PreservePermissions is on, RCS_cmp_file is
7286d7f5d3SJohn Marino                going to call RCS_checkout into a temporary file
7386d7f5d3SJohn Marino                anyhow.  In that case, it would be more efficient to
7486d7f5d3SJohn Marino                call RCS_checkout here, compare the resulting files
7586d7f5d3SJohn Marino                using xcmp, and rename if necessary.  I think this
7686d7f5d3SJohn Marino                should be fixed in RCS_cmp_file.  */
7786d7f5d3SJohn Marino 	    if ((1
7886d7f5d3SJohn Marino #ifdef PRESERVE_PERMISSIONS_SUPPORT
7986d7f5d3SJohn Marino 		 !config->preserve_perms
8086d7f5d3SJohn Marino #endif /* PRESERVE_PERMISSIONS_SUPPORT */
8186d7f5d3SJohn Marino 		 && options
8286d7f5d3SJohn Marino 		 && (!strcmp (options, "-ko") || !strcmp (options, "-kb")))
8386d7f5d3SJohn Marino 		|| !RCS_cmp_file (finfo->rcs, rev, NULL, NULL,
8486d7f5d3SJohn Marino 	                          options, finfo->file))
8586d7f5d3SJohn Marino 	    {
8686d7f5d3SJohn Marino 		/* The existing file is correct.  We don't have to do
8786d7f5d3SJohn Marino                    anything.  */
8886d7f5d3SJohn Marino 		set_time = 0;
8986d7f5d3SJohn Marino 	    }
9086d7f5d3SJohn Marino 	    else
9186d7f5d3SJohn Marino 	    {
9286d7f5d3SJohn Marino 		/* The existing file is incorrect.  We need to check
9386d7f5d3SJohn Marino                    out the correct file contents.  */
9486d7f5d3SJohn Marino 		if (RCS_checkout (finfo->rcs, finfo->file, rev, NULL,
9586d7f5d3SJohn Marino 				  options, RUN_TTY, NULL, NULL) != 0)
9686d7f5d3SJohn Marino 		    error (1, 0, "failed when checking out new copy of %s",
9786d7f5d3SJohn Marino 			   finfo->fullname);
9886d7f5d3SJohn Marino 		xchmod (finfo->file, 1);
9986d7f5d3SJohn Marino 		set_time = 1;
10086d7f5d3SJohn Marino 	    }
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino 	    wrap_fromcvs_process_file (finfo->file);
10386d7f5d3SJohn Marino 
10486d7f5d3SJohn Marino 	    /*
10586d7f5d3SJohn Marino 	     * If we want read-only files, muck the permissions here, before
10686d7f5d3SJohn Marino 	     * getting the file time-stamp.
10786d7f5d3SJohn Marino 	     */
10886d7f5d3SJohn Marino 	    if (!cvswrite || fileattr_get (finfo->file, "_watched"))
10986d7f5d3SJohn Marino 		xchmod (finfo->file, 0);
11086d7f5d3SJohn Marino 
11186d7f5d3SJohn Marino 	    /* Re-register with the new data.  */
11286d7f5d3SJohn Marino 	    vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
11386d7f5d3SJohn Marino 	    if (strcmp (vers->options, "-V4") == 0)
11486d7f5d3SJohn Marino 		vers->options[0] = '\0';
11586d7f5d3SJohn Marino 	    Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
11686d7f5d3SJohn Marino 		      vers->options, vers->tag, vers->date, NULL);
11786d7f5d3SJohn Marino 	    history_write (type, NULL, vers->vn_rcs,
11886d7f5d3SJohn Marino 			   finfo->file, finfo->repository);
11986d7f5d3SJohn Marino 
12086d7f5d3SJohn Marino 	    if (tocvsPath)
12186d7f5d3SJohn Marino 		if (unlink_file_dir (tocvsPath) < 0)
12286d7f5d3SJohn Marino 		    error (0, errno, "cannot remove %s", tocvsPath);
12386d7f5d3SJohn Marino 
12486d7f5d3SJohn Marino 	    break;
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 	case -1:			/* fork failed */
12786d7f5d3SJohn Marino 	    if (tocvsPath)
12886d7f5d3SJohn Marino 		if (unlink_file_dir (tocvsPath) < 0)
12986d7f5d3SJohn Marino 		    error (0, errno, "cannot remove %s", tocvsPath);
13086d7f5d3SJohn Marino 
13186d7f5d3SJohn Marino 	    if (!noexec)
13286d7f5d3SJohn Marino 		error (1, errno, "could not check in %s -- fork failed",
13386d7f5d3SJohn Marino 		       finfo->fullname);
13486d7f5d3SJohn Marino 	    return (1);
13586d7f5d3SJohn Marino 
13686d7f5d3SJohn Marino 	default:			/* ci failed */
13786d7f5d3SJohn Marino 
13886d7f5d3SJohn Marino 	    /* The checkin failed, for some unknown reason, so we
13986d7f5d3SJohn Marino 	       print an error, and return an error.  We assume that
14086d7f5d3SJohn Marino 	       the original file has not been touched.  */
14186d7f5d3SJohn Marino 	    if (tocvsPath)
14286d7f5d3SJohn Marino 		if (unlink_file_dir (tocvsPath) < 0)
14386d7f5d3SJohn Marino 		    error (0, errno, "cannot remove %s", tocvsPath);
14486d7f5d3SJohn Marino 
14586d7f5d3SJohn Marino 	    if (!noexec)
14686d7f5d3SJohn Marino 		error (0, 0, "could not check in %s", finfo->fullname);
14786d7f5d3SJohn Marino 	    return (1);
14886d7f5d3SJohn Marino     }
14986d7f5d3SJohn Marino 
15086d7f5d3SJohn Marino     /*
15186d7f5d3SJohn Marino      * When checking in a specific revision, we may have locked the wrong
15286d7f5d3SJohn Marino      * branch, so to be sure, we do an extra unlock here before
15386d7f5d3SJohn Marino      * returning.
15486d7f5d3SJohn Marino      */
15586d7f5d3SJohn Marino     if (rev)
15686d7f5d3SJohn Marino     {
15786d7f5d3SJohn Marino 	(void) RCS_unlock (finfo->rcs, NULL, 1);
15886d7f5d3SJohn Marino 	RCS_rewrite (finfo->rcs, NULL, NULL);
15986d7f5d3SJohn Marino     }
16086d7f5d3SJohn Marino 
16186d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
16286d7f5d3SJohn Marino     if (server_active)
16386d7f5d3SJohn Marino     {
16486d7f5d3SJohn Marino 	if (set_time)
16586d7f5d3SJohn Marino 	    /* Need to update the checked out file on the client side.  */
16686d7f5d3SJohn Marino 	    server_updated (finfo, vers, SERVER_UPDATED,
16786d7f5d3SJohn Marino 			    (mode_t) -1, NULL, NULL);
16886d7f5d3SJohn Marino 	else
16986d7f5d3SJohn Marino 	    server_checked_in (finfo->file, finfo->update_dir,
17086d7f5d3SJohn Marino 			       finfo->repository);
17186d7f5d3SJohn Marino     }
17286d7f5d3SJohn Marino     else
17386d7f5d3SJohn Marino #endif
17486d7f5d3SJohn Marino 	mark_up_to_date (finfo->file);
17586d7f5d3SJohn Marino 
17686d7f5d3SJohn Marino     freevers_ts (&vers);
17786d7f5d3SJohn Marino     return 0;
17886d7f5d3SJohn Marino }
179