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