summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/checkin.c
blob: e1ce9cbcbde6949d92ffa49d6d055549087482c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * Copyright (c) 1992, Brian Berliner and Jeff Polk
 * Copyright (c) 1989-1992, Brian Berliner
 * 
 * You may distribute under the terms of the GNU General Public License as
 * specified in the README file that comes with the CVS 1.4 kit.
 * 
 * Check In
 * 
 * Does a very careful checkin of the file "user", and tries not to spoil its
 * modification time (to avoid needless recompilations). When RCS ID keywords
 * get expanded on checkout, however, the modification time is updated and
 * there is no good way to get around this.
 * 
 * Returns non-zero on error.
 */

#include "cvs.h"
#include "fileattr.h"
#include "edit.h"

int
Checkin (type, file, update_dir, repository,
	 rcs, rev, tag, options, message, entries)
    int type;
    char *file;
    char *update_dir;
    char *repository;
    char *rcs;
    char *rev;
    char *tag;
    char *options;
    char *message;
    List *entries;
{
    char fname[PATH_MAX];
    Vers_TS *vers;
    int set_time;
    char *fullname;

    char *tocvsPath = NULL;

    fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
    if (update_dir[0] == '\0')
	strcpy (fullname, file);
    else
	sprintf (fullname, "%s/%s", update_dir, file);

    (void) printf ("Checking in %s;\n", fullname);
    (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);

    /*
     * Move the user file to a backup file, so as to preserve its
     * modification times, then place a copy back in the original file name
     * for the checkin and checkout.
     */

    tocvsPath = wrap_tocvs_process_file (fullname);

    if (!noexec)
    {
        if (tocvsPath)
	{
            copy_file (tocvsPath, fname);
	    if (unlink_file_dir (file) < 0)
		if (! existence_error (errno))
		    error (1, errno, "cannot remove %s", file);
	    copy_file (tocvsPath, file);
	}
	else
	{
	    copy_file (file, fname);
	}
    }

    switch (RCS_checkin (rcs, NULL, message, rev, 0, 0))
    {
	case 0:			/* everything normal */

	    /*
	     * The checkin succeeded, so now check the new file back out and
	     * see if it matches exactly with the one we checked in. If it
	     * does, just move the original user file back, thus preserving
	     * the modes; otherwise, we have no recourse but to leave the
	     * newly checkout file as the user file and remove the old
	     * original user file.
	     */

	    if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
		options[0] = '\0';

	    /* FIXME: should be checking for errors.  */
	    (void) RCS_checkout (rcs, "", rev, options, RUN_TTY, 0, 0);

	    xchmod (file, 1);
	    if (xcmp (file, fname) == 0)
	    {
		rename_file (fname, file);
		/* the time was correct, so leave it alone */
		set_time = 0;
	    }
	    else
	    {
		if (unlink_file (fname) < 0)
		    error (0, errno, "cannot remove %s", fname);
		/* sync up with the time from the RCS file */
		set_time = 1;
	    }

	    wrap_fromcvs_process_file (file);

	    /*
	     * If we want read-only files, muck the permissions here, before
	     * getting the file time-stamp.
	     */
	    if (cvswrite == FALSE || fileattr_get (file, "_watched"))
		xchmod (file, 0);

	    /* re-register with the new data */
	    vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
			       file, 1, set_time, entries, (RCSNode *) NULL);
	    if (strcmp (vers->options, "-V4") == 0)
		vers->options[0] = '\0';
	    Register (entries, file, vers->vn_rcs, vers->ts_user,
		      vers->options, vers->tag, vers->date, (char *) 0);
	    history_write (type, (char *) 0, vers->vn_rcs, file, repository);
	    freevers_ts (&vers);

	    if (tocvsPath)
		if (unlink_file_dir (tocvsPath) < 0)
		    error (0, errno, "cannot remove %s", tocvsPath);

	    break;

	case -1:			/* fork failed */
	    if (tocvsPath)
		if (unlink_file_dir (tocvsPath) < 0)
		    error (0, errno, "cannot remove %s", tocvsPath);

	    if (!noexec)
		error (1, errno, "could not check in %s -- fork failed",
		       fullname);
	    return (1);

	default:			/* ci failed */

	    /*
	     * The checkin failed, for some unknown reason, so we restore the
	     * original user file, print an error, and return an error
	     */
	    if (tocvsPath)
		if (unlink_file_dir (tocvsPath) < 0)
		    error (0, errno, "cannot remove %s", tocvsPath);

	    if (!noexec)
	    {
		rename_file (fname, file);
		error (0, 0, "could not check in %s", fullname);
	    }
	    return (1);
    }

    /*
     * When checking in a specific revision, we may have locked the wrong
     * branch, so to be sure, we do an extra unlock here before
     * returning.
     */
    if (rev)
    {
	(void) RCS_unlock (rcs, NULL, 1);
    }

#ifdef SERVER_SUPPORT
    if (server_active)
    {
	if (set_time)
	    /* Need to update the checked out file on the client side.  */
	    server_updated (file, update_dir, repository, SERVER_UPDATED,
			    NULL, NULL);
	else
	    server_checked_in (file, update_dir, repository);
    }
    else
#endif
	mark_up_to_date (file);

    return (0);
}
OpenPOWER on IntegriCloud