Merge import conflicts
This commit is contained in:
parent
02e03a8b5f
commit
625799437a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=25843
@ -16,46 +16,159 @@
|
||||
|
||||
#include "cvs.h"
|
||||
|
||||
static Dtype diff_dirproc PROTO((char *dir, char *pos_repos, char *update_dir));
|
||||
static int diff_filesdoneproc PROTO((int err, char *repos, char *update_dir));
|
||||
static int diff_dirleaveproc PROTO((char *dir, int err, char *update_dir));
|
||||
static int diff_file_nodiff PROTO((char *file, char *repository, List *entries,
|
||||
RCSNode *rcs, Vers_TS *vers));
|
||||
static int diff_fileproc PROTO((struct file_info *finfo));
|
||||
enum diff_file
|
||||
{
|
||||
DIFF_ERROR,
|
||||
DIFF_ADDED,
|
||||
DIFF_REMOVED,
|
||||
DIFF_DIFFERENT,
|
||||
DIFF_SAME
|
||||
};
|
||||
|
||||
static Dtype diff_dirproc PROTO ((void *callerdat, char *dir,
|
||||
char *pos_repos, char *update_dir,
|
||||
List *entries));
|
||||
static int diff_filesdoneproc PROTO ((void *callerdat, int err,
|
||||
char *repos, char *update_dir,
|
||||
List *entries));
|
||||
static int diff_dirleaveproc PROTO ((void *callerdat, char *dir,
|
||||
int err, char *update_dir,
|
||||
List *entries));
|
||||
static enum diff_file diff_file_nodiff PROTO ((struct file_info *finfo,
|
||||
Vers_TS *vers,
|
||||
enum diff_file));
|
||||
static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
|
||||
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;
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
/* Revision of the user file, if it is unchanged from something in the
|
||||
repository and we want to use that fact. */
|
||||
static char *user_file_rev;
|
||||
#endif
|
||||
|
||||
static char *options;
|
||||
static char opts[PATH_MAX];
|
||||
static char *opts;
|
||||
static size_t opts_allocated = 1;
|
||||
static int diff_errors;
|
||||
static int empty_files = 0;
|
||||
|
||||
/* FIXME: should be documenting all the options here. They don't
|
||||
perfectly match rcsdiff options (for example, we always support
|
||||
--ifdef and --context, but rcsdiff only does if diff does). */
|
||||
static const char *const diff_usage[] =
|
||||
{
|
||||
"Usage: %s %s [-lN] [rcsdiff-options]\n",
|
||||
#ifdef CVS_DIFFDATE
|
||||
"Usage: %s %s [-lNR] [rcsdiff-options]\n",
|
||||
" [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n",
|
||||
#else
|
||||
" [-r rev1 [-r rev2]] [files...] \n",
|
||||
#endif
|
||||
"\t-l\tLocal directory only, not recursive\n",
|
||||
"\t-R\tProcess directories recursively.\n",
|
||||
"\t-D d1\tDiff revision for date against working file.\n",
|
||||
"\t-D d2\tDiff rev1/date1 against date2.\n",
|
||||
"\t-N\tinclude diffs for added and removed files.\n",
|
||||
"\t-r rev1\tDiff revision for rev1 against working file.\n",
|
||||
"\t-r rev2\tDiff rev1/date1 against rev2.\n",
|
||||
"\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",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* I copied this array directly out of diff.c in diffutils 2.7, after
|
||||
removing the following entries, none of which seem relevant to use
|
||||
with CVS:
|
||||
--help
|
||||
--version
|
||||
--recursive
|
||||
--unidirectional-new-file
|
||||
--starting-file
|
||||
--exclude
|
||||
--exclude-from
|
||||
--sdiff-merge-assist
|
||||
|
||||
I changed the options which take optional arguments (--context and
|
||||
--unified) to return a number rather than a letter, so that the
|
||||
optional argument could be handled more easily. I changed the
|
||||
--paginate and --brief options to return a number, since -l and -q
|
||||
mean something else to cvs diff.
|
||||
|
||||
The numbers 129- that appear in the fourth element of some entries
|
||||
tell the big switch in `diff' how to process those options. -- Ian
|
||||
|
||||
The following options, which diff lists as "An alias, no longer
|
||||
recommended" have been removed: --file-label --entire-new-file
|
||||
--ascii --print. */
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"ignore-blank-lines", 0, 0, 'B'},
|
||||
{"context", 2, 0, 143},
|
||||
{"ifdef", 1, 0, 147},
|
||||
{"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'},
|
||||
{"width", 1, 0, 'W'},
|
||||
{"text", 0, 0, 'a'},
|
||||
{"ignore-space-change", 0, 0, 'b'},
|
||||
{"minimal", 0, 0, 'd'},
|
||||
{"ed", 0, 0, 'e'},
|
||||
{"forward-ed", 0, 0, 'f'},
|
||||
{"ignore-case", 0, 0, 'i'},
|
||||
{"paginate", 0, 0, 144},
|
||||
{"rcs", 0, 0, 'n'},
|
||||
{"show-c-function", 0, 0, 'p'},
|
||||
|
||||
/* This is a potentially very useful option, except the output is so
|
||||
silly. It would be much better for it to look like "cvs rdiff -s"
|
||||
which displays all the same info, minus quite a few lines of
|
||||
extraneous garbage. */
|
||||
{"brief", 0, 0, 145},
|
||||
|
||||
{"report-identical-files", 0, 0, 's'},
|
||||
{"expand-tabs", 0, 0, 't'},
|
||||
{"ignore-all-space", 0, 0, 'w'},
|
||||
{"side-by-side", 0, 0, 'y'},
|
||||
{"unified", 2, 0, 146},
|
||||
{"left-column", 0, 0, 129},
|
||||
{"suppress-common-lines", 0, 0, 130},
|
||||
{"old-line-format", 1, 0, 132},
|
||||
{"new-line-format", 1, 0, 133},
|
||||
{"unchanged-line-format", 1, 0, 134},
|
||||
{"line-format", 1, 0, 135},
|
||||
{"old-group-format", 1, 0, 136},
|
||||
{"new-group-format", 1, 0, 137},
|
||||
{"unchanged-group-format", 1, 0, 138},
|
||||
{"changed-group-format", 1, 0, 139},
|
||||
{"horizon-lines", 1, 0, 140},
|
||||
{"binary", 0, 0, 142},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static void strcat_and_allocate PROTO ((char **, size_t *, const char *));
|
||||
|
||||
/* *STR is a pointer to a malloc'd string. *LENP is its allocated
|
||||
length. Add SRC to the end of it, reallocating if necessary. */
|
||||
static void
|
||||
strcat_and_allocate (str, lenp, src)
|
||||
char **str;
|
||||
size_t *lenp;
|
||||
const char *src;
|
||||
{
|
||||
size_t new_size;
|
||||
|
||||
new_size = strlen (*str) + strlen (src) + 1;
|
||||
if (*str == NULL || new_size >= *lenp)
|
||||
{
|
||||
while (new_size >= *lenp)
|
||||
*lenp *= 2;
|
||||
*str = xrealloc (*str, *lenp);
|
||||
}
|
||||
strcat (*str, src);
|
||||
}
|
||||
|
||||
int
|
||||
diff (argc, argv)
|
||||
int argc;
|
||||
@ -65,6 +178,7 @@ diff (argc, argv)
|
||||
int c, err = 0;
|
||||
int local = 0;
|
||||
int which;
|
||||
int option_index;
|
||||
|
||||
if (argc == -1)
|
||||
usage (diff_usage);
|
||||
@ -74,37 +188,56 @@ diff (argc, argv)
|
||||
* intercept the -r arguments for doing revision diffs; and -l/-R for a
|
||||
* non-recursive/recursive diff.
|
||||
*/
|
||||
#ifdef SERVER_SUPPORT
|
||||
/* Need to be able to do this command more than once (according to
|
||||
the protocol spec, even if the current client doesn't use it). */
|
||||
|
||||
/* For server, need to be able to do this command more than once
|
||||
(according to the protocol spec, even if the current client
|
||||
doesn't use it). */
|
||||
if (opts == NULL)
|
||||
{
|
||||
opts_allocated = 1;
|
||||
opts = xmalloc (opts_allocated);
|
||||
}
|
||||
opts[0] = '\0';
|
||||
#endif
|
||||
|
||||
optind = 1;
|
||||
while ((c = getopt (argc, argv,
|
||||
"abcdefhilnpqtuw0123456789BHNQRTC:D:F:I:L:V:k:r:")) != -1)
|
||||
while ((c = getopt_long (argc, argv,
|
||||
"+abcdefhilnpstuwy0123456789BHNRTC: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 't': 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 'Q':
|
||||
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 '3': case '4': case '5': case '6': case '7': case '8':
|
||||
case '9': case 'B': case 'H': case 'T':
|
||||
(void) sprintf (tmp, " -%c", (char) c);
|
||||
(void) strcat (opts, tmp);
|
||||
if (c == 'Q')
|
||||
{
|
||||
quiet = 1;
|
||||
really_quiet = 1;
|
||||
c = 'q';
|
||||
}
|
||||
strcat_and_allocate (&opts, &opts_allocated, tmp);
|
||||
break;
|
||||
case 'C': case 'F': case 'I': case 'L': case 'V':
|
||||
#ifndef CVS_DIFFDATE
|
||||
case 'D':
|
||||
#endif
|
||||
(void) sprintf (tmp, " -%c%s", (char) c, optarg);
|
||||
(void) strcat (opts, tmp);
|
||||
case 'C': case 'F': case 'I': case 'L': 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:
|
||||
/* --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 135: case 136: case 137: case 138: case 139: case 140:
|
||||
case 141: case 142: case 143: case 144: case 145: case 146:
|
||||
strcat_and_allocate (&opts, &opts_allocated, " --");
|
||||
strcat_and_allocate (&opts, &opts_allocated,
|
||||
longopts[option_index].name);
|
||||
if (longopts[option_index].has_arg == 1
|
||||
|| (longopts[option_index].has_arg == 2
|
||||
&& optarg != NULL))
|
||||
{
|
||||
strcat_and_allocate (&opts, &opts_allocated, "=");
|
||||
strcat_and_allocate (&opts, &opts_allocated, optarg);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
local = 0;
|
||||
@ -112,9 +245,6 @@ diff (argc, argv)
|
||||
case 'l':
|
||||
local = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'k':
|
||||
if (options)
|
||||
free (options);
|
||||
@ -129,7 +259,6 @@ diff (argc, argv)
|
||||
else
|
||||
diff_rev1 = optarg;
|
||||
break;
|
||||
#ifdef CVS_DIFFDATE
|
||||
case 'D':
|
||||
if (diff_rev2 != NULL || diff_date2 != NULL)
|
||||
error (1, 0,
|
||||
@ -139,7 +268,6 @@ diff (argc, argv)
|
||||
else
|
||||
diff_date1 = Make_Date (optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'N':
|
||||
empty_files = 1;
|
||||
break;
|
||||
@ -168,6 +296,8 @@ diff (argc, argv)
|
||||
if (empty_files)
|
||||
send_arg("-N");
|
||||
send_option_string (opts);
|
||||
if (options[0] != '\0')
|
||||
send_arg (options);
|
||||
if (diff_rev1)
|
||||
option_with_arg ("-r", diff_rev1);
|
||||
if (diff_date1)
|
||||
@ -178,15 +308,12 @@ diff (argc, argv)
|
||||
client_senddate (diff_date2);
|
||||
|
||||
send_file_names (argc, argv, SEND_EXPAND_WILD);
|
||||
#if 0
|
||||
/* FIXME: We shouldn't have to send current files to diff two
|
||||
revs, but it doesn't work yet and I haven't debugged it.
|
||||
So send the files -- it's slower but it works.
|
||||
gnu@cygnus.com Apr94 */
|
||||
|
||||
/* Send the current files unless diffing two revs from the archive */
|
||||
if (diff_rev2 == NULL && diff_date2 == NULL)
|
||||
#endif
|
||||
send_files (argc, argv, local, 0);
|
||||
send_files (argc, argv, local, 0, 0);
|
||||
else
|
||||
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
|
||||
|
||||
send_to_server ("diff\012", 0);
|
||||
err = get_responses_and_close ();
|
||||
@ -201,15 +328,15 @@ diff (argc, argv)
|
||||
tag_check_valid (diff_rev2, argc, argv, local, 0, "");
|
||||
|
||||
which = W_LOCAL;
|
||||
if (diff_rev2 != NULL || diff_date2 != NULL)
|
||||
if (diff_rev1 != NULL || diff_date1 != NULL)
|
||||
which |= W_REPOS | W_ATTIC;
|
||||
|
||||
wrap_setup ();
|
||||
|
||||
/* start the recursion processor */
|
||||
err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
|
||||
diff_dirleaveproc, argc, argv, local,
|
||||
which, 0, 1, (char *) NULL, 1, 0);
|
||||
diff_dirleaveproc, NULL, argc, argv, local,
|
||||
which, 0, 1, (char *) NULL, 1);
|
||||
|
||||
/* clean up */
|
||||
free (options);
|
||||
@ -221,26 +348,19 @@ diff (argc, argv)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
diff_fileproc (finfo)
|
||||
diff_fileproc (callerdat, finfo)
|
||||
void *callerdat;
|
||||
struct file_info *finfo;
|
||||
{
|
||||
int status, err = 2; /* 2 == trouble, like rcsdiff */
|
||||
Vers_TS *vers;
|
||||
enum {
|
||||
DIFF_ERROR,
|
||||
DIFF_ADDED,
|
||||
DIFF_REMOVED,
|
||||
DIFF_NEITHER
|
||||
} empty_file = DIFF_NEITHER;
|
||||
char tmp[L_tmpnam+1];
|
||||
enum diff_file empty_file = DIFF_DIFFERENT;
|
||||
char *tmp;
|
||||
char *tocvsPath;
|
||||
char fname[PATH_MAX];
|
||||
char *fname;
|
||||
|
||||
#ifdef SERVER_SUPPORT
|
||||
user_file_rev = 0;
|
||||
#endif
|
||||
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
|
||||
finfo->file, 1, 0, finfo->entries, finfo->rcs);
|
||||
vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
|
||||
|
||||
if (diff_rev2 != NULL || diff_date2 != NULL)
|
||||
{
|
||||
@ -249,10 +369,46 @@ diff_fileproc (finfo)
|
||||
}
|
||||
else if (vers->vn_user == NULL)
|
||||
{
|
||||
error (0, 0, "I know nothing about %s", finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
/* The file does not exist in the working directory. */
|
||||
if ((diff_rev1 != NULL || diff_date1 != NULL)
|
||||
&& vers->srcfile != NULL)
|
||||
{
|
||||
/* The file does exist in the repository. */
|
||||
if (empty_files)
|
||||
empty_file = DIFF_REMOVED;
|
||||
else
|
||||
{
|
||||
int exists;
|
||||
|
||||
exists = 0;
|
||||
/* special handling for TAG_HEAD */
|
||||
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
|
||||
exists = vers->vn_rcs != NULL;
|
||||
else
|
||||
{
|
||||
Vers_TS *xvers;
|
||||
|
||||
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
|
||||
1, 0);
|
||||
exists = xvers->vn_rcs != NULL;
|
||||
freevers_ts (&xvers);
|
||||
}
|
||||
if (exists)
|
||||
error (0, 0,
|
||||
"%s no longer exists, no comparison available",
|
||||
finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error (0, 0, "I know nothing about %s", finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
|
||||
{
|
||||
@ -299,7 +455,6 @@ diff_fileproc (finfo)
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
#ifdef SERVER_SUPPORT
|
||||
else if (!strcmp (vers->ts_user, vers->ts_rcs))
|
||||
{
|
||||
/* The user file matches some revision in the repository
|
||||
@ -307,18 +462,76 @@ diff_fileproc (finfo)
|
||||
have a copy of the user file around). */
|
||||
user_file_rev = vers->vn_user;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (empty_file == DIFF_NEITHER && diff_file_nodiff (finfo->file, finfo->repository, finfo->entries, finfo->rcs, vers))
|
||||
empty_file = diff_file_nodiff (finfo, vers, empty_file);
|
||||
if (empty_file == DIFF_SAME || empty_file == DIFF_ERROR)
|
||||
{
|
||||
freevers_ts (&vers);
|
||||
return (0);
|
||||
if (empty_file == DIFF_SAME)
|
||||
{
|
||||
/* In the server case, would be nice to send a "Checked-in"
|
||||
response, so that the client can rewrite its timestamp.
|
||||
server_checked_in by itself isn't the right thing (it
|
||||
needs a server_register), but I'm not sure what is.
|
||||
It isn't clear to me how "cvs status" handles this (that
|
||||
is, for a client which sends Modified not Is-modified to
|
||||
"cvs status"), but it does. */
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Check whether use_rev1 and use_rev2 are dead and deal
|
||||
accordingly. */
|
||||
if (empty_file == DIFF_DIFFERENT)
|
||||
{
|
||||
int dead1, dead2;
|
||||
|
||||
if (use_rev1 == NULL)
|
||||
dead1 = 0;
|
||||
else
|
||||
dead1 = RCS_isdead (vers->srcfile, use_rev1);
|
||||
if (use_rev2 == NULL)
|
||||
dead2 = 0;
|
||||
else
|
||||
dead2 = RCS_isdead (vers->srcfile, use_rev2);
|
||||
|
||||
if (dead1 && dead2)
|
||||
{
|
||||
freevers_ts (&vers);
|
||||
return (0);
|
||||
}
|
||||
else if (dead1)
|
||||
{
|
||||
if (empty_files)
|
||||
empty_file = DIFF_ADDED;
|
||||
else
|
||||
{
|
||||
error (0, 0, "%s is a new entry, no comparison available",
|
||||
finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
else if (dead2)
|
||||
{
|
||||
if (empty_files)
|
||||
empty_file = DIFF_REMOVED;
|
||||
else
|
||||
{
|
||||
error (0, 0, "%s was removed, no comparison available",
|
||||
finfo->fullname);
|
||||
freevers_ts (&vers);
|
||||
diff_mark_errors (err);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Output an "Index:" line for patch to use */
|
||||
(void) fflush (stdout);
|
||||
@ -329,10 +542,14 @@ diff_fileproc (finfo)
|
||||
if (tocvsPath)
|
||||
{
|
||||
/* Backup the current version of the file to CVS/,,filename */
|
||||
fname = xmalloc (strlen (finfo->file)
|
||||
+ sizeof CVSADM
|
||||
+ sizeof CVSPREFIX
|
||||
+ 10);
|
||||
sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, finfo->file);
|
||||
if (unlink_file_dir (fname) < 0)
|
||||
if (! existence_error (errno))
|
||||
error (1, errno, "cannot remove %s", finfo->file);
|
||||
error (1, errno, "cannot remove %s", fname);
|
||||
rename_file (finfo->file, fname);
|
||||
/* Copy the wrapped file to the current directory then go to work */
|
||||
copy_file (tocvsPath, finfo->file);
|
||||
@ -348,23 +565,44 @@ diff_fileproc (finfo)
|
||||
|
||||
if (empty_file == DIFF_ADDED)
|
||||
{
|
||||
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, finfo->file);
|
||||
if (use_rev2 == NULL)
|
||||
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, finfo->file);
|
||||
else
|
||||
{
|
||||
int retcode;
|
||||
|
||||
tmp = cvs_temp_name ();
|
||||
retcode = RCS_checkout (vers->srcfile, (char *) NULL,
|
||||
use_rev2, (char *) NULL,
|
||||
(*options
|
||||
? options
|
||||
: vers->options),
|
||||
tmp, (RCSCHECKOUTPROC) NULL,
|
||||
(void *) NULL);
|
||||
if (retcode == -1)
|
||||
{
|
||||
(void) CVS_UNLINK (tmp);
|
||||
error (1, errno, "fork failed during checkout of %s",
|
||||
vers->srcfile->path);
|
||||
}
|
||||
/* FIXME: what if retcode > 0? */
|
||||
|
||||
run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int retcode;
|
||||
|
||||
/*
|
||||
* FIXME: Should be setting use_rev1 using the logic in
|
||||
* diff_file_nodiff, and using that revision. This code
|
||||
* is broken for "cvs diff -N -r foo".
|
||||
*/
|
||||
retcode = RCS_checkout (vers->srcfile->path, NULL, vers->vn_rcs,
|
||||
*options ? options : vers->options, tmpnam (tmp),
|
||||
0, 0);
|
||||
tmp = cvs_temp_name ();
|
||||
retcode = RCS_checkout (vers->srcfile, (char *) NULL,
|
||||
use_rev1, (char *) NULL,
|
||||
*options ? options : vers->options,
|
||||
tmp, (RCSCHECKOUTPROC) NULL,
|
||||
(void *) NULL);
|
||||
if (retcode == -1)
|
||||
{
|
||||
(void) unlink (tmp);
|
||||
(void) CVS_UNLINK (tmp);
|
||||
error (1, errno, "fork failed during checkout of %s",
|
||||
vers->srcfile->path);
|
||||
}
|
||||
@ -409,13 +647,18 @@ diff_fileproc (finfo)
|
||||
if (! existence_error (errno))
|
||||
error (1, errno, "cannot remove %s", finfo->file);
|
||||
|
||||
rename_file (fname,finfo->file);
|
||||
rename_file (fname, finfo->file);
|
||||
if (unlink_file (tocvsPath) < 0)
|
||||
error (1, errno, "cannot remove %s", finfo->file);
|
||||
error (1, errno, "cannot remove %s", tocvsPath);
|
||||
free (fname);
|
||||
}
|
||||
|
||||
if (empty_file == DIFF_REMOVED)
|
||||
(void) unlink (tmp);
|
||||
if (empty_file == DIFF_REMOVED
|
||||
|| (empty_file == DIFF_ADDED && use_rev2 != NULL))
|
||||
{
|
||||
(void) CVS_UNLINK (tmp);
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
(void) fflush (stdout);
|
||||
freevers_ts (&vers);
|
||||
@ -441,10 +684,12 @@ diff_mark_errors (err)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static Dtype
|
||||
diff_dirproc (dir, pos_repos, update_dir)
|
||||
diff_dirproc (callerdat, dir, pos_repos, update_dir, entries)
|
||||
void *callerdat;
|
||||
char *dir;
|
||||
char *pos_repos;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
/* XXX - check for dirs we don't want to process??? */
|
||||
|
||||
@ -462,10 +707,12 @@ diff_dirproc (dir, pos_repos, update_dir)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
diff_filesdoneproc (err, repos, update_dir)
|
||||
diff_filesdoneproc (callerdat, err, repos, update_dir, entries)
|
||||
void *callerdat;
|
||||
int err;
|
||||
char *repos;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
return (diff_errors);
|
||||
}
|
||||
@ -475,27 +722,26 @@ diff_filesdoneproc (err, repos, update_dir)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
diff_dirleaveproc (dir, err, update_dir)
|
||||
diff_dirleaveproc (callerdat, dir, err, update_dir, entries)
|
||||
void *callerdat;
|
||||
char *dir;
|
||||
int err;
|
||||
char *update_dir;
|
||||
List *entries;
|
||||
{
|
||||
return (diff_errors);
|
||||
}
|
||||
|
||||
/*
|
||||
* verify that a file is different 0=same 1=different
|
||||
* verify that a file is different
|
||||
*/
|
||||
static int
|
||||
diff_file_nodiff (file, repository, entries, rcs, vers)
|
||||
char *file;
|
||||
char *repository;
|
||||
List *entries;
|
||||
RCSNode *rcs;
|
||||
static enum diff_file
|
||||
diff_file_nodiff (finfo, vers, empty_file)
|
||||
struct file_info *finfo;
|
||||
Vers_TS *vers;
|
||||
enum diff_file empty_file;
|
||||
{
|
||||
Vers_TS *xvers;
|
||||
char tmp[L_tmpnam+1];
|
||||
int retcode;
|
||||
|
||||
/* free up any old use_rev* variables and reset 'em */
|
||||
@ -512,23 +758,9 @@ diff_file_nodiff (file, repository, entries, rcs, vers)
|
||||
use_rev1 = xstrdup (vers->vn_rcs);
|
||||
else
|
||||
{
|
||||
xvers = Version_TS (repository, (char *) NULL, diff_rev1,
|
||||
diff_date1, file, 1, 0, entries, rcs);
|
||||
if (xvers->vn_rcs == NULL)
|
||||
{
|
||||
/* Don't gripe if it doesn't exist, just ignore! */
|
||||
if (! isfile (file))
|
||||
/* null statement */ ;
|
||||
else if (diff_rev1)
|
||||
error (0, 0, "tag %s is not in file %s", diff_rev1, file);
|
||||
else
|
||||
error (0, 0, "no revision for date %s in file %s",
|
||||
diff_date1, file);
|
||||
|
||||
freevers_ts (&xvers);
|
||||
return (1);
|
||||
}
|
||||
use_rev1 = xstrdup (xvers->vn_rcs);
|
||||
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
|
||||
if (xvers->vn_rcs != NULL)
|
||||
use_rev1 = xstrdup (xvers->vn_rcs);
|
||||
freevers_ts (&xvers);
|
||||
}
|
||||
}
|
||||
@ -539,36 +771,85 @@ diff_file_nodiff (file, repository, entries, rcs, vers)
|
||||
use_rev2 = xstrdup (vers->vn_rcs);
|
||||
else
|
||||
{
|
||||
xvers = Version_TS (repository, (char *) NULL, diff_rev2,
|
||||
diff_date2, file, 1, 0, entries, rcs);
|
||||
if (xvers->vn_rcs == NULL)
|
||||
{
|
||||
/* Don't gripe if it doesn't exist, just ignore! */
|
||||
if (! isfile (file))
|
||||
/* null statement */ ;
|
||||
else if (diff_rev1)
|
||||
error (0, 0, "tag %s is not in file %s", diff_rev2, file);
|
||||
else
|
||||
error (0, 0, "no revision for date %s in file %s",
|
||||
diff_date2, file);
|
||||
|
||||
freevers_ts (&xvers);
|
||||
return (1);
|
||||
}
|
||||
use_rev2 = xstrdup (xvers->vn_rcs);
|
||||
xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
|
||||
if (xvers->vn_rcs != NULL)
|
||||
use_rev2 = xstrdup (xvers->vn_rcs);
|
||||
freevers_ts (&xvers);
|
||||
}
|
||||
|
||||
if (use_rev1 == NULL)
|
||||
{
|
||||
/* The first revision does not exist. If EMPTY_FILES is
|
||||
true, treat this as an added file. Otherwise, warn
|
||||
about the missing tag. */
|
||||
if (use_rev2 == NULL)
|
||||
/* At least in the case where DIFF_REV1 and DIFF_REV2
|
||||
are both numeric, we should be returning some kind
|
||||
of error (see basicb-8a0 in testsuite). The symbolic
|
||||
case may be more complicated. */
|
||||
return DIFF_SAME;
|
||||
else if (empty_files)
|
||||
return DIFF_ADDED;
|
||||
else if (diff_rev1)
|
||||
error (0, 0, "tag %s is not in file %s", diff_rev1,
|
||||
finfo->fullname);
|
||||
else
|
||||
error (0, 0, "no revision for date %s in file %s",
|
||||
diff_date1, finfo->fullname);
|
||||
return DIFF_ERROR;
|
||||
}
|
||||
|
||||
if (use_rev2 == NULL)
|
||||
{
|
||||
/* The second revision does not exist. If EMPTY_FILES is
|
||||
true, treat this as a removed file. Otherwise warn
|
||||
about the missing tag. */
|
||||
if (empty_files)
|
||||
return DIFF_REMOVED;
|
||||
else if (diff_rev2)
|
||||
error (0, 0, "tag %s is not in file %s", diff_rev2,
|
||||
finfo->fullname);
|
||||
else
|
||||
error (0, 0, "no revision for date %s in file %s",
|
||||
diff_date2, finfo->fullname);
|
||||
return DIFF_ERROR;
|
||||
}
|
||||
|
||||
/* now, see if we really need to do the diff */
|
||||
if (use_rev1 && use_rev2) {
|
||||
return (strcmp (use_rev1, use_rev2) == 0);
|
||||
} else {
|
||||
error(0, 0, "No HEAD revision for file %s", file);
|
||||
return (1);
|
||||
if (strcmp (use_rev1, use_rev2) == 0)
|
||||
return DIFF_SAME;
|
||||
else
|
||||
return DIFF_DIFFERENT;
|
||||
}
|
||||
|
||||
if ((diff_rev1 || diff_date1) && use_rev1 == NULL)
|
||||
{
|
||||
/* The first revision does not exist, and no second revision
|
||||
was given. */
|
||||
if (empty_files)
|
||||
{
|
||||
if (empty_file == DIFF_REMOVED)
|
||||
return DIFF_SAME;
|
||||
else
|
||||
{
|
||||
if (user_file_rev && use_rev2 == NULL)
|
||||
use_rev2 = xstrdup (user_file_rev);
|
||||
return DIFF_ADDED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff_rev1)
|
||||
error (0, 0, "tag %s is not in file %s", diff_rev1,
|
||||
finfo->fullname);
|
||||
else
|
||||
error (0, 0, "no revision for date %s in file %s",
|
||||
diff_date1, finfo->fullname);
|
||||
return DIFF_ERROR;
|
||||
}
|
||||
}
|
||||
#ifdef SERVER_SUPPORT
|
||||
if (user_file_rev)
|
||||
|
||||
if (user_file_rev)
|
||||
{
|
||||
/* drop user_file_rev into first unused use_rev */
|
||||
if (!use_rev1)
|
||||
@ -582,42 +863,45 @@ diff_file_nodiff (file, repository, entries, rcs, vers)
|
||||
/* now, see if we really need to do the diff */
|
||||
if (use_rev1 && use_rev2)
|
||||
{
|
||||
return (strcmp (use_rev1, use_rev2) == 0);
|
||||
if (strcmp (use_rev1, use_rev2) == 0)
|
||||
return DIFF_SAME;
|
||||
else
|
||||
return DIFF_DIFFERENT;
|
||||
}
|
||||
#endif /* SERVER_SUPPORT */
|
||||
if (use_rev1 == NULL || strcmp (use_rev1, vers->vn_user) == 0)
|
||||
|
||||
if (use_rev1 == NULL
|
||||
|| (vers->vn_user != NULL && strcmp (use_rev1, vers->vn_user) == 0))
|
||||
{
|
||||
if (strcmp (vers->ts_rcs, vers->ts_user) == 0 &&
|
||||
(!(*options) || strcmp (options, vers->options) == 0))
|
||||
if (empty_file == DIFF_DIFFERENT
|
||||
&& vers->ts_user != NULL
|
||||
&& strcmp (vers->ts_rcs, vers->ts_user) == 0
|
||||
&& (!(*options) || strcmp (options, vers->options) == 0))
|
||||
{
|
||||
return (1);
|
||||
return DIFF_SAME;
|
||||
}
|
||||
if (use_rev1 == NULL
|
||||
&& (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0'))
|
||||
{
|
||||
if (vers->vn_user[0] == '-')
|
||||
use_rev1 = xstrdup (vers->vn_user + 1);
|
||||
else
|
||||
use_rev1 = xstrdup (vers->vn_user);
|
||||
}
|
||||
if (use_rev1 == NULL)
|
||||
use_rev1 = xstrdup (vers->vn_user);
|
||||
}
|
||||
|
||||
/* If we already know that the file is being added or removed,
|
||||
then we don't want to do an actual file comparison here. */
|
||||
if (empty_file != DIFF_DIFFERENT)
|
||||
return empty_file;
|
||||
|
||||
/*
|
||||
* with 0 or 1 -r option specified, run a quick diff to see if we
|
||||
* should bother with it at all.
|
||||
*/
|
||||
retcode = RCS_checkout (vers->srcfile->path, NULL, use_rev1,
|
||||
*options ? options : vers->options, tmpnam (tmp), 0, 0);
|
||||
switch (retcode)
|
||||
{
|
||||
case 0: /* everything ok */
|
||||
if (xcmp (file, tmp) == 0)
|
||||
{
|
||||
(void) unlink (tmp);
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
case -1: /* fork failed */
|
||||
(void) unlink (tmp);
|
||||
error (1, errno, "fork failed during checkout of %s",
|
||||
vers->srcfile->path);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
(void) unlink (tmp);
|
||||
return (0);
|
||||
|
||||
retcode = RCS_cmp_file (vers->srcfile, use_rev1,
|
||||
*options ? options : vers->options,
|
||||
finfo->file);
|
||||
|
||||
return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,14 @@
|
||||
|
||||
#include "cvs.h"
|
||||
#include "savecwd.h"
|
||||
#include "getline.h"
|
||||
|
||||
#ifndef DBLKSIZ
|
||||
#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
|
||||
#endif
|
||||
|
||||
static int checkout_file PROTO((char *file, char *temp));
|
||||
static void make_tempfile PROTO((char *temp));
|
||||
static char *make_tempfile PROTO((void));
|
||||
static void rename_rcsfile PROTO((char *temp, char *real));
|
||||
|
||||
#ifndef MY_NDBM
|
||||
@ -28,38 +29,50 @@ struct admin_file {
|
||||
|
||||
/* This is a one line description of what the file is for. It is not
|
||||
currently used, although one wonders whether it should be, somehow.
|
||||
If NULL, then don't process this file in mkmodules (FIXME: a bit of
|
||||
If NULL, then don't process this file in mkmodules (FIXME?: a bit of
|
||||
a kludge; probably should replace this with a flags field). */
|
||||
char *errormsg;
|
||||
|
||||
/* Contents which the file should have in a new repository. To avoid
|
||||
problems with brain-dead compilers which choke on long string constants,
|
||||
this is a pointer to an array of char * terminated by NULL--each of
|
||||
the strings is concatenated. */
|
||||
the strings is concatenated.
|
||||
|
||||
If this field is NULL, the file is not created in a new
|
||||
repository, but it can be added with "cvs add" (just as if one
|
||||
had created the repository with a version of CVS which didn't
|
||||
know about the file) and the checked-out copy will be updated
|
||||
without having to add it to checkoutlist. */
|
||||
const char * const *contents;
|
||||
};
|
||||
|
||||
static const char *const loginfo_contents[] = {
|
||||
"# The \"loginfo\" file is used to control where \"cvs commit\" log information\n",
|
||||
"# is sent. The first entry on a line is a regular expression which is tested\n",
|
||||
"# against the directory that the change is being made to, relative to the\n",
|
||||
"# $CVSROOT. For the first match that is found, then the remainder of the\n",
|
||||
"# line is a filter program that should expect log information on its standard\n",
|
||||
"# input.\n",
|
||||
"# The \"loginfo\" file controls where \"cvs commit\" log information\n",
|
||||
"# is sent. The first entry on a line is a regular expression which must match\n",
|
||||
"# the directory that the change is being made to, relative to the\n",
|
||||
"# $CVSROOT. If a match is found, then the remainder of the line is a filter\n",
|
||||
"# program that should expect log information on its standard input.\n",
|
||||
"#\n",
|
||||
"# If the repository name does not match any of the regular expressions in the\n",
|
||||
"# first field of this file, the \"DEFAULT\" line is used, if it is specified.\n",
|
||||
"# If the repository name does not match any of the regular expressions in this\n",
|
||||
"# file, the \"DEFAULT\" line is used, if it is specified.\n",
|
||||
"#\n",
|
||||
"# If the name \"ALL\" appears as a regular expression it is always used\n",
|
||||
"# in addition to the first matching regex or \"DEFAULT\".\n",
|
||||
"# If the name ALL appears as a regular expression it is always used\n",
|
||||
"# in addition to the first matching regex or DEFAULT.\n",
|
||||
"#\n",
|
||||
"# The filter program may use one and only one \"%s\" modifier (ala printf). If\n",
|
||||
"# such a \"%s\" is specified in the filter program, a brief title is included\n",
|
||||
"# (as one argument, enclosed in single quotes) showing the relative directory\n",
|
||||
"# name and listing the modified file names.\n",
|
||||
"# You may specify a format string as part of the\n",
|
||||
"# filter. The string is composed of a `%' followed\n",
|
||||
"# by a single format character, or followed by a set of format\n",
|
||||
"# characters surrounded by `{' and `}' as separators. The format\n",
|
||||
"# characters are:\n",
|
||||
"#\n",
|
||||
"# s = file name\n",
|
||||
"# V = old version number (pre-checkin)\n",
|
||||
"# v = new version number (post-checkin)\n",
|
||||
"#\n",
|
||||
"# For example:\n",
|
||||
"#DEFAULT (echo \"\"; who am i; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
|
||||
"#DEFAULT (echo \"\"; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
|
||||
"# or\n",
|
||||
"#DEFAULT (echo \"\"; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -99,8 +112,33 @@ static const char *const editinfo_contents[] = {
|
||||
"# Actions such as mailing a copy of the report to each reviewer are\n",
|
||||
"# better handled by an entry in the loginfo file.\n",
|
||||
"#\n",
|
||||
"# One thing that should be noted is the the ALL keyword is not\n",
|
||||
"# supported. There can be only one entry that matches a given\n",
|
||||
"# One thing that should be noted is the the ALL keyword is not\n",
|
||||
"# supported. There can be only one entry that matches a given\n",
|
||||
"# repository.\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const verifymsg_contents[] = {
|
||||
"# The \"verifymsg\" file is used to allow verification of logging\n",
|
||||
"# information. It works best when a template (as specified in the\n",
|
||||
"# rcsinfo file) is provided for the logging procedure. Given a\n",
|
||||
"# template with locations for, a bug-id number, a list of people who\n",
|
||||
"# reviewed the code before it can be checked in, and an external\n",
|
||||
"# process to catalog the differences that were code reviewed, the\n",
|
||||
"# following test can be applied to the code:\n",
|
||||
"#\n",
|
||||
"# Making sure that the entered bug-id number is correct.\n",
|
||||
"# Validating that the code that was reviewed is indeed the code being\n",
|
||||
"# checked in (using the bug-id number or a seperate review\n",
|
||||
"# number to identify this particular code set.).\n",
|
||||
"#\n",
|
||||
"# If any of the above test failed, then the commit would be aborted.\n",
|
||||
"#\n",
|
||||
"# Actions such as mailing a copy of the report to each reviewer are\n",
|
||||
"# better handled by an entry in the loginfo file.\n",
|
||||
"#\n",
|
||||
"# One thing that should be noted is the the ALL keyword is not\n",
|
||||
"# supported. There can be only one entry that matches a given\n",
|
||||
"# repository.\n",
|
||||
NULL
|
||||
};
|
||||
@ -222,6 +260,9 @@ static const char *const modules_contents[] = {
|
||||
"# -d dir Place module in directory \"dir\" instead of module name.\n",
|
||||
"# -l Top-level directory only -- do not recurse.\n",
|
||||
"#\n",
|
||||
"# NOTE: If you change any of the \"Run\" options above, you'll have to\n",
|
||||
"# release and re-checkout any working directories of these modules.\n",
|
||||
"#\n",
|
||||
"# And \"directory\" is a path to a directory relative to $CVSROOT.\n",
|
||||
"#\n",
|
||||
"# The \"-a\" option specifies an alias. An alias is interpreted as if\n",
|
||||
@ -244,6 +285,9 @@ static const struct admin_file filelist[] = {
|
||||
{CVSROOTADM_EDITINFO,
|
||||
"a %s file can be used to validate log messages",
|
||||
editinfo_contents},
|
||||
{CVSROOTADM_VERIFYMSG,
|
||||
"a %s file can be used to validate log messages",
|
||||
verifymsg_contents},
|
||||
{CVSROOTADM_COMMITINFO,
|
||||
"a %s file can be used to configure 'cvs commit' checking",
|
||||
commitinfo_contents},
|
||||
@ -266,6 +310,20 @@ static const struct admin_file filelist[] = {
|
||||
/* modules is special-cased in mkmodules. */
|
||||
NULL,
|
||||
modules_contents},
|
||||
{CVSROOTADM_READERS,
|
||||
"a %s file specifies read-only users",
|
||||
NULL},
|
||||
{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. */
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -275,27 +333,26 @@ mkmodules (dir)
|
||||
char *dir;
|
||||
{
|
||||
struct saved_cwd cwd;
|
||||
/* FIXME: arbitrary limit */
|
||||
char temp[PATH_MAX];
|
||||
char *temp;
|
||||
char *cp, *last, *fname;
|
||||
#ifdef MY_NDBM
|
||||
DBM *db;
|
||||
#endif
|
||||
FILE *fp;
|
||||
/* FIXME: arbitrary limit */
|
||||
char line[512];
|
||||
char *line = NULL;
|
||||
size_t line_allocated = 0;
|
||||
const struct admin_file *fileptr;
|
||||
|
||||
if (save_cwd (&cwd))
|
||||
exit (EXIT_FAILURE);
|
||||
error_exit ();
|
||||
|
||||
if (chdir (dir) < 0)
|
||||
if ( CVS_CHDIR (dir) < 0)
|
||||
error (1, errno, "cannot chdir to %s", dir);
|
||||
|
||||
/*
|
||||
* First, do the work necessary to update the "modules" database.
|
||||
*/
|
||||
make_tempfile (temp);
|
||||
temp = make_tempfile ();
|
||||
switch (checkout_file (CVSROOTADM_MODULES, temp))
|
||||
{
|
||||
|
||||
@ -313,7 +370,7 @@ mkmodules (dir)
|
||||
|
||||
case -1: /* fork failed */
|
||||
(void) unlink_file (temp);
|
||||
exit (EXIT_FAILURE);
|
||||
error (1, errno, "cannot check out %s", CVSROOTADM_MODULES);
|
||||
/* NOTREACHED */
|
||||
|
||||
default:
|
||||
@ -324,12 +381,13 @@ mkmodules (dir)
|
||||
} /* switch on checkout_file() */
|
||||
|
||||
(void) unlink_file (temp);
|
||||
free (temp);
|
||||
|
||||
/* Checkout the files that need it in CVSROOT dir */
|
||||
for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
|
||||
if (fileptr->errormsg == NULL)
|
||||
continue;
|
||||
make_tempfile (temp);
|
||||
temp = make_tempfile ();
|
||||
if (checkout_file (fileptr->filename, temp) == 0)
|
||||
rename_rcsfile (temp, fileptr->filename);
|
||||
#if 0
|
||||
@ -344,10 +402,10 @@ mkmodules (dir)
|
||||
error (0, 0, fileptr->errormsg, fileptr->filename);
|
||||
#endif
|
||||
(void) unlink_file (temp);
|
||||
free (temp);
|
||||
}
|
||||
|
||||
/* Use 'fopen' instead of 'open_file' because we want to ignore error */
|
||||
fp = fopen (CVSROOTADM_CHECKOUTLIST, "r");
|
||||
fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r");
|
||||
if (fp)
|
||||
{
|
||||
/*
|
||||
@ -356,7 +414,7 @@ mkmodules (dir)
|
||||
*
|
||||
* comment lines begin with '#'
|
||||
*/
|
||||
while (fgets (line, sizeof (line), fp) != NULL)
|
||||
while (getline (&line, &line_allocated, fp) >= 0)
|
||||
{
|
||||
/* skip lines starting with # */
|
||||
if (line[0] == '#')
|
||||
@ -374,7 +432,7 @@ mkmodules (dir)
|
||||
;
|
||||
*cp = '\0';
|
||||
|
||||
make_tempfile (temp);
|
||||
temp = make_tempfile ();
|
||||
if (checkout_file (fname, temp) == 0)
|
||||
{
|
||||
rename_rcsfile (temp, fname);
|
||||
@ -386,12 +444,24 @@ mkmodules (dir)
|
||||
if (cp < last && *cp)
|
||||
error (0, 0, cp, fname);
|
||||
}
|
||||
free (temp);
|
||||
}
|
||||
(void) fclose (fp);
|
||||
if (line)
|
||||
free (line);
|
||||
if (ferror (fp))
|
||||
error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST);
|
||||
if (fclose (fp) < 0)
|
||||
error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error from CVS_FOPEN. */
|
||||
if (!existence_error (errno))
|
||||
error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST);
|
||||
}
|
||||
|
||||
if (restore_cwd (&cwd, NULL))
|
||||
exit (EXIT_FAILURE);
|
||||
error_exit ();
|
||||
free_cwd (&cwd);
|
||||
|
||||
return (0);
|
||||
@ -400,25 +470,27 @@ mkmodules (dir)
|
||||
/*
|
||||
* Yeah, I know, there are NFS race conditions here.
|
||||
*/
|
||||
static void
|
||||
make_tempfile (temp)
|
||||
char *temp;
|
||||
static char *
|
||||
make_tempfile ()
|
||||
{
|
||||
static int seed = 0;
|
||||
int fd;
|
||||
char *temp;
|
||||
|
||||
if (seed == 0)
|
||||
seed = getpid ();
|
||||
temp = xmalloc (sizeof (BAKPREFIX) + 40);
|
||||
while (1)
|
||||
{
|
||||
(void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
|
||||
if ((fd = open (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
|
||||
if ((fd = CVS_OPEN (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
|
||||
break;
|
||||
if (errno != EEXIST)
|
||||
error (1, errno, "cannot create temporary file %s", temp);
|
||||
}
|
||||
if (close(fd) < 0)
|
||||
error(1, errno, "cannot close temporary file %s", temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -426,18 +498,31 @@ checkout_file (file, temp)
|
||||
char *file;
|
||||
char *temp;
|
||||
{
|
||||
char rcs[PATH_MAX];
|
||||
char *rcs;
|
||||
RCSNode *rcsnode;
|
||||
int retcode = 0;
|
||||
|
||||
(void) sprintf (rcs, "%s%s", file, RCSEXT);
|
||||
if (noexec)
|
||||
return 0;
|
||||
|
||||
rcs = xmalloc (strlen (file) + 5);
|
||||
strcpy (rcs, file);
|
||||
strcat (rcs, RCSEXT);
|
||||
if (!isfile (rcs))
|
||||
return (1);
|
||||
run_setup ("%s%s -x,v/ -q -p", Rcsbin, RCS_CO);
|
||||
run_arg (rcs);
|
||||
if ((retcode = run_exec (RUN_TTY, temp, RUN_TTY, RUN_NORMAL)) != 0)
|
||||
{
|
||||
error (0, retcode == -1 ? errno : 0, "failed to check out %s file", file);
|
||||
free (rcs);
|
||||
return (1);
|
||||
}
|
||||
rcsnode = RCS_parsercsfile (rcs);
|
||||
retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp,
|
||||
(RCSCHECKOUTPROC) NULL, (void *) NULL);
|
||||
if (retcode != 0)
|
||||
{
|
||||
error (0, retcode == -1 ? errno : 0, "failed to check out %s file",
|
||||
file);
|
||||
}
|
||||
freercsnode (&rcsnode);
|
||||
free (rcs);
|
||||
return (retcode);
|
||||
}
|
||||
|
||||
@ -568,12 +653,12 @@ rename_dbmfile (temp)
|
||||
(void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
|
||||
(void) unlink_file (bakpag);
|
||||
(void) unlink_file (bakdb);
|
||||
(void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */
|
||||
(void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */
|
||||
(void) rename (dotdb, bakdb); /* mv modules.db .#modules.db */
|
||||
(void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */
|
||||
(void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */
|
||||
(void) rename (newdb, dotdb); /* mv "temp".db modules.db */
|
||||
(void) CVS_RENAME (dotdir, bakdir); /* mv modules.dir .#modules.dir */
|
||||
(void) CVS_RENAME (dotpag, bakpag); /* mv modules.pag .#modules.pag */
|
||||
(void) CVS_RENAME (dotdb, bakdb); /* mv modules.db .#modules.db */
|
||||
(void) CVS_RENAME (newdir, dotdir); /* mv "temp".dir modules.dir */
|
||||
(void) CVS_RENAME (newpag, dotpag); /* mv "temp".pag modules.pag */
|
||||
(void) CVS_RENAME (newdb, dotdb); /* mv "temp".db modules.db */
|
||||
|
||||
/* OK -- make my day */
|
||||
SIG_endCrSect ();
|
||||
@ -586,21 +671,25 @@ rename_rcsfile (temp, real)
|
||||
char *temp;
|
||||
char *real;
|
||||
{
|
||||
char bak[50];
|
||||
char *bak;
|
||||
struct stat statbuf;
|
||||
char rcs[PATH_MAX];
|
||||
|
||||
char *rcs;
|
||||
|
||||
/* Set "x" bits if set in original. */
|
||||
rcs = xmalloc (strlen (real) + sizeof (RCSEXT) + 10);
|
||||
(void) sprintf (rcs, "%s%s", real, RCSEXT);
|
||||
statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
|
||||
(void) stat (rcs, &statbuf);
|
||||
(void) CVS_STAT (rcs, &statbuf);
|
||||
free (rcs);
|
||||
|
||||
if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
|
||||
error (0, errno, "warning: cannot chmod %s", temp);
|
||||
bak = xmalloc (strlen (real) + sizeof (BAKPREFIX) + 10);
|
||||
(void) sprintf (bak, "%s%s", BAKPREFIX, real);
|
||||
(void) unlink_file (bak); /* rm .#loginfo */
|
||||
(void) rename (real, bak); /* mv loginfo .#loginfo */
|
||||
(void) rename (temp, real); /* mv "temp" loginfo */
|
||||
(void) CVS_RENAME (real, bak); /* mv loginfo .#loginfo */
|
||||
(void) CVS_RENAME (temp, real); /* mv "temp" loginfo */
|
||||
free (bak);
|
||||
}
|
||||
|
||||
const char *const init_usage[] = {
|
||||
@ -608,26 +697,6 @@ const char *const init_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Create directory NAME if it does not already exist; fatal error for
|
||||
other errors. FIXME: This should be in filesubr.c or thereabouts,
|
||||
probably. Perhaps it should be further abstracted, though (for example
|
||||
to handle CVSUMASK where appropriate?). */
|
||||
static void
|
||||
mkdir_if_needed (name)
|
||||
char *name;
|
||||
{
|
||||
if (CVS_MKDIR (name, 0777) < 0)
|
||||
{
|
||||
if (errno != EEXIST
|
||||
#ifdef EACCESS
|
||||
/* OS/2; see longer comment in client.c. */
|
||||
&& errno != EACCESS
|
||||
#endif
|
||||
)
|
||||
error (1, errno, "cannot mkdir %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
init (argc, argv)
|
||||
int argc;
|
||||
@ -647,6 +716,7 @@ init (argc, argv)
|
||||
if (argc == -1 || argc > 1)
|
||||
usage (init_usage);
|
||||
|
||||
#ifdef CLIENT_SUPPORT
|
||||
if (client_active)
|
||||
{
|
||||
start_server ();
|
||||
@ -655,21 +725,22 @@ init (argc, argv)
|
||||
send_init_command ();
|
||||
return get_responses_and_close ();
|
||||
}
|
||||
#endif /* CLIENT_SUPPORT */
|
||||
|
||||
/* Note: we do *not* create parent directories as needed like the
|
||||
old cvsinit.sh script did. Few utilities do that, and a
|
||||
non-existent parent directory is as likely to be a typo as something
|
||||
which needs to be created. */
|
||||
mkdir_if_needed (CVSroot);
|
||||
mkdir_if_needed (CVSroot_directory);
|
||||
|
||||
adm = xmalloc (strlen (CVSroot) + sizeof (CVSROOTADM) + 10);
|
||||
strcpy (adm, CVSroot);
|
||||
adm = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + 10);
|
||||
strcpy (adm, CVSroot_directory);
|
||||
strcat (adm, "/");
|
||||
strcat (adm, CVSROOTADM);
|
||||
mkdir_if_needed (adm);
|
||||
|
||||
/* This is needed by the call to "ci" below. */
|
||||
if (chdir (adm) < 0)
|
||||
if ( CVS_CHDIR (adm) < 0)
|
||||
error (1, errno, "cannot change to directory %s", adm);
|
||||
|
||||
/* 80 is long enough for all the administrative file names, plus
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user