summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r--contrib/cvs/src/NOTES60
-rw-r--r--contrib/cvs/src/README-rm-add31
-rw-r--r--contrib/cvs/src/commit.c186
-rw-r--r--contrib/cvs/src/cvs.h16
-rw-r--r--contrib/cvs/src/diff.c22
-rw-r--r--contrib/cvs/src/filesubr.c44
-rw-r--r--contrib/cvs/src/import.c34
-rw-r--r--contrib/cvs/src/lock.c7
-rw-r--r--contrib/cvs/src/login.c10
-rw-r--r--contrib/cvs/src/logmsg.c67
-rw-r--r--contrib/cvs/src/main.c136
-rw-r--r--contrib/cvs/src/mkmodules.c5
-rw-r--r--contrib/cvs/src/rcs.c1231
-rw-r--r--contrib/cvs/src/rcs.h12
-rw-r--r--contrib/cvs/src/rcscmds.c116
-rw-r--r--contrib/cvs/src/recurse.c52
-rw-r--r--contrib/cvs/src/server.c119
-rw-r--r--contrib/cvs/src/update.c84
18 files changed, 735 insertions, 1497 deletions
diff --git a/contrib/cvs/src/NOTES b/contrib/cvs/src/NOTES
deleted file mode 100644
index 646ebdf..0000000
--- a/contrib/cvs/src/NOTES
+++ /dev/null
@@ -1,60 +0,0 @@
-wishlist - Tue Nov 2 15:22:58 PST 1993
-
-* bcopy -> memcpy & friends.
- ** done 12/18/93
-
-* remove static buffers.
-* replace list & node cache with recursive obstacks, (xmalloc,
- getnode, getlist)
-* check all io functions for error return codes. also check all
- system calls.
-* error check mkdir.
-
----
-Old notes...
-
-* All sizing limits are gone. The rest of these items were incidental
- in that effort.
-
-* login name from history was duplicated. taught existing routine to
- cache and use that instead. Also add routines to cache uid, pid,
- etc.
-
-* ign strings were never freed. Now they are.
-
-* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now
- fixed.
-
-* The environment variables TMPDIR, HOME, and LOGNAME were not
- honored. Now they are.
-
-* extra line inserted by do_editor() is gone. Then obviated. Editor
- is now called exactly once per checkin.
-
-* revised editor behaviour. Never use /dev/tty. If the editor
- session fails, we haven't yet done anything. Therefor the user can
- safely rerun cvs and we should just fail. Also use the editor for
- initial log messages on added files. Also omit the confirmation
- when adding directories. Adding directories will require an
- explicit "commit" step soon. Make it possible to prevent null login
- messages using #define REQUIRE_LOG_MESSAGES
-
-* prototypes for all callbacks.
-
-* all callbacks get ref pointers.
-
-* do_recursion/start_recursion now use recusion_frame's rather than a
- list of a lot of pointers and global variables.
-
-* corrected types on status_dirproc().
-
-* CONFIRM_DIRECTORY_ADDS
-
-* re_comp was innappropriate in a few places. I've eliminated it.
-
-* FORCE_MESSAGE_ON_ADD
-
-* So I built a regression test. Let's call it a sanity check to be
- less ambitious. It exposed that cvs is difficult to call from
- scripts.
-
diff --git a/contrib/cvs/src/README-rm-add b/contrib/cvs/src/README-rm-add
deleted file mode 100644
index 87fd7c6..0000000
--- a/contrib/cvs/src/README-rm-add
+++ /dev/null
@@ -1,31 +0,0 @@
-WHAT THE "DEATH SUPPORT" FEATURES DO:
-
-(Some of the death support stuff is documented in the main manual, but
-this file is for stuff which noone has gotten around to adding to the
-main manual yet).
-
-CVS with death support can record when a file is active, or alive, and
-when it is removed, or dead. With this facility you can record the
-history of a file, including the fact that at some point in its life
-the file was removed and then later added.
-
-Files can now be added or removed in a branch and later merged
-into the trunk.
-
- cvs update -A
- touch a b c
- cvs add a b c ; cvs ci -m "added" a b c
- cvs tag -b branchtag
- cvs update -r branchtag
- touch d ; cvs add d
- rm a ; cvs rm a
- cvs ci -m "added d, removed a"
- cvs update -A
- cvs update -jbranchtag
-
-Added and removed files may also be merged between branches.
-
-Files removed in the trunk may be merged into branches.
-
-Files added on the trunk are a special case. They cannot be merged
-into a branch. Instead, simply branch the file by hand.
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 75d2e5ae..4488e2a 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -1,17 +1,17 @@
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
- *
+ *
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS source distribution.
- *
+ *
* Commit Files
- *
+ *
* "commit" commits the present version to the RCS repository, AFTER
* having done a test on conflicts.
*
* The call is: cvs commit [options] files...
- *
+ *
*/
#include <assert.h>
@@ -29,7 +29,7 @@ static int check_filesdoneproc PROTO ((void *callerdat, int err,
char *repos, char *update_dir,
List *entries));
static int checkaddfile PROTO((char *file, char *repository, char *tag,
- char *options, RCSNode **rcsnode));
+ char *options, RCSNode **rcsnode));
static Dtype commit_direntproc PROTO ((void *callerdat, char *dir,
char *repos, char *update_dir,
List *entries));
@@ -74,13 +74,12 @@ static int force_ci = 0;
static int got_message;
static int run_module_prog = 1;
static int aflag;
-static char *saved_tag;
+static char *tag;
static char *write_dirtag;
static int write_dirnonbranch;
static char *logfile;
static List *mulist;
-static List *saved_ulist;
-static char *saved_message;
+static char *message;
static time_t last_register_time;
static const char *const commit_usage[] =
@@ -248,7 +247,7 @@ find_fileproc (callerdat, finfo)
xfinfo.repository = NULL;
xfinfo.rcs = NULL;
- vers = Version_TS (&xfinfo, NULL, saved_tag, 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] == '-')
@@ -365,18 +364,18 @@ commit (argc, argv)
#else
use_editor = 0;
#endif
- if (saved_message)
+ if (message)
{
- free (saved_message);
- saved_message = NULL;
+ free (message);
+ message = NULL;
}
- saved_message = xstrdup(optarg);
+ message = xstrdup(optarg);
break;
case 'r':
- if (saved_tag)
- free (saved_tag);
- saved_tag = xstrdup (optarg);
+ if (tag)
+ free (tag);
+ tag = xstrdup (optarg);
break;
case 'l':
local = 1;
@@ -406,12 +405,12 @@ commit (argc, argv)
argv += optind;
/* numeric specified revision means we ignore sticky tags... */
- if (saved_tag && isdigit (*saved_tag))
+ if (tag && isdigit (*tag))
{
aflag = 1;
/* strip trailing dots */
- while (saved_tag[strlen (saved_tag) - 1] == '.')
- saved_tag[strlen (saved_tag) - 1] = '\0';
+ while (tag[strlen (tag) - 1] == '.')
+ tag[strlen (tag) - 1] = '\0';
}
/* some checks related to the "-F logfile" option */
@@ -420,7 +419,7 @@ commit (argc, argv)
int n, logfd;
struct stat statbuf;
- if (saved_message)
+ if (message)
error (1, 0, "cannot specify both a message and a log file");
/* FIXME: Why is this binary? Needs more investigation. */
@@ -430,20 +429,21 @@ commit (argc, argv)
if (fstat(logfd, &statbuf) < 0)
error (1, errno, "cannot find size of log file %s", logfile);
- saved_message = xmalloc (statbuf.st_size + 1);
+ message = xmalloc (statbuf.st_size + 1);
/* FIXME: Should keep reading until EOF, rather than assuming the
first read gets the whole thing. */
- if ((n = read (logfd, saved_message, statbuf.st_size + 1)) < 0)
+ if ((n = read (logfd, message, statbuf.st_size + 1)) < 0)
error (1, errno, "cannot read log message from %s", logfile);
(void) close (logfd);
- saved_message[n] = '\0';
+ message[n] = '\0';
}
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (client_active)
{
+ int err;
struct find_data find_args;
ign_setup ();
@@ -458,7 +458,7 @@ commit (argc, argv)
I haven't really thought about it much.
Anyway, I suspect that setting it unnecessarily only causes
a little unneeded network traffic. */
- find_args.force = force_ci || saved_tag != NULL;
+ find_args.force = force_ci || tag != NULL;
err = start_recursion (find_fileproc, find_filesdoneproc,
find_dirent_proc, (DIRLEAVEPROC) NULL,
@@ -500,17 +500,17 @@ commit (argc, argv)
* The protocol is designed this way. This is a feature.
*/
if (use_editor)
- do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
+ do_editor (".", &message, (char *)NULL, find_args.ulist);
/* Run the user-defined script to verify/check information in
*the log message
*/
- do_verify (saved_message, (char *)NULL);
+ 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", saved_message);
+ option_with_arg ("-m", message);
/* OK, now process all the questionable files we have been saving
up. */
@@ -559,7 +559,7 @@ commit (argc, argv)
send_arg("-f");
if (!run_module_prog)
send_arg("-n");
- option_with_arg ("-r", saved_tag);
+ option_with_arg ("-r", tag);
/* Sending only the names of the files which were modified, added,
or removed means that the server will only do an up-to-date
@@ -582,7 +582,7 @@ commit (argc, argv)
send_to_server ("ci\012", 0);
err = get_responses_and_close ();
- if (err != 0 && use_editor && saved_message != NULL)
+ 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
@@ -600,8 +600,7 @@ commit (argc, argv)
fp = CVS_FOPEN (fname, "w+");
if (fp == NULL)
error (1, 0, "cannot create temporary file %s", fname);
- if (fwrite (saved_message, 1, strlen (saved_message), fp)
- != strlen (saved_message))
+ 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);
@@ -611,12 +610,12 @@ commit (argc, argv)
}
#endif
- if (saved_tag != NULL)
- tag_check_valid (saved_tag, argc, argv, local, aflag, "");
+ if (tag != NULL)
+ tag_check_valid (tag, argc, argv, local, aflag, "");
/* XXX - this is not the perfect check for this */
if (argc <= 0)
- write_dirtag = saved_tag;
+ write_dirtag = tag;
wrap_setup ();
@@ -652,6 +651,17 @@ commit (argc, argv)
error (1, 0, "correct above errors first!");
}
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms)
+ {
+ /* hardlist now includes a complete index of the files
+ to be committed, indexed by inode. For each inode,
+ compile a list of the files that are linked to it,
+ and save this list in each file's hardlink_info node. */
+ (void) walklist (hardlist, cache_hardlinks_proc, NULL);
+ }
+#endif
+
/*
* Run the recursion processor to commit the files
*/
@@ -673,7 +683,7 @@ commit (argc, argv)
time_t now;
(void) time (&now);
- if (now == last_register_time)
+ if (now == last_register_time)
{
sleep (1); /* to avoid time-stamp races */
}
@@ -703,10 +713,10 @@ classify_file_internal (finfo, vers)
noexec = quiet = really_quiet = 1;
/* handle specified numeric revision specially */
- if (saved_tag && isdigit (*saved_tag))
+ if (tag && isdigit (*tag))
{
/* If the tag is for the trunk, make sure we're at the head */
- if (numdots (saved_tag) < 2)
+ if (numdots (tag) < 2)
{
status = Classify_File (finfo, (char *) NULL, (char *) NULL,
(char *) NULL, 1, aflag, vers, 0);
@@ -716,7 +726,7 @@ classify_file_internal (finfo, vers)
Ctype xstatus;
freevers_ts (vers);
- xstatus = Classify_File (finfo, saved_tag, (char *) NULL,
+ xstatus = Classify_File (finfo, tag, (char *) NULL,
(char *) NULL, 1, aflag, vers, 0);
if (xstatus == T_REMOVE_ENTRY)
status = T_MODIFIED;
@@ -734,7 +744,7 @@ classify_file_internal (finfo, vers)
* The revision is off the main trunk; make sure we're
* up-to-date with the head of the specified branch.
*/
- xtag = xstrdup (saved_tag);
+ xtag = xstrdup (tag);
if ((numdots (xtag) & 1) != 0)
{
cp = strrchr (xtag, '.');
@@ -755,12 +765,12 @@ classify_file_internal (finfo, vers)
}
/* now, muck with vers to make the tag correct */
free ((*vers)->tag);
- (*vers)->tag = xstrdup (saved_tag);
+ (*vers)->tag = xstrdup (tag);
free (xtag);
}
}
else
- status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
+ status = Classify_File (finfo, tag, (char *) NULL, (char *) NULL,
1, 0, vers, 0);
noexec = save_noexec;
quiet = save_quiet;
@@ -786,7 +796,7 @@ check_fileproc (callerdat, finfo)
Vers_TS *vers;
struct commit_info *ci;
struct logfile_info *li;
-
+
status = classify_file_internal (finfo, &vers);
/*
@@ -825,7 +835,7 @@ check_fileproc (callerdat, finfo)
* allow the commit if timestamp is identical or if we find
* an RCS_MERGE_PAT in the file.
*/
- if (!saved_tag || !isdigit (*saved_tag))
+ if (!tag || !isdigit (*tag))
{
if (vers->date)
{
@@ -1037,6 +1047,7 @@ warning: file `%s' seems to still contain conflict indicators",
hlinfo = (struct hardlink_info *)
xmalloc (sizeof (struct hardlink_info));
hlinfo->status = status;
+ hlinfo->links = NULL;
linkp->data = (char *) hlinfo;
}
}
@@ -1103,6 +1114,7 @@ precommit_list_proc (p, closure)
/*
* Callback proc for pre-commit checking
*/
+static List *ulist;
static int
precommit_proc (repository, filter)
char *repository;
@@ -1112,7 +1124,7 @@ precommit_proc (repository, filter)
if (isabsolute (filter))
{
char *s, *cp;
-
+
s = xstrdup (filter);
for (cp = s; *cp; cp++)
if (isspace (*cp))
@@ -1131,7 +1143,7 @@ precommit_proc (repository, filter)
run_setup (filter);
run_arg (repository);
- (void) walklist (saved_ulist, precommit_list_proc, NULL);
+ (void) walklist (ulist, precommit_list_proc, NULL);
return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
}
@@ -1153,12 +1165,12 @@ check_filesdoneproc (callerdat, err, repos, update_dir, entries)
/* find the update list for this dir */
p = findnode (mulist, update_dir);
if (p != NULL)
- saved_ulist = ((struct master_lists *) p->data)->ulist;
+ ulist = ((struct master_lists *) p->data)->ulist;
else
- saved_ulist = (List *) NULL;
+ ulist = (List *) NULL;
/* skip the checks if there's nothing to do */
- if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
+ if (ulist == NULL || ulist->list->next == ulist->list)
return (err);
/* run any pre-commit checks */
@@ -1226,9 +1238,8 @@ commit_fileproc (callerdat, finfo)
{
got_message = 1;
if (use_editor)
- do_editor (finfo->update_dir, &saved_message,
- finfo->repository, ulist);
- do_verify (saved_message, finfo->repository);
+ do_editor (finfo->update_dir, &message, finfo->repository, ulist);
+ do_verify (&message, finfo->repository);
}
p = findnode (cilist, finfo->file);
@@ -1268,7 +1279,7 @@ commit_fileproc (callerdat, finfo)
error (1, 0, "internal error: no parsed RCS file");
ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
- ci->tag, ci->options, saved_message);
+ ci->tag, ci->options, message);
if (err != 0)
{
unlockrcs (finfo->rcs);
@@ -1308,7 +1319,7 @@ commit_fileproc (callerdat, finfo)
{
err = Checkin ('M', finfo,
finfo->rcs->path, ci->rev, ci->tag,
- ci->options, saved_message);
+ ci->options, message);
(void) time (&last_register_time);
@@ -1320,7 +1331,7 @@ commit_fileproc (callerdat, finfo)
}
else if (ci->status == T_REMOVED)
{
- err = remove_file (finfo, ci->tag, saved_message);
+ err = remove_file (finfo, ci->tag, message);
#ifdef SERVER_SUPPORT
if (server_active) {
server_scratch_entry_only ();
@@ -1360,7 +1371,7 @@ out:
been removed from the archive, which is not the behavior we
want for our commitlog messages; we want the old version
number and then "NONE." */
-
+
if (ci->status != T_REMOVED)
{
p = findnode (ulist, finfo->file);
@@ -1368,7 +1379,7 @@ out:
{
Vers_TS *vers;
struct logfile_info *li;
-
+
(void) classify_file_internal (finfo, &vers);
li = (struct logfile_info *) p->data;
li->rev_new = xstrdup (vers->vn_rcs);
@@ -1404,7 +1415,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
got_message = 0;
- Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
+ Update_Logfile (repository, message, (FILE *) 0, ulist);
/* Build the administrative files if necessary. */
{
@@ -1412,17 +1423,11 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
if (strncmp (CVSroot_directory, repository,
strlen (CVSroot_directory)) != 0)
- error (0, 0,
- "internal error: repository (%s) doesn't begin with root (%s)",
- repository, CVSroot_directory);
+ error (0, 0, "internal error: repository (%s) doesn't begin with root (%s)", repository, CVSroot_directory);
p = repository + strlen (CVSroot_directory);
if (*p == '/')
++p;
- if (strcmp ("CVSROOT", p) == 0
- /* Check for subdirectories because people may want to create
- subdirectories and list files therein in checkoutlist. */
- || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
- )
+ if (strcmp ("CVSROOT", p) == 0)
{
/* "Database" might a little bit grandiose and/or vague,
but "checked-out copies of administrative files, unless
@@ -1430,21 +1435,11 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
case modules.{pag,dir,db}" is verbose and excessively
focused on how the database is implemented. */
- /* mkmodules requires the absolute name of the CVSROOT directory.
- Remove anything after the `CVSROOT' component -- this is
- necessary when committing in a subdirectory of CVSROOT. */
- char *admin_dir = xstrdup (repository);
- int cvsrootlen = strlen ("CVSROOT");
- assert (admin_dir[p - repository + cvsrootlen] == '\0'
- || admin_dir[p - repository + cvsrootlen] == '/');
- admin_dir[p - repository + cvsrootlen] = '\0';
-
cvs_output (program_name, 0);
cvs_output (" ", 1);
cvs_output (command_name, 0);
cvs_output (": Rebuilding administrative file database\n", 0);
- mkmodules (admin_dir);
- free (admin_dir);
+ mkmodules (repository);
}
}
@@ -1457,7 +1452,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
char *line;
int line_length;
size_t line_chars_allocated;
- char *repos;
+ char *repository;
line = NULL;
line_chars_allocated = 0;
@@ -1467,9 +1462,9 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
/* Remove any trailing newline. */
if (line[line_length - 1] == '\n')
line[--line_length] = '\0';
- repos = Name_Repository ((char *) NULL, update_dir);
+ repository = Name_Repository ((char *) NULL, update_dir);
run_setup (line);
- run_arg (repos);
+ run_arg (repository);
cvs_output (program_name, 0);
cvs_output (" ", 1);
cvs_output (command_name, 0);
@@ -1477,7 +1472,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
run_print (stdout);
cvs_output ("'\n", 0);
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
- free (repos);
+ free (repository);
}
else
{
@@ -1534,8 +1529,8 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
real_repos = Name_Repository (dir, update_dir);
got_message = 1;
if (use_editor)
- do_editor (update_dir, &saved_message, real_repos, ulist);
- do_verify (saved_message, real_repos);
+ do_editor (update_dir, &message, real_repos, ulist);
+ do_verify (&message, real_repos);
free (real_repos);
return (R_PROCESS);
}
@@ -1627,7 +1622,7 @@ remove_file (finfo, tag, message)
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)) != 0)
+ if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
@@ -1660,7 +1655,7 @@ remove_file (finfo, tag, message)
error (0, 0, "cannot find branch \"%s\".", tag);
return (1);
}
-
+
branchname = RCS_getbranch (finfo->rcs, rev, 1);
if (branchname == NULL)
{
@@ -1681,12 +1676,12 @@ remove_file (finfo, tag, message)
/* Get current head revision of file. */
prev_rev = RCS_head (finfo->rcs);
}
-
+
/* if removing without a tag or a branch, then make sure the default
branch is the trunk. */
if (!tag && !branch)
{
- if (RCS_setbranch (finfo->rcs, NULL) != 0)
+ if (RCS_setbranch (finfo->rcs, NULL) != 0)
{
error (0, 0, "cannot change branch to default for %s",
finfo->fullname);
@@ -1745,7 +1740,7 @@ remove_file (finfo, tag, message)
if (!branch)
{
/* this was the head; really move it into the Attic */
- tmp = xmalloc(strlen(finfo->repository) +
+ tmp = xmalloc(strlen(finfo->repository) +
sizeof('/') +
sizeof(CVSATTIC) +
sizeof('/') +
@@ -1755,9 +1750,8 @@ remove_file (finfo, tag, message)
omask = umask (cvsumask);
(void) CVS_MKDIR (tmp, 0777);
(void) umask (omask);
- (void) sprintf (tmp, "%s/%s/%s%s", finfo->repository, CVSATTIC,
- finfo->file, RCSEXT);
-
+ (void) sprintf (tmp, "%s/%s/%s%s", finfo->repository, CVSATTIC, finfo->file, RCSEXT);
+
if (strcmp (finfo->rcs->path, tmp) != 0
&& CVS_RENAME (finfo->rcs->path, tmp) == -1
&& (isreadable (finfo->rcs->path) || !isreadable (tmp)))
@@ -1800,7 +1794,7 @@ finaladd (finfo, rev, tag, options)
char *rcs;
rcs = locate_rcs (finfo->file, finfo->repository);
- ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message);
+ ret = Checkin ('A', finfo, rcs, rev, tag, options, message);
if (ret == 0)
{
char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
@@ -1937,7 +1931,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
Attic. */
oldfile = xstrdup (rcs);
sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
-
+
if (strcmp (oldfile, rcs) == 0)
{
error (0, 0, "internal error: confused about attic for %s",
@@ -2134,6 +2128,8 @@ internal error: `%s' didn't move out of the attic",
char *head;
char *magicrev;
+ fixbranch(rcsfile, sbranch);
+
head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
magicrev = RCS_magicrev (rcsfile, head);
@@ -2160,7 +2156,7 @@ internal error: `%s' didn't move out of the attic",
retval = 1;
goto out;
}
- }
+ }
if (rcsnode && *rcsnode != rcsfile)
{
@@ -2206,7 +2202,7 @@ lock_RCS (user, rcs, rev, repository)
* For a specified, numeric revision of the form "1" or "1.1", (or when
* no revision is specified ""), definitely move the branch to the trunk
* before locking the RCS file.
- *
+ *
* The assumption is that if there is more than one revision on the trunk,
* the head points to the trunk, not a branch... and as such, it's not
* necessary to move the head in this case.
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index f8b1552..b194d16 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -187,6 +187,7 @@ extern int errno;
#define CVSROOTADM_WRITERS "writers"
#define CVSROOTADM_PASSWD "passwd"
#define CVSROOTADM_CONFIG "config"
+#define CVSROOTADM_OPTIONS "options"
#define CVSNULLREPOS "Emptydir" /* an empty directory */
@@ -256,6 +257,8 @@ extern int errno;
#define CVSREAD_ENV "CVSREAD" /* make files read-only */
#define CVSREAD_DFLT 0 /* writable files by default */
+#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */
+
#define TMPDIR_ENV "TMPDIR" /* Temporary directory */
/* #define TMPDIR_DFLT Set by options.h */
@@ -363,6 +366,7 @@ extern int really_quiet, quiet;
extern int use_editor;
extern int cvswrite;
extern mode_t cvsumask;
+extern char *RCS_citag;
/* Access method specified in CVSroot. */
typedef enum {
@@ -383,9 +387,9 @@ 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 */
extern int logoff; /* Don't write history entry */
-
-extern int top_level_admin;
+extern int require_real_user; /* skip CVSROOT/passwd, /etc/passwd users only*/
#ifdef AUTH_SERVER_SUPPORT
extern char *Pserver_Repos; /* used to check that same repos is
@@ -431,8 +435,6 @@ 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 *date_from_time_t PROTO ((time_t));
-
char *Name_Repository PROTO((char *dir, char *update_dir));
char *Short_Repository PROTO((char *repository));
void Sanitize_Repository_Name PROTO((char *repository));
@@ -475,11 +477,13 @@ char *xreadlink PROTO((const char *link));
char *last_component PROTO((char *path));
char *get_homedir PROTO ((void));
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));
int update PROTO((int argc, char *argv[]));
int xcmp PROTO((const char *file1, const char *file2));
@@ -561,7 +565,7 @@ void Update_Logfile PROTO((char *repository, char *xmessage, FILE * xlogfp,
void do_editor PROTO((char *dir, char **messagep,
char *repository, List * changes));
-void do_verify PROTO((char *message, char *repository));
+void do_verify PROTO((char **messagep, char *repository));
typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten, int local_specified,
@@ -837,7 +841,7 @@ extern int patch PROTO((int argc, char **argv));
extern int release PROTO((int argc, char **argv));
extern int cvsremove PROTO((int argc, char **argv));
extern int rtag PROTO((int argc, char **argv));
-extern int cvsstatus PROTO((int argc, char **argv));
+extern int status PROTO((int argc, char **argv));
extern int cvstag PROTO((int argc, char **argv));
extern unsigned long int lookup_command_attribute PROTO((char *));
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c
index 341c04c..66d155e 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -434,22 +434,16 @@ diff_fileproc (callerdat, finfo)
exists = 0;
/* special handling for TAG_HEAD */
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
- {
- char *head =
- (vers->vn_rcs == NULL
- ? NULL
- : RCS_branch_head (vers->srcfile, vers->vn_rcs));
- exists = head != NULL;
- if (head != NULL)
- free (head);
- }
+ exists = (vers->vn_rcs != NULL && /* XXX ? */
+ !RCS_isdead (vers->srcfile, vers->vn_rcs)); /*XXX*/
else
{
Vers_TS *xvers;
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
1, 0);
- exists = xvers->vn_rcs != NULL;
+ exists = (vers->vn_rcs != NULL &&
+ !RCS_isdead (vers->srcfile, vers->vn_rcs)); /*XXX*/
freevers_ts (&xvers);
}
if (exists)
@@ -822,9 +816,7 @@ diff_file_nodiff (finfo, vers, empty_file)
{
/* special handling for TAG_HEAD */
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
- use_rev1 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
- ? NULL
- : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ use_rev1 = xstrdup (vers->vn_rcs);
else
{
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
@@ -837,9 +829,7 @@ diff_file_nodiff (finfo, vers, empty_file)
{
/* special handling for TAG_HEAD */
if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
- use_rev2 = ((vers->vn_rcs == NULL || vers->srcfile == NULL)
- ? NULL
- : RCS_branch_head (vers->srcfile, vers->vn_rcs));
+ use_rev2 = xstrdup (vers->vn_rcs);
else
{
xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
index 1c24b2f..c85fe60 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -415,6 +415,29 @@ rename_file (from, to)
}
/*
+ * link a file, if possible. Warning: the Windows NT version of this
+ * function just copies the file, so only use this function in ways
+ * that can deal with either a link or a copy.
+ */
+int
+link_file (from, to)
+ const char *from;
+ const char *to;
+{
+ if (trace)
+#ifdef SERVER_SUPPORT
+ (void) fprintf (stderr, "%c-> link(%s,%s)\n",
+ (server_active) ? 'S' : ' ', from, to);
+#else
+ (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
+#endif
+ if (noexec)
+ return (0);
+
+ return (link (from, to));
+}
+
+/*
* unlink a file, if possible.
*/
int
@@ -747,9 +770,8 @@ xreadlink (link)
const char *link;
{
char *file = NULL;
- char *tfile;
- int buflen = 128;
- int link_name_len;
+ int buflen = BUFSIZ;
+ int linklen;
if (!islink (link))
return NULL;
@@ -760,23 +782,21 @@ xreadlink (link)
do
{
file = xrealloc (file, buflen);
- link_name_len = readlink (link, file, buflen - 1);
+ errno = 0;
+ linklen = readlink (link, file, buflen - 1);
buflen *= 2;
}
- while (link_name_len < 0 && errno == ENAMETOOLONG);
+ while (linklen == -1 && errno == ENAMETOOLONG);
- if (link_name_len < 0)
+ if (linklen == -1)
error (1, errno, "cannot readlink %s", link);
+ file[linklen] = '\0';
- file[link_name_len] = '\0';
-
- tfile = xstrdup (file);
- free (file);
-
- return tfile;
+ return file;
}
+
/* Return a pointer into PATH's last component. */
char *
last_component (path)
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 77c617a..18cd482 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -20,6 +20,8 @@
#include "savecwd.h"
#include <assert.h>
+#define FILE_HOLDER ".#cvsxxx"
+
static char *get_comment PROTO((char *user));
static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,
char *vers));
@@ -192,7 +194,7 @@ import (argc, argv)
do_editor ((char *) NULL, &message, repository,
(List *) NULL);
}
- do_verify (message, repository);
+ do_verify (&message, repository);
msglen = message == NULL ? 0 : strlen (message);
if (msglen == 0 || message[msglen - 1] != '\n')
{
@@ -653,15 +655,39 @@ add_rev (message, rcs, vfile, vers)
RCS_rewrite (rcs, NULL, NULL);
}
tocvsPath = wrap_tocvs_process_file (vfile);
+ if (tocvsPath == NULL)
+ {
+ /* We play with hard links rather than passing -u to ci to avoid
+ expanding RCS keywords (see test 106.5 in sanity.sh). */
+ if (link_file (vfile, FILE_HOLDER) < 0)
+ {
+ if (errno == EEXIST)
+ {
+ (void) unlink_file (FILE_HOLDER);
+ (void) link_file (vfile, FILE_HOLDER);
+ }
+ else
+ {
+ ierrno = errno;
+ fperror (logfp, 0, ierrno,
+ "ERROR: cannot create link to %s", vfile);
+ error (0, ierrno, "ERROR: cannot create link to %s", vfile);
+ return (1);
+ }
+ }
+ }
status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
message, vbranch,
- (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
+ (RCS_FLAGS_QUIET
| (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
ierrno = errno;
- if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
- error (0, errno, "cannot remove %s", tocvsPath);
+ if (tocvsPath == NULL)
+ rename_file (FILE_HOLDER, vfile);
+ else
+ if (unlink_file_dir (tocvsPath) < 0)
+ error (0, errno, "cannot remove %s", tocvsPath);
if (status)
{
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 72818f3..1f2ccad 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -243,7 +243,7 @@ Reader_Lock (xrepository)
FILE *fp;
char *tmp;
- if (noexec)
+ if (noexec || readonlyfs)
return (0);
/* we only do one directory at a time for read locks! */
@@ -319,6 +319,11 @@ Writer_Lock (list)
if (noexec)
return (0);
+ if (readonlyfs) {
+ error (0, 0, "write lock failed - read-only repository");
+ return (1);
+ }
+
/* We only know how to do one list at a time */
if (locklist != (List *) NULL)
{
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
index 4ffce36..0a74f37 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -293,6 +293,9 @@ get_cvs_password ()
FILE *fp;
char *passfile;
int line_length;
+ int anoncvs;
+
+ anoncvs = (strcmp(CVSroot_username, "anoncvs") == 0);
/* If someone (i.e., login()) is calling connect_to_pserver() out of
context, then assume they have supplied the correct, scrambled
@@ -333,6 +336,10 @@ get_cvs_password ()
fp = CVS_FOPEN (passfile, "r");
if (fp == NULL)
{
+ if (anoncvs) {
+ free (passfile);
+ return strdup("Ay=0=h<Z"); /* scrambled "anoncvs" */
+ }
error (0, errno, "could not open %s", passfile);
free (passfile);
error (1, 0, "use \"cvs login\" to log in first");
@@ -354,6 +361,7 @@ get_cvs_password ()
error (0, errno, "cannot read %s", passfile);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", passfile);
+ free (passfile);
if (found_it)
{
@@ -373,6 +381,8 @@ get_cvs_password ()
{
if (linebuf)
free (linebuf);
+ if (anoncvs)
+ return strdup("Ay=0=h<Z"); /* scrambled "anoncvs" */
error (0, 0, "cannot find password");
error (1, 0, "use \"cvs login\" to log in first");
}
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index 67194be..6807937 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -385,14 +385,20 @@ do_editor (dir, messagep, repository, changes)
independant of the running of an editor for getting a message.
*/
void
-do_verify (message, repository)
- char *message;
+do_verify (messagep, repository)
+ char **messagep;
char *repository;
{
FILE *fp;
char *fname;
int retcode = 0;
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char *p;
+ struct stat stbuf;
+
#ifdef CLIENT_SUPPORT
if (client_active)
/* The verification will happen on the server. */
@@ -406,7 +412,7 @@ do_verify (message, repository)
/* If there's no message, then we have nothing to verify. Can this
case happen? And if so why would we print a message? */
- if (message == NULL)
+ if (*messagep == NULL)
{
cvs_output ("No message to verify\n", 0);
return;
@@ -422,9 +428,9 @@ do_verify (message, repository)
error (1, errno, "cannot create temporary file %s", fname);
else
{
- fprintf (fp, "%s", message);
- if ((message)[0] == '\0' ||
- (message)[strlen (message) - 1] != '\n')
+ fprintf (fp, "%s", *messagep);
+ if ((*messagep)[0] == '\0' ||
+ (*messagep)[strlen (*messagep) - 1] != '\n')
(void) fprintf (fp, "%s", "\n");
if (fclose (fp) == EOF)
error (1, errno, "%s", fname);
@@ -453,6 +459,55 @@ do_verify (message, repository)
}
}
+ /* put the entire message back into the *messagep variable */
+
+ fp = open_file (fname, "r");
+ if (fp == NULL)
+ {
+ error (1, errno, "cannot open temporary file %s", fname);
+ return;
+ }
+
+ if (*messagep)
+ free (*messagep);
+
+ if ( CVS_STAT (fname, &stbuf) != 0)
+ error (1, errno, "cannot find size of temp file %s", fname);
+
+ if (stbuf.st_size == 0)
+ *messagep = NULL;
+ else
+ {
+ /* On NT, we might read less than st_size bytes, but we won't
+ read more. So this works. */
+ *messagep = (char *) xmalloc (stbuf.st_size + 1);
+ *messagep[0] = '\0';
+ }
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if (*messagep)
+ {
+ p = *messagep;
+ while (1)
+ {
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length == -1)
+ {
+ if (ferror (fp))
+ error (0, errno, "warning: cannot read %s", fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
+ continue;
+ (void) strcpy (p, line);
+ p += line_length;
+ }
+ }
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", fname);
+
/* Delete the temp file */
unlink_file (fname);
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index 68513df..9cb7bc0 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -40,13 +40,9 @@ int really_quiet = 0;
int quiet = 0;
int trace = 0;
int noexec = 0;
+int readonlyfs = 0;
+int require_real_user = 0;
int logoff = 0;
-
-/* Set if we should be writing CVSADM directories at top level. At
- least for now we'll make the default be off (the CVS 1.9, not CVS
- 1.9.2, behavior). */
-int top_level_admin = 0;
-
mode_t cvsumask = UMASK_DFLT;
char *CurDir;
@@ -114,7 +110,7 @@ static const struct cmd
{ "rdiff", "patch", "pa", patch },
{ "release", "re", "rel", release },
{ "remove", "rm", "delete", cvsremove },
- { "status", "st", "stat", cvsstatus },
+ { "status", "st", "stat", status },
{ "rtag", "rt", "rfreeze", rtag },
{ "tag", "ta", "freeze", cvstag },
{ "unedit", NULL, NULL, unedit },
@@ -215,9 +211,11 @@ static const char *const opt_usage[] =
" -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",
+ " -g Force group-write perms on checked-out files.\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",
@@ -287,10 +285,6 @@ lookup_command_attribute (cmd_name)
}
- /* The following commands do not use a checked-out working
- directory. We conservatively assume that everything else does.
- Feel free to add to this list if you are _certain_ something
- something doesn't use the WD. */
if ((strcmp (cmd_name, "checkout") != 0) &&
(strcmp (cmd_name, "init") != 0) &&
(strcmp (cmd_name, "login") != 0) &&
@@ -306,10 +300,8 @@ lookup_command_attribute (cmd_name)
/* The following commands do not modify the repository; we
conservatively assume that everything else does. Feel free to
add to this list if you are _certain_ something is safe. */
- if ((strcmp (cmd_name, "annotate") != 0) &&
- (strcmp (cmd_name, "checkout") != 0) &&
+ if ((strcmp (cmd_name, "checkout") != 0) &&
(strcmp (cmd_name, "diff") != 0) &&
- (strcmp (cmd_name, "rdiff") != 0) &&
(strcmp (cmd_name, "update") != 0) &&
(strcmp (cmd_name, "history") != 0) &&
(strcmp (cmd_name, "editors") != 0) &&
@@ -456,6 +448,10 @@ main (argc, argv)
}
if (getenv (CVSREAD_ENV) != NULL)
cvswrite = 0;
+ if (getenv (CVSREADONLYFS_ENV) != NULL) {
+ readonlyfs = 1;
+ logoff = 1;
+ }
/* Set this to 0 to force getopt initialization. getopt() sets
this to 1 internally. */
@@ -485,7 +481,7 @@ main (argc, argv)
opterr = 1;
while ((c = getopt_long
- (argc, argv, "+Qqrwtnlvb:T:e:d:Hfz:s:xa", long_options, &option_index))
+ (argc, argv, "+QqgrwtnRlvb:T:e:d:Hfz:s:xaU", long_options, &option_index))
!= EOF)
{
switch (c)
@@ -518,9 +514,20 @@ main (argc, argv)
case 'w':
cvswrite = 1;
break;
+ case 'g':
+ /*
+ * force full group write perms (used for shared checked-out
+ * source trees, see manual page)
+ */
+ umask(umask(077) & 007);
+ break;
case 't':
trace = 1;
break;
+ case 'R':
+ readonlyfs = 1;
+ logoff = 1;
+ break;
case 'n':
noexec = 1;
case 'l': /* Fall through */
@@ -604,6 +611,11 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
We will issue an error later if stream
authentication is not supported. */
break;
+ case 'U':
+#ifdef SERVER_SUPPORT
+ require_real_user = 1;
+#endif
+ break;
case '?':
default:
usage (usg);
@@ -823,7 +835,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
- if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
{
save_errno = errno;
error (0, 0, "Sorry, you don't have read/write access to the history file");
@@ -875,6 +887,12 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
(void) putenv (env);
/* do not free env, as putenv has control of it */
}
+ {
+ char *env;
+ env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */
+ (void) sprintf (env, "CVS_PID=%ld", (long) getpid ());
+ (void) putenv (env);
+ }
#endif
#ifndef DONT_USE_SIGNALS
@@ -935,6 +953,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
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);
+
+ /* Now is a convenient time to read CVSROOT/options */
+ parseopts(CVSroot_directory);
}
} /* end of stuff that gets done if the user DOESN'T ask for help */
@@ -979,37 +1000,20 @@ char *
Make_Date (rawdate)
char *rawdate;
{
+ struct tm *ftm;
time_t unixtime;
+ char date[MAXDATELEN];
+ char *ret;
unixtime = get_date (rawdate, (struct timeb *) NULL);
if (unixtime == (time_t) - 1)
error (1, 0, "Can't parse date/time: %s", rawdate);
- return date_from_time_t (unixtime);
-}
-
-/* Convert a time_t to an RCS format date. This is mainly for the
- use of "cvs history", because the CVSROOT/history file contains
- time_t format dates; most parts of CVS will want to avoid using
- time_t's directly, and instead use RCS_datecmp, Make_Date, &c.
- Assuming that the time_t is in GMT (as it generally should be),
- then the result will be in GMT too.
-
- Returns a newly malloc'd string. */
-
-char *
-date_from_time_t (unixtime)
- time_t unixtime;
-{
- struct tm *ftm;
- char date[MAXDATELEN];
- char *ret;
ftm = gmtime (&unixtime);
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 (get_date of course being the relevant
- issue for Make_Date, and for history.c too I think). */
+ hack I added to get_date. */
ftm = localtime (&unixtime);
(void) sprintf (date, DATEFORM,
@@ -1029,3 +1033,61 @@ usage (cpp)
(void) fprintf (stderr, *cpp);
error_exit ();
}
+
+void
+parseopts(root)
+ const char *root;
+{
+ char path[PATH_MAX];
+ int save_errno;
+ char buf[1024];
+ const char *p;
+ char *q;
+ FILE *fp;
+
+ if (root == NULL) {
+ printf("no CVSROOT in parseopts\n");
+ return;
+ }
+ p = strchr (root, ':');
+ if (p)
+ p++;
+ else
+ p = root;
+ if (p == NULL) {
+ printf("mangled CVSROOT in parseopts\n");
+ return;
+ }
+ (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
+ if ((fp = fopen(path, "r")) != NULL) {
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ if (buf[0] == '#')
+ continue;
+ q = strrchr(buf, '\n');
+ if (q)
+ *q = '\0';
+
+ if (!strncmp(buf, "tag=", 4)) {
+ char *what;
+ char *rcs_localid;
+
+ rcs_localid = buf + 4;
+ RCS_setlocalid(rcs_localid);
+ }
+ if (!strncmp(buf, "tagexpand=", 10)) {
+ char *what;
+ char *rcs_incexc;
+
+ rcs_incexc = buf + 10;
+ RCS_setincexc(rcs_incexc);
+ }
+ /*
+ * OpenBSD has a "umask=" and "dlimit=" command, we silently
+ * ignore them here since they are not much use to us. cvsumask
+ * defaults to 002 already, and the dlimit (data size limit)
+ * should really be handled elsewhere (eg: login.conf).
+ */
+ }
+ fclose(fp);
+ }
+}
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index e716222..c3c530d 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -283,11 +283,6 @@ static const char *const config_contents[] = {
"# Set `PreservePermissions' to `yes' to save file status information\n",
"# in the repository.\n",
"#PreservePermissions=no\n",
- "\n",
- "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n",
- "# level of the new working directory when using the `cvs checkout'\n",
- "# command.\n",
- "#TopLevelAdmin=no\n",
NULL
};
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 951736e..735502a 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -81,9 +81,6 @@ static void free_rcsnode_contents PROTO((RCSNode *));
static void free_rcsvers_contents PROTO((RCSVers *));
static void rcsvers_delproc PROTO((Node * p));
static char *translate_symtag PROTO((RCSNode *, const char *));
-static char *RCS_addbranch PROTO ((RCSNode *, const char *));
-static char *truncate_revnum_in_place PROTO ((char *));
-static char *truncate_revnum PROTO ((const char *));
static char *printable_date PROTO((const char *));
static char *escape_keyword_value PROTO ((const char *, int *));
static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
@@ -124,6 +121,8 @@ static char *rcs_lockfilename PROTO ((char *));
evaluates its arguments multiple times. */
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
+static char * getfullCVSname PROTO ((char *, char **));
+
/*
* We don't want to use isspace() from the C library because:
*
@@ -566,9 +565,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
key, rcsfile);
free (rdata->desc);
}
- /* Don't need to rcsbuf_valcopy `value' because
- getdelta already did that. */
- rdata->desc = xstrdup (value);
+ rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
}
rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
@@ -804,9 +801,6 @@ free_rcsnode_contents (rnode)
/* free_rcsvers_contents -- free up the contents of an RCSVers node,
but also free the pointer to the node itself. */
-/* Note: The `hardlinks' list is *not* freed, since it is merely a
- pointer into the `hardlist' structure (defined in hardlink.c), and
- that structure is freed elsewhere in the program. */
static void
free_rcsvers_contents (rnode)
@@ -1289,480 +1283,6 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
#undef my_whitespace
}
-/* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid,
- rcsbuf_getstring, rcsbuf_getword. These last three functions were
- all created by hacking monstrous swaths of code from rcsbuf_getkey,
- and some engineering would make the code easier to read and
- maintain.
-
- Note that the extreme hair in rcsbuf_getkey is because profiling
- statistics show that it was worth it.
-
- We probably could be processing "hardlinks" by first calling
- rcsbuf_getkey, and breaking up the value afterwards; the code to
- break it up would not need to be hacked for speed. This would
- remove the need for rcsbuf_getword, rcsbuf_getid, and
- rcsbuf_getstring, as the other calls are easy to remove. */
-
-/* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in
- IDP. */
-
-static int
-rcsbuf_getid (rcsbuf, idp)
- struct rcsbuffer *rcsbuf;
- char **idp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- return 0;
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* We've found the start of the key. */
-
- *idp = ptr;
-
- if (c != ';')
- {
- while (1)
- {
- ++ptr;
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "EOF in key in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- c = *ptr;
- if (c == ';' || my_whitespace (c))
- break;
- }
- }
-
- /* Here *IDP points to the id in the buffer, C is the character
- we found at the end of the key, and PTR points to the location in
- the buffer where we found C. We may not set *PTR to \0, because
- it may overwrite a terminating semicolon. The calling function
- must copy and terminate the id on its own. */
-
- rcsbuf->ptr = ptr;
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS @-delimited string. Store the result in STRP. */
-
-static int
-rcsbuf_getstring (rcsbuf, strp)
- struct rcsbuffer *rcsbuf;
- char **strp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char *pat;
- size_t vlen;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* PTR should now point to the start of a string. */
- if (c != '@')
- error (1, 0, "expected @-string at `%c' in %s", c, rcsbuf->filename);
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *strp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, strp);
- if (pat == NULL)
- {
- /* EOF here is OK; it just means that the last
- character of the file was an '@' terminating a
- value for a key type which does not require a
- trailing ';'. */
- pat = rcsbuf->ptrend - 1;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *strp;
- if (vlen == 0)
- *strp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a
- @-delimited string, or `:'). Store the result in WORDP. If a
- `;' is reached without reading any text, the result is NULL. */
-
-static int
-rcsbuf_getword (rcsbuf, wordp)
- struct rcsbuffer *rcsbuf;
- char **wordp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* If we have reached `;', there is no value. */
- if (c == ';')
- {
- *wordp = NULL;
- *ptr++ = '\0';
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 0;
- return 1;
- }
-
- /* PTR now points to the start of a value. Find out whether it is
- a num, an id, a string or a colon. */
- if (c == ':')
- {
- *wordp = ptr++;
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 1;
- return 1;
- }
-
- if (c == '@')
- {
- char *pat;
- size_t vlen;
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *wordp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp);
- if (pat == NULL)
- {
- /* EOF here is OK; it just means that the last
- character of the file was an '@' terminating a
- value for a key type which does not require a
- trailing ';'. */
- pat = rcsbuf->ptrend - 1;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *wordp;
- if (vlen == 0)
- *wordp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
- }
-
- /* C is neither `:', `;' nor `@', so it should be the start of a num
- or an id. Make sure it is not another special character. */
- if (c == '$' || c == '.' || c == ',')
- {
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- }
-
- *wordp = ptr;
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Legitimate ID characters are digits, dots and any `graphic
- printing character that is not a special.' This test ought
- to do the trick. */
- c = *ptr;
- if (isprint (c) &&
- c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
- {
- ++ptr;
- continue;
- }
- break;
- }
-
- /* PTR points to the last non-id character in this word, and C is
- the character in its memory cell. Check to make sure that it
- is a legitimate word delimiter -- whitespace or semicolon. */
- if (c == ';' || my_whitespace (c))
- {
- rcsbuf->vlen = ptr - *wordp;
- rcsbuf->ptr = ptr;
- return 1;
- }
-
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- /* Shut up compiler warnings. */
- return 0;
-
-#undef my_whitespace
-}
-
/* Read an RCS revision number from an RCS file. This sets *REVP to
point to the revision number; it will point to space that is
managed by the rcsbuf functions, and is only good until the next
@@ -2357,89 +1877,6 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
}
/*
- * Get existing revision number corresponding to tag or revision.
- * Similar to RCS_gettag but less interpretation imposed.
- * For example:
- * -- If tag designates a magic branch, RCS_tag2rev
- * returns the magic branch number.
- * -- If tag is a branch tag, returns the branch number, not
- * the revision of the head of the branch.
- * If tag or revision is not valid or does not exist in file,
- * exit with error.
- */
-char *
-RCS_tag2rev (rcs, tag)
- RCSNode *rcs;
- char *tag;
-{
- char *rev, *pa, *pb;
- int i;
-
- assert (rcs != NULL);
-
- if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
-
- /* If a valid revision, try to look it up */
- if ( RCS_valid_rev (tag) )
- {
- /* Make a copy so we can scribble on it */
- rev = xstrdup (tag);
-
- /* If revision exists, return the copy */
- if (RCS_exist_rev (rcs, tag))
- return rev;
-
- /* Nope, none such. If tag is not a branch we're done. */
- i = numdots (rev);
- if ((i & 1) == 1 )
- {
- pa = strrchr (rev, '.');
- if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.')
- {
- free (rev);
- error (1, 0, "revision `%s' does not exist", tag);
- }
- }
-
- /* Tag is branch, but does not exist, try corresponding
- * magic branch tag.
- *
- * FIXME: assumes all magic branches are of
- * form "n.n.n ... .0.n". I'll fix if somebody can
- * send me a method to get a magic branch tag with
- * the 0 in some other position -- <dan@gasboy.com>
- */
- pa = strrchr (rev, '.');
- pb = xmalloc (strlen (rev) + 3);
- *pa++ = 0;
- (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa);
- free (rev);
- rev = pb;
- if (RCS_exist_rev (rcs, rev))
- return rev;
- error (1, 0, "revision `%s' does not exist", tag);
- }
-
-
- RCS_check_tag (tag); /* exit if not a valid tag */
-
- /* If tag is "HEAD", special case to get head RCS revision */
- if (tag && (strcmp (tag, TAG_HEAD) == 0))
- return (RCS_head (rcs));
-
- /* If valid tag let translate_symtag say yea or nay. */
- rev = translate_symtag (rcs, tag);
-
- if (rev)
- return rev;
-
- error (1, 0, "tag `%s' does not exist", tag);
- /* NOT REACHED -- error (1 ... ) does not return here */
- return 0;
-}
-
-/*
* Find the revision for a specific tag.
* If force_tag_match is set, return NULL if an exact match is not
* possible otherwise return RCS_head (). We are careful to look for
@@ -2618,13 +2055,25 @@ RCS_magicrev (rcs, rev)
char *rev;
{
int rev_num;
- char *xrev, *test_branch;
+ char *xrev, *test_branch, *local_branch_num;
xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
check_rev = xrev;
+ local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
+ if (local_branch_num)
+ {
+ rev_num = atoi(local_branch_num);
+ if (rev_num < 2)
+ rev_num = 2;
+ else
+ rev_num &= ~1;
+ }
+ else
+ rev_num = 2;
+
/* only look at even numbered branches */
- for (rev_num = 2; ; rev_num += 2)
+ for ( ; ; rev_num += 2)
{
/* see if the physical branch exists */
(void) sprintf (xrev, "%s.%d", rev, rev_num);
@@ -2909,41 +2358,6 @@ RCS_getbranch (rcs, tag, force_tag_match)
return (xstrdup (vn->version));
}
-/* Returns the head of the branch which REV is on. REV can be a
- branch tag or non-branch tag; symbolic or numeric.
-
- Returns a newly malloc'd string. Returns NULL if a symbolic name
- isn't found. */
-
-char *
-RCS_branch_head (rcs, rev)
- RCSNode *rcs;
- char *rev;
-{
- char *num;
- char *br;
- char *retval;
-
- assert (rcs != NULL);
-
- if (RCS_nodeisbranch (rcs, rev))
- return RCS_getbranch (rcs, rev, 1);
-
- if (isdigit (*rev))
- num = xstrdup (rev);
- else
- {
- num = translate_symtag (rcs, rev);
- if (num == NULL)
- return NULL;
- }
- br = truncate_revnum (num);
- retval = RCS_getbranch (rcs, br, 1);
- free (br);
- free (num);
- return retval;
-}
-
/* Get the branch point for a particular branch, that is the first
revision on that branch. For example, RCS_getbranchpoint (rcs,
"1.3.2") will normally return "1.3.2.1". TARGET may be either a
@@ -3471,40 +2885,6 @@ RCS_check_tag (tag)
}
/*
- * TRUE if argument has valid syntax for an RCS revision or
- * branch number. All characters must be digits or dots, first
- * and last characters must be digits, and no two consecutive
- * characters may be dots.
- *
- * Intended for classifying things, so this function doesn't
- * call error.
- */
-int
-RCS_valid_rev (rev)
- char *rev;
-{
- char last, c;
- last = *rev++;
- if (!isdigit (last))
- return 0;
- while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
- {
- if (c == '.')
- {
- if (last == '.')
- return 0;
- continue;
- }
- last = c;
- if (!isdigit (c))
- return 0;
- }
- if (!isdigit (last))
- return 0;
- return 1;
-}
-
-/*
* Return true if RCS revision with TAG is a dead revision.
*/
int
@@ -3544,27 +2924,31 @@ struct rcs_keyword
{
const char *string;
size_t len;
+ int expandit;
};
#define KEYWORD_INIT(s) (s), sizeof (s) - 1
-static const struct rcs_keyword keywords[] =
+static struct rcs_keyword keywords[] =
{
- { KEYWORD_INIT ("Author") },
- { KEYWORD_INIT ("Date") },
- { KEYWORD_INIT ("Header") },
- { KEYWORD_INIT ("Id") },
- { KEYWORD_INIT ("Locker") },
- { KEYWORD_INIT ("Log") },
- { KEYWORD_INIT ("Name") },
- { KEYWORD_INIT ("RCSfile") },
- { KEYWORD_INIT ("Revision") },
- { KEYWORD_INIT ("Source") },
- { KEYWORD_INIT ("State") },
- { NULL, 0 }
+ { KEYWORD_INIT ("Author"), 1 },
+ { KEYWORD_INIT ("Date"), 1 },
+ { KEYWORD_INIT ("CVSHeader"), 1 },
+ { KEYWORD_INIT ("Header"), 1 },
+ { KEYWORD_INIT ("Id"), 1 },
+ { KEYWORD_INIT ("Locker"), 1 },
+ { KEYWORD_INIT ("Log"), 1 },
+ { KEYWORD_INIT ("Name"), 1 },
+ { KEYWORD_INIT ("RCSfile"), 1 },
+ { KEYWORD_INIT ("Revision"), 1 },
+ { KEYWORD_INIT ("Source"), 1 },
+ { KEYWORD_INIT ("State"), 1 },
+ { NULL, 0, 0 },
+ { NULL, 0, 0 }
};
enum keyword
{
KEYWORD_AUTHOR = 0,
KEYWORD_DATE,
+ KEYWORD_CVSHEADER,
KEYWORD_HEADER,
KEYWORD_ID,
KEYWORD_LOCKER,
@@ -3573,8 +2957,10 @@ enum keyword
KEYWORD_RCSFILE,
KEYWORD_REVISION,
KEYWORD_SOURCE,
- KEYWORD_STATE
+ KEYWORD_STATE,
+ KEYWORD_LOCALID
};
+enum keyword keyword_local = KEYWORD_ID;
/* Convert an RCS date string into a readable string. This is like
the RCS date2str function. */
@@ -3752,7 +3138,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
slen = s - srch;
for (keyword = keywords; keyword->string != NULL; keyword++)
{
- if (keyword->len == slen
+ if (keyword->expandit
+ && keyword->len == slen
&& strncmp (keyword->string, srch, slen) == 0)
{
break;
@@ -3799,15 +3186,25 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
free_value = 1;
break;
+ case KEYWORD_CVSHEADER:
case KEYWORD_HEADER:
case KEYWORD_ID:
+ case KEYWORD_LOCALID:
{
char *path;
int free_path;
char *date;
+ char *old_path;
- if (kw == KEYWORD_HEADER)
+ old_path = NULL;
+ if (kw == KEYWORD_HEADER ||
+ (kw == KEYWORD_LOCALID &&
+ keyword_local == KEYWORD_HEADER))
path = rcs->path;
+ else if (kw == KEYWORD_CVSHEADER ||
+ (kw == KEYWORD_LOCALID &&
+ keyword_local == KEYWORD_CVSHEADER))
+ path = getfullCVSname(rcs->path, &old_path);
else
path = last_component (rcs->path);
path = escape_keyword_value (path, &free_path);
@@ -3827,6 +3224,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
locker != NULL ? locker : "");
if (free_path)
free (path);
+ if (old_path)
+ free (old_path);
free (date);
free_value = 1;
}
@@ -4159,10 +3558,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
size_t loglen;
Node *vp = NULL;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
- uid_t rcs_owner = (uid_t) -1;
- gid_t rcs_group = (gid_t) -1;
+ uid_t rcs_owner;
+ gid_t rcs_group;
mode_t rcs_mode;
- int change_rcs_owner_or_group = 0;
+ int change_rcs_owner = 0;
+ int change_rcs_group = 0;
int change_rcs_mode = 0;
int special_file = 0;
unsigned long devnum_long;
@@ -4314,6 +3714,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
{
RCSVers *vers;
Node *info;
+ struct hardlink_info *hlinfo;
vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
if (vp == NULL)
@@ -4362,36 +3763,64 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (workfile != NULL)
{
- List *links = vers->hardlinks;
- if (links != NULL)
+ info = findnode (vers->other_delta, "hardlinks");
+ if (info != NULL)
{
- Node *uptodate_link;
+ char *links = xstrdup (info->data);
+ char *working_dir = xgetwd();
+ char *p, *file = NULL;
+ Node *n, *uptodate_link;
/* For each file in the hardlinks field, check to see
if it exists, and if so, if it has been checked out
- this iteration. When walklist returns, uptodate_link
- should point to a hardlist node representing a file
- in `links' which has recently been checked out, or
- NULL if no file in `links' has yet been checked out. */
-
+ this iteration. */
uptodate_link = NULL;
- (void) walklist (links, find_checkedout_proc, &uptodate_link);
- dellist (&links);
+ for (p = strtok (links, " ");
+ p != NULL && uptodate_link == NULL;
+ p = strtok (NULL, " "))
+ {
+ file = (char *)
+ xmalloc (sizeof(char) *
+ (strlen(working_dir) + strlen(p) + 2));
+ sprintf (file, "%s/%s", working_dir, p);
+ n = lookup_file_by_inode (file);
+ if (n == NULL)
+ {
+ if (strcmp (p, workfile) != 0)
+ {
+ /* One of the files that WORKFILE should be
+ linked to is not even in the working directory.
+ The user should probably be warned. */
+ error (0, 0,
+ "warning: %s should be hardlinked to %s, but is missing",
+ p, workfile);
+ }
+ free (file);
+ continue;
+ }
+
+ /* hlinfo may be NULL if, for instance, a file is being
+ removed. */
+ hlinfo = (struct hardlink_info *) n->data;
+ if (hlinfo && hlinfo->checked_out)
+ uptodate_link = n;
+ free (file);
+ }
+ free (links);
+ free (working_dir);
/* If we've found a file that `workfile' is supposed to be
linked to, and it has been checked out since CVS was
- invoked, then simply link workfile to that file and return.
+ invoked, then simply link workfile to that file.
- If one of these conditions is not met, then
- workfile is the first one in its hardlink group to
- be checked out, and we must continue with a full
+ If one of these conditions is not met, then we're
+ checking out workfile to a temp file or stdout, or
+ workfile is the first one in its hardlink group to be
+ checked out. Either way we must continue with a full
checkout. */
if (uptodate_link != NULL)
{
- struct hardlink_info *hlinfo =
- (struct hardlink_info *) uptodate_link->data;
-
if (link (uptodate_link->key, workfile) < 0)
error (1, errno, "cannot link %s to %s",
workfile, uptodate_link->key);
@@ -4408,13 +3837,13 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
info = findnode (vers->other_delta, "owner");
if (info != NULL)
{
- change_rcs_owner_or_group = 1;
+ change_rcs_owner = 1;
rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
}
info = findnode (vers->other_delta, "group");
if (info != NULL)
{
- change_rcs_owner_or_group = 1;
+ change_rcs_group = 1;
rcs_group = (gid_t) strtoul (info->data, NULL, 10);
}
info = findnode (vers->other_delta, "permissions");
@@ -4470,9 +3899,6 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
}
}
- if (free_rev)
- free (rev);
-
if (log != NULL)
{
free (log);
@@ -4542,25 +3968,9 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (islink (workfile))
if (unlink_file (workfile) < 0)
error (1, errno, "cannot remove %s", workfile);
-
ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
-
- /* If the open failed because the existing workfile was not
- writable, try to chmod the file and retry the open. */
- if (ofp == NULL && errno == EACCES
- && isfile (workfile) && !iswritable (workfile))
- {
- xchmod (workfile, 1);
- ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
- }
-
if (ofp == NULL)
- {
- error (0, errno, "cannot open %s", workfile);
- if (free_value)
- free (value);
- return 1;
- }
+ error (1, errno, "cannot open %s", workfile);
}
if (workfile == NULL && sout == RUN_TTY)
@@ -4592,15 +4002,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
while (nleft > 0)
{
if (fwrite (p, 1, nstep, ofp) != nstep)
- {
- error (0, errno, "cannot write %s",
+ error (1, errno, "cannot write %s",
(workfile != NULL
? workfile
: (sout != RUN_TTY ? sout : "stdout")));
- if (free_value)
- free (value);
- return 1;
- }
p += nstep;
nleft -= nstep;
if (nleft < nstep)
@@ -4609,24 +4014,18 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
}
}
- if (free_value)
- free (value);
-
if (workfile != NULL)
{
int ret;
#ifdef PRESERVE_PERMISSIONS_SUPPORT
if (!special_file && fclose (ofp) < 0)
- {
- error (0, errno, "cannot close %s", workfile);
- return 1;
- }
+ error (1, errno, "cannot close %s", workfile);
- if (change_rcs_owner_or_group)
+ if (change_rcs_owner || change_rcs_group)
{
if (chown (workfile, rcs_owner, rcs_group) < 0)
- error (0, errno, "could not change owner or group of %s",
+ error (0, errno, "could not change file ownership on %s",
workfile);
}
@@ -4636,10 +4035,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
: sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
#else
if (fclose (ofp) < 0)
- {
- error (0, errno, "cannot close %s", workfile);
- return 1;
- }
+ error (1, errno, "cannot close %s", workfile);
ret = chmod (workfile,
sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
@@ -4657,10 +4053,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
!special_file &&
#endif
fclose (ofp) < 0)
- {
- error (0, errno, "cannot close %s", sout);
- return 1;
- }
+ error (1, errno, "cannot close %s", sout);
}
#ifdef PRESERVE_PERMISSIONS_SUPPORT
@@ -4670,6 +4063,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
update_hardlink_info (workfile);
#endif
+ if (free_value)
+ free (value);
+ if (free_rev)
+ free (rev);
+
return 0;
}
@@ -4996,7 +4394,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
int status, checkin_quiet, allocated_workfile;
struct tm *ftm;
time_t modtime;
- int adding_branch = 0;
commitpt = NULL;
@@ -5017,41 +4414,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
allocated_workfile = 1;
}
- /* Is the backend file a symbolic link? Follow it and replace the
- filename with the destination of the link. */
-
- while (islink (rcs->path))
- {
- char *newname;
-#ifdef HAVE_READLINK
- /* The clean thing to do is probably to have each filesubr.c
- implement this (with an error if not supported by the
- platform, in which case islink would presumably return 0).
- But that would require editing each filesubr.c and so the
- expedient hack seems to be looking at HAVE_READLINK. */
- newname = xreadlink (rcs->path);
-#else
- error (1, 0, "internal error: islink doesn't like readlink");
-#endif
-
- if (isabsolute (newname))
- {
- free (rcs->path);
- rcs->path = newname;
- }
- else
- {
- char *oldname = last_component (rcs->path);
- int dirlen = oldname - rcs->path;
- char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
- strncpy (fullnewname, rcs->path, dirlen);
- strcpy (fullnewname + dirlen, newname);
- free (newname);
- free (rcs->path);
- rcs->path = fullnewname;
- }
- }
-
checkin_quiet = flags & RCS_FLAGS_QUIET;
if (!checkin_quiet)
{
@@ -5098,6 +4460,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
Node *np;
struct stat sb;
char buf[64]; /* static buffer should be safe: see usage. -twp */
+ char *fullpath;
delta->other_delta = getlist();
@@ -5152,7 +4515,25 @@ RCS_checkin (rcs, workfile, message, rev, flags)
}
/* Save hardlinks. */
- delta->hardlinks = list_linked_files_on_disk (workfile);
+ fullpath = xgetwd();
+ fullpath = xrealloc (fullpath,
+ strlen(fullpath) + strlen(workfile) + 2);
+ sprintf (fullpath + strlen(fullpath), "/%s", workfile);
+
+ np = lookup_file_by_inode (fullpath);
+ if (np == NULL)
+ {
+ error (1, 0, "lost information on %s's linkage", workfile);
+ }
+ else
+ {
+ struct hardlink_info *hlinfo;
+ hlinfo = (struct hardlink_info *) np->data;
+ np = getnode();
+ np->key = xstrdup ("hardlinks");
+ np->data = xstrdup (hlinfo->links);
+ (void) addnode (delta->other_delta, np);
+ }
}
}
#endif
@@ -5326,7 +4707,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
goto checkin_done;
}
delta->version = RCS_addbranch (rcs, branch);
- adding_branch = 1;
p = strrchr (branch, '.');
*p = '\0';
tip = xstrdup (branch);
@@ -5372,26 +4752,13 @@ RCS_checkin (rcs, workfile, message, rev, flags)
{
if (! STREQ (nodep->data, delta->author))
{
- /* If we are adding a branch, then leave the old lock around.
- That is sensible in the sense that when adding a branch,
- we don't need to use the lock to tell us where to check
- in. It is fishy in the sense that if it is our own lock,
- we break it. However, this is the RCS 5.7 behavior (at
- the end of addbranch in ci.c in RCS 5.7, it calls
- removelock only if it is our own lock, not someone
- else's). */
-
- if (!adding_branch)
- {
- error (0, 0, "%s: revision %s locked by %s",
- rcs->path,
- nodep->key, nodep->data);
- status = 1;
- goto checkin_done;
- }
+ error (0, 0, "%s: revision %s locked by %s",
+ rcs->path,
+ nodep->key, nodep->data);
+ status = 1;
+ goto checkin_done;
}
- else
- delnode (nodep);
+ delnode (nodep);
}
dtext->version = xstrdup (delta->version);
@@ -5658,9 +5025,6 @@ RCS_cmp_file (rcs, rev, options, filename)
#endif
{
fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
- if (fp == NULL)
- /* FIXME-update-dir: should include update_dir in message. */
- error (1, errno, "cannot open file %s for comparing", filename);
data.filename = filename;
data.fp = fp;
@@ -5852,11 +5216,8 @@ RCS_setbranch (rcs, rev)
}
/* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME:
- Most of the callers only call us because RCS_checkin still tends to
- like a lock (a relic of old behavior inherited from the RCS ci
- program). If we clean this up, only "cvs admin -l" will still need
- to call RCS_lock. */
-
+ This is only required because the RCS ci program requires a lock.
+ If we eventually do the checkin ourselves, this can become a no-op. */
/* FIXME-twp: if a lock owned by someone else is broken, should this
send mail to the lock owner? Prompt user? It seems like such an
obscure situation for CVS as almost not worth worrying much
@@ -5925,18 +5286,6 @@ RCS_lock (rcs, rev, lock_quiet)
return 0;
}
-#if 0
- /* Well, first of all, "rev" below should be "xrev" to avoid
- core dumps. But more importantly, should we really be
- breaking the lock unconditionally? What CVS 1.9 does (via
- RCS) is to prompt "Revision 1.1 is already locked by fred.
- Do you want to break the lock? [ny](n): ". Well, we don't
- want to interact with the user (certainly not at the
- server/protocol level, and probably not in the command-line
- client), but isn't it more sensible to give an error and
- let the user run "cvs admin -u" if they want to break the
- lock? */
-
/* Break the lock. */
if (!lock_quiet)
{
@@ -5944,9 +5293,6 @@ RCS_lock (rcs, rev, lock_quiet)
cvs_output (" unlocked\n", 0);
}
delnode (p);
-#else
- error (1, 0, "Revision %s is already locked by %s", xrev, p->data);
-#endif
}
/* Create a new lock. */
@@ -6477,18 +5823,6 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
goto delrev_done;
}
- if (after == NULL && before == NULL)
- {
- /* The user is trying to delete all revisions. While an
- RCS file without revisions makes sense to RCS (e.g. the
- state after "rcs -i"), CVS has never been able to cope with
- it. So at least for now we just make this an error.
-
- We don't include rcs->path in the message since "cvs admin"
- already printed "RCS file:" and the name. */
- error (1, 0, "attempt to delete all revisions");
- }
-
/* The conditionals at this point get really hairy. Here is the
general idea:
@@ -6501,6 +5835,8 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
RCS_exec_rcsdiff with some changes, like being able
to suppress diagnostic messages and to direct output. */
+ assert (before != NULL || after != NULL);
+
if (after != NULL)
{
char *diffbuf;
@@ -6672,52 +6008,6 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
return status;
}
-
-/*
- * TRUE if there exists a symbolic tag "tag" in file.
- */
-int
-RCS_exist_tag (rcs, tag)
- RCSNode *rcs;
- char *tag;
-{
-
- assert (rcs != NULL);
-
- if (findnode (RCS_symbols (rcs), tag))
- return 1;
- return 0;
-
-}
-
-/*
- * TRUE if RCS revision number "rev" exists.
- * This includes magic branch revisions, not found in rcs->versions,
- * but only in rcs->symbols, requiring a list walk to find them.
- * Take advantage of list walk callback function already used by
- * RCS_delete_revs, above.
- */
-int
-RCS_exist_rev (rcs, rev)
- RCSNode *rcs;
- char *rev;
-{
-
- assert (rcs != NULL);
-
- if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
-
- if (findnode(rcs->versions, rev) != 0)
- return 1;
-
- if (walklist (RCS_symbols(rcs), findtag, rev) != 0)
- return 1;
-
- return 0;
-
-}
-
/* RCS_deltas and friends. Processing of the deltas in RCS files. */
@@ -7514,7 +6804,7 @@ getdelta (rcsbuf, rcsfile, keyp, valp)
char **valp;
{
RCSVers *vnode;
- char *key, *value, *keybuf, *valbuf, *cp;
+ char *key, *value, *cp;
Node *kv;
/* Get revision number if it wasn't passed in. This uses
@@ -7578,8 +6868,7 @@ unable to parse %s; `author' not in the expected place", rcsfile);
error (1, 0, "\
unable to parse %s; `state' not in the expected place", rcsfile);
vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
- /* The value is optional, according to rcsfile(5). */
- if (value != NULL && STREQ (value, "dead"))
+ if (STREQ (value, "dead"))
{
vnode->dead = 1;
}
@@ -7630,80 +6919,11 @@ unable to parse %s; `state' not in the expected place", rcsfile);
*/
while (1)
{
- int len;
- size_t valbuflen;
-
- key = NULL;
-
- if (! rcsbuf_getid (rcsbuf, &keybuf))
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
error (1, 0, "unexpected end of file reading %s", rcsfile);
- /* rcsbuf_getid did not terminate the key, so copy it to new space. */
- len = rcsbuf->ptr - keybuf;
- key = (char *) xmalloc (sizeof(char) * (len + 1));
- strncpy (key, keybuf, len);
- key[len] = '\0';
-
- /* The `desc' keyword has only a single string value, with no
- trailing semicolon, so it must be handled specially. */
if (STREQ (key, RCSDESC))
- {
- (void) rcsbuf_getstring (rcsbuf, &valbuf);
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
break;
- }
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* The `hardlinks' value is a group of words, which must
- be parsed separately and added as a list to vnode->hardlinks. */
- if (STREQ (key, "hardlinks"))
- {
- Node *n;
-
- vnode->hardlinks = getlist();
- while (1)
- {
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
- n = getnode();
- n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL);
- addnode (vnode->hardlinks, n);
- }
- continue;
- }
-#endif
-
- /* Get the value. */
- value = NULL;
- while (1)
- {
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
-
- /* Copy valbuf to new space so we can polish it, then
- append it to value. */
-
- if (value == NULL)
- {
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- }
- else
- {
- char *temp_value;
-
- temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- len = strlen (value);
- value = (char *) xrealloc
- (value, sizeof(char) * (len + valbuflen + 2));
- value[len] = ' ';
- strcpy (value + len + 1, temp_value);
- free (temp_value);
- }
- }
/* Enable use of repositories created by certain obsolete
versions of CVS. This code should remain indefinately;
@@ -7732,8 +6952,8 @@ unable to parse %s; `state' not in the expected place", rcsfile);
vnode->other_delta = getlist ();
kv = getnode ();
kv->type = RCSFIELD;
- kv->key = key;
- kv->data = value;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
if (addnode (vnode->other_delta, kv) != 0)
{
/* Complaining about duplicate keys in newphrases seems
@@ -7923,36 +7143,6 @@ putrcsfield_proc (node, vfp)
return 0;
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
-
-/* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain
- a full pathname, but currently only basenames are stored in the RCS
- node. Assume that the filename includes nasty characters and
- @-escape it. */
-
-static int
-puthardlink_proc (node, vfp)
- Node *node;
- void *vfp;
-{
- FILE *fp = (FILE *) vfp;
- char *basename = strrchr (node->key, '/');
-
- if (basename == NULL)
- basename = node->key;
- else
- ++basename;
-
- putc ('\t', fp);
- putc ('@', fp);
- (void) expand_at_signs (basename, strlen (basename), fp);
- putc ('@', fp);
-
- return 0;
-}
-
-#endif
-
/* Output the admin node for RCS into stream FP. */
static void
@@ -8038,14 +7228,6 @@ putdelta (vers, fp)
walklist (vers->other_delta, putrcsfield_proc, fp);
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (vers->hardlinks)
- {
- fprintf (fp, "\nhardlinks");
- walklist (vers->hardlinks, puthardlink_proc, fp);
- putc (';', fp);
- }
-#endif
putc ('\n', fp);
}
@@ -8279,7 +7461,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
to count the number of RCS revisions for which some special action
is required. */
-static int
+int
count_delta_actions (np, ignore)
Node *np;
void *ignore;
@@ -8375,6 +7557,8 @@ rcs_internal_lockfile (rcsfile)
error (1, errno, "could not open lock file `%s'", lockfile);
}
+ free (lockfile);
+
/* Force the file permissions, and return a stream object. */
/* Because we change the modes later, we don't worry about
this in the non-HAVE_FCHMOD case. */
@@ -8385,9 +7569,6 @@ rcs_internal_lockfile (rcsfile)
fp = fdopen (fd, FOPEN_BINARY_WRITE);
if (fp == NULL)
error (1, errno, "cannot fdopen %s", lockfile);
-
- free (lockfile);
-
return fp;
}
@@ -8619,9 +7800,6 @@ annotate (argc, argv)
}
#endif /* CLIENT_SUPPORT */
- if (tag != NULL)
- tag_check_valid (tag, argc, argv, local, 0, "");
-
return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL,
(DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
@@ -8681,3 +7859,104 @@ make_file_label (path, rev, rcs)
return label;
}
+void
+RCS_setlocalid (arg)
+ const char *arg;
+{
+ char *copy, *next, *key;
+
+ copy = xstrdup(arg);
+ next = copy;
+ key = strtok(next, "=");
+
+ keywords[KEYWORD_LOCALID].string = xstrdup(key);
+ keywords[KEYWORD_LOCALID].len = strlen(key);
+ keywords[KEYWORD_LOCALID].expandit = 1;
+
+ /* options? */
+ while (key = strtok(NULL, ",")) {
+ if (!strcmp(key, keywords[KEYWORD_ID].string))
+ keyword_local = KEYWORD_ID;
+ else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
+ keyword_local = KEYWORD_HEADER;
+ else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
+ keyword_local = KEYWORD_CVSHEADER;
+ else
+ error(1, 0, "Unknown LocalId mode: %s", key);
+ }
+ free(copy);
+}
+
+void
+RCS_setincexc (arg)
+ const char *arg;
+{
+ char *key;
+ char *copy, *next;
+ int include = 0;
+ struct rcs_keyword *keyword;
+
+ copy = xstrdup(arg);
+ next = copy;
+ switch (*next++) {
+ case 'e':
+ include = 0;
+ break;
+ case 'i':
+ include = 1;
+ break;
+ default:
+ free(copy);
+ return;
+ }
+
+ if (include)
+ for (keyword = keywords; keyword->string != NULL; keyword++)
+ {
+ keyword->expandit = 0;
+ }
+
+ key = strtok(next, ",");
+ while (key) {
+ for (keyword = keywords; keyword->string != NULL; keyword++) {
+ if (strcmp (keyword->string, key) == 0)
+ keyword->expandit = include;
+ }
+ key = strtok(NULL, ",");
+ }
+ free(copy);
+ return;
+}
+
+#define ATTIC "/" CVSATTIC
+static char *
+getfullCVSname(CVSname, pathstore)
+ char *CVSname, **pathstore;
+{
+ if (CVSroot_directory) {
+ int rootlen;
+ char *c = NULL;
+ int alen = sizeof(ATTIC) - 1;
+
+ *pathstore = xstrdup(CVSname);
+ if ((c = strrchr(*pathstore, '/')) != NULL) {
+ if (c - *pathstore >= alen) {
+ if (!strncmp(c - alen, ATTIC, alen)) {
+ while (*c != '\0') {
+ *(c - alen) = *c;
+ c++;
+ }
+ *(c - alen) = '\0';
+ }
+ }
+ }
+
+ rootlen = strlen(CVSroot_directory);
+ if (!strncmp(*pathstore, CVSroot_directory, rootlen) &&
+ (*pathstore)[rootlen] == '/')
+ CVSname = (*pathstore + rootlen + 1);
+ else
+ CVSname = (*pathstore);
+ }
+ return CVSname;
+}
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index f92988f..fab0f0b 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -154,10 +154,6 @@ struct rcsversnode
List *other;
/* Newphrase fields from delta nodes. */
List *other_delta;
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Hard link information for each revision. */
- List *hardlinks;
-#endif
};
typedef struct rcsversnode RCSVers;
@@ -189,9 +185,6 @@ char *RCS_check_kflag PROTO((const char *arg));
char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match,
int *simple_tag));
-int RCS_exist_rev PROTO((RCSNode *rcs, char *rev));
-int RCS_exist_tag PROTO((RCSNode *rcs, char *tag));
-char *RCS_tag2rev PROTO((RCSNode *rcs, char *tag));
char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date,
int force_tag_match, int *simple_tag));
char *RCS_magicrev PROTO((RCSNode *rcs, char *rev));
@@ -203,11 +196,9 @@ int RCS_datecmp PROTO((char *date1, char *date2));
time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
List *RCS_symbols PROTO((RCSNode *rcs));
void RCS_check_tag PROTO((const char *tag));
-int RCS_valid_rev PROTO ((char *rev));
List *RCS_getlocks PROTO((RCSNode *rcs));
void freercsnode PROTO((RCSNode ** rnodep));
char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match));
-char *RCS_branch_head PROTO ((RCSNode *rcs, char *rev));
int RCS_isdead PROTO((RCSNode *, const char *));
char *RCS_getexpand PROTO ((RCSNode *));
@@ -228,6 +219,9 @@ char *RCS_getaccess PROTO ((RCSNode *));
void RCS_rewrite PROTO ((RCSNode *, Deltatext *, char *));
int rcs_change_text PROTO ((const char *, char *, size_t, const char *,
size_t, char **, size_t *));
+void RCS_setincexc PROTO ((const char *arg));
+
+void RCS_setlocalid PROTO ((const char *arg));
char *make_file_label PROTO ((char *, char *, RCSNode *));
extern int preserve_perms;
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index f889233..490bf68 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -11,8 +11,6 @@
#include "cvs.h"
#include <assert.h>
-#include <stdio.h>
-#include "diffrun.h"
/* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
library", are intended to define our interface to RCS files.
@@ -77,11 +75,6 @@ static void call_diff_setup PROTO ((const char *prog));
static int call_diff PROTO ((char *out));
static int call_diff3 PROTO ((char *out));
-static void call_diff_write_output PROTO((const char *, size_t));
-static void call_diff_flush_output PROTO((void));
-static void call_diff_write_stdout PROTO((const char *));
-static void call_diff_error PROTO((const char *, const char *, const char *));
-
/* VARARGS */
static void
call_diff_setup (prog)
@@ -139,92 +132,59 @@ call_diff_add_arg (s)
call_diff_argv[call_diff_argc] = (char *) 0;
}
-/* Callback function for the diff library to write data to the output
- file. This is used when we are producing output to stdout. */
-
-static void
-call_diff_write_output (text, len)
- const char *text;
- size_t len;
-{
- cvs_output (text, len);
-}
-
-/* Call back function for the diff library to flush the output file.
- This is used when we are producing output to stdout. */
-
-static void
-call_diff_flush_output ()
-{
- cvs_flushout ();
-}
-
-/* Call back function for the diff library to write to stdout. */
-
-static void
-call_diff_write_stdout (text)
- const char *text;
-{
- cvs_output (text, 0);
-}
-
-/* Call back function for the diff library to write to stderr. */
-
-static void
-call_diff_error (format, a1, a2)
- const char *format;
- const char *a1;
- const char *a2;
-{
- /* FIXME: Should we somehow indicate that this error is coming from
- the diff library? */
- error (0, 0, format, a1, a2);
-}
-
-/* This set of callback functions is used if we are sending the diff
- to stdout. */
-
-static struct diff_callbacks call_diff_stdout_callbacks =
-{
- call_diff_write_output,
- call_diff_flush_output,
- call_diff_write_stdout,
- call_diff_error
-};
-
-/* This set of callback functions is used if we are sending the diff
- to a file. */
-
-static struct diff_callbacks call_diff_file_callbacks =
-{
- (void (*) PROTO((const char *, size_t))) NULL,
- (void (*) PROTO((void))) NULL,
- call_diff_write_stdout,
- call_diff_error
-};
+/* diff_run is imported from libdiff.a. */
+extern int diff_run PROTO ((int argc, char **argv, char *out));
static int
call_diff (out)
char *out;
{
+ /* Try to keep the out-of-order bugs at bay (protocol_pipe for cvs_output
+ with has "Index: foo" and such; stdout and/or stderr for diff's
+ output). I think the only reason that this used to not be such
+ a problem is that the time spent on the fork() and exec() of diff
+ slowed us down enough to let the "Index:" make it through first.
+
+ The real fix, of course, will be to have the diff library do all
+ its output through callbacks (which CVS will supply as cvs_output
+ and cvs_outerr). */
+#if defined(SERVER_SUPPORT)
+ /* only do this on the server if it's in protocol mode */
+ if (error_use_protocol || server_active)
+ usleep (50);
+#endif
+
if (out == RUN_TTY)
- return diff_run (call_diff_argc, call_diff_argv, NULL,
- &call_diff_stdout_callbacks);
+ return diff_run (call_diff_argc, call_diff_argv, NULL);
else
- return diff_run (call_diff_argc, call_diff_argv, out,
- &call_diff_file_callbacks);
+ return diff_run (call_diff_argc, call_diff_argv, out);
}
+extern int diff3_run PROTO ((int argc, char **argv, char *out));
+
static int
call_diff3 (out)
char *out;
{
+ /* Try to keep the out-of-order bugs at bay (protocol_pipe for cvs_output
+ with has "Index: foo" and such; stdout and/or stderr for diff's
+ output). I think the only reason that this used to not be such
+ a problem is that the time spent on the fork() and exec() of diff
+ slowed us down enough to let the "Index:" make it through first.
+
+ The real fix, of course, will be to have the diff library do all
+ its output through callbacks (which CVS will supply as cvs_output
+ and cvs_outerr). */
+#if defined(SERVER_SUPPORT)
+ /* only do this on the server if it's in protocol mode */
+ if (error_use_protocol || server_active)
+ usleep (50);
+#endif
+
if (out == RUN_TTY)
- return diff3_run (call_diff_argc, call_diff_argv, NULL,
- &call_diff_stdout_callbacks);
+ return diff3_run (call_diff_argc, call_diff_argv, NULL);
else
- return diff3_run (call_diff_argc, call_diff_argv, out,
- &call_diff_file_callbacks);
+ return diff3_run (call_diff_argc, call_diff_argv, out);
}
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index d88bf2b..484c048 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -13,9 +13,6 @@
#include "fileattr.h"
#include "edit.h"
-#ifdef CLIENT_SUPPORT
-static int do_argument_proc PROTO((Node * p, void *closure));
-#endif
static int do_dir_proc PROTO((Node * p, void *closure));
static int do_file_proc PROTO((Node * p, void *closure));
static void addlist PROTO((List ** listp, char *key));
@@ -61,24 +58,6 @@ struct frame_and_entries {
List *entries;
};
-#ifdef CLIENT_SUPPORT
-/* This is a callback to send "Argument" commands to the server in the
- case we've done a "cvs update" or "cvs commit" in a top-level
- directory where there is no CVSADM directory. */
-
-static int
-do_argument_proc (p, closure)
- Node *p;
- void *closure;
-{
- char *dir = p->key;
- send_to_server ("Argument ", 0);
- send_to_server (dir, 0);
- send_to_server ("\012", 1);
- return 0;
-}
-#endif
-
/* Start a recursive command.
Command line arguments (ARGC, ARGV) dictate the directories and
@@ -196,19 +175,6 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
"there is no version here; run '%s checkout' first",
program_name);
}
-#ifdef CLIENT_SUPPORT
- else if (client_active && server_started)
- {
- /* In the the case "cvs update foo bar baz", a call to
- send_file_names in update.c will have sent the
- appropriate "Argument" commands to the server. In
- this case, that won't have happened, so we need to
- do it here. While this example uses "update", this
- generalizes to other commands. */
-
- err += walklist (dirlist, do_argument_proc, NULL);
- }
-#endif
}
else
addlist (&dirlist, ".");
@@ -620,6 +586,7 @@ do_dir_proc (p, closure)
char *newrepos;
List *sdirlist;
char *srepository;
+ char *cp;
Dtype dir_return = R_PROCESS;
int stripped_dot = 0;
int err = 0;
@@ -823,8 +790,25 @@ but CVS uses %s for its own purposes; skipping %s directory",
repository = srepository;
}
+#if 0
+ /* Put back update_dir. I think this is the same as just setting
+ update_dir back to saved_update_dir, but there are a few cases I'm
+ not sure about (in particular, if DIR is "." and update_dir is
+ not ""), so for conservatism I'm leaving this here. */
+ cp = last_component (update_dir);
+ if (cp > update_dir)
+ cp[-1] = '\0';
+ else
+ update_dir[0] = '\0';
+ free (saved_update_dir);
+#else
+ /* The above code is cactus!!! - it doesn't handle descending
+ multiple directories at once! ie: it recurses down several
+ dirs and then back up one. This breaks 'diff', 'update',
+ 'commit', etc. */
free (update_dir);
update_dir = saved_update_dir;
+#endif
return (err);
}
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index f6e64a5..5d4ffbc 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -42,20 +42,8 @@ static Key_schedule sched;
#ifdef HAVE_GSSAPI
#include <netdb.h>
-
-#ifdef HAVE_GSSAPI_H
-#include <gssapi.h>
-#endif
-#ifdef HAVE_GSSAPI_GSSAPI_H
#include <gssapi/gssapi.h>
-#endif
-#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
#include <gssapi/gssapi_generic.h>
-#endif
-
-#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
-#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
-#endif
/* We use Kerberos 5 routines to map the GSSAPI credential to a user
name. */
@@ -378,8 +366,7 @@ mkdir_p (dir)
int saved_errno = errno;
if (saved_errno != EEXIST
- && ((saved_errno != EACCES && saved_errno != EROFS)
- || !isdir (q)))
+ && (saved_errno != EACCES || !isdir (q)))
{
retval = saved_errno;
goto done;
@@ -597,6 +584,9 @@ serve_root (arg)
nothing. But for rsh, we need to do it now. */
parse_config (CVSroot_directory);
+ /* Now is a good time to read CVSROOT/options too. */
+ parseopts(CVSroot_directory);
+
path = xmalloc (strlen (CVSroot_directory)
+ sizeof (CVSROOTADM)
+ sizeof (CVSROOTADM_HISTORY)
@@ -612,7 +602,7 @@ serve_root (arg)
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
- if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
{
save_errno = errno;
pending_error_text = malloc (80 + strlen (path));
@@ -648,18 +638,6 @@ server_pathname_check (path)
and is unlikely to do us any good here. It also is probably capable
of being a security hole in the anonymous readonly case. */
if (isabsolute (path))
- /* Giving an error is actually kind of a cop-out, in the sense
- that it would be nice for "cvs co -d /foo/bar/baz" to work.
- A quick fix in the server would be requiring Max-dotdot of
- at least one if pathnames are absolute, and then putting
- /abs/foo/bar/baz in the temp dir beside the /d/d/d stuff.
- A cleaner fix in the server might be to decouple the
- pathnames we pass back to the client from pathnames in our
- temp directory (this would also probably remove the need
- for Max-dotdot). A fix in the client would have the client
- turn it into "cd /foo/bar; cvs co -d baz" (more or less).
- This probably has some problems with pathnames which appear
- in messages. */
error (1, 0, "absolute pathname `%s' illegal for server", path);
if (pathname_levels (path) > max_dotdot_limit)
{
@@ -2281,9 +2259,6 @@ error \n");
/* We shouldn't have any partial lines from cvs_output and
cvs_outerr, but we handle them here in case there is a bug. */
- /* FIXME: appending a newline, rather than using "MT" as we
- do in the child process, is probably not really a very good
- way to "handle" them. */
if (! buf_empty_p (saved_output))
{
buf_append_char (saved_output, '\n');
@@ -2354,19 +2329,6 @@ error \n");
exitstatus = (*command) (argument_count, argument_vector);
- /* Output any partial lines. If the client doesn't support
- "MT", we just throw out the partial line, like old versions
- of CVS did, since the protocol can't support this. */
- if (supported_response ("MT") && ! buf_empty_p (saved_output))
- {
- buf_output0 (protocol, "MT text ");
- buf_append_buffer (protocol, saved_output);
- buf_output (protocol, "\n", 1);
- buf_send_counted (protocol);
- }
- /* For now we just discard partial lines on stderr. I suspect
- that CVS can't write such lines unless there is a bug. */
-
/*
* When we exit, that will close the pipes, giving an EOF to
* the parent.
@@ -2881,9 +2843,8 @@ server_register (name, version, timestamp, options, tag, date, conflict)
(void) fprintf (stderr,
"%c-> server_register(%s, %s, %s, %s, %s, %s, %s)\n",
(server_active) ? 'S' : ' ', /* silly */
- name, version, timestamp ? timestamp : "", options,
- tag ? tag : "", date ? date : "",
- conflict ? conflict : "");
+ name, version, timestamp, options, tag ? tag : "",
+ date ? date : "", conflict ? conflict : "");
}
if (entries_line != NULL)
@@ -3113,21 +3074,21 @@ static void
serve_remove (arg)
char *arg;
{
- do_cvs_command ("remove", cvsremove);
+ do_cvs_command ("cvsremove", cvsremove);
}
static void
serve_status (arg)
char *arg;
{
- do_cvs_command ("status", cvsstatus);
+ do_cvs_command ("status", status);
}
static void
serve_rdiff (arg)
char *arg;
{
- do_cvs_command ("rdiff", patch);
+ do_cvs_command ("patch", patch);
}
static void
@@ -3396,17 +3357,6 @@ server_modtime (finfo, vers_ts)
/* See server.h for description. */
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-/* Need to prototype because mode_t might be smaller than int. */
-void
-server_updated (
- struct file_info *finfo,
- Vers_TS *vers,
- enum server_updated_arg4 updated,
- mode_t mode,
- unsigned char *checksum,
- struct buffer *filebuf)
-#else
void
server_updated (finfo, vers, updated, mode, checksum, filebuf)
struct file_info *finfo;
@@ -3415,7 +3365,6 @@ server_updated (finfo, vers, updated, mode, checksum, filebuf)
mode_t mode;
unsigned char *checksum;
struct buffer *filebuf;
-#endif
{
if (noexec)
{
@@ -3634,7 +3583,7 @@ CVS server internal error: unhandled case in server_updated");
if ((updated == SERVER_UPDATED
|| updated == SERVER_PATCHED
|| updated == SERVER_RCS_DIFF)
- && filebuf == NULL
+ && filebuf != NULL
/* But if we are joining, we'll need the file when we call
join_file. */
&& !joining ())
@@ -4769,15 +4718,18 @@ check_repository_password (username, password, repository, host_user_ptr)
/* If found_it != 0, then linebuf contains the information we need. */
if (found_it)
{
- char *found_password, *host_user_tmp;
+ char *found_password, *host_user_tmp = NULL;
+ char *linebufp = linebuf;
- strtok (linebuf, ":");
- found_password = strtok (NULL, ": \n");
- host_user_tmp = strtok (NULL, ": \n");
+ strsep (&linebufp, ":");
+ found_password = strsep (&linebufp, ": \n");
+ if (found_password)
+ host_user_tmp = strsep (&linebufp, ": \n");
if (host_user_tmp == NULL)
host_user_tmp = username;
- if (strcmp (found_password, crypt (password, found_password)) == 0)
+ if (found_password == NULL || *found_password == '\0' ||
+ strcmp (found_password, crypt (password, found_password)) == 0)
{
/* Give host_user_ptr permanent storage. */
*host_user_ptr = xstrdup (host_user_tmp);
@@ -4815,7 +4767,10 @@ check_password (username, password, repository)
password file. If so, that's enough to authenticate with. If
not, we'll check /etc/passwd. */
- rc = check_repository_password (username, password, repository,
+ if (require_real_user)
+ rc = 0; /* "not found" */
+ else
+ rc = check_repository_password (username, password, repository,
&host_user);
if (rc == 2)
@@ -4833,23 +4788,25 @@ check_password (username, password, repository)
/* No cvs password found, so try /etc/passwd. */
const char *found_passwd = NULL;
- struct passwd *pw;
#ifdef HAVE_GETSPNAM
- struct spwd *spw;
+ struct spwd *pw;
- spw = getspnam (username);
- if (spw != NULL)
+ pw = getspnam (username);
+ if (pw != NULL)
{
- found_passwd = spw->sp_pwdp;
+ found_passwd = pw->sp_pwdp;
}
-#endif
+#else
+ struct passwd *pw;
- if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
+ pw = getpwnam (username);
+ if (pw != NULL)
{
found_passwd = pw->pw_passwd;
}
+#endif
- if (found_passwd == NULL)
+ if (pw == NULL)
{
printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", username);
@@ -4867,9 +4824,8 @@ error 0 %s: no such user\n", username);
exit (EXIT_FAILURE);
}
- if (*found_passwd)
+ if (found_passwd && *found_passwd)
{
- /* user exists and has a password */
host_user = ((! strcmp (found_passwd,
crypt (password, found_passwd)))
? username : NULL);
@@ -4877,14 +4833,11 @@ error 0 %s: no such user\n", username);
}
else if (password && *password)
{
- /* user exists and has no system password, but we got
- one as parameter */
host_user = username;
goto handle_return;
}
else
{
- /* user exists but has no password at all */
host_user = NULL;
goto handle_return;
}
@@ -5242,7 +5195,7 @@ gserver_authenticate_connection ()
tok_in.value = buf;
tok_in.length = strlen (buf);
- if (gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
+ if (gss_import_name (&stat_min, &tok_in, gss_nt_service_name,
&server_name) != GSS_S_COMPLETE)
error (1, 0, "could not import GSSAPI service name %s", buf);
@@ -5643,7 +5596,7 @@ cvs_output_binary (str, len)
if (error_use_protocol)
buf = buf_to_net;
- else
+ else if (server_active)
buf = protocol;
if (!supported_response ("Mbinary"))
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index d25eeb2..a329d49 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -530,6 +530,7 @@ get_linkinfo_proc (callerdat, finfo)
hlinfo->status = (Ctype) 0; /* is this dumb? */
hlinfo->checked_out = 0;
+ hlinfo->links = NULL;
linkp->data = (char *) hlinfo;
@@ -571,7 +572,7 @@ update_fileproc (callerdat, finfo)
&& tag != NULL
&& finfo->rcs != NULL)
{
- char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
+ char *rev = RCS_getversion (finfo->rcs, tag, date, 1, NULL);
if (rev != NULL
&& !RCS_nodeisbranch (finfo->rcs, tag))
nonbranch = 1;
@@ -1638,6 +1639,8 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
{
char *diff_options;
+ /* FIXME: It might be better to come up with a diff library
+ which can be shared with the diffutils. */
/* If the client does not support the Rcs-diff command, we
send a context diff, and the client must invoke patch.
That approach was problematical for various reasons. The
@@ -1646,10 +1649,8 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
program. */
if (! rcs_diff_patches)
{
- /* We use -c, not -u, because that is what CVS has
- traditionally used. Kind of a moot point, now that
- Rcs-diff is preferred, so there is no point in making
- the compatibility issues worse. */
+ /* We use -c, not -u, because we have no way of knowing
+ which DIFF is in use. */
diff_options = "-c";
}
else
@@ -1921,21 +1922,14 @@ merge_file (finfo, vers)
if (strcmp (vers->options, "-V4") == 0)
vers->options[0] = '\0';
-
- /* This file is the result of a merge, which means that it has
- been modified. We use a special timestamp string which will
- not compare equal to any actual timestamp. */
+ (void) time (&last_register_time);
{
char *cp = 0;
if (status)
- {
- (void) time (&last_register_time);
cp = time_stamp (finfo->file);
- }
- Register (finfo->entries, finfo->file, vers->vn_rcs,
- "Result of merge", vers->options, vers->tag,
- vers->date, cp);
+ Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, vers->options,
+ vers->tag, vers->date, cp);
if (cp)
free (cp);
}
@@ -2434,27 +2428,25 @@ join_file (finfo, vers)
free (rev1);
free (rev2);
- /* The file has changed, but if we just checked it out it may
- still have the same timestamp it did when it was first
- registered above in checkout_file. We register it again with a
- dummy timestamp to make sure that later runs of CVS will
- recognize that it has changed.
-
- We don't actually need to register again if we called
- RCS_checkout above, and we aren't running as the server.
- However, that is not the normal case, and calling Register
- again won't cost much in that case. */
+#ifdef SERVER_SUPPORT
+ /*
+ * If we're in server mode, then we need to re-register the file
+ * even if there were no conflicts (status == 0).
+ * This tells server_updated() to send the modified file back to
+ * the client.
+ */
+ if (status == 1 || (status == 0 && server_active))
+#else
+ if (status == 1)
+#endif
{
char *cp = 0;
if (status)
- {
- (void) time (&last_register_time);
cp = time_stamp (finfo->file);
- }
- Register (finfo->entries, finfo->file, vers->vn_rcs,
- "Result of merge", vers->options, vers->tag,
- vers->date, cp);
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs, vers->ts_rcs, vers->options,
+ vers->tag, vers->date, cp);
if (cp)
free(cp);
}
@@ -2502,8 +2494,8 @@ special_file_mismatch (finfo, rev1, rev2)
dev_t rev1_dev, rev2_dev;
char *rev1_symlink = NULL;
char *rev2_symlink = NULL;
- List *rev1_hardlinks;
- List *rev2_hardlinks;
+ char *rev1_hardlinks = NULL;
+ char *rev2_hardlinks = NULL;
int check_uids, check_gids, check_modes;
int result;
@@ -2541,7 +2533,7 @@ special_file_mismatch (finfo, rev1, rev2)
if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
rev1_dev = sb.st_rdev;
}
- rev1_hardlinks = list_linked_files_on_disk (finfo->file);
+ rev1_hardlinks = list_files_linked_to (finfo->file);
}
else
{
@@ -2592,9 +2584,11 @@ special_file_mismatch (finfo, rev1, rev2)
finfo->file, rev1, ftype);
}
- rev1_hardlinks = vp->hardlinks;
- if (rev1_hardlinks == NULL)
- rev1_hardlinks = getlist();
+ n = findnode (vp->other_delta, "hardlinks");
+ if (n == NULL)
+ rev1_hardlinks = xstrdup ("");
+ else
+ rev1_hardlinks = xstrdup (n->data);
}
}
@@ -2614,7 +2608,7 @@ special_file_mismatch (finfo, rev1, rev2)
if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
rev2_dev = sb.st_rdev;
}
- rev2_hardlinks = list_linked_files_on_disk (finfo->file);
+ rev2_hardlinks = list_files_linked_to (finfo->file);
}
else
{
@@ -2665,9 +2659,11 @@ special_file_mismatch (finfo, rev1, rev2)
finfo->file, rev2, ftype);
}
- rev2_hardlinks = vp->hardlinks;
- if (rev2_hardlinks == NULL)
- rev2_hardlinks = getlist();
+ n = findnode (vp->other_delta, "hardlinks");
+ if (n == NULL)
+ rev2_hardlinks = xstrdup ("");
+ else
+ rev2_hardlinks = xstrdup (n->data);
}
}
@@ -2748,7 +2744,7 @@ special_file_mismatch (finfo, rev1, rev2)
}
/* Compare hard links. */
- if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
+ if (strcmp (rev1_hardlinks, rev2_hardlinks) != 0)
{
error (0, 0, "%s: hard linkage of %s and %s do not match",
finfo->file,
@@ -2763,9 +2759,9 @@ special_file_mismatch (finfo, rev1, rev2)
if (rev2_symlink != NULL)
free (rev2_symlink);
if (rev1_hardlinks != NULL)
- dellist (&rev1_hardlinks);
+ free (rev1_hardlinks);
if (rev2_hardlinks != NULL)
- dellist (&rev2_hardlinks);
+ free (rev2_hardlinks);
return result;
#else
OpenPOWER on IntegriCloud