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