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