Merge changes from CYCLIC branch onto mainline. rcs.[ch] still to come.
This commit is contained in:
parent
edd1d86130
commit
d302a0c08c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=32788
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* Commit Files
|
||||
*
|
||||
@ -92,6 +92,7 @@ static const char *const commit_usage[] =
|
||||
"\t-F file\tRead the log message from file.\n",
|
||||
"\t-m msg\tLog message.\n",
|
||||
"\t-r rev\tCommit to this branch or trunk revision.\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -144,8 +145,22 @@ find_dirent_proc (callerdat, dir, repository, update_dir, entries)
|
||||
{
|
||||
struct find_data *find_data = (struct find_data *)callerdat;
|
||||
|
||||
/* This check seems to slowly be creeping throughout CVS (update
|
||||
and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
|
||||
is that it (or some variant thereof) should go in all the
|
||||
dirent procs. Unless someone has some better idea... */
|
||||
if (!isdir (dir))
|
||||
return (R_SKIP_ALL);
|
||||
|
||||
/* initialize the ignore list for this directory */
|
||||
find_data->ignlist = getlist ();
|
||||
|
||||
/* Print the same warm fuzzy as in check_direntproc, since that
|
||||
code will never be run during client/server operation and we
|
||||
want the messages to match. */
|
||||
if (!quiet)
|
||||
error (0, 0, "Examining %s", update_dir);
|
||||
|
||||
return R_PROCESS;
|
||||
}
|
||||
|
||||
@ -232,7 +247,7 @@ find_fileproc (callerdat, finfo)
|
||||
xfinfo.repository = NULL;
|
||||
xfinfo.rcs = NULL;
|
||||
|
||||
vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0);
|
||||
vers = Version_TS (&xfinfo, NULL, tag, NULL, 0, 0);
|
||||
if (vers->ts_user == NULL
|
||||
&& vers->vn_user != NULL
|
||||
&& vers->vn_user[0] == '-')
|
||||
@ -246,8 +261,8 @@ find_fileproc (callerdat, finfo)
|
||||
if (vers->ts_user == NULL)
|
||||
error (0, 0, "nothing known about `%s'", finfo->fullname);
|
||||
else
|
||||
error (0, 0, "use `cvs add' to create an entry for %s",
|
||||
finfo->fullname);
|
||||
error (0, 0, "use `%s add' to create an entry for %s",
|
||||
program_name, finfo->fullname);
|
||||
return 1;
|
||||
}
|
||||
else if (vers->ts_user != NULL
|
||||
@ -321,6 +336,9 @@ commit (argc, argv)
|
||||
* For log purposes, do not allow "root" to commit files. If you look
|
||||
* like root, but are really logged in as a non-root user, it's OK.
|
||||
*/
|
||||
/* FIXME: Shouldn't this check be much more closely related to the
|
||||
readonly user stuff (CVSROOT/readers, &c). That is, why should
|
||||
root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
|
||||
if (geteuid () == (uid_t) 0)
|
||||
{
|
||||
struct passwd *pw;
|
||||
@ -342,9 +360,9 @@ commit (argc, argv)
|
||||
break;
|
||||
case 'm':
|
||||
#ifdef FORCE_USE_EDITOR
|
||||
use_editor = TRUE;
|
||||
use_editor = 1;
|
||||
#else
|
||||
use_editor = FALSE;
|
||||
use_editor = 0;
|
||||
#endif
|
||||
if (message)
|
||||
{
|
||||
@ -371,9 +389,9 @@ commit (argc, argv)
|
||||
break;
|
||||
case 'F':
|
||||
#ifdef FORCE_USE_EDITOR
|
||||
use_editor = TRUE;
|
||||
use_editor = 1;
|
||||
#else
|
||||
use_editor = FALSE;
|
||||
use_editor = 0;
|
||||
#endif
|
||||
logfile = optarg;
|
||||
break;
|
||||
@ -425,6 +443,7 @@ commit (argc, argv)
|
||||
#ifdef CLIENT_SUPPORT
|
||||
if (client_active)
|
||||
{
|
||||
int err;
|
||||
struct find_data find_args;
|
||||
|
||||
ign_setup ();
|
||||
@ -489,6 +508,8 @@ commit (argc, argv)
|
||||
do_verify (&message, (char *)NULL);
|
||||
|
||||
/* We always send some sort of message, even if empty. */
|
||||
/* FIXME: is that true? There seems to be some code in do_editor
|
||||
which can leave the message NULL. */
|
||||
option_with_arg ("-m", message);
|
||||
|
||||
/* OK, now process all the questionable files we have been saving
|
||||
@ -553,14 +574,39 @@ commit (argc, argv)
|
||||
"cvs commit -r 2" across a whole bunch of files a very slow
|
||||
operation (and it isn't documented in cvsclient.texi). I
|
||||
haven't looked at the server code carefully enough to be
|
||||
_sure_ why this is needed, but if it is because RCS_CI
|
||||
wants the file to exist, then it would be relatively simple
|
||||
(but not trivial) to fix in the server. */
|
||||
_sure_ why this is needed, but if it is because the "ci"
|
||||
program, which we used to call, wanted the file to exist,
|
||||
then it would be relatively simple to fix in the server. */
|
||||
send_files (find_args.argc, find_args.argv, local, 0,
|
||||
find_args.force ? SEND_FORCE : 0);
|
||||
|
||||
send_to_server ("ci\012", 0);
|
||||
return get_responses_and_close ();
|
||||
err = get_responses_and_close ();
|
||||
if (err != 0 && use_editor && message != NULL)
|
||||
{
|
||||
/* If there was an error, don't nuke the user's carefully
|
||||
constructed prose. This is something of a kludge; a better
|
||||
solution is probably more along the lines of #150 in TODO
|
||||
(doing a second up-to-date check before accepting the
|
||||
log message has also been suggested, but that seems kind of
|
||||
iffy because the real up-to-date check could still fail,
|
||||
another error could occur, &c. Also, a second check would
|
||||
slow things down). */
|
||||
|
||||
char *fname;
|
||||
FILE *fp;
|
||||
|
||||
fname = cvs_temp_name ();
|
||||
fp = CVS_FOPEN (fname, "w+");
|
||||
if (fp == NULL)
|
||||
error (1, 0, "cannot create temporary file %s", fname);
|
||||
if (fwrite (message, 1, strlen (message), fp) != strlen (message))
|
||||
error (1, errno, "cannot write temporary file %s", fname);
|
||||
if (fclose (fp) < 0)
|
||||
error (0, errno, "cannot close temporary file %s", fname);
|
||||
error (0, 0, "saving log message in %s", fname);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -633,7 +679,10 @@ classify_file_internal (finfo, vers)
|
||||
{
|
||||
int save_noexec, save_quiet, save_really_quiet;
|
||||
Ctype status;
|
||||
|
||||
|
||||
/* FIXME: Do we need to save quiet as well as really_quiet? Last
|
||||
time I glanced at Classify_File I only saw it looking at really_quiet
|
||||
not quiet. */
|
||||
save_noexec = noexec;
|
||||
save_quiet = quiet;
|
||||
save_really_quiet = really_quiet;
|
||||
@ -817,16 +866,30 @@ check_fileproc (callerdat, finfo)
|
||||
|
||||
if (file_has_markers (finfo))
|
||||
{
|
||||
/* Make this a warning, not an error, because we have
|
||||
no way of knowing whether the "conflict indicators"
|
||||
are really from a conflict or whether they are part
|
||||
of the document itself (cvs.texinfo and sanity.sh in
|
||||
CVS itself, for example, tend to want to have strings
|
||||
like ">>>>>>>" at the start of a line). Making people
|
||||
kludge this the way they need to kludge keyword
|
||||
expansion seems undesirable. And it is worse than
|
||||
keyword expansion, because there is no -ko
|
||||
analogue. */
|
||||
error (0, 0,
|
||||
"file `%s' still contains conflict indicators",
|
||||
"\
|
||||
warning: file `%s' seems to still contain conflict indicators",
|
||||
finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
|
||||
{
|
||||
/* Remove also tries to forbid this, but we should check
|
||||
here. I'm only _sure_ about somewhat obscure cases
|
||||
(hacking the Entries file, using an old version of
|
||||
CVS for the remove and a new one for the commit), but
|
||||
there might be other cases. */
|
||||
error (0, 0,
|
||||
"cannot remove file `%s' which has a numeric sticky tag of `%s'",
|
||||
finfo->fullname, vers->tag);
|
||||
@ -946,7 +1009,8 @@ check_fileproc (callerdat, finfo)
|
||||
}
|
||||
|
||||
/*
|
||||
* Print warm fuzzies while examining the dirs
|
||||
* By default, return the code that tells do_recursion to examine all
|
||||
* directories
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static Dtype
|
||||
@ -957,6 +1021,9 @@ check_direntproc (callerdat, dir, repos, update_dir, entries)
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
if (!isdir (dir))
|
||||
return (R_SKIP_ALL);
|
||||
|
||||
if (!quiet)
|
||||
error (0, 0, "Examining %s", update_dir);
|
||||
|
||||
@ -1013,7 +1080,8 @@ precommit_proc (repository, filter)
|
||||
free (s);
|
||||
}
|
||||
|
||||
run_setup ("%s %s", filter, repository);
|
||||
run_setup (filter);
|
||||
run_arg (repository);
|
||||
(void) walklist (ulist, precommit_list_proc, NULL);
|
||||
return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
|
||||
}
|
||||
@ -1333,7 +1401,8 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
|
||||
if (line[line_length - 1] == '\n')
|
||||
line[--line_length] = '\0';
|
||||
repository = Name_Repository ((char *) NULL, update_dir);
|
||||
run_setup ("%s %s", line, repository);
|
||||
run_setup (line);
|
||||
run_arg (repository);
|
||||
cvs_output (program_name, 0);
|
||||
cvs_output (" ", 1);
|
||||
cvs_output (command_name, 0);
|
||||
@ -1365,7 +1434,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the log message for a dir and print a warm fuzzy
|
||||
* Get the log message for a dir
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static Dtype
|
||||
@ -1380,6 +1449,9 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
|
||||
List *ulist;
|
||||
char *real_repos;
|
||||
|
||||
if (!isdir (dir))
|
||||
return (R_SKIP_ALL);
|
||||
|
||||
/* find the update list for this dir */
|
||||
p = findnode (mulist, update_dir);
|
||||
if (p != NULL)
|
||||
@ -1391,10 +1463,6 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
|
||||
if (ulist == NULL || ulist->list->next == ulist->list)
|
||||
return (R_SKIP_FILES);
|
||||
|
||||
/* print the warm fuzzy */
|
||||
if (!quiet)
|
||||
error (0, 0, "Committing %s", update_dir);
|
||||
|
||||
/* get commit message */
|
||||
real_repos = Name_Repository (dir, update_dir);
|
||||
got_message = 1;
|
||||
@ -1489,10 +1557,10 @@ remove_file (finfo, tag, message)
|
||||
error (1, 0, "internal error: no parsed RCS file");
|
||||
|
||||
branch = 0;
|
||||
if (tag && !(branch = RCS_isbranch (finfo->rcs, tag)))
|
||||
if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
|
||||
{
|
||||
/* a symbolic tag is specified; just remove the tag from the file */
|
||||
if ((retcode = RCS_deltag (finfo->rcs, tag, 1)) != 0)
|
||||
if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
|
||||
{
|
||||
if (!quiet)
|
||||
error (0, retcode == -1 ? errno : 0,
|
||||
@ -1500,6 +1568,7 @@ remove_file (finfo, tag, message)
|
||||
finfo->fullname);
|
||||
return (1);
|
||||
}
|
||||
RCS_rewrite (finfo->rcs, NULL, NULL);
|
||||
Scratch_Entry (finfo->entries, finfo->file);
|
||||
return (0);
|
||||
}
|
||||
@ -1556,6 +1625,7 @@ remove_file (finfo, tag, message)
|
||||
finfo->fullname);
|
||||
return (1);
|
||||
}
|
||||
RCS_rewrite (finfo->rcs, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
@ -1584,12 +1654,15 @@ remove_file (finfo, tag, message)
|
||||
/* Except when we are creating a branch, lock the revision so that
|
||||
we can check in the new revision. */
|
||||
if (lockflag)
|
||||
RCS_lock (finfo->rcs, rev ? corev : NULL, 0);
|
||||
{
|
||||
if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
|
||||
RCS_rewrite (finfo->rcs, NULL, NULL);
|
||||
}
|
||||
|
||||
if (corev != NULL)
|
||||
free (corev);
|
||||
|
||||
retcode = RCS_checkin (finfo->rcs->path, finfo->file, message, rev,
|
||||
retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev,
|
||||
RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
|
||||
if (retcode != 0)
|
||||
{
|
||||
@ -1690,6 +1763,8 @@ unlockrcs (rcs)
|
||||
if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0)
|
||||
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
|
||||
"could not unlock %s", rcs->path);
|
||||
else
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1730,6 +1805,7 @@ fixbranch (rcs, branch)
|
||||
if ((retcode = RCS_setbranch (rcs, branch)) != 0)
|
||||
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
|
||||
"cannot restore branch to %s for %s", branch, rcs->path);
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1841,29 +1917,63 @@ internal error: `%s' didn't move out of the attic",
|
||||
{
|
||||
/* this is the first time we have ever seen this file; create
|
||||
an rcs file. */
|
||||
run_setup ("%s%s -x,v/ -i", Rcsbin, RCS);
|
||||
|
||||
char *desc;
|
||||
size_t descalloc;
|
||||
size_t desclen;
|
||||
|
||||
char *opt;
|
||||
|
||||
desc = NULL;
|
||||
descalloc = 0;
|
||||
desclen = 0;
|
||||
fname = xmalloc (strlen (file) + sizeof (CVSADM)
|
||||
+ sizeof (CVSEXT_LOG) + 10);
|
||||
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
|
||||
/* If the file does not exist, no big deal. In particular, the
|
||||
server does not (yet at least) create CVSEXT_LOG files. */
|
||||
if (isfile (fname))
|
||||
run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG);
|
||||
/* FIXME: Should be including update_dir in the appropriate
|
||||
place here. */
|
||||
get_file (fname, fname, "r", &desc, &descalloc, &desclen);
|
||||
free (fname);
|
||||
|
||||
/* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
|
||||
end of the log message if the message is nonempty.
|
||||
Do it. RCS also deletes certain whitespace, in cleanlogmsg,
|
||||
which we don't try to do here. */
|
||||
if (desclen > 0)
|
||||
{
|
||||
expand_string (&desc, &descalloc, desclen + 1);
|
||||
desc[desclen++] = '\012';
|
||||
}
|
||||
|
||||
/* Set RCS keyword expansion options. */
|
||||
if (options && options[0] == '-' && options[1] == 'k')
|
||||
run_arg (options);
|
||||
run_arg (rcs);
|
||||
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
|
||||
opt = options + 2;
|
||||
else
|
||||
opt = NULL;
|
||||
|
||||
/* This message is an artifact of the time when this
|
||||
was implemented via "rcs -i". It should be revised at
|
||||
some point (does the "initial revision" in the message from
|
||||
RCS_checkin indicate that this is a new file? Or does the
|
||||
"RCS file" message serve some function?). */
|
||||
cvs_output ("RCS file: ", 0);
|
||||
cvs_output (rcs, 0);
|
||||
cvs_output ("\ndone\n", 0);
|
||||
|
||||
if (add_rcs_file (NULL, rcs, file, NULL, opt,
|
||||
NULL, NULL, 0, NULL,
|
||||
desc, desclen, NULL) != 0)
|
||||
{
|
||||
error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
|
||||
"could not create %s", rcs);
|
||||
retval = 1;
|
||||
goto out;
|
||||
}
|
||||
rcsfile = RCS_parsercsfile (rcs);
|
||||
newfile = 1;
|
||||
if (desc != NULL)
|
||||
free (desc);
|
||||
}
|
||||
|
||||
/* when adding a file for the first time, and using a tag, we need
|
||||
@ -1883,7 +1993,7 @@ internal error: `%s' didn't move out of the attic",
|
||||
/* commit a dead revision. */
|
||||
(void) sprintf (tmp, "file %s was initially added on branch %s.",
|
||||
file, tag);
|
||||
retcode = RCS_checkin (rcs, NULL, tmp, NULL,
|
||||
retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
|
||||
RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
|
||||
free (tmp);
|
||||
if (retcode != 0)
|
||||
@ -1898,7 +2008,8 @@ internal error: `%s' didn't move out of the attic",
|
||||
rename_file (fname, file);
|
||||
free (fname);
|
||||
|
||||
assert (rcsfile == NULL);
|
||||
/* double-check that the file was written correctly */
|
||||
freercsnode (&rcsfile);
|
||||
rcsfile = RCS_parse (file, repository);
|
||||
if (rcsfile == NULL)
|
||||
{
|
||||
@ -1954,6 +2065,7 @@ internal error: `%s' didn't move out of the attic",
|
||||
magicrev = RCS_magicrev (rcsfile, head);
|
||||
|
||||
retcode = RCS_settag (rcsfile, tag, magicrev);
|
||||
RCS_rewrite (rcsfile, NULL, NULL);
|
||||
|
||||
free (head);
|
||||
free (magicrev);
|
||||
@ -1986,7 +2098,14 @@ internal error: `%s' didn't move out of the attic",
|
||||
|
||||
fileattr_newfile (file);
|
||||
|
||||
/* I don't think fix_rcs_modes is needed any more. In the
|
||||
add_rcs_file case, the algorithms used by add_rcs_file and
|
||||
fix_rcs_modes are the same, so there is no need to go through
|
||||
it all twice. In the other cases, I think we want to just
|
||||
preserve the mode that the file had before we started. That is
|
||||
a behavior change, but I would think a desirable one. */
|
||||
fix_rcs_modes (rcs, file);
|
||||
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
@ -2033,12 +2152,13 @@ lock_RCS (user, rcs, rev, repository)
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
err = RCS_lock(rcs, NULL, 0);
|
||||
err = RCS_lock(rcs, NULL, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void) RCS_lock(rcs, rev, 1);
|
||||
}
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
|
@ -127,6 +127,8 @@ extern int errno;
|
||||
#define CVSADM_NOTIFY "CVS/Notify."
|
||||
#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
|
||||
#define CVSADM_BASE "CVS/Base"
|
||||
#define CVSADM_BASEREV "CVS/Baserev."
|
||||
#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
|
||||
#define CVSADM_TEMPLATE "CVS/Template."
|
||||
#else /* USE_VMS_FILENAMES */
|
||||
#define CVSADM "CVS"
|
||||
@ -144,6 +146,8 @@ extern int errno;
|
||||
/* A directory in which we store base versions of files we currently are
|
||||
editing with "cvs edit". */
|
||||
#define CVSADM_BASE "CVS/Base"
|
||||
#define CVSADM_BASEREV "CVS/Baserev"
|
||||
#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
|
||||
/* File which contains the template for use in log messages. */
|
||||
#define CVSADM_TEMPLATE "CVS/Template"
|
||||
#endif /* USE_VMS_FILENAMES */
|
||||
@ -182,6 +186,7 @@ extern int errno;
|
||||
#define CVSROOTADM_READERS "readers"
|
||||
#define CVSROOTADM_WRITERS "writers"
|
||||
#define CVSROOTADM_PASSWD "passwd"
|
||||
#define CVSROOTADM_CONFIG "config"
|
||||
#define CVSROOTADM_OPTIONS "options"
|
||||
|
||||
#define CVSNULLREPOS "Emptydir" /* an empty directory */
|
||||
@ -207,11 +212,10 @@ extern int errno;
|
||||
/* Command attributes -- see function lookup_command_attribute(). */
|
||||
#define CVS_CMD_IGNORE_ADMROOT 1
|
||||
|
||||
/* Set if CVS does _not_ need to create a CVS/Root file upon
|
||||
completion of this command. The name is confusing, both because
|
||||
the meaning is closer to "does not use working directory" than
|
||||
"uses working directory" and because the flag isn't really as
|
||||
general purpose as it seems (cvs release sets it). */
|
||||
/* Set if CVS needs to create a CVS/Root file upon completion of this
|
||||
command. The name may be slightly confusing, because the flag
|
||||
isn't really as general purpose as it seems (it is not set for cvs
|
||||
release). */
|
||||
|
||||
#define CVS_CMD_USES_WORK_DIR 2
|
||||
|
||||
@ -241,9 +245,6 @@ extern int errno;
|
||||
#endif
|
||||
#endif /* USE_VMS_FILENAMES */
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/*
|
||||
* Special tags. -rHEAD refers to the head of an RCS file, regardless of any
|
||||
* sticky tags. -rBASE refers to the current revision the user has checked
|
||||
@ -254,13 +255,10 @@ extern int errno;
|
||||
|
||||
/* Environment variable used by CVS */
|
||||
#define CVSREAD_ENV "CVSREAD" /* make files read-only */
|
||||
#define CVSREAD_DFLT FALSE /* writable files by default */
|
||||
#define CVSREAD_DFLT 0 /* writable files by default */
|
||||
|
||||
#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */
|
||||
|
||||
#define RCSBIN_ENV "RCSBIN" /* RCS binary directory */
|
||||
/* #define RCSBIN_DFLT Set by options.h */
|
||||
|
||||
#define TMPDIR_ENV "TMPDIR" /* Temporary directory */
|
||||
/* #define TMPDIR_DFLT Set by options.h */
|
||||
|
||||
@ -303,8 +301,13 @@ struct entnode
|
||||
enum ent_type type;
|
||||
char *user;
|
||||
char *version;
|
||||
|
||||
/* Timestamp, or "" if none (never NULL). */
|
||||
char *timestamp;
|
||||
|
||||
/* Keyword expansion options, or "" if none (never NULL). */
|
||||
char *options;
|
||||
|
||||
char *tag;
|
||||
char *date;
|
||||
char *conflict;
|
||||
@ -356,7 +359,7 @@ typedef enum direnter_type Dtype;
|
||||
#endif
|
||||
|
||||
extern char *program_name, *program_path, *command_name;
|
||||
extern char *Rcsbin, *Tmpdir, *Editor;
|
||||
extern char *Tmpdir, *Editor;
|
||||
extern int cvsadmin_root;
|
||||
extern char *CurDir;
|
||||
extern int really_quiet, quiet;
|
||||
@ -367,7 +370,8 @@ extern char *RCS_citag;
|
||||
|
||||
/* Access method specified in CVSroot. */
|
||||
typedef enum {
|
||||
local_method, server_method, pserver_method, kserver_method, ext_method
|
||||
local_method, server_method, pserver_method, kserver_method, gserver_method,
|
||||
ext_method
|
||||
} CVSmethod;
|
||||
extern char *method_names[]; /* change this in root.c if you change
|
||||
the enum above */
|
||||
@ -379,6 +383,8 @@ extern char *CVSroot_username; /* the username or NULL if method == local */
|
||||
extern char *CVSroot_hostname; /* the hostname or NULL if method == local */
|
||||
extern char *CVSroot_directory; /* the directory name */
|
||||
|
||||
extern char *emptydir_name PROTO ((void));
|
||||
|
||||
extern int trace; /* Show all commands */
|
||||
extern int noexec; /* Don't modify disk anywhere */
|
||||
extern int readonlyfs; /* fail on all write locks; succeed all read locks */
|
||||
@ -394,20 +400,24 @@ extern char hostname[];
|
||||
|
||||
/* Externs that are included directly in the CVS sources */
|
||||
|
||||
int RCS_exec_settag PROTO((const char *, const char *, const char *));
|
||||
int RCS_exec_deltag PROTO((const char *, const char *, int));
|
||||
int RCS_exec_setbranch PROTO((const char *, const char *));
|
||||
int RCS_exec_lock PROTO((const char *, const char *, int));
|
||||
int RCS_exec_unlock PROTO((const char *, const char *, int));
|
||||
int RCS_merge PROTO((const char *, const char *, const char *, const char *));
|
||||
int RCS_merge PROTO((RCSNode *, char *, char *, char *, char *, char *));
|
||||
/* Flags used by RCS_* functions. See the description of the individual
|
||||
functions for which flags mean what for each function. */
|
||||
#define RCS_FLAGS_FORCE 1
|
||||
#define RCS_FLAGS_DEAD 2
|
||||
#define RCS_FLAGS_QUIET 4
|
||||
#define RCS_FLAGS_MODTIME 8
|
||||
int RCS_checkin PROTO ((char *rcsfile, char *workfile, char *message,
|
||||
char *rev, int flags));
|
||||
|
||||
extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile,
|
||||
char *opts, char *options,
|
||||
char *rev1, char *rev2,
|
||||
char *label1, char *label2,
|
||||
char *workfile));
|
||||
extern int diff_exec PROTO ((char *file1, char *file2, char *options,
|
||||
char *out));
|
||||
extern int diff_execv PROTO ((char *file1, char *file2,
|
||||
char *label1, char *label2,
|
||||
char *options, char *out));
|
||||
|
||||
|
||||
|
||||
@ -421,9 +431,11 @@ List *Entries_Open PROTO((int aflag));
|
||||
void Subdirs_Known PROTO((List *entries));
|
||||
void Subdir_Register PROTO((List *, const char *, const char *));
|
||||
void Subdir_Deregister PROTO((List *, const char *, const char *));
|
||||
|
||||
char *Make_Date PROTO((char *rawdate));
|
||||
char *Name_Repository PROTO((char *dir, char *update_dir));
|
||||
|
||||
char *Short_Repository PROTO((char *repository));
|
||||
void Sanitize_Repository_Name PROTO((char *repository));
|
||||
|
||||
char *Name_Root PROTO((char *dir, char *update_dir));
|
||||
int parse_cvsroot PROTO((char *CVSroot));
|
||||
@ -433,9 +445,8 @@ void root_allow_add PROTO ((char *));
|
||||
void root_allow_free PROTO ((void));
|
||||
int root_allow_ok PROTO ((char *));
|
||||
|
||||
int same_directories PROTO((char *dir1, char *dir2));
|
||||
char *Short_Repository PROTO((char *repository));
|
||||
char *gca PROTO((char *rev1, char *rev2));
|
||||
char *gca PROTO((const char *rev1, const char *rev2));
|
||||
extern void check_numeric PROTO ((const char *, int, char **));
|
||||
char *getcaller PROTO((void));
|
||||
char *time_stamp PROTO((char *file));
|
||||
|
||||
@ -448,6 +459,8 @@ int pathname_levels PROTO ((char *path));
|
||||
|
||||
typedef int (*CALLPROC) PROTO((char *repository, char *value));
|
||||
int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all));
|
||||
extern int parse_config PROTO ((char *));
|
||||
|
||||
typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(());
|
||||
int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup));
|
||||
int isdir PROTO((const char *file));
|
||||
@ -463,6 +476,8 @@ char *cvs_temp_name PROTO ((void));
|
||||
void parseopts PROTO ((const char *root));
|
||||
|
||||
int numdots PROTO((const char *s));
|
||||
char *increment_revnum PROTO ((const char *));
|
||||
int compare_revnums PROTO ((const char *, const char *));
|
||||
int unlink_file PROTO((const char *f));
|
||||
int link_file PROTO ((const char *from, const char *to));
|
||||
int unlink_file_dir PROTO((const char *f));
|
||||
@ -471,9 +486,10 @@ int xcmp PROTO((const char *file1, const char *file2));
|
||||
int yesno PROTO((void));
|
||||
void *valloc PROTO((size_t bytes));
|
||||
time_t get_date PROTO((char *date, struct timeb *now));
|
||||
void Create_Admin PROTO((char *dir, char *update_dir,
|
||||
char *repository, char *tag, char *date,
|
||||
int nonbranch));
|
||||
extern int Create_Admin PROTO ((char *dir, char *update_dir,
|
||||
char *repository, char *tag, char *date,
|
||||
int nonbranch, int warn));
|
||||
extern int expand_at_signs PROTO ((char *, off_t, FILE *));
|
||||
|
||||
/* Locking subsystem (implemented in lock.c). */
|
||||
|
||||
@ -511,7 +527,7 @@ extern int ign_case;
|
||||
|
||||
#include "update.h"
|
||||
|
||||
void line2argv PROTO ((int *pargc, char ***argv, char *line));
|
||||
void line2argv PROTO ((int *pargc, char ***argv, char *line, char *sepchars));
|
||||
void make_directories PROTO((const char *name));
|
||||
void make_directory PROTO((const char *name));
|
||||
extern int mkdir_if_needed PROTO ((char *name));
|
||||
@ -548,7 +564,7 @@ void do_editor PROTO((char *dir, char **messagep,
|
||||
void do_verify PROTO((char **messagep, char *repository));
|
||||
|
||||
typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
|
||||
char *mwhere, char *mfile, int horten, int local_specified,
|
||||
char *mwhere, char *mfile, int shorten, int local_specified,
|
||||
char *omodule, char *msg));
|
||||
|
||||
/* This is the structure that the recursion processor passes to the
|
||||
@ -609,7 +625,9 @@ void SIG_endCrSect PROTO((void));
|
||||
void read_cvsrc PROTO((int *argc, char ***argv, char *cmdname));
|
||||
|
||||
char *make_message_rcslegal PROTO((char *message));
|
||||
extern int file_has_markers PROTO ((struct file_info *));
|
||||
extern int file_has_markers PROTO ((const struct file_info *));
|
||||
extern void get_file PROTO ((const char *, const char *, const char *,
|
||||
char **, size_t *, size_t *));
|
||||
|
||||
/* flags for run_exec(), the fast system() for CVS */
|
||||
#define RUN_NORMAL 0x0000 /* no special behaviour */
|
||||
@ -622,14 +640,9 @@ extern int file_has_markers PROTO ((struct file_info *));
|
||||
|
||||
void run_arg PROTO((const char *s));
|
||||
void run_print PROTO((FILE * fp));
|
||||
#ifdef HAVE_VPRINTF
|
||||
void run_setup PROTO((const char *fmt,...));
|
||||
void run_args PROTO((const char *fmt,...));
|
||||
#else
|
||||
void run_setup ();
|
||||
void run_args ();
|
||||
#endif
|
||||
int run_exec PROTO((char *stin, char *stout, char *sterr, int flags));
|
||||
void run_setup PROTO ((const char *prog));
|
||||
int run_exec PROTO((const char *stin, const char *stout, const char *sterr,
|
||||
int flags));
|
||||
|
||||
/* other similar-minded stuff from run.c. */
|
||||
FILE *run_popen PROTO((const char *, const char *));
|
||||
@ -649,10 +662,16 @@ pid_t waitpid PROTO((pid_t, int *, int));
|
||||
struct vers_ts
|
||||
{
|
||||
/* rcs version user file derives from, from CVS/Entries.
|
||||
* it can have the following special values:
|
||||
* empty = no user file
|
||||
* 0 = user file is new
|
||||
* -vers = user file to be removed. */
|
||||
It can have the following special values:
|
||||
|
||||
NULL = file is not mentioned in Entries (this is also used for a
|
||||
directory).
|
||||
"" = ILLEGAL! The comment used to say that it meant "no user file"
|
||||
but as far as I know CVS didn't actually use it that way.
|
||||
Note that according to cvs.texinfo, "" is not legal in the
|
||||
Entries file.
|
||||
0 = user file is new
|
||||
-vers = user file to be removed. */
|
||||
char *vn_user;
|
||||
|
||||
/* Numeric revision number corresponding to ->vn_tag (->vn_tag
|
||||
@ -675,7 +694,8 @@ struct vers_ts
|
||||
and if they differ it is modified. */
|
||||
char *ts_rcs;
|
||||
|
||||
/* Options from CVS/Entries (keyword expansion). */
|
||||
/* Options from CVS/Entries (keyword expansion), malloc'd. If none,
|
||||
then it is an empty string (never NULL). */
|
||||
char *options;
|
||||
|
||||
/* If non-NULL, there was a conflict (or merely a merge? See merge_file)
|
||||
@ -714,6 +734,11 @@ int Checkin PROTO ((int type, struct file_info *finfo, char *rcs, char *rev,
|
||||
char *tag, char *options, char *message));
|
||||
int No_Difference PROTO ((struct file_info *finfo, Vers_TS *vers));
|
||||
|
||||
/* CVSADM_BASEREV stuff, from entries.c. */
|
||||
extern char *base_get PROTO ((struct file_info *));
|
||||
extern void base_register PROTO ((struct file_info *, char *));
|
||||
extern void base_deregister PROTO ((struct file_info *));
|
||||
|
||||
/*
|
||||
* defines for Classify_File() to determine the current state of a file.
|
||||
* These are also used as types in the data field for the list we make for
|
||||
@ -824,10 +849,13 @@ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *));
|
||||
extern void tag_check_valid_join PROTO ((char *, int, char **, int, int,
|
||||
char *));
|
||||
|
||||
/* From server.c and documented there. */
|
||||
extern void cvs_output PROTO ((const char *, size_t));
|
||||
extern void cvs_output_binary PROTO ((char *, size_t));
|
||||
extern void cvs_outerr PROTO ((const char *, size_t));
|
||||
extern void cvs_flusherr PROTO ((void));
|
||||
extern void cvs_flushout PROTO ((void));
|
||||
extern void cvs_output_tagged PROTO ((char *, char *));
|
||||
|
||||
#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
|
||||
#include "server.h"
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* Difference
|
||||
*
|
||||
@ -43,6 +43,7 @@ static void diff_mark_errors PROTO((int err));
|
||||
static char *diff_rev1, *diff_rev2;
|
||||
static char *diff_date1, *diff_date2;
|
||||
static char *use_rev1, *use_rev2;
|
||||
static int have_rev1_label, have_rev2_label;
|
||||
|
||||
/* Revision of the user file, if it is unchanged from something in the
|
||||
repository and we want to use that fact. */
|
||||
@ -71,6 +72,7 @@ static const char *const diff_usage[] =
|
||||
"\t--ifdef=arg\tOutput diffs in ifdef format.\n",
|
||||
"(consult the documentation for your diff program for rcsdiff-options.\n",
|
||||
"The most popular is -c for context diffs but there are many more).\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -103,13 +105,13 @@ static struct option const longopts[] =
|
||||
{
|
||||
{"ignore-blank-lines", 0, 0, 'B'},
|
||||
{"context", 2, 0, 143},
|
||||
{"ifdef", 1, 0, 147},
|
||||
{"ifdef", 1, 0, 131},
|
||||
{"show-function-line", 1, 0, 'F'},
|
||||
{"speed-large-files", 0, 0, 'H'},
|
||||
{"ignore-matching-lines", 1, 0, 'I'},
|
||||
{"label", 1, 0, 'L'},
|
||||
{"new-file", 0, 0, 'N'},
|
||||
{"initial-tab", 0, 0, 'T'},
|
||||
{"initial-tab", 0, 0, 148},
|
||||
{"width", 1, 0, 'W'},
|
||||
{"text", 0, 0, 'a'},
|
||||
{"ignore-space-change", 0, 0, 'b'},
|
||||
@ -130,7 +132,7 @@ static struct option const longopts[] =
|
||||
{"report-identical-files", 0, 0, 's'},
|
||||
{"expand-tabs", 0, 0, 't'},
|
||||
{"ignore-all-space", 0, 0, 'w'},
|
||||
{"side-by-side", 0, 0, 'y'},
|
||||
{"side-by-side", 0, 0, 147},
|
||||
{"unified", 2, 0, 146},
|
||||
{"left-column", 0, 0, 129},
|
||||
{"suppress-common-lines", 0, 0, 130},
|
||||
@ -147,6 +149,37 @@ static struct option const longopts[] =
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* CVS 1.9 and similar versions seemed to have pretty weird handling
|
||||
of -y and -T. In the cases where it called rcsdiff,
|
||||
they would have the meanings mentioned below. In the cases where it
|
||||
called diff, they would have the meanings mentioned in "longopts".
|
||||
Noone seems to have missed them, so I think the right thing to do is
|
||||
just to remove the options altogether (which I have done).
|
||||
|
||||
In the case of -z and -q, "cvs diff" did not accept them even back
|
||||
when we called rcsdiff (at least, it hasn't accepted them
|
||||
recently).
|
||||
|
||||
In comparing rcsdiff to the new CVS implementation, I noticed that
|
||||
the following rcsdiff flags are not handled by CVS diff:
|
||||
|
||||
-y: perform diff even when the requested revisions are the
|
||||
same revision number
|
||||
-q: run quietly
|
||||
-T: preserve modification time on the RCS file
|
||||
-z: specify timezone for use in file labels
|
||||
|
||||
I think these are not really relevant. -y is undocumented even in
|
||||
RCS 5.7, and seems like a minor change at best. According to RCS
|
||||
documentation, -T only applies when a RCS file has been modified
|
||||
because of lock changes; doesn't CVS sidestep RCS's entire lock
|
||||
structure? -z seems to be unsupported by CVS diff, and has a
|
||||
different meaning as a global option anyway. (Adding it could be
|
||||
a feature, but if it is left out for now, it should not break
|
||||
anything.) For the purposes of producing output, CVS diff appears
|
||||
mostly to ignore -q. Maybe this should be fixed, but I think it's
|
||||
a larger issue than the changes included here. */
|
||||
|
||||
static void strcat_and_allocate PROTO ((char **, size_t *, const char *));
|
||||
|
||||
/* *STR is a pointer to a malloc'd string. *LENP is its allocated
|
||||
@ -183,6 +216,8 @@ diff (argc, argv)
|
||||
if (argc == -1)
|
||||
usage (diff_usage);
|
||||
|
||||
have_rev1_label = have_rev2_label = 0;
|
||||
|
||||
/*
|
||||
* Note that we catch all the valid arguments here, so that we can
|
||||
* intercept the -r arguments for doing revision diffs; and -l/-R for a
|
||||
@ -201,33 +236,44 @@ diff (argc, argv)
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt_long (argc, argv,
|
||||
"+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:",
|
||||
"+abcdefhilnpstuw0123456789BHNRC:D:F:I:L:U:V:W:k:r:",
|
||||
longopts, &option_index)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
case 'h': case 'i': case 'n': case 'p': case 's': case 't':
|
||||
case 'u': case 'w': case 'y': case '0': case '1': case '2':
|
||||
case 'u': case 'w': case '0': case '1': case '2':
|
||||
case '3': case '4': case '5': case '6': case '7': case '8':
|
||||
case '9': case 'B': case 'H': case 'T':
|
||||
case '9': case 'B': case 'H':
|
||||
(void) sprintf (tmp, " -%c", (char) c);
|
||||
strcat_and_allocate (&opts, &opts_allocated, tmp);
|
||||
break;
|
||||
case 'C': case 'F': case 'I': case 'L': case 'U': case 'V':
|
||||
case 'W':
|
||||
case 'L':
|
||||
if (have_rev1_label++)
|
||||
if (have_rev2_label++)
|
||||
{
|
||||
error (0, 0, "extra -L arguments ignored");
|
||||
break;
|
||||
}
|
||||
|
||||
strcat_and_allocate (&opts, &opts_allocated, " -L");
|
||||
strcat_and_allocate (&opts, &opts_allocated, optarg);
|
||||
break;
|
||||
case 'C': case 'F': case 'I': case 'U': case 'V': case 'W':
|
||||
(void) sprintf (tmp, " -%c", (char) c);
|
||||
strcat_and_allocate (&opts, &opts_allocated, tmp);
|
||||
strcat_and_allocate (&opts, &opts_allocated, optarg);
|
||||
break;
|
||||
case 147:
|
||||
case 131:
|
||||
/* --ifdef. */
|
||||
strcat_and_allocate (&opts, &opts_allocated, " -D");
|
||||
strcat_and_allocate (&opts, &opts_allocated, optarg);
|
||||
break;
|
||||
case 129: case 130: case 131: case 132: case 133: case 134:
|
||||
case 129: case 130: case 132: case 133: case 134:
|
||||
case 135: case 136: case 137: case 138: case 139: case 140:
|
||||
case 141: case 142: case 143: case 144: case 145: case 146:
|
||||
case 147: case 148:
|
||||
strcat_and_allocate (&opts, &opts_allocated, " --");
|
||||
strcat_and_allocate (&opts, &opts_allocated,
|
||||
longopts[option_index].name);
|
||||
@ -359,6 +405,11 @@ diff_fileproc (callerdat, finfo)
|
||||
char *tocvsPath;
|
||||
char *fname;
|
||||
|
||||
/* Initialize these solely to avoid warnings from gcc -Wall about
|
||||
variables that might be used uninitialized. */
|
||||
tmp = NULL;
|
||||
fname = NULL;
|
||||
|
||||
user_file_rev = 0;
|
||||
vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
|
||||
|
||||
@ -536,9 +587,9 @@ diff_fileproc (callerdat, finfo)
|
||||
}
|
||||
|
||||
/* Output an "Index:" line for patch to use */
|
||||
(void) fflush (stdout);
|
||||
(void) printf ("Index: %s\n", finfo->fullname);
|
||||
(void) fflush (stdout);
|
||||
cvs_output ("Index: ", 0);
|
||||
cvs_output (finfo->fullname, 0);
|
||||
cvs_output ("\n", 1);
|
||||
|
||||
tocvsPath = wrap_tocvs_process_file(finfo->file);
|
||||
if (tocvsPath)
|
||||
@ -561,14 +612,20 @@ diff_fileproc (callerdat, finfo)
|
||||
{
|
||||
/* This is file, not fullname, because it is the "Index:" line which
|
||||
is supposed to contain the directory. */
|
||||
(void) printf ("===================================================================\nRCS file: %s\n",
|
||||
finfo->file);
|
||||
(void) printf ("diff -N %s\n", finfo->file);
|
||||
cvs_output ("\
|
||||
===================================================================\n\
|
||||
RCS file: ", 0);
|
||||
cvs_output (finfo->file, 0);
|
||||
cvs_output ("\n", 1);
|
||||
|
||||
cvs_output ("diff -N ", 0);
|
||||
cvs_output (finfo->file, 0);
|
||||
cvs_output ("\n", 1);
|
||||
|
||||
if (empty_file == DIFF_ADDED)
|
||||
{
|
||||
if (use_rev2 == NULL)
|
||||
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, finfo->file);
|
||||
status = diff_exec (DEVNULL, finfo->file, opts, RUN_TTY);
|
||||
else
|
||||
{
|
||||
int retcode;
|
||||
@ -589,7 +646,7 @@ diff_fileproc (callerdat, finfo)
|
||||
}
|
||||
/* FIXME: what if retcode > 0? */
|
||||
|
||||
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, tmp);
|
||||
status = diff_exec (DEVNULL, tmp, opts, RUN_TTY);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -610,30 +667,36 @@ diff_fileproc (callerdat, finfo)
|
||||
}
|
||||
/* FIXME: what if retcode > 0? */
|
||||
|
||||
run_setup ("%s %s %s %s", DIFF, opts, tmp, DEVNULL);
|
||||
status = diff_exec (tmp, DEVNULL, opts, RUN_TTY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_rev2)
|
||||
{
|
||||
run_setup ("%s%s -x,v/ %s %s -r%s -r%s", Rcsbin, RCS_DIFF,
|
||||
opts, *options ? options : vers->options,
|
||||
use_rev1, use_rev2);
|
||||
}
|
||||
else
|
||||
{
|
||||
run_setup ("%s%s -x,v/ %s %s -r%s", Rcsbin, RCS_DIFF, opts,
|
||||
*options ? options : vers->options, use_rev1);
|
||||
}
|
||||
run_arg (vers->srcfile->path);
|
||||
char *label1 = NULL;
|
||||
char *label2 = NULL;
|
||||
|
||||
if (!have_rev1_label)
|
||||
label1 =
|
||||
make_file_label (finfo->fullname, use_rev1, vers->srcfile);
|
||||
|
||||
if (!have_rev2_label)
|
||||
label2 =
|
||||
make_file_label (finfo->fullname, use_rev2, vers->srcfile);
|
||||
|
||||
status = RCS_exec_rcsdiff (vers->srcfile, opts,
|
||||
*options ? options : vers->options,
|
||||
use_rev1, use_rev2,
|
||||
label1, label2,
|
||||
finfo->file);
|
||||
|
||||
if (label1) free (label1);
|
||||
if (label2) free (label2);
|
||||
}
|
||||
|
||||
switch ((status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
|
||||
RUN_REALLY|RUN_COMBINED)))
|
||||
switch (status)
|
||||
{
|
||||
case -1: /* fork failed */
|
||||
error (1, errno, "fork failed during rcsdiff of %s",
|
||||
error (1, errno, "fork failed while diffing %s",
|
||||
vers->srcfile->path);
|
||||
case 0: /* everything ok */
|
||||
err = 0;
|
||||
@ -662,7 +725,6 @@ diff_fileproc (callerdat, finfo)
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
(void) fflush (stdout);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
@ -696,9 +758,9 @@ diff_dirproc (callerdat, dir, pos_repos, update_dir, entries)
|
||||
/* XXX - check for dirs we don't want to process??? */
|
||||
|
||||
/* YES ... for instance dirs that don't exist!!! -- DW */
|
||||
if (!isdir (dir) )
|
||||
return (R_SKIP_ALL);
|
||||
|
||||
if (!isdir (dir))
|
||||
return (R_SKIP_ALL);
|
||||
|
||||
if (!quiet)
|
||||
error (0, 0, "Diffing %s", update_dir);
|
||||
return (R_PROCESS);
|
||||
@ -855,9 +917,9 @@ diff_file_nodiff (finfo, vers, empty_file)
|
||||
{
|
||||
/* drop user_file_rev into first unused use_rev */
|
||||
if (!use_rev1)
|
||||
use_rev1 = xstrdup (user_file_rev);
|
||||
use_rev1 = xstrdup (user_file_rev);
|
||||
else if (!use_rev2)
|
||||
use_rev2 = xstrdup (user_file_rev);
|
||||
use_rev2 = xstrdup (user_file_rev);
|
||||
/* and if not, it wasn't needed anyhow */
|
||||
user_file_rev = 0;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* "import" checks in the vendor release located in the current directory into
|
||||
* the CVS source repository. The CVS vendor branch support is utilized.
|
||||
@ -23,7 +23,6 @@
|
||||
#define FILE_HOLDER ".#cvsxxx"
|
||||
|
||||
static char *get_comment PROTO((char *user));
|
||||
static int expand_at_signs PROTO((char *buf, off_t size, FILE *fp));
|
||||
static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
|
||||
char *vers));
|
||||
static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,
|
||||
@ -56,6 +55,7 @@ static const char *const import_usage[] =
|
||||
"\t-b bra\tVendor branch id.\n",
|
||||
"\t-m msg\tLog message.\n",
|
||||
"\t-W spec\tWrappers specification line.\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -104,9 +104,9 @@ import (argc, argv)
|
||||
break;
|
||||
case 'm':
|
||||
#ifdef FORCE_USE_EDITOR
|
||||
use_editor = TRUE;
|
||||
use_editor = 1;
|
||||
#else
|
||||
use_editor = FALSE;
|
||||
use_editor = 0;
|
||||
#endif
|
||||
message = xstrdup(optarg);
|
||||
break;
|
||||
@ -199,6 +199,7 @@ import (argc, argv)
|
||||
if (msglen == 0 || message[msglen - 1] != '\n')
|
||||
{
|
||||
char *nm = xmalloc (msglen + 2);
|
||||
*nm = '\0';
|
||||
if (message != NULL)
|
||||
{
|
||||
(void) strcpy (nm, message);
|
||||
@ -467,6 +468,8 @@ process_import_file (message, vfile, vtag, targc, targv)
|
||||
if (!isfile (attic_name))
|
||||
{
|
||||
int retval;
|
||||
char *free_opt = NULL;
|
||||
char *our_opt = keyword_opt;
|
||||
|
||||
free (attic_name);
|
||||
/*
|
||||
@ -474,8 +477,42 @@ process_import_file (message, vfile, vtag, targc, targv)
|
||||
* repository nor in the Attic -- create it anew.
|
||||
*/
|
||||
add_log ('N', vfile);
|
||||
retval = add_rcs_file (message, rcs, vfile, vhead, vbranch,
|
||||
vtag, targc, targv, logfp);
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
/* The most reliable information on whether the file is binary
|
||||
is what the client told us. That is because if the client had
|
||||
the wrong idea about binaryness, it corrupted the file, so
|
||||
we might as well believe the client. */
|
||||
if (server_active)
|
||||
{
|
||||
Node *node;
|
||||
List *entries;
|
||||
|
||||
/* Reading all the entries for each file is fairly silly, and
|
||||
probably slow. But I am too lazy at the moment to do
|
||||
anything else. */
|
||||
entries = Entries_Open (0);
|
||||
node = findnode_fn (entries, vfile);
|
||||
if (node != NULL)
|
||||
{
|
||||
Entnode *entdata = (Entnode *) node->data;
|
||||
if (entdata->type == ENT_FILE)
|
||||
{
|
||||
assert (entdata->options[0] == '-'
|
||||
&& entdata->options[1] == 'k');
|
||||
our_opt = xstrdup (entdata->options + 2);
|
||||
free_opt = our_opt;
|
||||
}
|
||||
}
|
||||
Entries_Close (entries);
|
||||
}
|
||||
#endif
|
||||
|
||||
retval = add_rcs_file (message, rcs, vfile, vhead, our_opt,
|
||||
vbranch, vtag, targc, targv,
|
||||
NULL, 0, logfp);
|
||||
if (free_opt != NULL)
|
||||
free (free_opt);
|
||||
free (rcs);
|
||||
return retval;
|
||||
}
|
||||
@ -602,12 +639,14 @@ add_rev (message, rcs, vfile, vers)
|
||||
/* Before RCS_lock existed, we were directing stdout, as well as
|
||||
stderr, from the RCS command, to DEVNULL. I wouldn't guess that
|
||||
was necessary, but I don't know for sure. */
|
||||
if (RCS_lock (rcs, vbranch, 1) != 0)
|
||||
{
|
||||
error (0, errno, "fork failed");
|
||||
return (1);
|
||||
}
|
||||
/* Earlier versions of this function printed a `fork failed' error
|
||||
when RCS_lock returned an error code. That's not appropriate
|
||||
now that RCS_lock is librarified, but should the error text be
|
||||
preserved? */
|
||||
if (RCS_lock (rcs, vbranch, 1) != 0)
|
||||
return 1;
|
||||
locked = 1;
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
}
|
||||
tocvsPath = wrap_tocvs_process_file (vfile);
|
||||
if (tocvsPath == NULL)
|
||||
@ -632,7 +671,7 @@ add_rev (message, rcs, vfile, vers)
|
||||
}
|
||||
}
|
||||
|
||||
status = RCS_checkin (rcs->path, tocvsPath == NULL ? vfile : tocvsPath,
|
||||
status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
|
||||
message, vbranch,
|
||||
(RCS_FLAGS_QUIET
|
||||
| (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
|
||||
@ -656,6 +695,7 @@ add_rev (message, rcs, vfile, vers)
|
||||
if (locked)
|
||||
{
|
||||
(void) RCS_unlock(rcs, vbranch, 0);
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
@ -693,6 +733,7 @@ add_tags (rcs, vfile, vtag, targc, targv)
|
||||
"ERROR: Failed to set tag %s in %s", vtag, rcs->path);
|
||||
return (1);
|
||||
}
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
|
||||
memset (&finfo, 0, sizeof finfo);
|
||||
finfo.file = vfile;
|
||||
@ -705,7 +746,9 @@ add_tags (rcs, vfile, vtag, targc, targv)
|
||||
vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0);
|
||||
for (i = 0; i < targc; i++)
|
||||
{
|
||||
if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) != 0)
|
||||
if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0)
|
||||
RCS_rewrite (rcs, NULL, NULL);
|
||||
else
|
||||
{
|
||||
ierrno = errno;
|
||||
fperror (logfp, 0, retcode == -1 ? ierrno : 0,
|
||||
@ -879,23 +922,33 @@ get_comment (user)
|
||||
/* Create a new RCS file from scratch.
|
||||
|
||||
This probably should be moved to rcs.c now that it is called from
|
||||
places outside import.c. */
|
||||
places outside import.c.
|
||||
|
||||
Return value is 0 for success, or nonzero for failure (in which
|
||||
case an error message will have already been printed). */
|
||||
int
|
||||
add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
add_logfp)
|
||||
/* Log message for the addition. */
|
||||
add_rcs_file (message, rcs, user, add_vhead, key_opt,
|
||||
add_vbranch, vtag, targc, targv,
|
||||
desctext, desclen, add_logfp)
|
||||
/* Log message for the addition. Not used if add_vhead == NULL. */
|
||||
char *message;
|
||||
/* Filename of the RCS file to create. */
|
||||
char *rcs;
|
||||
/* Filename of the file to serve as the contents of the initial
|
||||
revision. */
|
||||
revision. Even if add_vhead is NULL, we use this to determine
|
||||
the modes to give the new RCS file. */
|
||||
char *user;
|
||||
|
||||
/* Revision number of head that we are adding. Normally 1.1 but
|
||||
could be another revision as long as ADD_VBRANCH is a branch
|
||||
from it. */
|
||||
from it. If NULL, then just add an empty file without any
|
||||
revisions (similar to the one created by "rcs -i"). */
|
||||
char *add_vhead;
|
||||
|
||||
/* Keyword expansion mode, e.g., "b" for binary. NULL means the
|
||||
default behavior. */
|
||||
char *key_opt;
|
||||
|
||||
/* Vendor branch to import to, or NULL if none. If non-NULL, then
|
||||
vtag should also be non-NULL. */
|
||||
char *add_vbranch;
|
||||
@ -903,6 +956,11 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
int targc;
|
||||
char *targv[];
|
||||
|
||||
/* If non-NULL, description for the file. If NULL, the description
|
||||
will be empty. */
|
||||
char *desctext;
|
||||
size_t desclen;
|
||||
|
||||
/* Write errors to here as well as via error (), or NULL if we should
|
||||
use only error (). */
|
||||
FILE *add_logfp;
|
||||
@ -912,20 +970,24 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
struct tm *ftm;
|
||||
time_t now;
|
||||
char altdate1[MAXDATELEN];
|
||||
#ifndef HAVE_RCS5
|
||||
char altdate2[MAXDATELEN];
|
||||
#endif
|
||||
char *author;
|
||||
int i, ierrno, err = 0;
|
||||
mode_t mode;
|
||||
char *tocvsPath;
|
||||
char *userfile;
|
||||
char *local_opt = keyword_opt;
|
||||
char *local_opt = key_opt;
|
||||
char *free_opt = NULL;
|
||||
|
||||
if (noexec)
|
||||
return (0);
|
||||
|
||||
/* Note that as the code stands now, the -k option overrides any
|
||||
settings in wrappers (whether CVSROOT/cvswrappers, -W, or
|
||||
whatever). Some have suggested this should be the other way
|
||||
around. As far as I know the documentation doesn't say one way
|
||||
or the other. Before making a change of this sort, should think
|
||||
about what is best, document it (in cvs.texinfo and NEWS), &c. */
|
||||
|
||||
if (local_opt == NULL)
|
||||
{
|
||||
if (wrap_name_has (user, WRAP_RCSOPTION))
|
||||
@ -936,7 +998,17 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
|
||||
tocvsPath = wrap_tocvs_process_file (user);
|
||||
userfile = (tocvsPath == NULL ? user : tocvsPath);
|
||||
fpuser = CVS_FOPEN (userfile, "r");
|
||||
|
||||
/* Opening in text mode is probably never the right thing for the
|
||||
server (because the protocol encodes text files in a fashion
|
||||
which does not depend on what the client or server OS is, as
|
||||
documented in cvsclient.texi), but as long as the server just
|
||||
runs on unix it is a moot point. */
|
||||
fpuser = CVS_FOPEN (userfile,
|
||||
((local_opt != NULL && strcmp (local_opt, "b") == 0)
|
||||
? "rb"
|
||||
: "r")
|
||||
);
|
||||
if (fpuser == NULL)
|
||||
{
|
||||
/* not fatal, continue import */
|
||||
@ -954,8 +1026,17 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
/*
|
||||
* putadmin()
|
||||
*/
|
||||
if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
|
||||
goto write_error;
|
||||
if (add_vhead != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "head %s;\012", add_vhead) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fprintf (fprcs, "head ;\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0)
|
||||
@ -1001,126 +1082,126 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
if (fprintf (fprcs, "\012") < 0)
|
||||
goto write_error;
|
||||
|
||||
/*
|
||||
* puttree()
|
||||
*/
|
||||
/* Get information on modtime and mode. */
|
||||
if (fstat (fileno (fpuser), &sb) < 0)
|
||||
error (1, errno, "cannot fstat %s", user);
|
||||
if (use_file_modtime)
|
||||
now = sb.st_mtime;
|
||||
else
|
||||
(void) time (&now);
|
||||
#ifdef HAVE_RCS5
|
||||
ftm = gmtime (&now);
|
||||
#else
|
||||
ftm = localtime (&now);
|
||||
#endif
|
||||
(void) sprintf (altdate1, DATEFORM,
|
||||
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
|
||||
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
|
||||
ftm->tm_min, ftm->tm_sec);
|
||||
#ifdef HAVE_RCS5
|
||||
#define altdate2 altdate1
|
||||
#else
|
||||
/*
|
||||
* If you don't have RCS V5 or later, you need to lie about the ci
|
||||
* time, since RCS V4 and earlier insist that the times differ.
|
||||
*/
|
||||
now++;
|
||||
ftm = localtime (&now);
|
||||
(void) sprintf (altdate2, DATEFORM,
|
||||
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
|
||||
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
|
||||
ftm->tm_min, ftm->tm_sec);
|
||||
#endif
|
||||
author = getcaller ();
|
||||
|
||||
if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
|
||||
/* Write the revision(s), with the date and author and so on
|
||||
(that is "delta" rather than "deltatext" from rcsfile(5)). */
|
||||
if (add_vhead != NULL)
|
||||
{
|
||||
if (use_file_modtime)
|
||||
now = sb.st_mtime;
|
||||
else
|
||||
(void) time (&now);
|
||||
ftm = gmtime (&now);
|
||||
(void) sprintf (altdate1, DATEFORM,
|
||||
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
|
||||
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
|
||||
ftm->tm_min, ftm->tm_sec);
|
||||
author = getcaller ();
|
||||
|
||||
if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
|
||||
fprintf (fprcs, "date %s; author %s; state Exp;\012",
|
||||
altdate1, author) < 0)
|
||||
goto write_error;
|
||||
|
||||
if (fprintf (fprcs, "branches") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
|
||||
if (fprintf (fprcs, "branches") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (fprintf (fprcs, ";\012") < 0)
|
||||
goto write_error;
|
||||
|
||||
if (fprintf (fprcs, "next ;\012") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
|
||||
fprintf (fprcs, "date %s; author %s; state Exp;\012",
|
||||
altdate2, author) < 0 ||
|
||||
fprintf (fprcs, "branches ;\012") < 0 ||
|
||||
fprintf (fprcs, "next ;\012\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (
|
||||
/*
|
||||
* putdesc()
|
||||
*/
|
||||
fprintf (fprcs, "\012desc\012") < 0 ||
|
||||
fprintf (fprcs, "@@\012\012\012") < 0 ||
|
||||
/*
|
||||
* putdelta()
|
||||
*/
|
||||
fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
|
||||
fprintf (fprcs, "log\012@") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
/* We are going to put the log message in the revision on the
|
||||
branch. So putting it here too seems kind of redundant, I
|
||||
guess (and that is what CVS has always done, anyway). */
|
||||
if (fprintf (fprcs, "Initial revision\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (fprintf (fprcs, "@\012") < 0 ||
|
||||
fprintf (fprcs, "text\012@") < 0)
|
||||
{
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
/* Now copy over the contents of the file, expanding at signs. */
|
||||
{
|
||||
char buf[8192];
|
||||
unsigned int len;
|
||||
|
||||
while (1)
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
len = fread (buf, 1, sizeof buf, fpuser);
|
||||
if (len == 0)
|
||||
{
|
||||
if (ferror (fpuser))
|
||||
error (1, errno, "cannot read file %s for copying", user);
|
||||
break;
|
||||
}
|
||||
if (expand_at_signs (buf, len, fprcs) < 0)
|
||||
if (fprintf (fprcs, " %s.1", add_vbranch) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (fprintf (fprcs, ";\012") < 0)
|
||||
goto write_error;
|
||||
|
||||
if (fprintf (fprcs, "next ;\012") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
|
||||
fprintf (fprcs, "date %s; author %s; state Exp;\012",
|
||||
altdate1, author) < 0 ||
|
||||
fprintf (fprcs, "branches ;\012") < 0 ||
|
||||
fprintf (fprcs, "next ;\012\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
if (fprintf (fprcs, "@\012\012") < 0)
|
||||
|
||||
/* Now write the description (possibly empty). */
|
||||
if (fprintf (fprcs, "\012desc\012") < 0 ||
|
||||
fprintf (fprcs, "@") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
if (desctext != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
|
||||
fprintf (fprcs, "log\012@") < 0 ||
|
||||
expand_at_signs (message, (off_t) strlen (message), fprcs) < 0 ||
|
||||
fprintf (fprcs, "@\012text\012") < 0 ||
|
||||
fprintf (fprcs, "@@\012") < 0)
|
||||
/* The use of off_t not size_t for the second argument is very
|
||||
strange, since we are dealing with something which definitely
|
||||
fits in memory. */
|
||||
if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (fprintf (fprcs, "@\012\012\012") < 0)
|
||||
goto write_error;
|
||||
|
||||
/* Now write the log messages and contents for the revision(s) (that
|
||||
is, "deltatext" rather than "delta" from rcsfile(5)). */
|
||||
if (add_vhead != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 ||
|
||||
fprintf (fprcs, "log\012@") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
/* We are going to put the log message in the revision on the
|
||||
branch. So putting it here too seems kind of redundant, I
|
||||
guess (and that is what CVS has always done, anyway). */
|
||||
if (fprintf (fprcs, "Initial revision\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
if (fprintf (fprcs, "@\012") < 0 ||
|
||||
fprintf (fprcs, "text\012@") < 0)
|
||||
{
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
/* Now copy over the contents of the file, expanding at signs. */
|
||||
{
|
||||
char buf[8192];
|
||||
unsigned int len;
|
||||
|
||||
while (1)
|
||||
{
|
||||
len = fread (buf, 1, sizeof buf, fpuser);
|
||||
if (len == 0)
|
||||
{
|
||||
if (ferror (fpuser))
|
||||
error (1, errno, "cannot read file %s for copying",
|
||||
user);
|
||||
break;
|
||||
}
|
||||
if (expand_at_signs (buf, len, fprcs) < 0)
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
if (fprintf (fprcs, "@\012\012") < 0)
|
||||
goto write_error;
|
||||
if (add_vbranch != NULL)
|
||||
{
|
||||
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
|
||||
fprintf (fprcs, "log\012@") < 0 ||
|
||||
expand_at_signs (message,
|
||||
(off_t) strlen (message), fprcs) < 0 ||
|
||||
fprintf (fprcs, "@\012text\012") < 0 ||
|
||||
fprintf (fprcs, "@@\012") < 0)
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose (fprcs) == EOF)
|
||||
{
|
||||
@ -1184,7 +1265,7 @@ add_rcs_file (message, rcs, user, add_vhead, add_vbranch, vtag, targc, targv,
|
||||
* signs. If an error occurs, return a negative value and set errno
|
||||
* to indicate the error. If not, return a nonnegative value.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
expand_at_signs (buf, size, fp)
|
||||
char *buf;
|
||||
off_t size;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* Set Lock
|
||||
*
|
||||
@ -39,9 +39,9 @@
|
||||
be.
|
||||
|
||||
* Readlocks ensure that we won't find the file in the state in
|
||||
which it is in between the "rcs -i" and the RCS_checkin in commit.c
|
||||
(when a file is being added). This state is a state in which the
|
||||
RCS file parsing routines in rcs.c cannot parse the file.
|
||||
which it is in between the calls to add_rcs_file and RCS_checkin in
|
||||
commit.c (when a file is being added). This state is a state in
|
||||
which the RCS file parsing routines in rcs.c cannot parse the file.
|
||||
|
||||
* Readlocks ensure that a reader won't try to look at a
|
||||
half-written fileattr file (fileattr is not updated atomically).
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*/
|
||||
|
||||
#include "cvs.h"
|
||||
@ -282,7 +282,7 @@ do_editor (dir, messagep, repository, changes)
|
||||
(void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0);
|
||||
|
||||
/* run the editor */
|
||||
run_setup ("%s", editinfo_editor ? editinfo_editor : Editor);
|
||||
run_setup (editinfo_editor ? editinfo_editor : Editor);
|
||||
run_arg (fname);
|
||||
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
|
||||
RUN_NORMAL | RUN_SIGIGNORE)) != 0)
|
||||
@ -345,8 +345,16 @@ do_editor (dir, messagep, repository, changes)
|
||||
(void) printf ("Action: (continue) ");
|
||||
(void) fflush (stdout);
|
||||
line_length = getline (&line, &line_chars_allocated, stdin);
|
||||
if (line_length <= 0
|
||||
|| *line == '\n' || *line == 'c' || *line == 'C')
|
||||
if (line_length < 0)
|
||||
{
|
||||
error (0, errno, "cannot read from stdin");
|
||||
if (unlink_file (fname) < 0)
|
||||
error (0, errno,
|
||||
"warning: cannot remove temp file %s", fname);
|
||||
error (1, 0, "aborting");
|
||||
}
|
||||
else if (line_length == 0
|
||||
|| *line == '\n' || *line == 'c' || *line == 'C')
|
||||
break;
|
||||
if (*line == 'a' || *line == 'A')
|
||||
{
|
||||
@ -417,10 +425,7 @@ do_verify (messagep, repository)
|
||||
|
||||
fp = fopen (fname, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
error (1, errno, "cannot create temporary file %s", fname);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "%s", *messagep);
|
||||
@ -440,10 +445,15 @@ do_verify (messagep, repository)
|
||||
|
||||
if (verifymsg_script)
|
||||
{
|
||||
run_setup ("%s", verifymsg_script);
|
||||
run_setup (verifymsg_script);
|
||||
run_arg (fname);
|
||||
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
|
||||
RUN_NORMAL | RUN_SIGIGNORE)) != 0)
|
||||
{
|
||||
/* Since following error() exits, delete the temp file
|
||||
now. */
|
||||
unlink_file (fname);
|
||||
|
||||
error (1, retcode == -1 ? errno : 0,
|
||||
"Message verification failed");
|
||||
}
|
||||
@ -497,7 +507,7 @@ do_verify (messagep, repository)
|
||||
if (fclose (fp) < 0)
|
||||
error (0, errno, "warning: cannot close %s", fname);
|
||||
|
||||
/* Close and delete the temp file */
|
||||
/* Delete the temp file */
|
||||
|
||||
unlink_file (fname);
|
||||
free (fname);
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* as specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* This is the main C driver for the CVS system.
|
||||
*
|
||||
@ -33,15 +33,15 @@ char *command_name;
|
||||
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
int use_editor = TRUE;
|
||||
int use_cvsrc = TRUE;
|
||||
int use_editor = 1;
|
||||
int use_cvsrc = 1;
|
||||
int cvswrite = !CVSREAD_DFLT;
|
||||
int really_quiet = FALSE;
|
||||
int quiet = FALSE;
|
||||
int trace = FALSE;
|
||||
int noexec = FALSE;
|
||||
int readonlyfs = FALSE;
|
||||
int logoff = FALSE;
|
||||
int really_quiet = 0;
|
||||
int quiet = 0;
|
||||
int trace = 0;
|
||||
int noexec = 0;
|
||||
int readonlyfs = 0;
|
||||
int logoff = 0;
|
||||
mode_t cvsumask = UMASK_DFLT;
|
||||
|
||||
char *CurDir;
|
||||
@ -49,7 +49,6 @@ char *CurDir;
|
||||
/*
|
||||
* Defaults, for the environment variables that are not set
|
||||
*/
|
||||
char *Rcsbin = RCSBIN_DFLT;
|
||||
char *Tmpdir = TMPDIR_DFLT;
|
||||
char *Editor = EDITOR_DFLT;
|
||||
|
||||
@ -125,33 +124,47 @@ static const struct cmd
|
||||
|
||||
static const char *const usg[] =
|
||||
{
|
||||
"Usage: %s [cvs-options] command [command-options] [files...]\n",
|
||||
" Where 'cvs-options' are:\n",
|
||||
" -H Displays Usage information for command\n",
|
||||
" -Q Cause CVS to be really quiet.\n",
|
||||
" -q Cause CVS to be somewhat quiet.\n",
|
||||
" -r Make checked-out files read-only\n",
|
||||
" -w Make checked-out files read-write (default)\n",
|
||||
" -l Turn History logging off\n",
|
||||
" -n Do not execute anything that will change the disk\n",
|
||||
" -R Assume repository is read-only, such as CDROM\n",
|
||||
" -t Show trace of program execution -- Try with -n\n",
|
||||
" -v CVS version and copyright\n",
|
||||
" -b bindir Find RCS programs in 'bindir'\n",
|
||||
" -T tmpdir Use 'tmpdir' for temporary files\n",
|
||||
" -e editor Use 'editor' for editing log information\n",
|
||||
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n",
|
||||
" -f Do not use the ~/.cvsrc file\n",
|
||||
#ifdef CLIENT_SUPPORT
|
||||
" -z # Use compression level '#' for net traffic.\n",
|
||||
#ifdef ENCRYPTION
|
||||
" -x Encrypt all net traffic.\n",
|
||||
#endif
|
||||
#endif
|
||||
" -s VAR=VAL Set CVS user variable.\n",
|
||||
/* CVS usage messages never have followed the GNU convention of
|
||||
putting metavariables in uppercase. I don't know whether that
|
||||
is a good convention or not, but if it changes it would have to
|
||||
change in all the usage messages. For now, they consistently
|
||||
use lowercase, as far as I know. Puncutation is pretty funky,
|
||||
though. Sometimes they use none, as here. Sometimes they use
|
||||
single quotes (not the TeX-ish `' stuff), as in --help-options.
|
||||
Sometimes they use double quotes, as in cvs -H add.
|
||||
|
||||
Most (not all) of the usage messages seem to have periods at
|
||||
the end of each line. I haven't tried to duplicate this style
|
||||
in --help as it is a rather different format from the rest. */
|
||||
|
||||
"Usage: %s [cvs-options] command [command-options-and-arguments]\n",
|
||||
" where cvs-options are -q, -n, etc.\n",
|
||||
" (specify --help-options for a list of options)\n",
|
||||
" where command is add, admin, etc.\n",
|
||||
" (specify --help-commands for a list of commands\n",
|
||||
" or --help-synonyms for a list of command synonyms)\n",
|
||||
" where command-options-and-arguments depend on the specific command\n",
|
||||
" (specify -H followed by a command name for command-specific help)\n",
|
||||
" Specify --help to receive this message\n",
|
||||
"\n",
|
||||
" and where 'command' is: add, admin, etc. (use the --help-commands\n",
|
||||
" option for a list of commands)\n",
|
||||
|
||||
/* Some people think that a bug-reporting address should go here. IMHO,
|
||||
the web sites are better because anything else is very likely to go
|
||||
obsolete in the years between a release and when someone might be
|
||||
reading this help. Besides, we could never adequately discuss
|
||||
bug reporting in a concise enough way to put in a help message. */
|
||||
|
||||
/* I was going to put this at the top, but usage() wants the %s to
|
||||
be in the first line. */
|
||||
"The Concurrent Versions System (CVS) is a tool for version control.\n",
|
||||
/* I really don't think I want to try to define "version control"
|
||||
in one line. I'm not sure one can get more concise than the
|
||||
paragraph in ../cvs.spec without assuming the reader knows what
|
||||
version control means. */
|
||||
|
||||
"For CVS updates and additional information, see\n",
|
||||
" Cyclic Software at http://www.cyclic.com/ or\n",
|
||||
" Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -185,17 +198,48 @@ static const char *const cmd_usage[] =
|
||||
" update Bring work tree in sync with repository\n",
|
||||
" watch Set watches\n",
|
||||
" watchers See who is watching a file\n",
|
||||
"(Use the --help-synonyms option for a list of alternate command names)\n",
|
||||
"(Specify the --help option for a list of other help options)\n",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *const opt_usage[] =
|
||||
{
|
||||
"CVS global options (specified before the command name) are:\n",
|
||||
" -H Displays usage information for command.\n",
|
||||
" -Q Cause CVS to be really quiet.\n",
|
||||
" -q Cause CVS to be somewhat quiet.\n",
|
||||
" -r Make checked-out files read-only.\n",
|
||||
" -w Make checked-out files read-write (default).\n",
|
||||
" -l Turn history logging off.\n",
|
||||
" -n Do not execute anything that will change the disk.\n",
|
||||
" -t Show trace of program execution -- try with -n.\n",
|
||||
" -R Assume repository is read-only, such as CDROM\n",
|
||||
" -v CVS version and copyright.\n",
|
||||
" -b bindir Find RCS programs in 'bindir'.\n",
|
||||
" -T tmpdir Use 'tmpdir' for temporary files.\n",
|
||||
" -e editor Use 'editor' for editing log information.\n",
|
||||
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
|
||||
" -f Do not use the ~/.cvsrc file.\n",
|
||||
#ifdef CLIENT_SUPPORT
|
||||
" -z # Use compression level '#' for net traffic.\n",
|
||||
#ifdef ENCRYPTION
|
||||
" -x Encrypt all net traffic.\n",
|
||||
#endif
|
||||
" -a Authenticate all net traffic.\n",
|
||||
#endif
|
||||
" -s VAR=VAL Set CVS user variable.\n",
|
||||
"(Specify the --help option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const*
|
||||
cmd_synonyms ()
|
||||
{
|
||||
char ** synonyms;
|
||||
char ** line;
|
||||
const struct cmd *c = &cmds[0];
|
||||
int numcmds = 2; /* two more for title and end */
|
||||
/* Three more for title, "specify --help" line, and NULL. */
|
||||
int numcmds = 3;
|
||||
|
||||
while (c->fullname != NULL)
|
||||
{
|
||||
@ -220,6 +264,7 @@ cmd_synonyms ()
|
||||
line++;
|
||||
}
|
||||
}
|
||||
*line++ = "(Specify the --help option for a list of other help options)\n";
|
||||
*line = NULL;
|
||||
|
||||
return (const char * const*) synonyms; /* will never be freed */
|
||||
@ -330,11 +375,10 @@ main (argc, argv)
|
||||
char *cp, *end;
|
||||
const struct cmd *cm;
|
||||
int c, err = 0;
|
||||
int rcsbin_update_env, tmpdir_update_env, cvs_update_env;
|
||||
int tmpdir_update_env, cvs_update_env;
|
||||
int free_CVSroot = 0;
|
||||
int free_Editor = 0;
|
||||
int free_Tmpdir = 0;
|
||||
int free_Rcsbin = 0;
|
||||
|
||||
int help = 0; /* Has the user asked for help? This
|
||||
lets us support the `cvs -H cmd'
|
||||
@ -345,6 +389,7 @@ main (argc, argv)
|
||||
{"version", 0, NULL, 'v'},
|
||||
{"help-commands", 0, NULL, 1},
|
||||
{"help-synonyms", 0, NULL, 2},
|
||||
{"help-options", 0, NULL, 4},
|
||||
{"allow-root", required_argument, NULL, 3},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
@ -382,12 +427,6 @@ main (argc, argv)
|
||||
* they can be overridden by command line arguments
|
||||
*/
|
||||
cvs_update_env = 0;
|
||||
rcsbin_update_env = *Rcsbin; /* RCSBIN_DFLT must be set */
|
||||
if ((cp = getenv (RCSBIN_ENV)) != NULL)
|
||||
{
|
||||
Rcsbin = cp;
|
||||
rcsbin_update_env = 0; /* it's already there */
|
||||
}
|
||||
tmpdir_update_env = *Tmpdir; /* TMPDIR_DFLT must be set */
|
||||
if ((cp = getenv (TMPDIR_ENV)) != NULL)
|
||||
{
|
||||
@ -406,10 +445,10 @@ main (argc, argv)
|
||||
cvs_update_env = 0; /* it's already there */
|
||||
}
|
||||
if (getenv (CVSREAD_ENV) != NULL)
|
||||
cvswrite = FALSE;
|
||||
cvswrite = 0;
|
||||
if (getenv (CVSREADONLYFS_ENV) != NULL) {
|
||||
readonlyfs = TRUE;
|
||||
logoff = TRUE;
|
||||
readonlyfs = 1;
|
||||
logoff = 1;
|
||||
}
|
||||
|
||||
/* Set this to 0 to force getopt initialization. getopt() sets
|
||||
@ -427,7 +466,7 @@ main (argc, argv)
|
||||
!= EOF)
|
||||
{
|
||||
if (c == 'f')
|
||||
use_cvsrc = FALSE;
|
||||
use_cvsrc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -440,7 +479,7 @@ main (argc, argv)
|
||||
opterr = 1;
|
||||
|
||||
while ((c = getopt_long
|
||||
(argc, argv, "+QqrwtnRlvb:T:e:d:Hfz:s:x", long_options, &option_index))
|
||||
(argc, argv, "+QqrwtnRlvb:T:e:d:Hfz:s:xa", long_options, &option_index))
|
||||
!= EOF)
|
||||
{
|
||||
switch (c)
|
||||
@ -453,51 +492,63 @@ main (argc, argv)
|
||||
/* --help-synonyms */
|
||||
usage (cmd_synonyms());
|
||||
break;
|
||||
case 4:
|
||||
/* --help-options */
|
||||
usage (opt_usage);
|
||||
break;
|
||||
case 3:
|
||||
/* --allow-root */
|
||||
root_allow_add (optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
really_quiet = TRUE;
|
||||
really_quiet = 1;
|
||||
/* FALL THROUGH */
|
||||
case 'q':
|
||||
quiet = TRUE;
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'r':
|
||||
cvswrite = FALSE;
|
||||
cvswrite = 0;
|
||||
break;
|
||||
case 'w':
|
||||
cvswrite = TRUE;
|
||||
cvswrite = 1;
|
||||
break;
|
||||
case 't':
|
||||
trace = TRUE;
|
||||
trace = 1;
|
||||
break;
|
||||
case 'R':
|
||||
readonlyfs = TRUE;
|
||||
logoff = TRUE;
|
||||
readonlyfs = 1;
|
||||
logoff = 1;
|
||||
break;
|
||||
case 'n':
|
||||
noexec = TRUE;
|
||||
noexec = 1;
|
||||
case 'l': /* Fall through */
|
||||
logoff = TRUE;
|
||||
logoff = 1;
|
||||
break;
|
||||
case 'v':
|
||||
/* Having the year here is a good idea, so people have
|
||||
some idea of how long ago their version of CVS was
|
||||
released. */
|
||||
(void) fputs (version_string, stdout);
|
||||
(void) fputs (config_string, stdout);
|
||||
(void) fputs ("\n", stdout);
|
||||
(void) fputs ("Copyright (c) 1993-1994 Brian Berliner\n", stdout);
|
||||
(void) fputs ("Copyright (c) 1993-1994 david d `zoo' zuhn\n", stdout);
|
||||
(void) fputs ("Copyright (c) 1992, Brian Berliner and Jeff Polk\n", stdout);
|
||||
(void) fputs ("Copyright (c) 1989-1992, Brian Berliner\n", stdout);
|
||||
(void) fputs ("\
|
||||
Copyright (c) 1989-1997 Brian Berliner, david d `zoo' zuhn, \n\
|
||||
Jeff Polk, and other authors\n", stdout);
|
||||
(void) fputs ("\n", stdout);
|
||||
(void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
|
||||
(void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout);
|
||||
(void) fputs ("\n", stdout);
|
||||
|
||||
(void) fputs ("Specify the --help option for further information about CVS\n", stdout);
|
||||
|
||||
exit (0);
|
||||
break;
|
||||
case 'b':
|
||||
Rcsbin = xstrdup (optarg);
|
||||
free_Rcsbin = 1;
|
||||
rcsbin_update_env = 1; /* need to update environment */
|
||||
/* This option used to specify the directory for RCS
|
||||
executables. But since we don't run them any more,
|
||||
this is a noop. Silently ignore it so that .cvsrc
|
||||
and scripts and inetd.conf and such can work with
|
||||
either new or old CVS. */
|
||||
break;
|
||||
case 'T':
|
||||
Tmpdir = xstrdup (optarg);
|
||||
@ -517,7 +568,7 @@ main (argc, argv)
|
||||
help = 1;
|
||||
break;
|
||||
case 'f':
|
||||
use_cvsrc = FALSE; /* unnecessary, since we've done it above */
|
||||
use_cvsrc = 0; /* unnecessary, since we've done it above */
|
||||
break;
|
||||
case 'z':
|
||||
#ifdef CLIENT_SUPPORT
|
||||
@ -542,6 +593,15 @@ main (argc, argv)
|
||||
If no ENCRYPTION, we still accept -x, but issue an
|
||||
error if we are being run as a client. */
|
||||
break;
|
||||
case 'a':
|
||||
#ifdef CLIENT_SUPPORT
|
||||
cvsauthenticate = 1;
|
||||
#endif
|
||||
/* If no CLIENT_SUPPORT, ignore -a, so that users can
|
||||
have it in their .cvsrc and not cause any trouble.
|
||||
We will issue an error later if stream
|
||||
authentication is not supported. */
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage (usg);
|
||||
@ -572,6 +632,9 @@ main (argc, argv)
|
||||
else
|
||||
command_name = cm->fullname; /* Global pointer for later use */
|
||||
|
||||
/* This should probably remain a warning, rather than an error,
|
||||
for quite a while. For one thing the version of VC distributed
|
||||
with GNU emacs 19.34 invokes 'cvs rlog' instead of 'cvs log'. */
|
||||
if (strcmp (argv[0], "rlog") == 0)
|
||||
{
|
||||
error (0, 0, "warning: the rlog command is deprecated");
|
||||
@ -615,7 +678,7 @@ main (argc, argv)
|
||||
#endif /* HAVE_KERBEROS */
|
||||
|
||||
|
||||
#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT)
|
||||
#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT)
|
||||
if (strcmp (command_name, "pserver") == 0)
|
||||
{
|
||||
/* The reason that --allow-root is not a command option
|
||||
@ -632,15 +695,16 @@ main (argc, argv)
|
||||
/* Pretend we were invoked as a plain server. */
|
||||
command_name = "server";
|
||||
}
|
||||
#endif /* AUTH_SERVER_SUPPORT && SERVER_SUPPORT */
|
||||
#endif /* (AUTH_SERVER_SUPPORT || HAVE_GSSAPI) && SERVER_SUPPORT */
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
server_active = strcmp (command_name, "server") == 0;
|
||||
|
||||
/* Fiddling with CVSROOT doesn't make sense if we're running
|
||||
in server mode, since the client will send the repository
|
||||
directory after the connection is made. */
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
if (strcmp (command_name, "server") != 0)
|
||||
if (!server_active)
|
||||
#endif
|
||||
{
|
||||
char *CVSADM_Root;
|
||||
@ -788,7 +852,7 @@ main (argc, argv)
|
||||
it is worth the trouble. */
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
if (strcmp (command_name, "server") == 0)
|
||||
if (server_active)
|
||||
CurDir = xstrdup ("<remote>");
|
||||
else
|
||||
#endif
|
||||
@ -802,16 +866,6 @@ main (argc, argv)
|
||||
Tmpdir = "/tmp";
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
/* Now, see if we should update the environment with the
|
||||
Rcsbin value */
|
||||
if (rcsbin_update_env)
|
||||
{
|
||||
char *env;
|
||||
env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1);
|
||||
(void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin);
|
||||
(void) putenv (env);
|
||||
/* do not free env, as putenv has control of it */
|
||||
}
|
||||
if (tmpdir_update_env)
|
||||
{
|
||||
char *env;
|
||||
@ -828,24 +882,6 @@ main (argc, argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If Rcsbin is set to something, make sure it is terminated with
|
||||
* a slash character. If not, add one.
|
||||
*/
|
||||
if (*Rcsbin)
|
||||
{
|
||||
int len = strlen (Rcsbin);
|
||||
char *rcsbin;
|
||||
|
||||
if (Rcsbin[len - 1] != '/')
|
||||
{
|
||||
rcsbin = Rcsbin;
|
||||
Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */
|
||||
(void) strcpy (Rcsbin, rcsbin);
|
||||
(void) strcat (Rcsbin, "/");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DONT_USE_SIGNALS
|
||||
/* make sure we clean up on error */
|
||||
#ifdef SIGHUP
|
||||
@ -883,6 +919,28 @@ main (argc, argv)
|
||||
if (use_cvsrc)
|
||||
read_cvsrc (&argc, &argv, command_name);
|
||||
|
||||
/* Parse the CVSROOT/config file, but only for local. For the
|
||||
server, we parse it after we know $CVSROOT. For the
|
||||
client, it doesn't get parsed at all, obviously. The
|
||||
presence of the parse_config call here is not mean to
|
||||
predetermine whether CVSROOT/config overrides things from
|
||||
read_cvsrc and other such places or vice versa. That sort
|
||||
of thing probably needs more thought. */
|
||||
if (1
|
||||
#ifdef SERVER_SUPPORT
|
||||
&& !server_active
|
||||
#endif
|
||||
#ifdef CLIENT_SUPPORT
|
||||
&& !client_active
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* If there was an error parsing the config file, parse_config
|
||||
already printed an error. We keep going. Why? Because
|
||||
if we didn't, then there would be no way to check in a new
|
||||
CVSROOT/config file to fix the broken one! */
|
||||
parse_config (CVSroot_directory);
|
||||
}
|
||||
} /* end of stuff that gets done if the user DOESN'T ask for help */
|
||||
|
||||
err = (*(cm->func)) (argc, argv);
|
||||
@ -891,7 +949,10 @@ main (argc, argv)
|
||||
{
|
||||
/* Update the CVS/Root file. We might want to do this in
|
||||
all directories that we recurse into, but currently we
|
||||
don't. */
|
||||
don't. Note that if there is an error writing the file,
|
||||
we give an error/warning. This is so if users try to rewrite
|
||||
CVS/Root with the -d option (a documented feature), they will
|
||||
either succeed, or be told why it didn't work. */
|
||||
Create_Root (NULL, CVSroot);
|
||||
}
|
||||
|
||||
@ -904,8 +965,6 @@ main (argc, argv)
|
||||
free (Editor);
|
||||
if (free_Tmpdir)
|
||||
free (Tmpdir);
|
||||
if (free_Rcsbin)
|
||||
free (Rcsbin);
|
||||
root_allow_free ();
|
||||
|
||||
#ifdef SYSTEM_CLEANUP
|
||||
@ -917,6 +976,8 @@ main (argc, argv)
|
||||
/* This is exit rather than return because apparently that keeps
|
||||
some tools which check for memory leaks happier. */
|
||||
exit (err ? EXIT_FAILURE : 0);
|
||||
/* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
@ -931,11 +992,14 @@ Make_Date (rawdate)
|
||||
unixtime = get_date (rawdate, (struct timeb *) NULL);
|
||||
if (unixtime == (time_t) - 1)
|
||||
error (1, 0, "Can't parse date/time: %s", rawdate);
|
||||
#ifdef HAVE_RCS5
|
||||
|
||||
ftm = gmtime (&unixtime);
|
||||
#else
|
||||
ftm = localtime (&unixtime);
|
||||
#endif
|
||||
if (ftm == NULL)
|
||||
/* This is a system, like VMS, where the system clock is in local
|
||||
time. Hopefully using localtime here matches the "zero timezone"
|
||||
hack I added to get_date. */
|
||||
ftm = localtime (&unixtime);
|
||||
|
||||
(void) sprintf (date, DATEFORM,
|
||||
ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
|
||||
ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
|
||||
|
@ -275,6 +275,12 @@ static const char *const modules_contents[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const config_contents[] = {
|
||||
"# Set this to \"no\" if pserver shouldn't check system users/passwords\n",
|
||||
"#SystemAuth=no\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct admin_file filelist[] = {
|
||||
{CVSROOTADM_LOGINFO,
|
||||
"no logging of 'cvs commit' messages is done without a %s file",
|
||||
@ -316,14 +322,27 @@ static const struct admin_file filelist[] = {
|
||||
{CVSROOTADM_WRITERS,
|
||||
"a %s file specifies read/write users",
|
||||
NULL},
|
||||
/* Some have suggested listing CVSROOTADM_PASSWD here too. The
|
||||
security implications of transmitting hashed passwords over the
|
||||
net are no worse than transmitting cleartext passwords which pserver
|
||||
does, so this isn't a problem. But I'm worried about the implications
|
||||
of storing old passwords--if someone used a password in the past
|
||||
they might be using it elsewhere, using a similar password, etc,
|
||||
and so it doesn't seem to me like we should be saving old passwords,
|
||||
even hashed. */
|
||||
|
||||
/* Some have suggested listing CVSROOTADM_PASSWD here too. This
|
||||
would mean that CVS commands which operate on the
|
||||
CVSROOTADM_PASSWD file would transmit hashed passwords over the
|
||||
net. This might seem to be no big deal, as pserver normally
|
||||
transmits cleartext passwords, but the difference is that
|
||||
CVSROOTADM_PASSWD contains *all* passwords, not just the ones
|
||||
currently being used. For example, it could be too easy to
|
||||
accidentally give someone readonly access to CVSROOTADM_PASSWD
|
||||
(e.g. via anonymous CVS or cvsweb), and then if there are any
|
||||
guessable passwords for read/write access (usually there will be)
|
||||
they get read/write access.
|
||||
|
||||
Another worry is the implications of storing old passwords--if
|
||||
someone used a password in the past they might be using it
|
||||
elsewhere, using a similar password, etc, and so saving old
|
||||
passwords, even hashed, is probably not a good idea. */
|
||||
|
||||
{CVSROOTADM_CONFIG,
|
||||
"a %s file configures various behaviors",
|
||||
config_contents},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -694,6 +713,7 @@ rename_rcsfile (temp, real)
|
||||
|
||||
const char *const init_usage[] = {
|
||||
"Usage: %s %s\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -785,8 +805,12 @@ init (argc, argv)
|
||||
"initial checkin" but I fail to see the point as we know what
|
||||
file it is from the name. */
|
||||
retcode = add_rcs_file ("initial checkin", info_v,
|
||||
fileptr->filename, "1.1", NULL, NULL,
|
||||
0, NULL, NULL);
|
||||
fileptr->filename, "1.1", NULL,
|
||||
|
||||
/* No vendor branch. */
|
||||
NULL, NULL, 0, NULL,
|
||||
|
||||
NULL, 0, NULL);
|
||||
if (retcode != 0)
|
||||
/* add_rcs_file already printed an error message. */
|
||||
err = 1;
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1992, Brian Berliner and Jeff Polk
|
||||
*
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* General recursion handler
|
||||
*
|
||||
@ -157,7 +157,25 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
|
||||
* called with the list of sub-dirs of the current dir as args
|
||||
*/
|
||||
if ((which & W_LOCAL) && !isdir (CVSADM))
|
||||
{
|
||||
dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL);
|
||||
/* If there are no sub-directories, there is a certain logic in
|
||||
favor of doing nothing, but in fact probably the user is just
|
||||
confused about what directory they are in, or whether they
|
||||
cvs add'd a new directory. In the case of at least one
|
||||
sub-directory, at least when we recurse into them we
|
||||
notice (hopefully) whether they are under CVS control. */
|
||||
if (list_isempty (dirlist))
|
||||
{
|
||||
if (update_dir[0] == '\0')
|
||||
error (0, 0, "in directory .:");
|
||||
else
|
||||
error (0, 0, "in directory %s:", update_dir);
|
||||
error (1, 0,
|
||||
"there is no version here; run '%s checkout' first",
|
||||
program_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
addlist (&dirlist, ".");
|
||||
|
||||
@ -637,7 +655,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
|
||||
else
|
||||
{
|
||||
newrepos = xmalloc (strlen (repository) + strlen (dir) + 5);
|
||||
(void) sprintf (newrepos, "%s/%s", repository, dir);
|
||||
sprintf (newrepos, "%s/%s", repository, dir);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -651,10 +669,78 @@ but CVS uses %s for its own purposes; skipping %s directory",
|
||||
newrepos = xstrdup (repository);
|
||||
}
|
||||
|
||||
/* Check to see that the CVSADM directory, if it exists, seems to be
|
||||
well-formed. It can be missing files if the user hit ^C in the
|
||||
middle of a previous run. We want to (a) make this a nonfatal
|
||||
error, and (b) make sure we print which directory has the
|
||||
problem.
|
||||
|
||||
Do this before the direntproc, so that (1) the direntproc
|
||||
doesn't have to guess/deduce whether we will skip the directory
|
||||
(e.g. send_dirent_proc and whether to send the directory), and
|
||||
(2) so that the warm fuzzy doesn't get printed if we skip the
|
||||
directory. */
|
||||
if (frame->which & W_LOCAL)
|
||||
{
|
||||
char *cvsadmdir;
|
||||
|
||||
cvsadmdir = xmalloc (strlen (dir)
|
||||
+ sizeof (CVSADM_REP)
|
||||
+ sizeof (CVSADM_ENT)
|
||||
+ 80);
|
||||
|
||||
strcpy (cvsadmdir, dir);
|
||||
strcat (cvsadmdir, "/");
|
||||
strcat (cvsadmdir, CVSADM);
|
||||
if (isdir (cvsadmdir))
|
||||
{
|
||||
strcpy (cvsadmdir, dir);
|
||||
strcat (cvsadmdir, "/");
|
||||
strcat (cvsadmdir, CVSADM_REP);
|
||||
if (!isfile (cvsadmdir))
|
||||
{
|
||||
/* Some commands like update may have printed "? foo" but
|
||||
if we were planning to recurse, and don't on account of
|
||||
CVS/Repository, we want to say why. */
|
||||
error (0, 0, "ignoring %s (%s missing)", update_dir,
|
||||
CVSADM_REP);
|
||||
dir_return = R_SKIP_ALL;
|
||||
}
|
||||
|
||||
/* Likewise for CVS/Entries. */
|
||||
if (dir_return != R_SKIP_ALL)
|
||||
{
|
||||
strcpy (cvsadmdir, dir);
|
||||
strcat (cvsadmdir, "/");
|
||||
strcat (cvsadmdir, CVSADM_ENT);
|
||||
if (!isfile (cvsadmdir))
|
||||
{
|
||||
/* Some commands like update may have printed "? foo" but
|
||||
if we were planning to recurse, and don't on account of
|
||||
CVS/Repository, we want to say why. */
|
||||
error (0, 0, "ignoring %s (%s missing)", update_dir,
|
||||
CVSADM_ENT);
|
||||
dir_return = R_SKIP_ALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
free (cvsadmdir);
|
||||
}
|
||||
|
||||
/* call-back dir entry proc (if any) */
|
||||
if (frame->direntproc != NULL)
|
||||
if (dir_return == R_SKIP_ALL)
|
||||
;
|
||||
else if (frame->direntproc != NULL)
|
||||
dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
|
||||
update_dir, frent->entries);
|
||||
else
|
||||
{
|
||||
/* Generic behavior. I don't see a reason to make the caller specify
|
||||
a direntproc just to get this. */
|
||||
if ((frame->which & W_LOCAL) && !isdir (dir))
|
||||
dir_return = R_SKIP_ALL;
|
||||
}
|
||||
|
||||
free (newrepos);
|
||||
|
||||
/* only process the dir if the return code was 0 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
* 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.
|
||||
* specified in the README file that comes with the CVS source distribution.
|
||||
*
|
||||
* "update" updates the version in the present directory with respect to the RCS
|
||||
* repository. The present version must have been created by "checkout". The
|
||||
@ -64,12 +64,8 @@ static int update_fileproc PROTO ((void *callerdat, struct file_info *));
|
||||
static int update_filesdone_proc PROTO ((void *callerdat, int err,
|
||||
char *repository, char *update_dir,
|
||||
List *entries));
|
||||
static int write_letter PROTO((char *file, int letter, char *update_dir));
|
||||
#ifdef SERVER_SUPPORT
|
||||
static void write_letter PROTO ((struct file_info *finfo, int letter));
|
||||
static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
|
||||
#else
|
||||
static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
|
||||
#endif
|
||||
|
||||
static char *options = NULL;
|
||||
static char *tag = NULL;
|
||||
@ -113,6 +109,7 @@ static const char *const update_usage[] =
|
||||
"\t-j rev\tMerge in changes made between current revision and rev.\n",
|
||||
"\t-I ign\tMore files to ignore (! to reset).\n",
|
||||
"\t-W spec\tWrappers specification line.\n",
|
||||
"(Specify the --help global option for a list of other help options)\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -259,16 +256,18 @@ update (argc, argv)
|
||||
|
||||
/* If the server supports the command "update-patches", that means
|
||||
that it knows how to handle the -u argument to update, which
|
||||
means to send patches instead of complete files. */
|
||||
means to send patches instead of complete files.
|
||||
|
||||
We don't send -u if failed_patches != NULL, so that the
|
||||
server doesn't try to send patches which will just fail
|
||||
again. At least currently, the client also clobbers the
|
||||
file and tells the server it is lost, which also will get
|
||||
a full file instead of a patch, but it seems clean to omit
|
||||
-u. */
|
||||
if (failed_patches == NULL)
|
||||
{
|
||||
#ifndef DONT_USE_PATCH
|
||||
/* Systems which don't have the patch program ported to them
|
||||
will want to define DONT_USE_PATCH; then CVS won't try to
|
||||
invoke patch. */
|
||||
if (supported_request ("update-patches"))
|
||||
send_arg ("-u");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (failed_patches == NULL)
|
||||
@ -548,44 +547,17 @@ update_fileproc (callerdat, finfo)
|
||||
break;
|
||||
case T_CONFLICT: /* old punt-type errors */
|
||||
retval = 1;
|
||||
(void) write_letter (finfo->file, 'C', finfo->update_dir);
|
||||
write_letter (finfo, 'C');
|
||||
break;
|
||||
case T_NEEDS_MERGE: /* needs merging */
|
||||
if (noexec)
|
||||
{
|
||||
retval = 1;
|
||||
(void) write_letter (finfo->file, 'C', finfo->update_dir);
|
||||
write_letter (finfo, 'C');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wrap_merge_is_copy (finfo->file))
|
||||
#if 0
|
||||
/* Look, we can't clobber the user's file. We
|
||||
know it is modified and we're going to
|
||||
overwrite their mod? Puh-leeze. The
|
||||
correct behavior is probably something like
|
||||
what merge_file does for -kb, which is to
|
||||
give the users both files and tell them
|
||||
what the two filenames are. Of course, -m
|
||||
in wrappers needs to be documented *much*
|
||||
better. Anyway, until then, make this a
|
||||
fatal error. */
|
||||
|
||||
/* Should we be warning the user that we are
|
||||
* overwriting the user's copy of the file? */
|
||||
retval =
|
||||
checkout_file (finfo, vers, 0);
|
||||
#else
|
||||
{
|
||||
error (0, 0, "A -m 'COPY' wrapper is specified");
|
||||
error (0, 0, "but file %s needs merge",
|
||||
finfo->fullname);
|
||||
error (1, 0, "\
|
||||
You probably want to avoid -m 'COPY' wrappers");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
retval = merge_file (finfo, vers);
|
||||
retval = merge_file (finfo, vers);
|
||||
}
|
||||
break;
|
||||
case T_MODIFIED: /* locally modified */
|
||||
@ -622,7 +594,7 @@ You probably want to avoid -m 'COPY' wrappers");
|
||||
|
||||
if (!retcode)
|
||||
{
|
||||
(void) write_letter (finfo->file, 'C', finfo->update_dir);
|
||||
write_letter (finfo, 'C');
|
||||
retval = 1;
|
||||
}
|
||||
else
|
||||
@ -634,7 +606,10 @@ You probably want to avoid -m 'COPY' wrappers");
|
||||
}
|
||||
}
|
||||
if (!retval)
|
||||
retval = write_letter (finfo->file, 'M', finfo->update_dir);
|
||||
{
|
||||
write_letter (finfo, 'M');
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
#ifdef SERVER_SUPPORT
|
||||
case T_PATCH: /* needs patch */
|
||||
@ -658,10 +633,9 @@ You probably want to avoid -m 'COPY' wrappers");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Fall through. */
|
||||
/* If we're not running as a server, just check the
|
||||
file out. It's simpler and faster than starting up
|
||||
two new processes (diff and patch). */
|
||||
file out. It's simpler and faster than producing
|
||||
and applying patches. */
|
||||
/* Fall through. */
|
||||
#endif
|
||||
case T_CHECKOUT: /* needs checkout */
|
||||
@ -674,10 +648,12 @@ You probably want to avoid -m 'COPY' wrappers");
|
||||
#endif
|
||||
break;
|
||||
case T_ADDED: /* added but not committed */
|
||||
retval = write_letter (finfo->file, 'A', finfo->update_dir);
|
||||
write_letter (finfo, 'A');
|
||||
retval = 0;
|
||||
break;
|
||||
case T_REMOVED: /* removed but not committed */
|
||||
retval = write_letter (finfo->file, 'R', finfo->update_dir);
|
||||
write_letter (finfo, 'R');
|
||||
retval = 0;
|
||||
break;
|
||||
case T_REMOVE_ENTRY: /* needs to be un-registered */
|
||||
retval = scratch_file (finfo);
|
||||
@ -727,7 +703,23 @@ update_ignproc (file, dir)
|
||||
char *file;
|
||||
char *dir;
|
||||
{
|
||||
(void) write_letter (file, '?', dir);
|
||||
struct file_info finfo;
|
||||
|
||||
memset (&finfo, 0, sizeof (finfo));
|
||||
finfo.file = file;
|
||||
finfo.update_dir = dir;
|
||||
if (dir[0] == '\0')
|
||||
finfo.fullname = xstrdup (file);
|
||||
else
|
||||
{
|
||||
finfo.fullname = xmalloc (strlen (file) + strlen (dir) + 10);
|
||||
strcpy (finfo.fullname, dir);
|
||||
strcat (finfo.fullname, "/");
|
||||
strcat (finfo.fullname, file);
|
||||
}
|
||||
|
||||
write_letter (&finfo, '?');
|
||||
free (finfo.fullname);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
@ -808,7 +800,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
|
||||
if (noexec)
|
||||
{
|
||||
/* ignore the missing dir if -n is specified */
|
||||
error (0, 0, "New directory `%s' -- ignored", dir);
|
||||
error (0, 0, "New directory `%s' -- ignored", update_dir);
|
||||
return (R_SKIP_ALL);
|
||||
}
|
||||
else
|
||||
@ -818,6 +810,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
|
||||
Create_Admin (dir, update_dir, repository, tag, date,
|
||||
/* This is a guess. We will rewrite it later
|
||||
via WriteTag. */
|
||||
0,
|
||||
0);
|
||||
rewrite_tag = 1;
|
||||
nonbranch = 0;
|
||||
@ -920,7 +913,8 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
|
||||
{
|
||||
if ((cp = strrchr (line, '\n')) != NULL)
|
||||
*cp = '\0';
|
||||
run_setup ("%s %s", line, repository);
|
||||
run_setup (line);
|
||||
run_arg (repository);
|
||||
cvs_output (program_name, 0);
|
||||
cvs_output (" ", 1);
|
||||
cvs_output (command_name, 0);
|
||||
@ -1080,6 +1074,9 @@ checkout_file (finfo, vers_ts, adding)
|
||||
int status;
|
||||
int file_is_dead;
|
||||
|
||||
/* Solely to suppress a warning from gcc -Wall. */
|
||||
backup = NULL;
|
||||
|
||||
/* don't screw with backup files if we're going to stdout */
|
||||
if (!pipeout)
|
||||
{
|
||||
@ -1093,7 +1090,13 @@ checkout_file (finfo, vers_ts, adding)
|
||||
else
|
||||
/* If -f/-t wrappers are being used to wrap up a directory,
|
||||
then backup might be a directory instead of just a file. */
|
||||
(void) unlink_file_dir (backup);
|
||||
if (unlink_file_dir (backup) < 0)
|
||||
{
|
||||
/* Not sure if the existence_error check is needed here. */
|
||||
if (!existence_error (errno))
|
||||
/* FIXME: should include update_dir in message. */
|
||||
error (0, errno, "error removing %s", backup);
|
||||
}
|
||||
}
|
||||
|
||||
file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
|
||||
@ -1133,7 +1136,7 @@ VERS: ", 0);
|
||||
{
|
||||
Vers_TS *xvers_ts;
|
||||
|
||||
if (cvswrite == TRUE
|
||||
if (cvswrite
|
||||
&& !file_is_dead
|
||||
&& !fileattr_get (finfo->file, "_watched"))
|
||||
xchmod (finfo->file, 1);
|
||||
@ -1155,13 +1158,11 @@ VERS: ", 0);
|
||||
}
|
||||
|
||||
/* set the time from the RCS file iff it was unknown before */
|
||||
if (vers_ts->vn_user == NULL ||
|
||||
strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
|
||||
{
|
||||
set_time = 1;
|
||||
}
|
||||
else
|
||||
set_time = 0;
|
||||
set_time =
|
||||
(!noexec
|
||||
&& (vers_ts->vn_user == NULL ||
|
||||
strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
|
||||
&& !file_is_dead);
|
||||
|
||||
wrap_fromcvs_process_file (finfo->file);
|
||||
|
||||
@ -1222,7 +1223,7 @@ VERS: ", 0);
|
||||
|
||||
if (!really_quiet && !file_is_dead)
|
||||
{
|
||||
write_letter (finfo->file, 'U', finfo->update_dir);
|
||||
write_letter (finfo, 'U');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1243,7 +1244,13 @@ VERS: ", 0);
|
||||
{
|
||||
/* If -f/-t wrappers are being used to wrap up a directory,
|
||||
then backup might be a directory instead of just a file. */
|
||||
(void) unlink_file_dir (backup);
|
||||
if (unlink_file_dir (backup) < 0)
|
||||
{
|
||||
/* Not sure if the existence_error check is needed here. */
|
||||
if (!existence_error (errno))
|
||||
/* FIXME: should include update_dir in message. */
|
||||
error (0, errno, "error removing %s", backup);
|
||||
}
|
||||
free (backup);
|
||||
}
|
||||
|
||||
@ -1306,6 +1313,27 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First check that the first revision exists. If it has been nuked
|
||||
by cvs admin -o, then just fall back to checking out entire
|
||||
revisions. In some sense maybe we don't have to do this; after
|
||||
all cvs.texinfo says "Make sure that no-one has checked out a
|
||||
copy of the revision you outdate" but then again, that advice
|
||||
doesn't really make complete sense, because "cvs admin" operates
|
||||
on a working directory and so _someone_ will almost always have
|
||||
_some_ revision checked out. */
|
||||
{
|
||||
char *rev;
|
||||
|
||||
rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
|
||||
if (rev == NULL)
|
||||
{
|
||||
*docheckout = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
free (rev);
|
||||
}
|
||||
|
||||
backup = xmalloc (strlen (finfo->file)
|
||||
+ sizeof (CVSADM)
|
||||
+ sizeof (CVSPREFIX)
|
||||
@ -1382,7 +1410,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
|
||||
retcode = 0;
|
||||
if (! fail)
|
||||
{
|
||||
const char *diff_options;
|
||||
char *diff_options;
|
||||
|
||||
/* FIXME: It might be better to come up with a diff library
|
||||
which can be shared with the diffutils. */
|
||||
@ -1400,21 +1428,22 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: We should use -a if diff supports it. We should
|
||||
probably just copy over most or all of the diff
|
||||
handling in the RCS configure script. */
|
||||
/* IMHO, we shouldn't copy over anything which even
|
||||
vaguely resembles the RCS configure script. That kind of
|
||||
thing tends to be ugly, slow, and fragile. It also is a
|
||||
a support headache for CVS to behave differently in subtle
|
||||
ways based on whether it was installed correctly. Instead we
|
||||
should come up with a diff library. -kingdon, Apr 1997. */
|
||||
/* Now that diff is librarified, we could be passing -a if
|
||||
we wanted to. However, it is unclear to me whether we
|
||||
would want to. Does diff -a, in any significant
|
||||
percentage of cases, produce patches which are smaller
|
||||
than the files it is patching? I guess maybe text
|
||||
files with character sets which diff regards as
|
||||
'binary'. Conversely, do they tend to be much larger
|
||||
in the bad cases? This needs some more
|
||||
thought/investigation, I suspect. */
|
||||
|
||||
diff_options = "-n";
|
||||
}
|
||||
run_setup ("%s %s %s %s", DIFF, diff_options, file1, file2);
|
||||
retcode = diff_exec (file1, file2, diff_options, finfo->file);
|
||||
|
||||
/* A retcode of 0 means no differences. 1 means some differences. */
|
||||
if ((retcode = run_exec (RUN_TTY, finfo->file, RUN_TTY, RUN_NORMAL)) != 0
|
||||
if (retcode != 0
|
||||
&& retcode != 1)
|
||||
{
|
||||
fail = 1;
|
||||
@ -1434,7 +1463,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
|
||||
file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
|
||||
< 0)
|
||||
error (0, errno, "cannot change mode of file %s", finfo->file);
|
||||
if (cvswrite == TRUE
|
||||
if (cvswrite
|
||||
&& !fileattr_get (finfo->file, "_watched"))
|
||||
xchmod (finfo->file, 1);
|
||||
|
||||
@ -1482,7 +1511,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
|
||||
|
||||
if (!really_quiet)
|
||||
{
|
||||
write_letter (finfo->file, 'P', finfo->update_dir);
|
||||
write_letter (finfo, 'P');
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1528,7 +1557,7 @@ patch_file_write (callerdat, buffer, len)
|
||||
data->final_nl = (buffer[len - 1] == '\n');
|
||||
|
||||
if (data->compute_checksum)
|
||||
MD5Update (&data->context, buffer, len);
|
||||
MD5Update (&data->context, (unsigned char *) buffer, len);
|
||||
}
|
||||
|
||||
#endif /* SERVER_SUPPORT */
|
||||
@ -1537,27 +1566,45 @@ patch_file_write (callerdat, buffer, len)
|
||||
* Several of the types we process only print a bit of information consisting
|
||||
* of a single letter and the name.
|
||||
*/
|
||||
static int
|
||||
write_letter (file, letter, update_dir)
|
||||
char *file;
|
||||
static void
|
||||
write_letter (finfo, letter)
|
||||
struct file_info *finfo;
|
||||
int letter;
|
||||
char *update_dir;
|
||||
{
|
||||
if (!really_quiet)
|
||||
{
|
||||
char buf[2];
|
||||
char *tag = NULL;
|
||||
/* Big enough for "+updated" or any of its ilk. */
|
||||
char buf[80];
|
||||
|
||||
switch (letter)
|
||||
{
|
||||
case 'U':
|
||||
tag = "updated";
|
||||
break;
|
||||
default:
|
||||
/* We don't yet support tagged output except for "U". */
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag != NULL)
|
||||
{
|
||||
sprintf (buf, "+%s", tag);
|
||||
cvs_output_tagged (buf, NULL);
|
||||
}
|
||||
buf[0] = letter;
|
||||
buf[1] = ' ';
|
||||
cvs_output (buf, 2);
|
||||
if (update_dir[0])
|
||||
buf[2] = '\0';
|
||||
cvs_output_tagged ("text", buf);
|
||||
cvs_output_tagged ("fname", finfo->fullname);
|
||||
cvs_output_tagged ("newline", NULL);
|
||||
if (tag != NULL)
|
||||
{
|
||||
cvs_output (update_dir, 0);
|
||||
cvs_output ("/", 1);
|
||||
sprintf (buf, "-%s", tag);
|
||||
cvs_output_tagged (buf, NULL);
|
||||
}
|
||||
cvs_output (file, 0);
|
||||
cvs_output ("\n", 1);
|
||||
}
|
||||
return (0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1590,7 +1637,8 @@ merge_file (finfo, vers)
|
||||
copy_file (finfo->file, backup);
|
||||
xchmod (finfo->file, 1);
|
||||
|
||||
if (strcmp (vers->options, "-kb") == 0)
|
||||
if (strcmp (vers->options, "-kb") == 0
|
||||
|| wrap_merge_is_copy (finfo->file))
|
||||
{
|
||||
/* For binary files, a merge is always a conflict. We give the
|
||||
user the two files, and let them resolve it. It is possible
|
||||
@ -1609,11 +1657,15 @@ merge_file (finfo, vers)
|
||||
(struct stat *) NULL, (unsigned char *) NULL);
|
||||
}
|
||||
#endif
|
||||
error (0, 0, "binary file needs merge");
|
||||
/* Is there a better term than "nonmergeable file"? What we
|
||||
really mean is, not something that CVS cannot or does not
|
||||
want to merge (there might be an external manual or
|
||||
automatic merge process). */
|
||||
error (0, 0, "nonmergeable file needs merge");
|
||||
error (0, 0, "revision %s from repository is now in %s",
|
||||
vers->vn_rcs, finfo->fullname);
|
||||
error (0, 0, "file from working directory is now in %s", backup);
|
||||
write_letter (finfo->file, 'C', finfo->update_dir);
|
||||
write_letter (finfo, 'C');
|
||||
|
||||
history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
|
||||
finfo->repository);
|
||||
@ -1621,7 +1673,7 @@ merge_file (finfo, vers)
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = RCS_merge(vers->srcfile->path,
|
||||
status = RCS_merge(finfo->rcs, vers->srcfile->path, finfo->file,
|
||||
vers->options, vers->vn_user, vers->vn_rcs);
|
||||
if (status != 0 && status != 1)
|
||||
{
|
||||
@ -1684,7 +1736,7 @@ merge_file (finfo, vers)
|
||||
if (!noexec)
|
||||
error (0, 0, "conflicts found in %s", finfo->fullname);
|
||||
|
||||
write_letter (finfo->file, 'C', finfo->update_dir);
|
||||
write_letter (finfo, 'C');
|
||||
|
||||
history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, finfo->repository);
|
||||
|
||||
@ -1696,7 +1748,7 @@ merge_file (finfo, vers)
|
||||
}
|
||||
else
|
||||
{
|
||||
write_letter (finfo->file, 'M', finfo->update_dir);
|
||||
write_letter (finfo, 'M');
|
||||
history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
|
||||
finfo->repository);
|
||||
}
|
||||
@ -1731,14 +1783,6 @@ join_file (finfo, vers)
|
||||
jdate1 = date_rev1;
|
||||
jdate2 = date_rev2;
|
||||
|
||||
if (wrap_merge_is_copy (finfo->file))
|
||||
{
|
||||
error (0, 0,
|
||||
"Cannot merge %s because it is a merge-by-copy file.",
|
||||
finfo->fullname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine if we need to do anything at all. */
|
||||
if (vers->srcfile == NULL ||
|
||||
vers->srcfile->path == NULL)
|
||||
@ -2034,7 +2078,7 @@ join_file (finfo, vers)
|
||||
"failed to check out %s file", finfo->fullname);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The users currently modified file is moved to a backup file name
|
||||
* ".#filename.version", so that it will stay around for a few days
|
||||
@ -2053,14 +2097,96 @@ join_file (finfo, vers)
|
||||
xchmod (finfo->file, 1);
|
||||
|
||||
options = vers->options;
|
||||
#ifdef HAVE_RCS5
|
||||
#if 0
|
||||
if (*options == '\0')
|
||||
options = "-kk"; /* to ignore keyword expansions */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
status = RCS_merge (vers->srcfile->path, options, rev1, rev2);
|
||||
/* If the source of the merge is the same as the working file
|
||||
revision, then we can just RCS_checkout the target (no merging
|
||||
as such). In the text file case, this is probably quite
|
||||
similar to the RCS_merge, but in the binary file case,
|
||||
RCS_merge gives all kinds of trouble. */
|
||||
if (vers->vn_user != NULL
|
||||
&& strcmp (rev1, vers->vn_user) == 0
|
||||
/* See comments above about how No_Difference has already been
|
||||
called. */
|
||||
&& vers->ts_user != NULL
|
||||
&& strcmp (vers->ts_user, vers->ts_rcs) == 0
|
||||
|
||||
/* This is because of the worry below about $Name. If that
|
||||
isn't a problem, I suspect this code probably works for
|
||||
text files too. */
|
||||
&& (strcmp (options, "-kb") == 0
|
||||
|| wrap_merge_is_copy (finfo->file)))
|
||||
{
|
||||
/* FIXME: what about nametag? What does RCS_merge do with
|
||||
$Name? */
|
||||
if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
|
||||
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
|
||||
status = 2;
|
||||
else
|
||||
status = 0;
|
||||
|
||||
/* OK, this is really stupid. RCS_checkout carefully removes
|
||||
write permissions, and we carefully put them back. But
|
||||
until someone gets around to fixing it, that seems like the
|
||||
easiest way to get what would seem to be the right mode.
|
||||
I don't check CVSWRITE or _watched; I haven't thought about
|
||||
that in great detail, but it seems like a watched file should
|
||||
be checked out (writable) after a merge. */
|
||||
xchmod (finfo->file, 1);
|
||||
|
||||
/* Traditionally, the text file case prints a whole bunch of
|
||||
scary looking and verbose output which fails to tell the user
|
||||
what is really going on (it gives them rev1 and rev2 but doesn't
|
||||
indicate in any way that rev1 == vn_user). I think just a
|
||||
simple "U foo" is good here; it seems analogous to the case in
|
||||
which the file was added on the branch in terms of what to
|
||||
print. */
|
||||
write_letter (finfo, 'U');
|
||||
}
|
||||
else if (strcmp (options, "-kb") == 0
|
||||
|| wrap_merge_is_copy (finfo->file))
|
||||
{
|
||||
/* We are dealing with binary files, but real merging would
|
||||
need to take place. This is a conflict. We give the user
|
||||
the two files, and let them resolve it. It is possible
|
||||
that we should require a "touch foo" or similar step before
|
||||
we allow a checkin. */
|
||||
if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
|
||||
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
|
||||
status = 2;
|
||||
else
|
||||
status = 0;
|
||||
|
||||
/* OK, this is really stupid. RCS_checkout carefully removes
|
||||
write permissions, and we carefully put them back. But
|
||||
until someone gets around to fixing it, that seems like the
|
||||
easiest way to get what would seem to be the right mode.
|
||||
I don't check CVSWRITE or _watched; I haven't thought about
|
||||
that in great detail, but it seems like a watched file should
|
||||
be checked out (writable) after a merge. */
|
||||
xchmod (finfo->file, 1);
|
||||
|
||||
/* Hmm. We don't give them REV1 anywhere. I guess most people
|
||||
probably don't have a 3-way merge tool for the file type in
|
||||
question, and might just get confused if we tried to either
|
||||
provide them with a copy of the file from REV1, or even just
|
||||
told them what REV1 is so they can get it themself, but it
|
||||
might be worth thinking about. */
|
||||
/* See comment in merge_file about the "nonmergeable file"
|
||||
terminology. */
|
||||
error (0, 0, "nonmergeable file needs merge");
|
||||
error (0, 0, "revision %s from repository is now in %s",
|
||||
rev2, finfo->fullname);
|
||||
error (0, 0, "file from working directory is now in %s", backup);
|
||||
write_letter (finfo, 'C');
|
||||
}
|
||||
else
|
||||
status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
|
||||
options, rev1, rev2);
|
||||
|
||||
if (status != 0 && status != 1)
|
||||
{
|
||||
error (0, status == -1 ? errno : 0,
|
||||
|
Loading…
Reference in New Issue
Block a user