186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
386d7f5d3SJohn Marino *
486d7f5d3SJohn Marino * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
586d7f5d3SJohn Marino * and others.
686d7f5d3SJohn Marino *
786d7f5d3SJohn Marino * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
886d7f5d3SJohn Marino * Portions Copyright (C) 1989-1992, Brian Berliner
986d7f5d3SJohn Marino *
1086d7f5d3SJohn Marino * You may distribute under the terms of the GNU General Public License as
1186d7f5d3SJohn Marino * specified in the README file that comes with the CVS source distribution.
1286d7f5d3SJohn Marino *
1386d7f5d3SJohn Marino * Check In
1486d7f5d3SJohn Marino *
1586d7f5d3SJohn Marino * Does a very careful checkin of the file "user", and tries not to spoil its
1686d7f5d3SJohn Marino * modification time (to avoid needless recompilations). When RCS ID keywords
1786d7f5d3SJohn Marino * get expanded on checkout, however, the modification time is updated and
1886d7f5d3SJohn Marino * there is no good way to get around this.
1986d7f5d3SJohn Marino *
2086d7f5d3SJohn Marino * Returns non-zero on error.
2186d7f5d3SJohn Marino */
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino #include "cvs.h"
2486d7f5d3SJohn Marino #include "fileattr.h"
2586d7f5d3SJohn Marino #include "edit.h"
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino int
Checkin(int type,struct file_info * finfo,char * rev,char * tag,char * options,char * message)2886d7f5d3SJohn Marino Checkin (int type, struct file_info *finfo, char *rev, char *tag,
2986d7f5d3SJohn Marino char *options, char *message)
3086d7f5d3SJohn Marino {
3186d7f5d3SJohn Marino Vers_TS *vers;
3286d7f5d3SJohn Marino int set_time;
3386d7f5d3SJohn Marino char *tocvsPath = NULL;
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino tocvsPath = wrap_tocvs_process_file (finfo->file);
3686d7f5d3SJohn Marino if (!noexec)
3786d7f5d3SJohn Marino {
3886d7f5d3SJohn Marino if (tocvsPath)
3986d7f5d3SJohn Marino {
4086d7f5d3SJohn Marino if (unlink_file_dir (finfo->file) < 0)
4186d7f5d3SJohn Marino if (! existence_error (errno))
4286d7f5d3SJohn Marino error (1, errno, "cannot remove %s", finfo->fullname);
4386d7f5d3SJohn Marino rename_file (tocvsPath, finfo->file);
4486d7f5d3SJohn Marino }
4586d7f5d3SJohn Marino }
4686d7f5d3SJohn Marino
4786d7f5d3SJohn Marino /* There use to be a check for finfo->rcs == NULL here and then a
4886d7f5d3SJohn Marino * call to RCS_parse when necessary, but Checkin() isn't called
4986d7f5d3SJohn Marino * if the RCS file hasn't already been parsed in one of the
5086d7f5d3SJohn Marino * check functions.
5186d7f5d3SJohn Marino */
5286d7f5d3SJohn Marino assert (finfo->rcs != NULL);
5386d7f5d3SJohn Marino
5486d7f5d3SJohn Marino switch (RCS_checkin (finfo->rcs, finfo->update_dir, finfo->file, message,
5586d7f5d3SJohn Marino rev, 0, RCS_FLAGS_KEEPFILE))
5686d7f5d3SJohn Marino {
5786d7f5d3SJohn Marino case 0: /* everything normal */
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino /* The checkin succeeded. If checking the file out again
6086d7f5d3SJohn Marino would not cause any changes, we are done. Otherwise,
6186d7f5d3SJohn Marino we need to check out the file, which will change the
6286d7f5d3SJohn Marino modification time of the file.
6386d7f5d3SJohn Marino
6486d7f5d3SJohn Marino The only way checking out the file could cause any
6586d7f5d3SJohn Marino changes is if the file contains RCS keywords. So we if
6686d7f5d3SJohn Marino we are not expanding RCS keywords, we are done. */
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */
6986d7f5d3SJohn Marino options[0] = '\0';
7086d7f5d3SJohn Marino
7186d7f5d3SJohn Marino /* FIXME: If PreservePermissions is on, RCS_cmp_file is
7286d7f5d3SJohn Marino going to call RCS_checkout into a temporary file
7386d7f5d3SJohn Marino anyhow. In that case, it would be more efficient to
7486d7f5d3SJohn Marino call RCS_checkout here, compare the resulting files
7586d7f5d3SJohn Marino using xcmp, and rename if necessary. I think this
7686d7f5d3SJohn Marino should be fixed in RCS_cmp_file. */
7786d7f5d3SJohn Marino if ((1
7886d7f5d3SJohn Marino #ifdef PRESERVE_PERMISSIONS_SUPPORT
7986d7f5d3SJohn Marino !config->preserve_perms
8086d7f5d3SJohn Marino #endif /* PRESERVE_PERMISSIONS_SUPPORT */
8186d7f5d3SJohn Marino && options
8286d7f5d3SJohn Marino && (!strcmp (options, "-ko") || !strcmp (options, "-kb")))
8386d7f5d3SJohn Marino || !RCS_cmp_file (finfo->rcs, rev, NULL, NULL,
8486d7f5d3SJohn Marino options, finfo->file))
8586d7f5d3SJohn Marino {
8686d7f5d3SJohn Marino /* The existing file is correct. We don't have to do
8786d7f5d3SJohn Marino anything. */
8886d7f5d3SJohn Marino set_time = 0;
8986d7f5d3SJohn Marino }
9086d7f5d3SJohn Marino else
9186d7f5d3SJohn Marino {
9286d7f5d3SJohn Marino /* The existing file is incorrect. We need to check
9386d7f5d3SJohn Marino out the correct file contents. */
9486d7f5d3SJohn Marino if (RCS_checkout (finfo->rcs, finfo->file, rev, NULL,
9586d7f5d3SJohn Marino options, RUN_TTY, NULL, NULL) != 0)
9686d7f5d3SJohn Marino error (1, 0, "failed when checking out new copy of %s",
9786d7f5d3SJohn Marino finfo->fullname);
9886d7f5d3SJohn Marino xchmod (finfo->file, 1);
9986d7f5d3SJohn Marino set_time = 1;
10086d7f5d3SJohn Marino }
10186d7f5d3SJohn Marino
10286d7f5d3SJohn Marino wrap_fromcvs_process_file (finfo->file);
10386d7f5d3SJohn Marino
10486d7f5d3SJohn Marino /*
10586d7f5d3SJohn Marino * If we want read-only files, muck the permissions here, before
10686d7f5d3SJohn Marino * getting the file time-stamp.
10786d7f5d3SJohn Marino */
10886d7f5d3SJohn Marino if (!cvswrite || fileattr_get (finfo->file, "_watched"))
10986d7f5d3SJohn Marino xchmod (finfo->file, 0);
11086d7f5d3SJohn Marino
11186d7f5d3SJohn Marino /* Re-register with the new data. */
11286d7f5d3SJohn Marino vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
11386d7f5d3SJohn Marino if (strcmp (vers->options, "-V4") == 0)
11486d7f5d3SJohn Marino vers->options[0] = '\0';
11586d7f5d3SJohn Marino Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
11686d7f5d3SJohn Marino vers->options, vers->tag, vers->date, NULL);
11786d7f5d3SJohn Marino history_write (type, NULL, vers->vn_rcs,
11886d7f5d3SJohn Marino finfo->file, finfo->repository);
11986d7f5d3SJohn Marino
12086d7f5d3SJohn Marino if (tocvsPath)
12186d7f5d3SJohn Marino if (unlink_file_dir (tocvsPath) < 0)
12286d7f5d3SJohn Marino error (0, errno, "cannot remove %s", tocvsPath);
12386d7f5d3SJohn Marino
12486d7f5d3SJohn Marino break;
12586d7f5d3SJohn Marino
12686d7f5d3SJohn Marino case -1: /* fork failed */
12786d7f5d3SJohn Marino if (tocvsPath)
12886d7f5d3SJohn Marino if (unlink_file_dir (tocvsPath) < 0)
12986d7f5d3SJohn Marino error (0, errno, "cannot remove %s", tocvsPath);
13086d7f5d3SJohn Marino
13186d7f5d3SJohn Marino if (!noexec)
13286d7f5d3SJohn Marino error (1, errno, "could not check in %s -- fork failed",
13386d7f5d3SJohn Marino finfo->fullname);
13486d7f5d3SJohn Marino return (1);
13586d7f5d3SJohn Marino
13686d7f5d3SJohn Marino default: /* ci failed */
13786d7f5d3SJohn Marino
13886d7f5d3SJohn Marino /* The checkin failed, for some unknown reason, so we
13986d7f5d3SJohn Marino print an error, and return an error. We assume that
14086d7f5d3SJohn Marino the original file has not been touched. */
14186d7f5d3SJohn Marino if (tocvsPath)
14286d7f5d3SJohn Marino if (unlink_file_dir (tocvsPath) < 0)
14386d7f5d3SJohn Marino error (0, errno, "cannot remove %s", tocvsPath);
14486d7f5d3SJohn Marino
14586d7f5d3SJohn Marino if (!noexec)
14686d7f5d3SJohn Marino error (0, 0, "could not check in %s", finfo->fullname);
14786d7f5d3SJohn Marino return (1);
14886d7f5d3SJohn Marino }
14986d7f5d3SJohn Marino
15086d7f5d3SJohn Marino /*
15186d7f5d3SJohn Marino * When checking in a specific revision, we may have locked the wrong
15286d7f5d3SJohn Marino * branch, so to be sure, we do an extra unlock here before
15386d7f5d3SJohn Marino * returning.
15486d7f5d3SJohn Marino */
15586d7f5d3SJohn Marino if (rev)
15686d7f5d3SJohn Marino {
15786d7f5d3SJohn Marino (void) RCS_unlock (finfo->rcs, NULL, 1);
15886d7f5d3SJohn Marino RCS_rewrite (finfo->rcs, NULL, NULL);
15986d7f5d3SJohn Marino }
16086d7f5d3SJohn Marino
16186d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
16286d7f5d3SJohn Marino if (server_active)
16386d7f5d3SJohn Marino {
16486d7f5d3SJohn Marino if (set_time)
16586d7f5d3SJohn Marino /* Need to update the checked out file on the client side. */
16686d7f5d3SJohn Marino server_updated (finfo, vers, SERVER_UPDATED,
16786d7f5d3SJohn Marino (mode_t) -1, NULL, NULL);
16886d7f5d3SJohn Marino else
16986d7f5d3SJohn Marino server_checked_in (finfo->file, finfo->update_dir,
17086d7f5d3SJohn Marino finfo->repository);
17186d7f5d3SJohn Marino }
17286d7f5d3SJohn Marino else
17386d7f5d3SJohn Marino #endif
17486d7f5d3SJohn Marino mark_up_to_date (finfo->file);
17586d7f5d3SJohn Marino
17686d7f5d3SJohn Marino freevers_ts (&vers);
17786d7f5d3SJohn Marino return 0;
17886d7f5d3SJohn Marino }
179