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