summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/cvs/BUGS2
-rw-r--r--contrib/cvs/COPYING6
-rw-r--r--contrib/cvs/COPYING.LIB7
-rw-r--r--contrib/cvs/ChangeLog200
-rw-r--r--contrib/cvs/FAQ243
-rw-r--r--contrib/cvs/HACKING109
-rw-r--r--contrib/cvs/INSTALL19
-rw-r--r--contrib/cvs/Makefile.in4
-rw-r--r--contrib/cvs/NEWS25
-rw-r--r--contrib/cvs/TESTS16
-rw-r--r--contrib/cvs/TODO23
-rwxr-xr-xcontrib/cvs/configure44
-rw-r--r--contrib/cvs/configure.in14
-rw-r--r--contrib/cvs/contrib/ChangeLog44
-rw-r--r--contrib/cvs/contrib/Makefile.in6
-rw-r--r--contrib/cvs/contrib/README11
-rw-r--r--contrib/cvs/contrib/log.pl5
-rw-r--r--contrib/cvs/contrib/rcs2log.sh326
-rw-r--r--contrib/cvs/diff/ChangeLog67
-rw-r--r--contrib/cvs/diff/Makefile.in7
-rw-r--r--contrib/cvs/diff/analyze.c4
-rw-r--r--contrib/cvs/diff/cmpbuf.c4
-rw-r--r--contrib/cvs/diff/cmpbuf.h4
-rw-r--r--contrib/cvs/diff/context.c4
-rw-r--r--contrib/cvs/diff/diff.c7
-rw-r--r--contrib/cvs/diff/diff.h4
-rw-r--r--contrib/cvs/diff/diff3.c14
-rw-r--r--contrib/cvs/diff/diffrun.h10
-rw-r--r--contrib/cvs/diff/dir.c4
-rw-r--r--contrib/cvs/diff/ed.c4
-rw-r--r--contrib/cvs/diff/io.c4
-rw-r--r--contrib/cvs/diff/normal.c4
-rw-r--r--contrib/cvs/diff/system.h7
-rw-r--r--contrib/cvs/diff/util.c56
-rw-r--r--contrib/cvs/doc/ChangeLog417
-rw-r--r--contrib/cvs/doc/RCSFILES30
-rw-r--r--contrib/cvs/doc/cvs-paper.ms4
-rw-r--r--contrib/cvs/doc/cvs.texinfo1352
-rw-r--r--contrib/cvs/doc/cvsclient.texi225
-rw-r--r--contrib/cvs/lib/ChangeLog42
-rw-r--r--contrib/cvs/lib/Makefile.in1
-rw-r--r--contrib/cvs/lib/fnmatch.c13
-rw-r--r--contrib/cvs/lib/getdate.y6
-rw-r--r--contrib/cvs/lib/getopt.h12
-rw-r--r--contrib/cvs/lib/md5.c55
-rw-r--r--contrib/cvs/lib/md5.h23
-rw-r--r--contrib/cvs/lib/memmove.c5
-rw-r--r--contrib/cvs/man/ChangeLog4
-rw-r--r--contrib/cvs/man/Makefile.in2
-rw-r--r--contrib/cvs/src/ChangeLog1518
-rw-r--r--contrib/cvs/src/Makefile.in6
-rw-r--r--contrib/cvs/src/add.c77
-rw-r--r--contrib/cvs/src/admin.c81
-rw-r--r--contrib/cvs/src/checkout.c2
-rw-r--r--contrib/cvs/src/client.c628
-rw-r--r--contrib/cvs/src/client.h5
-rw-r--r--contrib/cvs/src/commit.c278
-rw-r--r--contrib/cvs/src/create_adm.c6
-rw-r--r--contrib/cvs/src/cvs.h30
-rw-r--r--contrib/cvs/src/cvsrc.c7
-rw-r--r--contrib/cvs/src/diff.c30
-rw-r--r--contrib/cvs/src/edit.c42
-rw-r--r--contrib/cvs/src/entries.c41
-rw-r--r--contrib/cvs/src/error.c165
-rw-r--r--contrib/cvs/src/expand_path.c9
-rw-r--r--contrib/cvs/src/fileattr.h20
-rw-r--r--contrib/cvs/src/filesubr.c43
-rw-r--r--contrib/cvs/src/find_names.c63
-rw-r--r--contrib/cvs/src/hardlink.c2
-rw-r--r--contrib/cvs/src/history.c14
-rw-r--r--contrib/cvs/src/ignore.c19
-rw-r--r--contrib/cvs/src/import.c124
-rw-r--r--contrib/cvs/src/lock.c183
-rw-r--r--contrib/cvs/src/log.c19
-rw-r--r--contrib/cvs/src/login.c20
-rw-r--r--contrib/cvs/src/logmsg.c6
-rw-r--r--contrib/cvs/src/main.c472
-rw-r--r--contrib/cvs/src/mkmodules.c149
-rw-r--r--contrib/cvs/src/modules.c92
-rw-r--r--contrib/cvs/src/myndbm.c6
-rw-r--r--contrib/cvs/src/no_diff.c9
-rw-r--r--contrib/cvs/src/options.h.in11
-rw-r--r--contrib/cvs/src/parseinfo.c15
-rw-r--r--contrib/cvs/src/patch.c16
-rw-r--r--contrib/cvs/src/rcs.c417
-rw-r--r--contrib/cvs/src/rcs.h2
-rw-r--r--contrib/cvs/src/rcscmds.c3
-rw-r--r--contrib/cvs/src/recurse.c347
-rw-r--r--contrib/cvs/src/release.c73
-rw-r--r--contrib/cvs/src/remove.c8
-rw-r--r--contrib/cvs/src/root.c97
-rw-r--r--contrib/cvs/src/rtag.c15
-rw-r--r--contrib/cvs/src/run.c109
-rwxr-xr-xcontrib/cvs/src/sanity.sh5410
-rw-r--r--contrib/cvs/src/server.c856
-rw-r--r--contrib/cvs/src/server.h60
-rw-r--r--contrib/cvs/src/status.c73
-rw-r--r--contrib/cvs/src/subr.c100
-rw-r--r--contrib/cvs/src/tag.c38
-rw-r--r--contrib/cvs/src/update.c120
-rw-r--r--contrib/cvs/src/vers_ts.c20
-rw-r--r--contrib/cvs/src/version.c3
-rw-r--r--contrib/cvs/src/watch.c22
-rw-r--r--contrib/cvs/src/wrapper.c13
-rw-r--r--contrib/cvs/src/zlib.c84
-rw-r--r--contrib/cvs/tools/ChangeLog6
-rw-r--r--contrib/cvs/tools/Makefile.in3
-rw-r--r--contrib/cvs/tools/README14
108 files changed, 12644 insertions, 2956 deletions
diff --git a/contrib/cvs/BUGS b/contrib/cvs/BUGS
index 713d4c0..3609af4 100644
--- a/contrib/cvs/BUGS
+++ b/contrib/cvs/BUGS
@@ -95,8 +95,6 @@ file's description.
rtag does not recognize the -D option. It is documented to do so and I've
tested the use of -D with cvs update and cvs diff and it works fine there.
-* Defining RELATIVE_REPOS is said to not work with client/server CVS.
-
* From: "Charles M. Hannum" <mycroft@ai.mit.edu>
To: info-cvs@prep.ai.mit.edu
Subject: Still one more bug
diff --git a/contrib/cvs/COPYING b/contrib/cvs/COPYING
index 9a17037..57da8a4 100644
--- a/contrib/cvs/COPYING
+++ b/contrib/cvs/COPYING
@@ -1,9 +1,11 @@
+[I have snipped the snail mail address of the FSF because it has
+changed in the past and is likely to change again. The current
+address should be at http://www.gnu.org/]
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -217,7 +219,7 @@ the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Foundation, Inc.
Also add information on how to contact you by electronic and paper mail.
diff --git a/contrib/cvs/COPYING.LIB b/contrib/cvs/COPYING.LIB
index eb685a5..5e5cda2 100644
--- a/contrib/cvs/COPYING.LIB
+++ b/contrib/cvs/COPYING.LIB
@@ -1,8 +1,11 @@
+[I have snipped the snail mail address of the FSF because it has
+changed in the past and is likely to change again. The current
+address should be at http://www.gnu.org/]
+
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -464,7 +467,7 @@ convey the exclusion of warranty; and each file should have at least the
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Software Foundation, Inc.
Also add information on how to contact you by electronic and paper mail.
diff --git a/contrib/cvs/ChangeLog b/contrib/cvs/ChangeLog
index cb4801b..8a97c2f 100644
--- a/contrib/cvs/ChangeLog
+++ b/contrib/cvs/ChangeLog
@@ -1,3 +1,203 @@
+1999-07-12 Larry Jones <larry.jones@sdrc.com>
+
+ * TESTS: Remove suspicion that setting LC_COLLATE has fixed the
+ problem with Solaris sort -- people are still reporting it.
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ (These changes were run by devel-cvs; feedback was "They look fine"
+ from Jim Meyering and "I concur" from Noel Cragg).
+ * HACKING (Submitting patches): Rewrite parts to try to sketch out
+ a process which is less centralized and hopefully describes the
+ status quo better (for example, I've mostly removed the word
+ "submit" because it describes a process of sending your patch to a
+ central authority rather than to whoever wants it). Update to
+ reflect some of the current practices/thinking regarding quality
+ and other matters. Try to be more concise where feasible.
+
+1999-05-13 Jim Kingdon <http://www.cyclic.com>
+
+ * BUGS: Remove item about RELATIVE_REPOS not working with
+ client/server CVS; it must have been fixed because the testsuite
+ is working fine with RELATIVE_REPOS.
+
+1999-05-07 Jim Kingdon <http://www.cyclic.com>
+
+ * TESTS: Add note about send-expect style interaction.
+
+1999-04-26 Jim Kingdon
+
+ * cvsnt.mak: Revert to the version before today's changes
+ (modulo one "because the IDE feels like it" change). I
+ couldn't get O'Connor's cvsnt.mak to work with MSVC 4.0 at
+ all (I tried the IDE, which tried to wrap the makefile and
+ wouldn't build even with the wrap, and the command line NMAKE).
+ * .cvsignore: Add back cvsnt.mdp WinDebug WinRel, accordingly.
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add cvsnt.dsw.
+
+1999-04-26 (submitted 1999-03-24) John O'Connor <john@shore.net>
+
+ * cvsnt.dsw: new file. The workspace file used by MSVC 5+ to
+ manage multiple projects. It contains three projects: cvsnt,
+ zlib and diff.
+
+ * cvsnt.dsp: Fixed problem where CVS wouldn't build because of
+ file name conflicts. Removed all the files from zlib and diff
+ directories and moved to separate project files.
+
+ * cvsnt.mak: Re-generated due to the changes in cvsnt.dsp.
+
+ * .cvsignore: Removed un-used entries related to MSVC. Added
+ entries to cover all files generated by the NT build: *.ncb,
+ *.opt, *.plg, Debug and Release.
+
+1999-04-09 Jim Kingdon <http://www.cyclic.com>
+
+ * HACKING: Add a sentence about sending patches somewhere other
+ than bug-cvs, while still granting permission for people to use
+ them under the GPL.
+
+1999-04-08 Jim Kingdon <http://www.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Remove macintosh/Makefile (overlooked
+ in change of 1999-02-26; thanks to Erik Bertelsen for reporting it).
+ * configure: Regenerated.
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * macintosh: Remove this subdirectory and all its contents. It
+ contained MacCVS 2.x, but pretty much everyone has moved on to
+ MacCVS 3.x, MacCVS Pro, or MacCVSClient.
+ * Makefile.in (SUBDIRS): Remove macintosh.
+
+1999-02-25 Mehul N. Sanghvi (and Jim Kingdon)
+
+ * INSTALL: Add MkLinux on PowerPC.
+
+1999-02-18 Jim Kingdon
+
+ * cvsnt.mak: Remove vasprintf. Plus of course the usual
+ "because the IDE feels like it" changes.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * configure.in (AC_REPLACE_FUNCS): Remove vasprintf; see
+ lib/ChangeLog for rationale.
+ * configure: Regenerated.
+
+1999-01-31 Assar Westerlund of sics.se
+ and Jim Kingdon
+
+ * configure.in: The GSSAPI code in CVS requires krb5.h which
+ Solaris 2.7 doesn't have. Check for it.
+ * configure: Regenerated.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * COPYING, COPYING.LIB: Remove obsolete snail address of the Free
+ Software Foundation.
+
+1998-12-01 Jim Kingdon
+
+ * TODO (195): Check in a few clarifications from Andrew Tridgell,
+ the rsync author.
+
+1998-11-11 Jim Kingdon
+
+ * HACKING: Change prep.ai.mit.edu to gnu.org.
+
+1998-10-26 Jim Kingdon
+
+ * INSTALL: Add information for Sequent DYNIX/ptx4.0, from a report
+ by Marco Franzen.
+
+1998-10-14 Jim Kingdon
+
+ * configure.in (AC_OUTPUT): Remove contrib/elib/Makefile.
+ * configure: Regenerated using autoconf 2.10.
+
+1998-10-13 Jim Kingdon
+
+ * TODO (149): Update since -d doesn't rewrite CVS/Root any more.
+
+1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TODO (31): Mention the ,foo.c, and SIGINT issue.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * FAQ: Update from FAQ-O-Matic. This features fewer blank lines
+ and a few more minor formatting changes (not sure whether the
+ FAQ-O-Matic changed or whether this is because I upgraded Lynx).
+ I read through the diffs, and the real changes are: (A) In
+ /Advanced_Topics_/Setting_up_and_Manag/, #1, describe "cvs init",
+ don't describe committing modules file twice
+ (no longer needed now that mkmodules is not a separate program),
+ don't mention "cvs import" here. (B)
+ /Advanced_Topics_/Setting_up_and_Manag/, #5, describe special
+ issues with pserver and repository permissions,
+ (C), /Advanced_Topics_/Tricks_of_the_Trade/, renumber the question
+ "Why do timestamps sometimes get set to the date of the revision"
+ from #17 to #9. Renumber the questions between #9 and #17
+ accordingly, (D) /User_Tasks_/Less_Common_User_Tas/, "8. How do I
+ split a file into pieces, retaining revision histories?", include
+ a script which may help with this, (E)
+ /What_is_CVS_/How_does_CVS_differ_/, correct the name of SABLIME,
+ (F) /What_is_CVS_/Where_do_I_find_CVS_/, "2. Is there an archive
+ of CVS material?", note that http://www.delos.com/cvs doesn't
+ exist any more.
+
+ * NEWS: Mention :fork:.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL (Tested platforms): Update SCO OpenServer information,
+ from a report by Robert Lipe@DIGI.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add items about multiple roots and -d not updating
+ CVS/Root.
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * configure.in (AC_OUTPUT): Remove tools/pcl-cvs/Makefile.
+ * configure: Regenerated using autoconf 2.10.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * NEWS: Add item about LockDir.
+
+1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL (Tested platforms): Add Solaris x86 (reported by Jeremy of
+ exit109.com) and Irix 6.4 (reported by Russ Allbery).
+
+ * INSTALL (Tested platforms): Add Solaris 2.6 (reported by Russ
+ Allbery).
+
+1998-08-28 Noel Cragg <noel@swish.red-bean.com>
+
+ * TODO (196): new item.
+
+1998-08-26 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * TESTS: Update comments concerning Solaris sort and LC_COLLATE.
+
+1998-08-17 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Update Irix, Ultrix, and NetBSD/Alpha with test results
+ from Noel.
+
+1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * INSTALL: Add NetBSD/mac68k (reported by Hauke Fath of melog.de).
+ Add alpha-dec-osf4.0 and update SunOS and linux entries (reported
+ by Jim Kingdon and Noel Cragg).
+
1998-08-06 Jim Kingdon <kingdon@harvey.cyclic.com>
* INSTALL: Update for SCO OpenServer 5 (reported by Jeffery
diff --git a/contrib/cvs/FAQ b/contrib/cvs/FAQ
index 20912dd..06fe818 100644
--- a/contrib/cvs/FAQ
+++ b/contrib/cvs/FAQ
@@ -126,12 +126,10 @@ molli@loria.fr
CVS uses the word "branch" in a number of ways. The two most
important are:
-
- The vendor branch holds releases from (normally) an outside
software vendor. It is implemented using a specific RCS branch
(i.e. 1.1.1).
-
- The "Main Branch", which normally holds your "Main Line
Development", but is defined as the collection of revisions you
get when you "checkout" something fresh, or when you use the
@@ -142,7 +140,6 @@ molli@loria.fr
Branches, files you have never changed are on three branches at
the same time:
-
- The RCS 1.1.1 branch.
- The CVS Vendor branch.
- The CVS "Main Branch".
@@ -151,13 +148,11 @@ molli@loria.fr
In referring to CVS, "branch" can be used in four other ways:
-
- A CVS working directory satisfies the definition of "branch"
for a single developer -- you are on a private "virtual branch"
that does not appear in any of the RCS files or the CVS control
files.
-
- The CVS "default branch" is the Repository source for the
collection of files in your working directory. It is *not* the
same as the RCS "default branch". Normally the CVS default
@@ -166,26 +161,22 @@ molli@loria.fr
a "sticky" tag that changes your default branch to the one you
checked out.
-
- A "magic" branch can be a branch that hasn't happened yet. It
is implemented by a special tag you can check out that is not
attached to a real RCS branch. When you commit a file to a
magic branch, the branch becomes real (i.e. a physical RCS
branch).
-
- And, of course, CVS uses "branch" to indicate a
human-oriented "branch in development".
How RCS uses the word "branch":
-
- The RCS "Main Branch" (Synonym: "The Trunk") contains a
series of two-part revision numbers separated by a single '.'
(e.g. 1.2). It is treated specially and is the initial default
branch. (The default default?)
-
- The RCS "Default" branch starts out attached to the RCS "Main
Branch". For RCS purposes, it can be changed to point to any
branch. Within CVS, you *must*not* alter the RCS default
@@ -358,11 +349,9 @@ molli@loria.fr
directory (in ./CVS/Tag) and the checked-out files (on each line of
./CVS/Entries).
-
- A "sticky" <tag> (including a <branch_tag>) causes most CVS commands
to act as if "-r <tag>" were on the command line.
-
- A "sticky" <branch_tag> indicates that the working directory (and
working files) are "on the branch".
@@ -377,17 +366,13 @@ molli@loria.fr
Specifically, you must:
-
- Remember that the branch exists. (This is non-trivial if you create
a lot of them.)
-
- Plan when to merge it back into the main line of development.
-
- Schedule the order that multiple branch merges are to be done.
-
- If you ever intend to merge branches into each other, instead of
limiting merges of branch work back into the "main line", you must
keep careful track of which parts of which branches have merged into
@@ -1445,13 +1430,11 @@ You can branch a branch.
So, here's an un-reviewed suggestion originally from Graydon Dodson
<grdodson@lexmark.com>, which I've altered and edited heavily.
-
- Keep a directory where the whole tree is checked out. (It might be
built and tested once in a while to make sure it is worth linking to,
but that doesn't affect the source control aspect of this procedure).
Let's call it /master/build.
-
- Write a tool that creates a tree of directories (like the X11
"lndir" command) filled with links to the checked out files in the
/master/build tree.
@@ -1459,14 +1442,12 @@ You can branch a branch.
This tool should also provide real copies of, not symlinks to, all the
files within the CVS administrative directories.
-
- You could also provide a way for the tool to take a list of whole
directories that you will never change, for which it would create a
single symlink to the directory and not a subtree of symlinks to
files. Or you could rm -r pieces of the resulting working directory
yourself and replace it with links.
-
- If you want to edit a file, you have to grab a real copy and keep it
until your revision shows up in the /master/build tree. I'd create a
script to do this: cvsgrab <file>
@@ -1487,12 +1468,10 @@ You can branch a branch.
You'll have to run "update" before "commit" anyway if there are newer
revisions.
-
- Presumably there would also be a tool to traverse the link tree and
revert it to links if there are no modified files and/or if all the
real files match the revision of the /master/build tree.
-
- To avoid confusing CVS when the /master/build revisions are updated
but your CVS/Entries files is not, CVS would have to change to handle
symlinks. It currently causes problems with this scenario:
@@ -1627,7 +1606,6 @@ You can branch a branch.
RCS versions earlier than 5.5 print the above error when a file does
not end in a newline character. It can be caused by:
-
- Editing with Emacs and not using "require-final-newline".
- Committing a binary file.
- Filesystem failures (NFS!) that put nulls in your file.
@@ -1738,11 +1716,9 @@ You can branch a branch.
Recovery:
- If only the ,<file>, exists, rename it to <file>,v.
-
- If both ,<file>, and <file>,v exist and are linked, remove the
,<file>, file.
-
- If both ,<file>, and <file>,v exist and are separate files, look at
the dates, "diff" them and make your best guess. This sounds like the
remnants of two separate events.
@@ -1952,7 +1928,6 @@ You can branch a branch.
CAVEMAN is a front end to CVS written in PERL providing a collection
of features desired by the site where it was developed.
-
- The ability to spread a "project" over multiple Repositories.
- Optional automatic tagging after each commit.
- Additional locking of files.
@@ -1980,21 +1955,13 @@ You can branch a branch.
First, install all the programs. (See Section 4A.)
- Then create a Repository by executing "cvsinit", which works only from
- within the head of the CVS source directory. (It needs files from the
- distribution to work.)
-
- If you want a very primitive Repository and don't want to save a
- history log, refer to modules, or use any of the "info" files for
- logging, pre-commit checks, or editing templates, you can dispense
- with "cvsinit" entirely. I would advise executing it.
+ Then create a Repository by executing "cvs -d init". (This works with
+ CVS 1.9.)
- The cvsinit program will create a short modules file containing the
- module named "CVSROOT". Change to your work directory and type:
-
- cvs checkout CVSROOT
-
- Then read the files that are checked out.
+ Now you can configure your repository by checking out CVSROOT: "cvs -d
+ checkout CVSROOT". Change into the created directory CVSROOT. Edit the
+ files you want to edit, and afterwards, commit the changes by typing
+ "cvs commit".
You will certainly want to add modules of your own. Edit the "modules"
file and add lines to describe the items you want to "checkout" by
@@ -2014,15 +1981,9 @@ You can branch a branch.
test test
junk test/junk
- When you are done editing, "commit" the modules file. If you
- configured CVS to use "dbm", you might have to edit and commit the
- modules file twice to change the pathname of the mkmodules program in
- the modules file.
-
- Try using the "import" command to insert the "junk" module and play
- around until you are comfortable.
+ Andreas Kostyrka
- Last modified: _11/7/1997_
+ Last modified: _4/21/1998_
2. What are those files in $CVSROOT/CVSROOT?
@@ -2115,20 +2076,19 @@ You can branch a branch.
5. What file permissions should I use on (and in) the Repository?
+ If you are using pserver (password-authenticated access), see below.
+
If you run a completely open environment (which usually means that you
don't have, or don't want to waste, the time to deal with it):
-
- Set all directory permissions to 777.
-
- Have everyone set their umasks to 0.
(BTW, I don't suggest this. I am merely reporting it.)
If you are a normal Unix shop and want to use groups effectively:
-
- Set all the directory permissions in the Repository to 775.
If you are using a system that handles both System V and BSD
@@ -2136,25 +2096,20 @@ You can branch a branch.
If you are using one of the many recent versions of Unix that don't
allow you to use the full octal mode, then you'll have to type: chmod
- u=rwx,g=rwx,o=rx,g+s <dir>
-
+ u=rwx,g=rwx,o=rx,g+s dir&gt;
- Change all the groups on the directories to match the groups you
want to write to various directories.
-
- Make sure every user is in the appropriate groups.
-
- Have everyone set their umask to 002, including root.
If you don't want non-group members to even read the files, do the
above, but change:
-
- Repository directory permissions to 770. (or 2770)
-
- umasks to 007.
If you work in an environment where people can't be trusted to set
@@ -2168,7 +2123,21 @@ You can branch a branch.
exec /usr/local/bin/cvs.real ${1+"$@"}
^D
- Last modified: _6/13/1997_
+ Pserver (Password-Authenticated Access) &lt;blome@de.ibm.com&gt;
+
+ The above suggestions are not valid when you use the pserver facility.
+ Be sure to read and understand the manual section about this (should
+ be 4.6.something). Above all: do /not/ make the repository and CVSROOT
+ group writeable. In CVSROOT, make `history´ group or world writeable
+ instead.
+
+ I suggest creating one unix group per project group. In the
+ repository, you would then create one directory for each group, group
+ writeable. New projects must then be created in these group
+ directories. If you don't want to say &lt;group&gt;/&lt;project&gt; on
+ checkout, create a &lt;project&gt; module and point it there.
+
+ Last modified: _9/24/1998_
6. How do I structure my Repository?
@@ -2189,7 +2158,6 @@ You can branch a branch.
needs, usually tied in with the other tools you use to build, install
and distribute your work. Common needs include the ability to:
-
- mount (or automount) directories from many places in your
organization.
- check out just what you need and no more.
@@ -2242,20 +2210,16 @@ You can branch a branch.
- "update -r <tag>" produces the correct files.
-
- The duplicated revision history can be slightly misleading.
-
- A plain (i.e. without the "-r <tag>") "checkout" or "update -d" will
create directories "renamed" this way, but you can delete it and a
plain "update" won't bring it back.
Move the files and directories in the Repository to the new names.
-
- You save the revision history under a different file name.
-
- You save a little space.
- "update -r <tag>" produces the wrong files or directories.
@@ -2270,7 +2234,6 @@ You can branch a branch.
sophisticated, revision of the Makefile. (Yes, this changes the
"released" file if <tag> indicates a release. But it is an option.)
-
- Important Note: If you rename a directory, you must rename the
corresponding directory in every checked-out working directory. At the
same time, you must edit the pathname stored in the ./CVS/Repository
@@ -2280,7 +2243,6 @@ You can branch a branch.
everyone to remove their working directories and check them out again
from scratch.
-
- The file exists in the working directory and in the ./CVS/Entries
file, but not in the Repository. For the old file, "update" prints:
@@ -2302,11 +2264,9 @@ You can branch a branch.
"cvs add" to add the new one. Since there is no way for CVS to remove
a directory, this only works for files.
-
- This is what most people think of first. Without a "rename" command,
the remove/add technique seems obvious.
-
- You lose the connection of your new working file to its past
revision history.
@@ -2446,7 +2406,6 @@ You can branch a branch.
The best form of Repository control is a combination of:
-
- A reliable backup scheme (verify it!)
- Enough training to ensure your developers are competent and
knowledgeable about all areas of your sources.
@@ -2659,7 +2618,6 @@ kingdon@cyclic.com
people have succumbed to the urge to do so when pressed for time. The
reasons given, usually with evident contrition, include:
-
- Editing mistakes in, or adding text to, log entries. (If you have
RCS 5.6 or later, you should use `cvs admin -m'.)
- Renaming or moving symbolic names. (You should `cvs admin -N'
@@ -2940,7 +2898,36 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 9. While in the middle of a large "commit", how do I run other commands,
+ 9. Why do timestamps sometimes get set to the date of the revision,
+ sometimes not? The inconsistency causes unnecessary recompiles.
+
+ The "checkout" command normally sets the timestamp of a working file
+ to match the timestamp stored on the revision in the Repository's RCS
+ file.
+
+ The "commit" command retains the timestamp of the file, if the act of
+ checking it in didn't change it (by expanding keywords).
+
+ The "update" command sets the time to the revision time the first time
+ it sees the file. After that, it sets the time of the file to the
+ current time. See 4D.8 for a reason why.
+
+ Here's a two-line PERL program to set timestamps on files based on
+ other timestamps. I've found this program useful. When you are certain
+ you don't want a source file to be recompiled, you can set its
+ timestamp to the stamp on the object file.
+
+ #!/usr/local/bin/perl
+ #
+ # Set timestamp of args 2nd-Last to that of the first arg.
+ #
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
+ = stat(shift);
+ utime($atime,$mtime,@ARGV);
+
+ Last modified: _6/13/1997_
+
+ 10. While in the middle of a large "commit", how do I run other commands,
like "diff" or "stat" without seeing lock errors?
Type:
@@ -2977,7 +2964,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 10. Where did the ./CVS/Entries.Static file come from? What is it for?
+ 11. Where did the ./CVS/Entries.Static file come from? What is it for?
Each CVS working directory contains a ./CVS/Entries file listing the
files managed by CVS in that working directory. Normally, if the
@@ -3014,7 +3001,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 11. Why did I get the wrong Repository in the loginfo message?
+ 12. Why did I get the wrong Repository in the loginfo message?
You probably:
@@ -3038,7 +3025,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 12. How do I run CVS setuid so I can only allow access through the CVS
+ 13. How do I run CVS setuid so I can only allow access through the CVS
program itself?
Setuid to root is not a great idea. Any program that modifies files
@@ -3067,7 +3054,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 13. How about using groups and setgid() then?
+ 14. How about using groups and setgid() then?
Here is a way to run CVS setgid in some environments:
@@ -3122,7 +3109,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 14. How do I use the "commitinfo" file?
+ 15. How do I use the "commitinfo" file?
Go read 4B.2 first.
@@ -3133,7 +3120,6 @@ kingdon@cyclic.com
To fill out a "commitinfo" file, ask yourself (and those sharing your
Repository) these questions:
-
- Is there anything you want to check or change before someone is
allowed to commit a file? If not, forget commitinfo.
@@ -3141,7 +3127,6 @@ kingdon@cyclic.com
like the rcslock.pl program in the contrib directory of the CVS
sources.
-
- Do you want to execute the same exact thing before committing to
every file in the Repository? (This is useful if you want to program
the restrictions yourself.) If so, set up a single line in the
@@ -3156,7 +3141,6 @@ kingdon@cyclic.com
Write your program accordingly. Some examples exist in the contrib
directory.
-
- Do you want a different kind of sanity check performed for different
directories? If so, you'll have to decide what to do for all
directories and enter lines like this:
@@ -3165,7 +3149,6 @@ kingdon@cyclic.com
regexp2 /absolute/path/to/program-for-regexp2
DEFAULT /absolute/path/to/program-for-all-else
-
- Is there anything you want to happen before *all* commits, in
addition to other pattern matches? If so, include a line like this:
@@ -3176,7 +3159,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 15. How do I use the "loginfo" files?
+ 16. How do I use the "loginfo" files?
See 4B.2 and the "commitinfo" question above.
@@ -3196,7 +3179,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 16. How can I keep people with restrictive umask values from blocking
+ 17. How can I keep people with restrictive umask values from blocking
access to the Repository?
If a user creates a new file with restricted permissions (e.g. 0600),
@@ -3221,35 +3204,6 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 17. Why do timestamps sometimes get set to the date of the revision,
- sometimes not? The inconsistency causes unnecessary recompiles.
-
- The "checkout" command normally sets the timestamp of a working file
- to match the timestamp stored on the revision in the Repository's RCS
- file.
-
- The "commit" command retains the timestamp of the file, if the act of
- checking it in didn't change it (by expanding keywords).
-
- The "update" command sets the time to the revision time the first time
- it sees the file. After that, it sets the time of the file to the
- current time. See 4D.8 for a reason why.
-
- Here's a two-line PERL program to set timestamps on files based on
- other timestamps. I've found this program useful. When you are certain
- you don't want a source file to be recompiled, you can set its
- timestamp to the stamp on the object file.
-
- #!/usr/local/bin/perl
- #
- # Set timestamp of args 2nd-Last to that of the first arg.
- #
- ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
- = stat(shift);
- utime($atime,$mtime,@ARGV);
-
- Last modified: _6/13/1997_
-
Category: /Commands_/
" Commands "
@@ -4245,14 +4199,12 @@ kingdon@cyclic.com
Providing a list of files changed since
-
- A tagged release.
- Yesterday, last Thursday, or a specific date.
- Someone changed a specific file.
Providing a list of special events:
-
- Files added or removed since one of the above events.
- Merge failures since one of the above events. (Where did the
conflicts occur?)
@@ -4376,7 +4328,6 @@ kingdon@cyclic.com
To list (for the selected users): Type "cvs history" and:
-
* Checked out modules: -o (the default)
* Files added since creation: -x A
* Modified files since creation: -c
@@ -5939,15 +5890,12 @@ kingdon@cyclic.com
working file to contain conflict markers surrounding the overlapping
code segments. For example, say that
-
- Two developers acquire revision 1.2 of <file> via "checkout" or
"update".
-
- Developer A changes line 1 from "9999" to "5555", then commits the
file, creating revision 1.3.
-
- Developer B changes line 1 from "9999" to "7777", then tries to
commit the file, but is blocked because the file is not up to date.
Developer B then runs "update" and sees the conflict marker 'C'. The
@@ -7464,24 +7412,45 @@ kingdon@cyclic.com
If you decide to split the file, here's a suggestion. In many ways, it
is similar to multiple "renamings" as described in 2C.4 above.
- Say you want to split <fileA>, which already in the Repository, into
- three pieces, <fileA>, <fileB> and <fileC>.
+ Say you want to split , which already in the Repository, into three
+ pieces, , and .
Copy the RCS (",v") files directly in the Repository, creating the
new files, then bring readable copies of the new files into the
working directory via "update".
- cp $CVSROOT/<path>/<fileA>,v $CVSROOT/<path>/<fileB>,v cp
- $CVSROOT/<path>/<fileA>,v $CVSROOT/<path>/<fileC>,v
- cvs update <fileB> <fileC>
+ cp $CVSROOT//,v $CVSROOT//,v cp $CVSROOT//,v $CVSROOT//,v
+ cvs update
- Then remove all the <tags> from the new files by using:
+ Then remove all the from the new files, either using:
- cvs log <fileB> <fileC> # Save the list of <tag?>
- cvs tag -d <tag1> <fileB> <fileC>
- cvs tag -d <tag2> <fileB> <fileC>
+ cvs log # Save the list of
+ cvs tag -d
+ cvs tag -d
. . .
+ (eivind@freebsd.org) or using the following little script to
+ autmatically remove the tags directly from the repository files:
+
+#!/bin/sh
+for file in $*
+do
+ TAGS=`rlog $file | awk '/^symbolic names:/,/^keyword subst/' | awk 'BEG
+IN {FS=":"} /^\t/ {print $1}'`
+ echo The tags in $file are
+ echo $TAGS
+ echo Is it OK to remove these?
+ read confirm
+ if [ "$confirm" = "y" -o "$confirm" = "yes" ]
+ then
+ for tag in $TAGS
+ do
+ echo Removing $file:$tag
+ rcs -n$tag $file
+ done
+ fi
+done
+
Edit each file until it has the data you want in it. This is a
hand-editing job, not something CVS can handle. Then commit all the
files.
@@ -7491,8 +7460,8 @@ kingdon@cyclic.com
statements, which must be duplicated. And make sure the code
compiles.]
- emacs <fileA> <fileB> <fileC>
- cvs commit <fileA> <fileB> <fileC>
+ emacs
+ cvs commit
As in the "rename" case, by duplicating the files, you'll preserve the
change history and the ability to retrieve earlier revisions.
@@ -7500,7 +7469,7 @@ kingdon@cyclic.com
Of course, you have to alter your build system (e.g. Makefiles) to
take the new names and the change in contents into account.
- Last modified: _6/13/1997_
+ Last modified: _3/11/1998_
Category: /What_is_CVS_/
@@ -7772,7 +7741,7 @@ kingdon@cyclic.com
Last modified: _6/13/1997_
- 10. How does CVS differ from Sublime?
+ 10. How does CVS differ from SABLIME?
Produced by AT&T. Sablime uses SCCS as the underlying source code
control system. It uses some other control system (called sbcs I
@@ -7790,7 +7759,7 @@ kingdon@cyclic.com
weight though, and the interface is not too polished and does not work
on windows (though that may have changed). rama@savera.com
- Last modified: _12/12/1997_
+ Last modified: _7/30/1998_
11. How does CVS differ from PVCS?
@@ -8457,7 +8426,7 @@ kingdon@cyclic.com
ftp ftp.delos.com
>>> User: anonymous
- >>> Passwd: <Your Internet address>
+ >>> Passwd:
cd /pub/cvs
get README
get Index
@@ -8467,7 +8436,9 @@ kingdon@cyclic.com
A WWW home page is also available at http://www.delos.com/cvs.
- Last modified: _6/13/1997_
+ This Didn't Exist 6/23/1998
+
+ Last modified: _6/24/1998_
3. How do I get files out of the archive if I don't have FTP?
@@ -8569,17 +8540,17 @@ kingdon@cyclic.com
Last modified: _9/6/1997_
_________________________________________________________________
-
+
[Add an answer to this category]
[Category /]
_________________________________________________________________
-
- _Search the FAQ-O-Matic:_ ____________________ ______
+
+ _Search the FAQ-O-Matic:_ ____________________ Search
[matching all words]
- Or look for questions modified in the last: [7.] ____
+ Or look for questions modified in the last: [7.] Days
_________________________________________________________________
-
+
The FAQ-O-Matic lives at http://gille.loria.fr:7000/cgi-bin/faqomatic.
The code was written by Jon Howell, and the content by folks from all
over the web.
diff --git a/contrib/cvs/HACKING b/contrib/cvs/HACKING
index a1b3d37..aa6029d 100644
--- a/contrib/cvs/HACKING
+++ b/contrib/cvs/HACKING
@@ -98,32 +98,25 @@ Filenames for .c and .h files may contain _ but should not contain -
(the latter causes Visual C++ 2.1 to create makefiles which Visual C++
4.0 cannot use).
-* Submitting patches (strategy)
+* Writing patches (strategy)
Only some kinds of changes are suitable for inclusion in the
"official" CVS. Bugfixes, where CVS's behavior contradicts the
documentation and/or expectations that everyone agrees on, should be
OK (strategically). For features, the desirable attributes are that
the need is clear and that they fit nicely into the architecture of
-CVS.
-
-However, if there is reason to think that a change would significantly
-inconvenience any significant body of CVS users, or would be
-controversial for other reasons, then the design should be re-thought.
-Go back to the requirements (writing documentation might help, if you
-write the documentation to explain why one would use the feature not
-just what the feature does). Think about whether there is a behavior
-which works in both your situation and the other situations. Make a
-list of the issues (for example, submit a comment or documentation
-change). Ask your coworkers, a newsgroup, or a mailing list, and see
-what other people think. Distribute some experimental patches outside
-the "official" CVS and see what people think. By this process, the
-intention is that once-controversial changes can be refined to the
-point where they are relatively uncontroversial before they are
-actually checked in to the "official" CVS. Features like zlib,
-encryption, and others have benefitted from this process in the past
-by being mentioned in the documentation and/or discussed, before an
-implementation was checked in.
+CVS. Is it worth the cost (in terms of complexity or any other
+tradeoffs involved)? Are there better solutions?
+
+If the design is not yet clear (which is true of most features), then
+the design is likely to benefit from more work and community input.
+Make a list of issues, or write documentation including rationales for
+how one would use the feature. Discuss it with coworkers, a
+newsgroup, or a mailing list, and see what other people think.
+Distribute some experimental patches and see what people think. The
+intention is arrive at some kind of rough community consensus before
+changing the "official" CVS. Features like zlib, encryption, and
+the RCS library have benefitted from this process in the past.
If longstanding CVS behavior, that people may be relying on, is
clearly deficient, it can be changed, but only slowly and carefully.
@@ -131,37 +124,49 @@ For example, the global -q option was introduced in CVS 1.3 but the
command -q options, which the global -q replaced, were not removed
until CVS 1.6.
-* Submitting patches (tactics)
-
-Please include a ChangeLog entry (see the GNU coding standards for
-information on writing one) with patches. Include a description of
-what the patch does (sometimes the ChangeLog entry and/or comments in
-the code are appropriate for this, but not always)--patches should not
-be checked in unless there is some reason for them, and the
-description may be helpful if there is a better way to solve the
-problem. In addition to the ChangeLog entry, there should be a change
-to the NEWS file and cvs.texinfo, if the change is a user-visible
-change worth mentioning.
-
-It is nice to have a test case (see TESTS), especially for fixes which
-involve subtle behaviors or twisted sections of the code.
-
-If you solve several unrelated problems, submit a separate
-patch for each one. Patches should be tested before submission. Use
-context diffs or unidiffs for patches.
-
-Note that all submitted changes may be distributed under the terms of
-the GNU Public License, so if you don't like this, don't submit them.
-Submit changes to bug-cvs@gnu.org.
-
-Generally speaking if you follow the guidelines in this file you can
-expect a yes or no answer about whether your patch is accepted. But
-even in this case there is no guarantee because wading through a bunch
-of submissions can be time consuming, and noone has volunteered to
-offer any such guarantee. If you don't receive an answer one way or
-another within a month, feel free to ask what the status is. You can,
-if you wish, distribute your patch on mailing lists or newsgroups, if
-you want to make it available before it gets merged.
+* Writing patches (tactics)
+
+When you first distribute a patch it may be suitable to just put forth
+a rough patch, or even just an idea. But before the end of the
+process the following should exist:
+
+ - ChangeLog entry (see the GNU coding standards for details).
+
+ - Changes to the NEWS file and cvs.texinfo, if the change is a
+ user-visible change worth mentioning.
+
+ - Somewhere, a description of what the patch fixes (often in
+ comments in the code, or maybe the ChangeLog or documentation).
+
+ - Most of the time, a test case (see TESTS). It can be quite
+ frustrating to fix a bug only to see it reappear later, and adding
+ the case to the testsuite, where feasible, solves this and other
+ problems.
+
+If you solve several unrelated problems, it is generally easier to
+consider the desirability of the changes if there is a separate patch
+for each issue. Use context diffs or unidiffs for patches.
+
+Include words like "I grant permission to distribute this patch under
+the terms of the GNU Public License" with your patch. By sending a
+patch to bug-cvs@gnu.org, you implicitly grant this permission.
+
+Submitting a patch to bug-cvs is the way to reach the people who have
+signed up to receive such submissions (including CVS developers), but
+there may or may not be much (or any) response. If you want to pursue
+the matter further, you are probably best off working with the larger
+CVS community. Distribute your patch as widely as desired (mailing
+lists, newsgroups, web sites, whatever). Write a web page or other
+information describing what the patch is for. It is neither practical
+nor desirable for all/most contributions to be distributed through the
+"official" (whatever that means) mechanisms of CVS releases and CVS
+developers. Now, the "official" mechanisms do try to incorporate
+those patches which seem most suitable for widespread usage, together
+with test cases and documentation. So if a patch becomes sufficiently
+popular in the CVS community, it is likely that one of the CVS
+developers will eventually try to do something with it. But dealing
+with the CVS developers may be the last step of the process rather
+than the first.
* What is the schedule for the next release?
@@ -195,5 +200,5 @@ list which users are requested to send bug reports to. Anyone can
subscribe; to do so send mail to bug-cvs-request@gnu.org.
Other CVS discussions take place on the info-cvs mailing list
-(send mail to info-cvs-request@prep.ai.mit.edu to subscribe) or on
+(send mail to info-cvs-request@gnu.org to subscribe) or on
the newsgroup comp.software.config-mgmt.
diff --git a/contrib/cvs/INSTALL b/contrib/cvs/INSTALL
index 2528490..2400f07 100644
--- a/contrib/cvs/INSTALL
+++ b/contrib/cvs/INSTALL
@@ -108,8 +108,10 @@ Alpha:
DEC Alpha running OSF/1 version 2.1 (about 1.4A2)
DEC Alpha running OSF/1 version 3.0 (1.5.95) (footnote 7)
DEC Alpha running OSF/1 version 3.2 (1.9)
+ Alpha running alpha-dec-osf4.0 (1.10)
DEC Alpha running Digital UNIX v4.0C using gcc 2.7.2.2 (1.9.14)
DEC Alpha running VMS 6.2 (1.8.85 client-only)
+ Alpha running NetBSD 1.2E (1.10)
Cray:
J90 (CVS 970215 snapshot)
T3E (CVS 970215 snapshot)
@@ -124,17 +126,20 @@ HPPA:
NextSTEP 3.3 (1.7)
i386 family:
Solaris 2.4 using gcc (about 1.4A2)
+ Solaris 2.6 (1.9)
UnixWare v1.1.1 using gcc (about 1.4A2)
Unixware 2.1 (1.8.86)
Unixware 7 (1.9.29)
ISC 4.0.1 (1.8.87)
Linux (kernel 1.2.x) (1.8.86)
- Linux (kernel 2.0.x, RedHat 4.2) (1.9)
+ Linux (kernel 2.0.x, RedHat 4.2) (1.10)
+ Linux (kernel 2.0.x, RedHat 5.x) (1.10)
BSDI 2.0 (1.4.93) (footnote 5)
FreeBSD 2.1.5-stable (1.8.87)
NextSTEP 3.3 (1.7)
SCO Unix 3.2.4.2, gcc 2.7.2 (1.8.87) (footnote 4)
- SCO OpenServer 5 (1.9.29)
+ SCO OpenServer 5.0.5 (1.10.2)
+ Sequent DYNIX/ptx4.0 (1.10 or so) (remove -linet)
Sequent Dynix/PTX 4.1.4 (1.9.20 or so + patches)
Lynx 2.3.0 080695 (1.6.86) (footnote 9)
Windows NT 3.51 (1.8.86 client; 1.8.3 local)
@@ -150,17 +155,19 @@ m68k:
Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.8.86+)
NextSTEP 3.3p1 (1.8.87)
Lynx 2.3.0 062695 (1.6.86) (footnote 9)
+ NetBSD/mac68k (1.9.28)
m88k:
Data General AViiON running dgux 5.4R2.10 (1.5)
Data General AViiON running dgux 5.4R3.10 (1.7.1)
Harris Nighthawk 5800 running CX/UX 7.1 (1.5) (footnote 6)
MIPS:
DECstation running Ultrix 4.2a (1.4.90)
- DECstation running Ultrix 4.3 (1.8.85)
+ DECstation running Ultrix 4.3 (1.10)
SGI running Irix 4.0.5H using gcc and cc (about 1.4A2) (footnote 2)
- SGI running Irix 5.3 using gcc 2.7.2 (1.8.87)
+ SGI running Irix 5.3 (1.10)
SGI running Irix 6.2 using SGI MIPSpro 6.2 and beta 7.2 compilers (1.9)
SGI running Irix-6.2 (1.9.8)
+ SGI running IRIX 6.4 (1.10)
Siemens-Nixdorf RM600 running SINIX-Y (1.6)
PowerPC or RS/6000:
IBM RS/6000 running AIX 3.1 using gcc and cc (1.6.86)
@@ -168,12 +175,14 @@ PowerPC or RS/6000:
IBM RS/6000 running AIX 4.1 (1.9)
Lynx 2.3.1 120495 (1.6.86) (footnote 9)
Lynx 2.5 (1.9) (footnote 10)
+ MkLinux DR3 GENERIC #6 (1.10.5.1) (presumably LinuxPPC too)
SPARC:
- Sun SPARC running SunOS 4.1.x using gcc 2.7.2.1 (1.9.14)
+ Sun SPARC running SunOS 4.1.x (1.10)
Sun SPARCstation 10 running Solaris 2.3 using gcc and cc (about 1.4A2)
Sun SPARCstation running Solaris 2.4 using gcc and cc (about 1.5.91)
Sun SPARC running Solaris 2.5 (1.8.87)
Sun SPARC running Solaris 2.5.1 using gcc 2.7.2.2 (1.9.14)
+ Sun UltraSPARC running Solaris 2.6 using gcc 2.8.1 (1.10)
NextSTEP 3.3 (1.7)
Sun SPARC running Linux 2.0.17, gcc 2.7.2 (1.8.87)
VAX:
diff --git a/contrib/cvs/Makefile.in b/contrib/cvs/Makefile.in
index a7c69f1..dfced91 100644
--- a/contrib/cvs/Makefile.in
+++ b/contrib/cvs/Makefile.in
@@ -89,7 +89,7 @@ DISTFILES = \
ChangeLog NEWS ChangeLog.zoo \
configure configure.in stamp-h.in config.h.in Makefile.in acconfig.h \
cvs-format.el mkinstalldirs install-sh \
- cvsnt.mak cvsnt.dsp \
+ cvsnt.mak cvsnt.dsp cvsnt.dsw \
.cvsignore cvs.spec
### Subdirectories to run make in for the primary targets.
@@ -97,7 +97,7 @@ DISTFILES = \
USOURCE_SUBDIRS = lib zlib diff src
# All other subdirs:
SUBDIRS = ${USOURCE_SUBDIRS} man doc contrib tools \
- windows-NT os2 emx macintosh vms
+ windows-NT os2 emx vms
# Only make TAGS/tags files in these directories.
TSUBDIRS= src lib
diff --git a/contrib/cvs/NEWS b/contrib/cvs/NEWS
index 309c510..05506ef 100644
--- a/contrib/cvs/NEWS
+++ b/contrib/cvs/NEWS
@@ -1,4 +1,27 @@
-Changes since 1.9:
+Changes since 1.10:
+
+* There is a new access method :fork: which is similar to :local:
+except that it is implemented via the CVS remote protocol, and thus
+has a somewhat different set of quirks and bugs.
+
+* The -d command line option no longer updates the CVS/Root file. For
+one thing, the CVS 1.9/1.10 behavior never had updated CVS/Root in
+subdirectories, and for another, it didn't seem that popular in
+general. So this change restores the CVS 1.8 behavior (which is also
+the CVS 1.9/1.10 behavior if the environment variable
+CVS_IGNORE_REMOTE_ROOT is set; with this change,
+CVS_IGNORE_REMOTE_ROOT no longer has any effect).
+
+* It is now possible for a single CVS command to recurse into several
+CVS roots. This includes roots which are located on several servers,
+or which are both remote and local. CVS will make connections to as
+many servers as necessary.
+
+* It is now possible to put the CVS lock files in a directory
+set by the new LockDir option in CVSROOT/config. The default
+continues to be to put the lock files in the repository itself.
+
+Changes from 1.9 to 1.10:
* There is a new feature, enabled by TopLevelAdmin in CVSROOT/config,
which tells CVS to modify the behavior of the "checkout" command. The
diff --git a/contrib/cvs/TESTS b/contrib/cvs/TESTS
index 7281ac1..c27f970 100644
--- a/contrib/cvs/TESTS
+++ b/contrib/cvs/TESTS
@@ -17,11 +17,12 @@ can set the TESTDIR environment variable to the desired location
before running them.
You will probably need GNU expr, which is part of the GNU sh-utils
-package. You may also need sort from the GNU textutils; Solaris
-in particular has been reported to have a sort program which does not
-behave the way that the testsuite expects (with Solaris, lines
-starting with tabs sort before blank lines). These programs are just
-for running the tests; CVS itself doesn't require expr or sort.
+package. This is just for running the tests; CVS itself doesn't
+require expr.
+
+With CVS 1.10 people also had trouble with the Solaris sort program
+not behaving the way that the testsuite expects (with Solaris, lines
+starting with tabs sort before blank lines).
If there is some unexpected output, that is a failure which can be
somewhat hard to track down. Finding out which test is producing the
@@ -144,3 +145,8 @@ workaround).
b. pass stdin to the program under test (sanity.sh, again, handles
this by bypassing dotest).
+
+c. have a send-expect type dialog with the program under test
+ (e.g. see server-7 or pserver-4 which want to talk the CVS
+ protocol, or the many tests which need to answer the prompt of "cvs
+ release", e.g. deep-5).
diff --git a/contrib/cvs/TODO b/contrib/cvs/TODO
index cc40ab2..91313a3 100644
--- a/contrib/cvs/TODO
+++ b/contrib/cvs/TODO
@@ -11,6 +11,8 @@ too?). (perhaps should think a little harder about what this is
trying to accomplish and what the best way is -kingdon, Jul 1997).
31. Think hard about ^C recovery.
+ One particular issue: RCS removes the ,foo.c, file on ^C and CVS
+ doesn't.
38. Think hard about using RCS state information to allow one to checkin
a new vendor release without having it be accessed until it has been
@@ -254,10 +256,10 @@ trying to accomplish and what the best way is -kingdon, Jul 1997).
probably want to give an error if it disagreed with CVS/Root, as
CVS 1.8 and earlier did). The other is the "reposmv"
functionality above (in which the two repositories really are the
- same, and we want to update the CVS/Root files). A related issue
- is that the fact that CVS only sets and looks at the CVS/Root
- file in the directory where CVS is run; it doesn't do anything
- about CVS/Root files in subdirectories.
+ same, and we want to update the CVS/Root files). In CVS 1.9 and
+ 1.10, -d rewrites the CVS/Root file (but not in subdirectories).
+ This behavior was not particularly popular and has been since
+ reverted.
Note also RELATIVE_REPOS in options.h; it needs to be set for
changing CVS/Root (not CVS/Repository) to be sufficient in the
@@ -767,7 +769,8 @@ or vice versa.
a. Cases in which the status quo already sends a diff. For most text
files, this is probably already close to optimal. For binary files,
-and anomalous text files, it might be worth looking into other
+and anomalous (?) text files (e.g. those in which it would help to do
+moves, as well as adds and deletes), it might be worth looking into other
difference algorithms (see item #191).
b. Cases in which the status quo does not send a diff (e.g. "cvs
@@ -777,9 +780,9 @@ b1. With some frequency, people suggest rsync or a similar algorithm
(see ftp://samba.anu.edu.au/pub/rsync/). This could speed things up,
and in some ways involves the most minimal changes to the default CVS
paradigm. There are some downsides though: (1) there is an extra
-network turnaround, (2) the algorithm is not as efficient with network
-bandwidth as difference type programs (it transmits a fair bit of data
-to discover what a difference program discovers locally).
+network turnaround, (2) the algorithm needs to transmit some data to
+discover what difference type programs can discover locally (although
+this is only about 1% of the size of the files).
b2. If one is willing to require that users use "cvs edit" before
editing a file on the client side (in some cases, a development
@@ -788,3 +791,7 @@ request in the protocol could be extended to allow the client to just
send differences instead of entire files. In the degenerate case
(e.g. "cvs diff" without arguments) the required network traffic is
reduced to zero, and the client need not even contact the server.
+
+196. Using a CVSROOT with a trailing slash will confuse CVS. I think
+we need to add a call to strip_trailing_slashes in root.c
+(parse_cvsroot), but I haven't considered all of the ramifications.
diff --git a/contrib/cvs/configure b/contrib/cvs/configure
index 4fd7b5e..340c7ee 100755
--- a/contrib/cvs/configure
+++ b/contrib/cvs/configure
@@ -1782,7 +1782,7 @@ EOF
fi
-for ac_func in mkdir rename strstr dup2 strerror valloc waitpid memmove vasprintf strtoul
+for ac_func in mkdir rename strstr dup2 strerror valloc waitpid memmove strtoul
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
@@ -2939,7 +2939,7 @@ echo "default place for GSSAPI is $GSSAPI"
hold_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$GSSAPI/include "
-for ac_hdr in gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h
+for ac_hdr in krb5.h gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h
do
ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
@@ -2978,7 +2978,9 @@ done
CPPFLAGS=$hold_cppflags
-if test "$ac_cv_header_gssapi_h" = "yes" || test "$ac_cv_header_gssapi_gssapi_h" = "yes"; then
+if test "$ac_cv_header_krb5_h" = "yes" &&
+ (test "$ac_cv_header_gssapi_h" = "yes" ||
+ test "$ac_cv_header_gssapi_gssapi_h" = "yes"); then
cat >> confdefs.h <<\EOF
#define HAVE_GSSAPI 1
EOF
@@ -2994,7 +2996,7 @@ EOF
CPPFLAGS="-I$GSSAPI/include $CPPFLAGS"
if test "$ac_cv_header_gssapi_h" = "yes"; then
cat > conftest.$ac_ext <<EOF
-#line 2998 "configure"
+#line 3000 "configure"
#include "confdefs.h"
#include <gssapi.h>
EOF
@@ -3010,7 +3012,7 @@ rm -f conftest*
else
cat > conftest.$ac_ext <<EOF
-#line 3014 "configure"
+#line 3016 "configure"
#include "confdefs.h"
#include <gssapi/gssapi.h>
EOF
@@ -3036,7 +3038,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lgen $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 3040 "configure"
+#line 3042 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -3048,7 +3050,7 @@ int t() {
compile()
; return 0; }
EOF
-if { (eval echo configure:3052: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+if { (eval echo configure:3054: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3098,7 +3100,7 @@ if eval "test \"`echo '$''{'ac_cv_func_gethostname'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3102 "configure"
+#line 3104 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char gethostname(); below. */
@@ -3122,7 +3124,7 @@ gethostname();
; return 0; }
EOF
-if { (eval echo configure:3126: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+if { (eval echo configure:3128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_func_gethostname=yes"
else
@@ -3199,7 +3201,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lcrypt $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 3203 "configure"
+#line 3205 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -3211,7 +3213,7 @@ int t() {
crypt()
; return 0; }
EOF
-if { (eval echo configure:3215: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+if { (eval echo configure:3217: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3242,7 +3244,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3246 "configure"
+#line 3248 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -3266,7 +3268,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:3270: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+if { (eval echo configure:3272: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -3307,7 +3309,7 @@ if eval "test \"`echo '$''{'ccvs_cv_sys_cygwin32'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 3311 "configure"
+#line 3313 "configure"
#include "confdefs.h"
int main() { return 0; }
@@ -3315,7 +3317,7 @@ int t() {
return __CYGWIN32__;
; return 0; }
EOF
-if { (eval echo configure:3319: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3321: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ccvs_cv_sys_cygwin32=yes
else
@@ -3441,10 +3443,10 @@ ac_given_srcdir=$srcdir
ac_given_INSTALL="$INSTALL"
trap 'rm -fr `echo "Makefile lib/Makefile src/Makefile zlib/Makefile diff/Makefile doc/Makefile \
- man/Makefile tools/Makefile tools/pcl-cvs/Makefile \
- contrib/Makefile contrib/elib/Makefile \
+ man/Makefile tools/Makefile \
+ contrib/Makefile \
windows-NT/Makefile windows-NT/SCC/Makefile \
- os2/Makefile emx/Makefile macintosh/Makefile vms/Makefile \
+ os2/Makefile emx/Makefile vms/Makefile \
stamp-h config.h src/options.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS <<EOF
@@ -3495,10 +3497,10 @@ EOF
cat >> $CONFIG_STATUS <<EOF
CONFIG_FILES=\${CONFIG_FILES-"Makefile lib/Makefile src/Makefile zlib/Makefile diff/Makefile doc/Makefile \
- man/Makefile tools/Makefile tools/pcl-cvs/Makefile \
- contrib/Makefile contrib/elib/Makefile \
+ man/Makefile tools/Makefile \
+ contrib/Makefile \
windows-NT/Makefile windows-NT/SCC/Makefile \
- os2/Makefile emx/Makefile macintosh/Makefile vms/Makefile \
+ os2/Makefile emx/Makefile vms/Makefile \
stamp-h"}
EOF
cat >> $CONFIG_STATUS <<\EOF
diff --git a/contrib/cvs/configure.in b/contrib/cvs/configure.in
index 2907025..c60e98f 100644
--- a/contrib/cvs/configure.in
+++ b/contrib/cvs/configure.in
@@ -63,7 +63,7 @@ AC_TYPE_MODE_T
AC_TYPE_SIZE_T
AC_TYPE_PID_T
AC_STRUCT_ST_BLKSIZE
-AC_REPLACE_FUNCS(mkdir rename strstr dup2 strerror valloc waitpid memmove vasprintf strtoul)
+AC_REPLACE_FUNCS(mkdir rename strstr dup2 strerror valloc waitpid memmove strtoul)
AC_CHECK_FUNCS(fchmod fsync ftime mktemp putenv vprintf ftruncate timezone getpagesize initgroups fchdir sigaction sigprocmask sigvec sigsetmask sigblock tempnam tzset readlink wait3)
dnl
@@ -262,10 +262,12 @@ WITH_GSSAPI
hold_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$GSSAPI/include "
-AC_CHECK_HEADERS(gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h)
+AC_CHECK_HEADERS(krb5.h gssapi.h gssapi/gssapi.h gssapi/gssapi_generic.h)
CPPFLAGS=$hold_cppflags
-if test "$ac_cv_header_gssapi_h" = "yes" || test "$ac_cv_header_gssapi_gssapi_h" = "yes"; then
+if test "$ac_cv_header_krb5_h" = "yes" &&
+ (test "$ac_cv_header_gssapi_h" = "yes" ||
+ test "$ac_cv_header_gssapi_gssapi_h" = "yes"); then
AC_DEFINE(HAVE_GSSAPI)
includeopt="${includeopt} -I$GSSAPI/include"
# FIXME: This is ugly, but these things don't seem to be standardized.
@@ -381,8 +383,8 @@ test -f src/options.h && (
)
AC_OUTPUT(Makefile lib/Makefile src/Makefile zlib/Makefile diff/Makefile doc/Makefile \
- man/Makefile tools/Makefile tools/pcl-cvs/Makefile \
- contrib/Makefile contrib/elib/Makefile \
+ man/Makefile tools/Makefile \
+ contrib/Makefile \
windows-NT/Makefile windows-NT/SCC/Makefile \
- os2/Makefile emx/Makefile macintosh/Makefile vms/Makefile \
+ os2/Makefile emx/Makefile vms/Makefile \
stamp-h)
diff --git a/contrib/cvs/contrib/ChangeLog b/contrib/cvs/contrib/ChangeLog
index 8bf96a1..46cf007 100644
--- a/contrib/cvs/contrib/ChangeLog
+++ b/contrib/cvs/contrib/ChangeLog
@@ -1,3 +1,47 @@
+1999-01-19 Graham Stoney <greyham@research.canon.com.au>
+
+ * log.pl: The author commited the canonical perl "localtime" Y2K
+ offence, of printing "19$year" instead of (1900 + $year). Of
+ course, the result is non-compliance in year 2000. Fix it.
+
+1998-10-14 Jim Kingdon
+
+ * ccvs-rsh.pl: Removed; it was not in DISTFILES so it didn't
+ actually get distributed. I'm going to move it to the web on the
+ theory that the web is a better place for such things.
+ * README: Don't mention it.
+
+ * Makefile.in (dist-dir, distclean): Remove references to elib.
+ * elib: Remove this subdirectory and all its contents. It went
+ with pcl-cvs, which is no longer distributed with CVS.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * pvcs_to_rcs: Removed; it was not in DISTFILES so it didn't
+ actually get distributed. I'm going to move it to the web on the
+ theory that the web is a better place for such things.
+ * README: Don't mention it.
+
+1998-09-10 Jim Kingdon
+
+ Check in Paul Eggert <eggert@twinsun.com>'s submission of
+ 1998-08-15. I also ran "cvs admin -ko" on this file so that his
+ version number would be intact (not an ideal solution, because
+ people will import it into other repositories, but I don't feel
+ like hacking the master version).
+ * rcs2log.sh: Sync with master version at gnu.org.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Don't mention listener, since it was removed a while
+ ago.
+ * listen2.c, listen2.mak: Removed; because there is no easy way to
+ pass a socket (as opposed to file descriptor) from one process to
+ another on Windows, this isn't a promising approach (at least not
+ in this form).
+ * Makefile.in (DISTFILES): Remove them.
+ * .cvsignore: Remove listen2.ncb listen2.mdp Debug.
+
1998-05-11 W. Bradley Rubenstein
* log.pl: Check for errors from open and exec.
diff --git a/contrib/cvs/contrib/Makefile.in b/contrib/cvs/contrib/Makefile.in
index 9997bd8..1c56339 100644
--- a/contrib/cvs/contrib/Makefile.in
+++ b/contrib/cvs/contrib/Makefile.in
@@ -44,8 +44,7 @@ DISTFILES = \
Makefile.in clmerge.pl cln_hist.pl commit_prep.pl cvs2vendor.sh \
cvs_acls.pl cvscheck.sh cvscheck.man cvshelp.man descend.sh \
descend.man dirfns.shar log.pl log_accum.pl mfpipe.pl rcs-to-cvs.sh \
- rcs2log.sh rcslock.pl sccs2rcs.csh rcs2sccs.sh \
- listen2.c listen2.mak
+ rcs2log.sh rcslock.pl sccs2rcs.csh rcs2sccs.sh
# files installed in $(libdir)/cvs/contrib
#
@@ -110,7 +109,7 @@ clean:
.PHONY: clean
distclean: clean
- rm -f Makefile elib/Makefile $(PROGS) $(CONTRIB_PROGS)
+ rm -f Makefile $(PROGS) $(CONTRIB_PROGS)
.PHONY: distclean
realclean: distclean
@@ -121,7 +120,6 @@ dist-dir:
for i in ${DISTFILES}; do \
ln $(srcdir)/$${i} ${DISTDIR}; \
done
- cd elib; ${MAKE} dist-dir DISTDIR="../${DISTDIR}/elib"
.PHONY: dist-dir
subdir = contrib
diff --git a/contrib/cvs/contrib/README b/contrib/cvs/contrib/README
index 223b759..8a93f8f 100644
--- a/contrib/cvs/contrib/README
+++ b/contrib/cvs/contrib/README
@@ -64,9 +64,6 @@ An attempt at a table of Contents for this directory:
currently locked by someone else, as might be the
case for a binary file.
Contributed by John Rouillard <rouilj@cs.umb.edu>.
- ccvs-rsh A Perl script which allows "rsh pipelines" to
- be built in order to use Cyclic CVS from
- behind some varieties of firewall.
cvs_acls A perl script that implements Access Control Lists
by using the "commitinfo" hook provided with the
"cvs commit" command.
@@ -86,10 +83,6 @@ An attempt at a table of Contents for this directory:
into RCS files, retaining the info contained in the
SCCS file (like dates, author, and log message).
Contributed by Ken Cox <kenstir@viewlogic.com>.
- pvcs_to_rcs A perl script that can convert (some) PVCS histories
- into RCS files, retaining the info contained in the
- PVCS history. See the comments at the start of the
- file for more details.
intro.doc A user's view of what you need to know to get
started with CVS.
Contributed by <Steven.Pemberton@cwi.nl>.
@@ -105,10 +98,6 @@ An attempt at a table of Contents for this directory:
clmerge A perl script to handle merge conflicts in GNU
style ChangeLog files .
Contributed by Tom Tromey <tromey@busco.lanl.gov>.
- listener A program which listens to a TCP port, authenticates
- by hostname, then runs a subprocess whose input/output
- is redirected through the port.
- Contributed by Benjamin J. Lee <benjamin@cyclic.com>
cvs2vendor A shell script to move changes from a repository
that was started without a vendor branch to one
that has a vendor branch.
diff --git a/contrib/cvs/contrib/log.pl b/contrib/cvs/contrib/log.pl
index f1d66e3..3a8ad99 100644
--- a/contrib/cvs/contrib/log.pl
+++ b/contrib/cvs/contrib/log.pl
@@ -91,6 +91,7 @@ $mailcmd = "| Mail -s 'CVS update: $modulepath'";
@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
+$year += 1900;
# get a login name for the guy doing the commit....
#
@@ -111,12 +112,12 @@ if ($users) {
#
print OUT "\n";
print OUT "****************************************\n";
-print OUT "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
+print OUT "Date:\t$days[$wday] $mos[$mon] $mday, $year @ $hour:" . sprintf("%02d", $min) . "\n";
print OUT "Author:\t$login\n\n";
if (MAIL) {
print MAIL "\n";
- print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n";
+ print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, $year @ $hour:" . sprintf("%02d", $min) . "\n";
print MAIL "Author:\t$login\n\n";
}
diff --git a/contrib/cvs/contrib/rcs2log.sh b/contrib/cvs/contrib/rcs2log.sh
index 5548566..bc663d8 100644
--- a/contrib/cvs/contrib/rcs2log.sh
+++ b/contrib/cvs/contrib/rcs2log.sh
@@ -2,7 +2,8 @@
# RCS to ChangeLog generator
-# Generate a change log prefix from RCS files and the ChangeLog (if any).
+# Generate a change log prefix from RCS files (perhaps in the CVS repository)
+# and the ChangeLog (if any).
# Output the new prefix to standard output.
# You can edit this prefix by hand, and then prepend it to ChangeLog.
@@ -10,25 +11,49 @@
# Clump together log entries that start with `{topic} ',
# where `topic' contains neither white space nor `}'.
-# Author: Paul Eggert <eggert@twinsun.com>
+Help='The default FILEs are the files registered under the working directory.
+Options:
+
+ -c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog).
+ -h HOSTNAME Use HOSTNAME in change log entries (default current host).
+ -i INDENT Indent change log lines by INDENT spaces (default 8).
+ -l LENGTH Try to limit log lines to LENGTH characters (default 79).
+ -R If no FILEs are given and RCS is used, recurse through working directory.
+ -r OPTION Pass OPTION to subsidiary log command.
+ -t TABWIDTH Tab stops are every TABWIDTH characters (default 8).
+ -u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR.
+ -v Append RCS revision to file names in log lines.
+ --help Output help.
+ --version Output version number.
+
+Report bugs to <bug-gnu-emacs@gnu.org>.'
-# Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+Id='$Id: rcs2log,v 1.45 1998/08/12 22:33:01 eggert Exp $'
+
+# Copyright 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
+Copyright='Copyright 1998 Free Software Foundation, Inc.
+This program comes with NO WARRANTY, to the extent permitted by law.
+You may redistribute copies of this program
+under the terms of the GNU General Public License.
+For more information about these matters, see the files named COPYING.
+Author: Paul Eggert <eggert@twinsun.com>'
+
tab=' '
nl='
'
@@ -38,18 +63,23 @@ nl='
# defaults
: ${AWK=awk}
: ${TMPDIR=/tmp}
+changelog=ChangeLog # change log file name
+datearg= # rlog date option
hostname= # name of local host (if empty, will deduce it later)
indent=8 # indent of log line
length=79 # suggested max width of log line
logins= # login names for people we know fullnames and mailaddrs of
loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
+logTZ= # time zone for log dates (if empty, use local time)
recursive= # t if we want recursive rlog
+revision= # t if we want revision numbers
rlog_options= # options to pass to rlog
tabwidth=8 # width of horizontal tab
while :
do
case $1 in
+ -c) changelog=${2?}; shift;;
-i) indent=${2?}; shift;;
-h) hostname=${2?}; shift;;
-l) length=${2?}; shift;;
@@ -60,7 +90,10 @@ do
echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
exit 1
esac
- loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
+ case $loginFullnameMailaddrs in
+ '') loginFullnameMailaddrs=$2$tab$3$tab$4;;
+ ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
+ esac
shift; shift; shift;;
-u)
# If $2 is not tab-separated, use colon for separator.
@@ -83,19 +116,36 @@ do
echo >&2 "$0: -u '$2': not enough fields"
exit 1
esac
- loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
+ case $loginFullnameMailaddrs in
+ '') loginFullnameMailaddrs=$2;;
+ ?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
+ esac
shift
esac
- logins=$logins$nl$login
+ case $logins in
+ '') logins=$login;;
+ ?*) logins=$logins$nl$login
+ esac
;;
- -r) rlog_options=$rlog_options$nl${2?}; shift;;
+ -r)
+ case $rlog_options in
+ '') rlog_options=${2?};;
+ ?*) rlog_options=$rlog_options$nl${2?}
+ esac
+ shift;;
-R) recursive=t;;
-t) tabwidth=${2?}; shift;;
- -*) echo >&2 "$0: usage: $0 [options] [file ...]
-Options:
- [-h hostname] [-i indent] [-l length] [-R] [-r rlog_option]
- [-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..."
- exit 1;;
+ -v) revision=t;;
+ --version)
+ set $Id
+ rcs2logVersion=$3
+ echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
+ exit 0;;
+ -*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
+ case $1 in
+ --help) exit 0;;
+ *) exit 1
+ esac;;
*) break
esac
shift
@@ -106,12 +156,6 @@ month_data='
m[3]="Apr"; m[4]="May"; m[5]="Jun"
m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
-
- # days in non-leap year thus far, indexed by month (0-12)
- mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
- mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
- mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
- mo[12]=365
'
@@ -119,63 +163,59 @@ month_data='
# If no rlog options are given,
# log the revisions checked in since the first ChangeLog entry.
+# Since ChangeLog is only by date, some of these revisions may be duplicates of
+# what's already in ChangeLog; it's the user's responsibility to remove them.
case $rlog_options in
'')
- date=1970-01-01
- if test -s ChangeLog
+ if test -s "$changelog"
then
- # Add 1 to seconds to avoid duplicating most recent log.
e='
+ /^[0-9]+-[0-9][0-9]-[0-9][0-9]/{
+ # ISO 8601 date
+ print $1
+ exit
+ }
/^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
+ # old-fashioned date and time (Emacs 19.31 and earlier)
'"$month_data"'
year = $5
for (i=0; i<=11; i++) if (m[i] == $2) break
dd = $3
- hh = substr($0,12,2)
- mm = substr($0,15,2)
- ss = substr($0,18,2)
- ss++
- if (ss == 60) {
- ss = 0
- mm++
- if (mm == 60) {
- mm = 0
- hh++
- if (hh == 24) {
- hh = 0
- dd++
- monthdays = mo[i+1] - mo[i]
- if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
- if (dd == monthdays + 1) {
- dd = 1
- i++
- if (i == 12) {
- i = 0
- year++
- }
- }
- }
- }
- }
- printf "%02d/%02d/%d %02d:%02d:%02d\n", i+1,dd,year,hh,mm,ss
+ printf "%d-%02d-%02d\n", year, i+1, dd
exit
}
'
- d=`$AWK "$e" <ChangeLog` || exit
+ d=`$AWK "$e" <"$changelog"` || exit
case $d in
- ?*) date=$d
+ ?*) datearg="-d>$d"
esac
fi
- datearg="-d>$date"
esac
+# Use TZ specified by ChangeLog local variable, if any.
+if test -s "$changelog"
+then
+ extractTZ='
+ /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
+ s//\1/; p; q
+ }
+ /^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
+ s//UTC0/; p; q
+ }
+ '
+ logTZ=`tail "$changelog" | sed -n "$extractTZ"`
+ case $logTZ in
+ ?*) TZ=$logTZ; export TZ
+ esac
+fi
+
# If CVS is in use, examine its repository, not the normal RCS files.
if test ! -f CVS/Repository
then
rlog=rlog
repository=
else
- rlog='cvs log'
+ rlog='cvs -q log'
repository=`sed 1q <CVS/Repository` || exit
test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
case $CVSROOT in
@@ -196,6 +236,16 @@ else
esac
fi
+# Use $rlog's -zLT option, if $rlog supports it.
+case `$rlog -zLT 2>&1` in
+*' option'*) ;;
+*)
+ case $rlog_options in
+ '') rlog_options=-zLT;;
+ ?*) rlog_options=-zLT$nl$rlog_options
+ esac
+esac
+
# With no arguments, examine all files under the RCS directory.
case $# in
0)
@@ -210,7 +260,14 @@ case $# in
files=`
{
case $RCSdirs in
- ?*) find $RCSdirs -type f -print
+ ?*) find $RCSdirs \
+ -type f \
+ ! -name '*_' \
+ ! -name ',*,' \
+ ! -name '.*_' \
+ ! -name .rcsfreeze.log \
+ ! -name .rcsfreeze.ver \
+ -print
esac
find . -name '*,v' -print
} |
@@ -222,10 +279,16 @@ case $# in
for file in RCS/.* RCS/* .*,v *,v
do
case $file in
- RCS/. | RCS/..) continue;;
- RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
+ RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;;
+ RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;;
+ RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue;;
+ RCS/*,v | RCS/.*,v) ;;
+ RCS/* | RCS/.*) test -f "$file" || continue
+ esac
+ case $files in
+ '') files=$file;;
+ ?*) files=$files$nl$file
esac
- files=$files$nl$file
done
case $files in
'') exit 0
@@ -242,9 +305,9 @@ rlogout=$TMPDIR/rcs2log$$r
trap exit 1 2 13 15
trap "rm -f $llogout $rlogout; exit 1" 0
-case $rlog_options in
-?*) $rlog $rlog_options ${1+"$@"} >$rlogout;;
-'') $rlog "$datearg" ${1+"$@"} >$rlogout
+case $datearg in
+?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogout;;
+'') $rlog $rlog_options ${1+"$@"} >$rlogout
esac || exit
@@ -362,13 +425,16 @@ EOF
'
initialize_fullname=`
- (
- cat /etc/passwd
- for author in $authors
- do nismatch $author passwd.org_dir
- done
- ypmatch $authors passwd
- ) 2>/dev/null |
+ {
+ (getent passwd $authors) ||
+ (
+ cat /etc/passwd
+ for author in $authors
+ do NIS_PATH= nismatch $author passwd.org_dir
+ done
+ ypmatch $authors passwd
+ )
+ } 2>/dev/null |
$AWK -F: "$awkscript"
`$initialize_fullname
esac
@@ -376,7 +442,7 @@ esac
# Function to print a single log line.
# We don't use awk functions, to stay compatible with old awk versions.
-# `Log' is the log message (with \n replaced by \r).
+# `Log' is the log message (with \n replaced by \001).
# `files' contains the affected files.
printlogline='{
@@ -392,13 +458,13 @@ printlogline='{
# If "label: comment" is too long, break the line after the ":".
sep = " "
- if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
+ if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, SOH)) sep = "\n" indent_string
# Print the label.
printf "%s*%s:", indent_string, files
- # Print each line of the log, transliterating \r to \n.
- while ((i = index(Log, CR)) != 0) {
+ # Print each line of the log, transliterating \001 to \n.
+ while ((i = index(Log, SOH)) != 0) {
logline = substr(Log, 1, i-1)
if (logline ~ /[^'"$tab"' ]/) {
printf "%s%s\n", sep, logline
@@ -410,6 +476,9 @@ printlogline='{
}
}'
+# Pattern to match the `revision' line of rlog output.
+rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
+
case $hostname in
'')
hostname=`(
@@ -433,7 +502,7 @@ esac
# Process the rlog output, generating ChangeLog style entries.
# First, reformat the rlog output so that each line contains one log entry.
-# Transliterate \n to \r so that multiline entries fit on a single line.
+# Transliterate \n to \001 so that multiline entries fit on a single line.
# Discard irrelevant rlog output.
$AWK <$rlogout '
BEGIN { repository = "'"$repository"'" }
@@ -446,47 +515,66 @@ $AWK <$rlogout '
if (filename ~ /,v$/) {
filename = substr(filename, 1, length(filename) - 2)
}
+ if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
+ i = length(filename)
+ while (substr(filename, i, 1) != "/") i--
+ filename = substr(filename, 1, i - 6) substr(filename, i + 1)
+ }
}
+ rev = "?"
}
/^Working file:/ { if (repository == "") filename = $3 }
- /^date: /, /^(-----------*|===========*)$/ {
- if ($0 ~ /^branches: /) { next }
- if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) {
+ /'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
+ line = $0
+ if (line ~ /'"$rlog_revision_pattern"'/) {
+ rev = $2
+ next
+ }
+ if (line ~ /^date: [0-9][- +\/0-9:]*;/) {
date = $2
- if (date ~ /-/) {
- # An ISO format date. Replace all "-"s with "/"s.
+ if (date ~ /\//) {
+ # This is a traditional RCS format date YYYY/MM/DD.
+ # Replace "/"s with "-"s to get ISO format.
newdate = ""
- while ((i = index(date, "-")) != 0) {
- newdate = newdate substr(date, 1, i-1) "/"
+ while ((i = index(date, "/")) != 0) {
+ newdate = newdate substr(date, 1, i-1) "-"
date = substr(date, i+1)
}
date = newdate date
}
- # Ignore any time zone; ChangeLog has no room for it.
- time = substr($3, 1, 8)
+ time = substr($3, 1, length($3) - 1)
author = substr($5, 1, length($5)-1)
- printf "%s %s %s %s %c", filename, date, time, author, 13
+ printf "%s %s %s %s %s %c", filename, rev, date, time, author, 1
+ rev = "?"
next
}
- if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
- printf "%s%c", $0, 13
+ if (line ~ /^branches: /) { next }
+ if (line ~ /^(-----------*|===========*)$/) { print ""; next }
+ if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) {
+ line = "New file."
+ }
+ printf "%s%c", line, 1
}
' |
# Now each line is of the form
-# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
-# where \r stands for a carriage return,
-# and each line of the log is terminated by \r instead of \n.
+# FILENAME REVISION YYYY-MM-DD HH:MM:SS[+-TIMEZONE] AUTHOR \001LOG
+# where \001 stands for a carriage return,
+# and each line of the log is terminated by \001 instead of \n.
# Sort the log entries, first by date+time (in reverse order),
-# then by author, then by log entry, and finally by file name (just in case).
-sort +1 -3r +3 +0 |
+# then by author, then by log entry, and finally by file name and revision
+# (just in case).
+sort +2 -4r +4 +0 |
# Finally, reformat the sorted log entries.
$AWK '
BEGIN {
- # Some awk variants do not understand "\r" or "\013", so we have to
- # put a carriage return directly in the file.
- CR=" " # <-- There is a single CR between the " chars here.
+ logTZ = "'"$logTZ"'"
+ revision = "'"$revision"'"
+
+ # Some awk variants do not understand "\001", so we have to
+ # put the char directly in the file.
+ SOH="" # <-- There is a single SOH (octal code 001) here.
# Initialize the fullname and mailaddr associative arrays.
'"$initialize_fullname"'
@@ -500,28 +588,15 @@ $AWK '
indent_string = indent_string "\t"
while (1 <= i--)
indent_string = indent_string " "
-
- # Set up date conversion tables.
- # RCS uses a nice, clean, sortable format,
- # but ChangeLog wants the traditional, ugly ctime format.
-
- # January 1, 0 AD (Gregorian) was Saturday = 6
- EPOCH_WEEKDAY = 6
- # Of course, there was no 0 AD, but the algorithm works anyway.
-
- w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
- w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
-
- '"$month_data"'
}
{
- newlog = substr($0, 1 + index($0, CR))
+ newlog = substr($0, 1 + index($0, SOH))
# Ignore log entries prefixed by "#".
if (newlog ~ /^#/) { next }
- if (Log != newlog || date != $2 || author != $4) {
+ if (Log != newlog || date != $3 || author != $5) {
# The previous log and this log differ.
@@ -552,33 +627,25 @@ $AWK '
filesknown[i] = 0
files = ""
}
- if (date != $2 || author != $4) {
+ if (date != $3 || author != $5) {
# The previous date+author and this date+author differ.
# Print the new one.
- date = $2
- author = $4
-
- # Convert nice RCS date like "1992/01/03 00:03:44"
- # into ugly ctime date like "Fri Jan 3 00:03:44 1992".
- # Calculate day of week from Gregorian calendar.
- i = index($2, "/")
- year = substr($2, 1, i-1) + 0
- monthday = substr($2, i+1)
- i = index(monthday, "/")
- month = substr(monthday, 1, i-1) + 0
- day = substr(monthday, i+1) + 0
- leap = 0
- if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
- days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
-
- # Print "date fullname (email address)".
+ date = $3
+ time = $4
+ author = $5
+
+ zone = ""
+ if (logTZ && ((i = index(time, "-")) || (i = index(time, "+"))))
+ zone = " " substr(time, i)
+
+ # Print "date[ timezone] fullname <email address>".
# Get fullname and email address from associative arrays;
# default to author and author@hostname if not in arrays.
if (fullname[author])
auth = fullname[author]
else
auth = author
- printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth
+ printf "%s%s %s ", date, zone, auth
if (mailaddr[author])
printf "<%s>\n\n", mailaddr[author]
else
@@ -588,6 +655,7 @@ $AWK '
filesknown[$1] = 1
if (files == "") files = " " $1
else files = files ", " $1
+ if (revision && $2 != "?") files = files " " $2
}
}
END {
@@ -603,3 +671,7 @@ $AWK '
# Exit successfully.
exec rm -f $llogout $rlogout
+
+# Local Variables:
+# tab-width:4
+# End:
diff --git a/contrib/cvs/diff/ChangeLog b/contrib/cvs/diff/ChangeLog
index 3ebde5d..a435182 100644
--- a/contrib/cvs/diff/ChangeLog
+++ b/contrib/cvs/diff/ChangeLog
@@ -1,3 +1,70 @@
+1999-05-06 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Remove libdiff.mak.
+ * libdiff.mak: Removed; we are back to a single makefile for
+ Visual C++ version 4.
+
+1999-04-29 Jim Kingdon <http://www.cyclic.com>
+
+ * diff.c (diff_run): Use separate statement for setjmp call and if
+ statement. This is better style in general (IMHO) but in the case
+ of setjmp the UNICOS compiler apparently cares (I don't have the
+ standard handy, but there are lots of legitimate restrictions on
+ how you can call setjmp).
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add libdiff.dsp libdiff.mak .cvsignore.
+
+1999-04-26 (submitted 1999-03-24) John O'Connor <john@shore.net>
+
+ * libdiff.dsp: new file. MSVC project file used to build the library.
+
+ * libdiff.mak: new file. Makefile for building from the command-line.
+
+ * .cvsignore: Removed un-used entries related to MSVC. Added
+ entries to ignore directories generated by the NT build, Debug
+ and Release.
+
+1999-03-24 Larry Jones <larry.jones@sdrc.com>
+ and Olaf Brandes
+
+ * diff3.c (diff3_run): Use a separate stream for the input to
+ output_diff3_merge instead of reopening stdin to avoid problems
+ with leaving it open.
+
+1999-02-17 Jim Kingdon <http://www.cyclic.com>
+ and Hallvard B Furuseth.
+
+ * util.c: Use __STDC__ consistently with ./system.h.
+ * system.h: Add comment about PARAMS.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * Makefile.in, analyze.c, cmpbuf.c, cmpbuf.h, context.c, diff.c,
+ diff.h, diff3.c, diffrun.h, dir.c, ed.c, io.c, normal.c, system.h,
+ util.c: Remove paragraph containing the old snail mail address of
+ the Free Software Foundation.
+
+1998-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * util.c (printf_output): Make msg static; avoids auto
+ initializer, which is not portable to SunOS4 /bin/cc.
+ Reported by Mike Sutton@SAIC.
+
+1998-09-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (DISTFILES): Add diagmeet.note.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diffrun.h (struct diff_callbacks): Change calling convention of
+ write_output so that a zero length means to output zero bytes.
+ The cvs_output convention is just too ugly/error-prone.
+ * util.c (printf_output): Rewrite to parse format string
+ overselves rather than calling vasprintf, which cannot be
+ implemented in portable C.
+
1998-08-06 David Masterson of kla-tencor.com
* util.c (flush_output): Don't prototype.
diff --git a/contrib/cvs/diff/Makefile.in b/contrib/cvs/diff/Makefile.in
index b47d4c1..31f4910 100644
--- a/contrib/cvs/diff/Makefile.in
+++ b/contrib/cvs/diff/Makefile.in
@@ -12,10 +12,6 @@
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU DIFF; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
#### Start of system configuration section. ####
@@ -47,7 +43,8 @@ SOURCES = diff.c diff3.c analyze.c cmpbuf.c cmpbuf.h io.c context.c ed.c \
diffrun.h
OBJECTS = diff.o diff3.o analyze.o cmpbuf.o dir.o io.o util.o \
context.o ed.o ifdef.o normal.o side.o version.o
-DISTFILES = $(SOURCES) ChangeLog build_diff.com Makefile.in
+DISTFILES = $(SOURCES) ChangeLog build_diff.com Makefile.in diagmeet.note \
+ libdiff.dsp .cvsignore
all: libdiff.a
diff --git a/contrib/cvs/diff/analyze.c b/contrib/cvs/diff/analyze.c
index 0bda3cf..f292594 100644
--- a/contrib/cvs/diff/analyze.c
+++ b/contrib/cvs/diff/analyze.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
/* The basic algorithm is described in:
"An O(ND) Difference Algorithm and its Variations", Eugene Myers,
diff --git a/contrib/cvs/diff/cmpbuf.c b/contrib/cvs/diff/cmpbuf.c
index e95a8f9..2820dfa 100644
--- a/contrib/cvs/diff/cmpbuf.c
+++ b/contrib/cvs/diff/cmpbuf.c
@@ -11,9 +11,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ */
#include "system.h"
#include "cmpbuf.h"
diff --git a/contrib/cvs/diff/cmpbuf.h b/contrib/cvs/diff/cmpbuf.h
index e3852b7..b7b965d 100644
--- a/contrib/cvs/diff/cmpbuf.h
+++ b/contrib/cvs/diff/cmpbuf.h
@@ -13,8 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
size_t buffer_lcm PARAMS((size_t, size_t));
diff --git a/contrib/cvs/diff/context.c b/contrib/cvs/diff/context.c
index e843734..c4562c9 100644
--- a/contrib/cvs/diff/context.c
+++ b/contrib/cvs/diff/context.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
diff --git a/contrib/cvs/diff/diff.c b/contrib/cvs/diff/diff.c
index 3467b53..e5f7e42 100644
--- a/contrib/cvs/diff/diff.c
+++ b/contrib/cvs/diff/diff.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
/* GNU DIFF was written by Mike Haertel, David Hayes,
Richard Stallman, Len Tower, and Paul Eggert. */
@@ -690,7 +688,8 @@ diff_run (argc, argv, out, callbacks_arg)
/* Set the jump buffer, so that diff may abort execution without
terminating the process. */
- if ((val = setjmp (diff_abort_buf)) != 0)
+ val = setjmp (diff_abort_buf);
+ if (val != 0)
{
optind = optind_old;
if (opened_file)
diff --git a/contrib/cvs/diff/diff.h b/contrib/cvs/diff/diff.h
index 6107e62..642138d 100644
--- a/contrib/cvs/diff/diff.h
+++ b/contrib/cvs/diff/diff.h
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "system.h"
#include <stdio.h>
diff --git a/contrib/cvs/diff/diff3.c b/contrib/cvs/diff/diff3.c
index 64867f4..e3be150 100644
--- a/contrib/cvs/diff/diff3.c
+++ b/contrib/cvs/diff/diff3.c
@@ -11,9 +11,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ */
/* Written by Randy Smith */
/* Librarification by Tim Pierce */
@@ -459,13 +457,15 @@ diff3_run (argc, argv, out, callbacks_arg)
tag_strings[0], tag_strings[1], tag_strings[2]);
else if (merge)
{
- if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
+ FILE *mfp = fopen (file[rev_mapping[FILE0]], "r");
+ if (! mfp)
diff3_perror_with_exit (file[rev_mapping[FILE0]]);
- conflicts_found
- = output_diff3_merge (stdin, diff3, mapping, rev_mapping,
+ conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping,
tag_strings[0], tag_strings[1], tag_strings[2]);
- if (ferror (stdin))
+ if (ferror (mfp))
diff3_fatal ("read error");
+ if (fclose(mfp) != 0)
+ perror_with_name (file[rev_mapping[FILE0]]);
}
else
{
diff --git a/contrib/cvs/diff/diffrun.h b/contrib/cvs/diff/diffrun.h
index 28c1f45..08fbd0d 100644
--- a/contrib/cvs/diff/diffrun.h
+++ b/contrib/cvs/diff/diffrun.h
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#ifndef DIFFRUN_H
#define DIFFRUN_H
@@ -41,12 +39,14 @@ struct diff_callbacks
{
/* Write output. This function just writes a string of a given
length to the output file. The default is to fwrite to OUTFILE.
- If this callback is defined, flush_output must also be defined. */
+ If this callback is defined, flush_output must also be defined.
+ If the length is zero, output zero bytes. */
void (*write_output) DIFFPARAMS((char const *, size_t));
/* Flush output. The default is to fflush OUTFILE. If this
callback is defined, write_output must also be defined. */
void (*flush_output) DIFFPARAMS((void));
- /* Write to stdout. This is called for version and help messages. */
+ /* Write a '\0'-terminated string to stdout.
+ This is called for version and help messages. */
void (*write_stdout) DIFFPARAMS((char const *));
/* Print an error message. The first argument is a printf format,
and the next two are parameters. The default is to print a
diff --git a/contrib/cvs/diff/dir.c b/contrib/cvs/diff/dir.c
index 6eef9a6..fae74e8 100644
--- a/contrib/cvs/diff/dir.c
+++ b/contrib/cvs/diff/dir.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
diff --git a/contrib/cvs/diff/ed.c b/contrib/cvs/diff/ed.c
index 6b00d13..74fc2a4 100644
--- a/contrib/cvs/diff/ed.c
+++ b/contrib/cvs/diff/ed.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
diff --git a/contrib/cvs/diff/io.c b/contrib/cvs/diff/io.c
index 6605915..730c09a 100644
--- a/contrib/cvs/diff/io.c
+++ b/contrib/cvs/diff/io.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
diff --git a/contrib/cvs/diff/normal.c b/contrib/cvs/diff/normal.c
index 75dae88..b1f4955 100644
--- a/contrib/cvs/diff/normal.c
+++ b/contrib/cvs/diff/normal.c
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
diff --git a/contrib/cvs/diff/system.h b/contrib/cvs/diff/system.h
index 7812b76..76bc163 100644
--- a/contrib/cvs/diff/system.h
+++ b/contrib/cvs/diff/system.h
@@ -13,9 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
/* We must define `volatile' and `const' first (the latter inside config.h),
so that they're used consistently in all system includes. */
@@ -29,6 +27,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
+/* Note that PARAMS is just internal to the diff library; diffrun.h
+ has its own mechanism, which will hopefully be less likely to
+ conflict with the library's caller's namespace. */
#if __STDC__
#define PARAMS(args) args
#define VOID void
diff --git a/contrib/cvs/diff/util.c b/contrib/cvs/diff/util.c
index 1b28170..c4d2d71 100644
--- a/contrib/cvs/diff/util.c
+++ b/contrib/cvs/diff/util.c
@@ -13,13 +13,11 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GNU DIFF; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+*/
#include "diff.h"
-#ifdef __STDC__
+#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
@@ -340,14 +338,14 @@ write_output (text, len)
/* Printf something to the output file. */
-#ifdef __STDC__
+#if __STDC__
#define VA_START(args, lastarg) va_start(args, lastarg)
#else /* ! __STDC__ */
#define VA_START(args, lastarg) va_start(args)
#endif /* __STDC__ */
void
-#if defined (__STDC__)
+#if __STDC__
printf_output (const char *format, ...)
#else
printf_output (format, va_alist)
@@ -360,17 +358,51 @@ printf_output (format, va_alist)
VA_START (args, format);
if (callbacks && callbacks->write_output)
{
- char *p;
+ /* We implement our own limited printf-like functionality (%s, %d,
+ and %c only). Callers who want something fancier can use
+ sprintf. */
+ const char *p = format;
+ char *q;
+ char *str;
+ int num;
+ int ch;
+ unsigned char buf[100];
+
+ while ((q = strchr (p, '%')) != NULL)
+ {
+ static const char msg[] =
+ "\ninternal error: bad % in printf_output\n";
+ (*callbacks->write_output) (p, q - p);
- p = NULL;
- vasprintf (&p, format, args);
- if (p == NULL)
- fatal ("out of memory");
+ switch (q[1])
+ {
+ case 's':
+ str = va_arg (args, char *);
+ (*callbacks->write_output) (str, strlen (str));
+ break;
+ case 'd':
+ num = va_arg (args, int);
+ sprintf (buf, "%d", num);
+ (*callbacks->write_output) (buf, strlen (buf));
+ break;
+ case 'c':
+ ch = va_arg (args, int);
+ buf[0] = ch;
+ (*callbacks->write_output) (buf, 1);
+ break;
+ default:
+ (*callbacks->write_output) (msg, sizeof (msg) - 1);
+ /* Don't just keep going, because q + 1 might point to the
+ terminating '\0'. */
+ goto out;
+ }
+ p = q + 2;
+ }
(*callbacks->write_output) (p, strlen (p));
- free (p);
}
else
vfprintf (outfile, format, args);
+ out:
va_end (args);
}
diff --git a/contrib/cvs/doc/ChangeLog b/contrib/cvs/doc/ChangeLog
index e9e4925..33b7f91 100644
--- a/contrib/cvs/doc/ChangeLog
+++ b/contrib/cvs/doc/ChangeLog
@@ -1,3 +1,420 @@
+1999-07-16 Tom Tromey <tromey@cygnus.com>
+
+ * cvs.texinfo (admin): Mention admin -k exception. Add cvsadmin
+ to index.
+
+1999-07-14 Larry Jones <larry.jones@sdrc.com>
+
+ * cvs.texinfo (Password authentication server): Note inetd limits
+ and suggest using shell script to avoid.
+
+1999-06-01 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): For the import command, the
+ repository given to the Directory requests is ignored.
+
+1999-05-27 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Clarify that Modified, Is-modified,
+ Notify and Unchanged must specify a file within the current
+ directory.
+
+1999-05-24 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (checkoutlist): New node, contains more complete
+ documentation of this feature.
+ (CVSROOT storage): Refer to the new node when mentioning
+ checkoutlist.
+ (Administrative files): Update the menu entry for Wrappers.
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): For Notify request, strike duplicate
+ "Response expected: no" and fix "a edit" -> "an edit".
+
+1999-05-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Try to be more clear
+ about the conflict field.
+
+1999-05-11 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (config): Use comma after @xref (thanks to Pavel
+ Roskin for the report/fix).
+
+1999-05-10 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Document restrictions on characters
+ in Notify requests.
+
+1999-05-04 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Password authentication security): Remove sentence
+ about how no one has audited pserver for holes; a lot of holes
+ have been closed, looking for, &c, since that was written.
+ In the summary, reword to reflect the fact that sniffing a
+ readonly password does not imply general system access (as far as
+ I know, of course).
+
+ * cvs.texinfo (Connection): Also suggest inetd -d.
+
+1999-04-28 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Requests): Say what goes in the "watches" field
+ of the "Notify" request.
+
+ * cvs.texinfo (Common options): -r is for branches too.
+
+ * cvs.texinfo (Error messages): Add "no such tag" message.
+ (Common options): -f does not override val-tags check.
+
+1999-04-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Locks): #cvs.rfl locks must start with "#cvs.rfl."
+ not just "#cvs.rfl". As far as I know CVS has always implemented
+ the former behavior, and this just fixes the documentation.
+
+1999-04-23 Yoshiki Hayashi of u-tokyo.ac.jp
+
+ * cvs.texinfo (verifymsg): Correct wrong file name (bugid.edit ->
+ bugid.verify).
+
+1999-04-22 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Responses): The text in the "M" response is not
+ designed for machine parsing. Likewise for "error" in regular
+ protocol. Likewise for "E" and "error" in authentication protocol.
+
+1999-04-19 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "Cannot check out files into
+ the repository itself".
+
+1999-04-16 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Other problems): Add the Windows problem with home
+ directory ending in a slash.
+
+1999-04-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (CVS in repository): Include the format of the
+ fileattr file here, rather than referring to the CVS source code.
+
+1999-04-09 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Working directory storage): Whether the timestamp
+ in CVS/Entries is local or universal actually depends on the system.
+
+1999-04-05 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * cvs.texinfo (export options): Remove notation that the -r
+ tag is sticky. 'cvs export' doesn't store that data.
+
+1999-04-08 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "EOF in RCS file" and
+ "unexpected EOF" (in RCS file) messages.
+
+1999-03-25 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (admin options): Say there can be no space between
+ -e and its argument (since the previous sentence said the argument
+ can be omitted, this is the only possibility).
+
+1999-02-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Merging and keywords): When including conflict
+ markers, put @asis{} at the start of the line, in case this file
+ itself is in CVS. Thanks to Derek Price for pointing this out.
+
+1999-02-25 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo: Refer to "keywords" not "RCS keywords". We had
+ only used the latter term in a few places, and it seems like a
+ somewhat odd term in that this style of keyword is by no means
+ specific to RCS.
+ (Merging a branch): Remove spurious ")". Use ref, not xref, after
+ "see".
+ (Merging a branch, Substitution modes): Make sure that @ref is
+ followed by comma, since info wants that.
+ (Merging and keywords): Use samp not code for "-kk". Something of
+ a judgement call, but the rest of the manual uses samp and that
+ seems better to me.
+ (Merging and keywords): Rewrite, to (a) better motivate the
+ discussion based on what the user wants to do, (b) fix up lots of
+ convoluted sentences, (c) move the discussion of the binary files
+ to the end, that is get across the basic idea first and then
+ embellish it. Remove a few unnecessary index entries. Expand
+ example. Just tell people to avoid -kk with binary files (comment
+ out the discussion of using -A after the commit).
+
+1999-01-29 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * cvs.texinfo: Added new node/section on merging and keywords. It
+ contains advice on how to avoid RCS keyword conflicts when merging
+ and avoid corrupting your binary files while doing it.
+
+1999-02-24 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Request intro): Add paragraph about transmitting
+ more than one command.
+
+1999-01-29 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo: Use EXAMPLE.COM EXAMPLE.ORG and EXAMPLE.NET instead
+ of domains which might conflict with actual (current or future)
+ domains. The EXAMPLE domains are registered for this purpose.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Sticky tags): Refer to -j as the better way to undo
+ a change.
+ (Merging two revisions): Also talk about undoing removals and
+ adds. Move the index entries to here.
+
+1999-01-21 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Error messages): Add "waiting for USER's lock".
+
+1999-01-16 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Wrappers): Comment out all the -t/-f documentation,
+ since that feature is currently disabled.
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.texinfo (Connecting via rsh): Add some more index entries so
+ that people who want to use SSH and such are slightly less lost.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs-paper.ms: Remove comments which contained the FSF's old
+ address; it has changed.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * cvsclient.texi (Dates): Numeric timezones are preferred.
+ Also mention the Checkin-time request.
+
+1998-12-23 Jim Kingdon <http://www.cyclic.com>
+
+ * RCSFILES: Add clarification about certain character set issues
+ from Paul Eggert, the RCS maintainer. The last paragraph and the
+ change from Shift-JIS to JIS as an example of a character set
+ which contains 0x40 bytes which are not '@' characters are mine;
+ the rest is directly from Paul Eggert.
+
+1998-12-22 Martin Buchholz <martin@xemacs.org>
+
+ * cvs.texinfo: Fixed various trivial typos.
+
+1998-12-17 Jim Kingdon
+
+ * cvsclient.texi (Responses): Explicitly say that Mod-time need
+ not be sent for all files.
+
+1998-12-16 Jim Kingdon
+
+ Thanks to Ram Rajadhyaksha of the MacCVS Pro team for raising the
+ following issues.
+ * cvs.texinfo (Working directory storage): The deal about storing
+ files as text files applies to all the CVS/* files, not just
+ CVS/Entries. State the rationale too.
+ Document CVSROOT/Emptydir in CVS/Repository.
+ There is no set order in CVS/Entries.
+ Explicitly say that writing Entries.Log is optional.
+
+1998-12-03 Jim Kingdon
+
+ * cvs.texinfo (Error messages): Add "unrecognized auth response".
+ (Password authentication server): Remove comment about
+ "unrecognized auth response" and link to the troubleshooting
+ section.
+
+1998-12-02 Jim Kingdon
+
+ * cvs.texinfo (Multiple repositories): Add an example.
+
+1998-11-18 Jim Kingdon
+
+ * cvs.texinfo (Invoking CVS): Change "-r tag" to "-r rev". We
+ already use "tag" as the name of the tag we are adding.
+
+1998-11-13 Jim Kingdon
+
+ * cvs.texinfo (CVS commands): Add comment about whether part of
+ the manual should be organized by command.
+
+1998-11-06 Jim Kingdon
+
+ Clean up various confusions between modules and directories:
+ * cvs.texinfo: In "are you sure you want to release" message,
+ change module to directory. CVS was changed some time ago.
+ (Tags): "working copy of the module" -> "working directory".
+ (Merging two revisions): Remove unnecessary text "that make up a
+ module".
+ (Recursive behavior): Change "module" to "directory".
+ (Removing files): Likewise.
+ (Tracking sources): Remove "a module" from titles.
+ (Moving directories): Change "module" to "parent-dir".
+ (Inside): Remove "of the module".
+ (Inside): Change "module" to "dir".
+ (Rename by copying): Change "module" to "dir".
+ (Rename by copying): Remove "of the module".
+ (Moving directories): "copy of the module" -> "checked out copy of
+ the directory"; remove second "of the module". Change "check out
+ the module" to " check out again".
+ (Moving directories): Remove "of the module".
+ (Keyword substitution): "your working copy of a module" -> "a
+ working directory".
+ (CVS commands): Change "module" to "directory".
+ (release examples): "module" -> "tc directory".
+ (commitinfo): "relative path to the module" -> "directory in the
+ repository".
+ (verifymsg): Change "module" to "directory".
+ (Updating a file): "working copy of a module" -> "working directory".
+
+1998-10-25 Jim Kingdon
+
+ * cvs.texinfo (Branches and revisions): Fix error in branch
+ numbering which was introduced with change of 4 May 1997.
+
+1998-10-20 Jim Kingdon
+
+ * cvs.texinfo (Tags): Point to Invoking CVS node so people aren't
+ left wondering what the syntax is. When introducing -r option,
+ warn people about sticky tags right off.
+ (Tagging the working directory, Tagging by date/tag, Modifying
+ tags, Tagging add/remove): New sections.
+ (Invoking CVS): Adjust tag and rtag to point to the new sections,
+ and to add tag -c which had been omitted. Delete tag -n; there is
+ no such option.
+ (rtag, tag): Removed; no longer needed.
+ (commit examples): Update xref.
+
+1998-10-15 Jim Kingdon
+
+ * cvsclient.texi (Requests): It is OK to send Set before Root.
+
+1998-10-13 Jim Kingdon
+
+ * cvsclient.texi (Protocol Notes): Remove item about "cvs update"
+ sending modified files to the server; there are some better ideas
+ at http://www.cyclic.com/cvs/dev-update.txt
+ Add mention of www.cyclic.com.
+
+1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Committing your changes, Environment variables):
+ Document VISUAL.
+
+1998-09-27 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Password authentication server): Say explicitly
+ that you edit passwd directly, many users get confused by this.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Connecting via fork): :fork: may be of interest to
+ users, for example those who prefer CVS to prompt for one log
+ message per checkin, rather than one per directory.
+ (Connecting via fork): Document CVS_SERVER.
+
+1998-09-24 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Connecting via fork): new node about the fork
+ access method.
+
+1998-09-22 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Environment variables): Document
+ CVS_IGNORE_REMOTE_ROOT in the CVS 1.10 context.
+ (Moving a repository): Update comments concerning surgery on
+ CVS/Root and CVS/Repository files.
+
+1998-09-21 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Environment variables): remove information about
+ CVS_IGNORE_REMOTE_ROOT, since it's no longer used.
+
+1998-09-21 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): Mention that CVS 1.10 doesn't have
+ LockDir.
+
+1998-09-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list): Describe $Name and checking out with
+ a revision.
+
+1998-09-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo: RFC2346 is out; update comment.
+
+1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Keyword list, Substitution modes): In describing
+ $Locker and -kkvl, refer to cvs admin -l.
+
+ * cvsclient.texi (Requests): Re-word description of Sticky to
+ allow room for "Ntagname" (or other, future, values).
+
+ * cvs.texinfo (tag): Remove confusing wording about supplying
+ revision numbers "implicitly".
+
+1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (rdiff options): Thanks to the diff library, -u is
+ supported regardless of your diff program.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (config): Add LockDir.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): "Directory" and "Argument" are
+ requests, not commands. Likewise for "other-request". A command,
+ roughly, is a request that uses "Argument"s, but we might want to
+ phase out the use of that term more so than codify it, I'm not sure.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvsclient.texi (Requests): added a detailed explanation of the
+ Directory request and how it is handled, both for pre-1.10 and
+ post-1.10 servers.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Multiple repositories): Also describe the CVS 1.10
+ behavior. Looking at a mismatched version of the manual seems to
+ be a reasonably common occurrence.
+
+ * cvs.texinfo (Environment variables): Revert change regarding
+ CVS_SERVER_SLEEP*; having that kind of debugging code in the main
+ CVS is getting out of hand.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * cvs.texinfo (Multiple repositories): brief mention that cvs now
+ handles a working directory composed of multiple repositories.
+ (Environment variables): add note about CVS_SERVER_SLEEP2.
+
+1998-08-21 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvsclient.texi (Text tags): Document importmergecmd tag.
+
+1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.texinfo (Common options): Replace out of date URL concerning
+ ISO8601 dates with a more general statement and a few comments.
+
+1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvsclient.texi (Requests): Add "Checkin-time" request.
+
Sun Jul 26 02:42:20 1998 Noel Cragg <noel@swish.red-bean.com>
* cvs.texinfo (config): TopLevelAdmin variable.
diff --git a/contrib/cvs/doc/RCSFILES b/contrib/cvs/doc/RCSFILES
index 13c4f93..4650337 100644
--- a/contrib/cvs/doc/RCSFILES
+++ b/contrib/cvs/doc/RCSFILES
@@ -136,6 +136,36 @@ Both RCS 5.7 and current versions of CVS handle the $Log keyword in a
different way if the log message starts with "checked in with -k by ".
I don't think this behavior is documented anywhere.
+Here is a clarification regarding characters versus bytes in certain
+character sets like JIS and Big5:
+
+ The RCS file format, as described in the rcsfile(5) man page, is
+ actually byte-oriented, not character-oriented, despite hints to
+ the contrary in the man page. This distinction is important for
+ multibyte characters. For example, if a multibyte character
+ contains a `@' byte, the `@' must be doubled within strings in RCS
+ files, since RCS uses `@' bytes as escapes.
+
+ This point is not an issue for encodings like ISO 8859, which do
+ not have multibyte characters. Nor is it an issue for encodings
+ like UTF-8 and EUC-JIS, which never uses ASCII bytes within a
+ multibyte character. It is an issue only for multibyte encodings
+ like JIS and BIG5, which _do_ usurp ASCII bytes.
+
+ If `@' doubling occurs within a multibyte char, the resulting RCS
+ file is not a properly encoded text file. Instead, it is a byte
+ stream that does not use a consistent character encoding that can
+ be understood by the usual text tools, since doubling `@' messes
+ up the encoding. This point affects only programs that examine
+ the RCS files -- it doesn't affect the external RCS interface, as
+ the RCS commands always give you the properly encoded text files
+ and logs (assuming that you always check in properly encoded
+ text).
+
+ CVS 1.10 (and earlier) probably has some bugs in this area on
+ systems where a C "char" is signed and where the data contains
+ bytes with the eighth bit set.
+
One common concern about the RCS file format is the fact that to get
the head of a branch, one must apply deltas from the head of the trunk
to the branchpoint, and then from the branchpoint to the head of the
diff --git a/contrib/cvs/doc/cvs-paper.ms b/contrib/cvs/doc/cvs-paper.ms
index 567179b..ea9445a 100644
--- a/contrib/cvs/doc/cvs-paper.ms
+++ b/contrib/cvs/doc/cvs-paper.ms
@@ -14,10 +14,6 @@
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
-.\" You should have received a copy of the GNU General Public License
-.\" along with this program; if not, write to the Free Software
-.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\"
.\" The author can be reached at: berliner@prisma.com
.\"
.de SP
diff --git a/contrib/cvs/doc/cvs.texinfo b/contrib/cvs/doc/cvs.texinfo
index 5dd2f77..4d8b949 100644
--- a/contrib/cvs/doc/cvs.texinfo
+++ b/contrib/cvs/doc/cvs.texinfo
@@ -1,13 +1,13 @@
\input texinfo @c -*-texinfo-*-
@comment Documentation for CVS.
-@comment Copyright (C) 1992, 1993 Signum Support AB
+@comment Copyright (C) 1992, 1993, 1999 Signum Support AB
@comment Copyright (C) 1993 Free Software Foundation, Inc.
@comment This file is part of the CVS distribution.
@comment CVS is free software; you can redistribute it and/or modify
@comment it under the terms of the GNU General Public License as published by
-@comment the Free Software Foundation; either version 1, or (at your option)
+@comment the Free Software Foundation; either version 2, or (at your option)
@comment any later version.
@comment CVS is distributed in the hope that it will be useful,
@@ -27,8 +27,7 @@
@c http://www.ft.uni-erlangen.de/~mskuhn/iso-paper.html
@c for more on paper sizes. Insuring that margins are
@c big enough to print on either A4 or US letter does
-@c indeed seem to be the usual approach (according to
-@c an internet draft by Jacob Palme).
+@c indeed seem to be the usual approach (RFC2346).
@c This document seems to get overfull hboxes with some
@c frequency (probably because the tendency is to
@@ -556,6 +555,14 @@ which will vary with your operating system, for example
@code{vi} for unix or @code{notepad} for Windows
NT/95.
+@cindex VISUAL, environment variable
+In addition, @sc{cvs} checks the @code{$VISUAL} environment
+variable. Opinions vary on whether this behavior is desirable and
+whether future releases of @sc{cvs} should check @code{$VISUAL} or
+ignore it. You will be OK either way if you make sure that
+@code{$VISUAL} is either unset or set to the same thing as
+@code{$EDITOR}.
+
@c This probably should go into some new node
@c containing detailed info on the editor, rather than
@c the intro. In fact, perhaps some of the stuff with
@@ -624,7 +631,7 @@ $ cvs release -d tc
M driver.c
? tc
You have [1] altered files in this repository.
-Are you sure you want to release (and delete) module `tc': n
+Are you sure you want to release (and delete) directory `tc': n
** `release' aborted by user choice.
@end example
@@ -686,7 +693,7 @@ $ cd ..
$ cvs release -d tc
? tc
You have [0] altered files in this repository.
-Are you sure you want to release (and delete) module `tc': y
+Are you sure you want to release (and delete) directory `tc': y
@end example
@c ---------------------------------------------------------------------
@@ -818,10 +825,8 @@ repository, it will remember where its repository is
The @code{-d} option and the @file{CVS/Root} file both
override the @code{$CVSROOT} environment variable. If
@code{-d} option differs from @file{CVS/Root}, the
-former is used (and specifying @code{-d} will cause
-@file{CVS/Root} to be updated). Of course, for proper
-operation they should be two ways of referring to the
-same repository.
+former is used. Of course, for proper operation they
+should be two ways of referring to the same repository.
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Repository storage
@@ -1177,8 +1182,7 @@ non-@code{dead} state.
The @file{CVS} directory in each repository directory
contains information such as file attributes (in a file
-called @file{CVS/fileattr}; see fileattr.h in the CVS
-source distribution for more documentation). In the
+called @file{CVS/fileattr}. In the
future additional files may be added to this directory,
so implementations should silently ignore additional
files.
@@ -1186,6 +1190,86 @@ files.
This behavior is implemented only by @sc{cvs} 1.7 and
later; for details see @ref{Watches Compatibility}.
+The format of the fileattr file is a series of entries
+of the following form (where @samp{@{} and @samp{@}}
+means the text between the braces can be repeated zero
+or more times):
+
+@var{ent-type} @var{filename} <tab> @var{attrname} = @var{attrval}
+ @{; @var{attrname} = @var{attrval}@} <linefeed>
+
+@var{ent-type} is @samp{F} for a file, in which case the entry specifies the
+attributes for that file.
+
+@var{ent-type} is @samp{D},
+and @var{filename} empty, to specify default attributes
+to be used for newly added files.
+
+Other @var{ent-type} are reserved for future expansion. CVS 1.9 and older
+will delete them any time it writes file attributes.
+CVS 1.10 and later will preserve them.
+
+Note that the order of the lines is not significant;
+a program writing the fileattr file may
+rearrange them at its convenience.
+
+There is currently no way of quoting tabs or linefeeds in the
+filename, @samp{=} in @var{attrname},
+@samp{;} in @var{attrval}, etc. Note: some implementations also
+don't handle a NUL character in any of the fields, but
+implementations are encouraged to allow it.
+
+By convention, @var{attrname} starting with @samp{_} is for an attribute given
+special meaning by CVS; other @var{attrname}s are for user-defined attributes
+(or will be, once implementations start supporting user-defined attributes).
+
+Builtin attributes:
+
+@table @code
+@item _watched
+Present means the file is watched and should be checked out
+read-only.
+
+@item _watchers
+Users with watches for this file. Value is
+@var{watcher} > @var{type} @{ , @var{watcher} > @var{type} @}
+where @var{watcher} is a username, and @var{type}
+is zero or more of edit,unedit,commit separated by
+@samp{+} (that is, nothing if none; there is no "none" or "all" keyword).
+
+@item _editors
+Users editing this file. Value is
+@var{editor} > @var{val} @{ , @var{editor} > @var{val} @}
+where @var{editor} is a username, and @var{val} is
+@var{time}+@var{hostname}+@var{pathname}, where
+@var{time} is when the @code{cvs edit} command (or
+equivalent) happened,
+and @var{hostname} and @var{pathname} are for the working directory.
+@end table
+
+Example:
+
+@c FIXME: sanity.sh should contain a similar test case
+@c so we can compare this example from something from
+@c Real Life(TM). See cvsclient.texi (under Notify) for more
+@c discussion of the date format of _editors.
+@example
+Ffile1 _watched=;_watchers=joe>edit,mary>commit
+Ffile2 _watched=;_editors=sue>8 Jan 1975+workstn1+/home/sue/cvs
+D _watched=
+@end example
+
+means that the file @file{file1} should be checked out
+read-only. Furthermore, joe is watching for edits and
+mary is watching for commits. The file @file{file2}
+should be checked out read-only; sue started editing it
+on 8 Jan 1975 in the directory @file{/home/sue/cvs} on
+the machine @code{workstn1}. Future files which are
+added should be checked out read-only. To represent
+this example here, we have shown a space after
+@samp{D}, @samp{Ffile1}, and @samp{Ffile2}, but in fact
+there must be a single tab character there and no spaces.
+
@node Locks
@subsection CVS locks in the repository
@@ -1205,7 +1289,7 @@ operating systems or databases.
@cindex #cvs.tfl
Any file in the repository with a name starting
-with @file{#cvs.rfl} is a read lock. Any file in
+with @file{#cvs.rfl.} is a read lock. Any file in
the repository with a name starting with
@file{#cvs.wfl} is a write lock. Old versions of CVS
(before CVS 1.5) also created files with names starting
@@ -1220,7 +1304,7 @@ be true for creating a directory under most operating
systems). If it fails because the directory already
existed, wait for a while and try again. After
obtaining the @file{#cvs.lock} lock, create a file
-whose name is @file{#cvs.rfl} followed by information
+whose name is @file{#cvs.rfl.} followed by information
of your choice (for example, hostname and process
identification number). Then remove the
@file{#cvs.lock} directory to release the master lock.
@@ -1231,7 +1315,7 @@ read lock.
To obtain a writelock, first create the
@file{#cvs.lock} directory, as with a readlock. Then
check that there are no files whose names start with
-@file{#cvs.rfl}. If there are, remove
+@file{#cvs.rfl.}. If there are, remove
@file{#cvs.lock}, wait for a while, and try again. If
there are no readers, then create a file whose name is
@file{#cvs.wfl} followed by information of your choice
@@ -1287,14 +1371,12 @@ cvs commit: Rebuilding administrative file database
@end example
@noindent
-@cindex checkoutlist
and update the checked out copy in
@file{$CVSROOT/CVSROOT}. If it does not, there is
something wrong (@pxref{BUGS}). To add your own files
to the files to be updated in this fashion, you can add
-them to the @file{checkoutlist} administrative file.
-@c FIXME: checkoutlist probably should be documented
-@c somewhat more completely.
+them to the @file{checkoutlist} administrative file
+(@pxref{checkoutlist}).
@cindex modules.db
@cindex modules.pag
@@ -1349,6 +1431,14 @@ silently ignore files which are in the directory but
which are not documented here, to allow for future
expansion.
+The files are stored according to the text file
+convention for the system in question. This means that
+working directories are not portable between systems
+with differing conventions for storing text files.
+This is intentional, on the theory that the files being
+managed by CVS probably will not be portable between
+such systems either.
+
@table @file
@item Root
This file contains the current @sc{cvs} root, as
@@ -1390,19 +1480,15 @@ or
yoyodyne/tc
@end example
+If the particular working directory does not correspond
+to a directory in the repository, then @file{Repository}
+should contain @file{CVSROOT/Emptydir}.
+
@cindex Entries file, in CVS directory
@cindex CVS/Entries file
@item Entries
This file lists the files and directories in the
-working directory. It is a text file according to the
-conventions appropriate for the operating system in
-question.
-@c Using OS text file conventions makes it impossible (it
-@c would seem) to share a working directory via a
-@c networked file system between systems with diverse
-@c text file conventions. But that might be correct,
-@c because the text files under CVS control are subject
-@c to the same problem. It is also the status quo.
+working directory.
The first character of each line indicates what sort of
line it is. If the character is unrecognized, programs
reading the file should silently skip that line, to
@@ -1424,7 +1510,7 @@ revision for a removed file. @var{timestamp} is the
timestamp of the file at the time that @sc{cvs} created
it; if the timestamp differs with the actual
modification time of the file it means the file has
-been modified. It is in Universal Time (UT), stored in
+been modified. It is stored in
the format used by the ISO C asctime() function (for
example, @samp{Sun Apr 7 01:29:26 1996}). One may
write a string which is not in that format, for
@@ -1433,8 +1519,10 @@ file should always be considered to be modified. This
is not a special case; to see whether a file is
modified a program should take the timestamp of the file
and simply do a string compare with @var{timestamp}.
-@var{conflict} indicates that there was
-a conflict; if it is the same as the actual
+If there was a conflict, @var{conflict} can be set to
+the modification time of the file after the file has been
+written with conflict markers (@pxref{Conflicts example}).
+Thus if @var{conflict} is subsequently the same as the actual
modification time of the file it means that the user
has obviously not resolved the conflict. @var{options}
contains sticky options (for example @samp{-kb} for a
@@ -1446,6 +1534,19 @@ rather than a single timestamp, you are dealing with a
version of @sc{cvs} earlier than @sc{cvs} 1.5 (not
documented here).
+The timezone on the timestamp in CVS/Entries (local or
+universal) should be the same as the operating system
+stores for the timestamp of the file itself. For
+example, on Unix the file's timestamp is in universal
+time (UT), so the timestamp in CVS/Entries should be
+too. On @sc{vms}, the file's timestamp is in local
+time, so @sc{cvs} on @sc{vms} should use local time.
+This rule is so that files do not appear to be modified
+merely because the timezone changed (for example, to or
+from summer time).
+@c See comments and calls to gmtime() and friends in
+@c src/vers_ts.c (function time_stamp).
+
If the first character of a line in @file{Entries} is
@samp{D}, then it indicates a subdirectory. @samp{D}
on a line all by itself indicates that the program
@@ -1464,6 +1565,8 @@ all the @var{filler} fields should be silently ignored,
for future expansion. Programs which modify
@code{Entries} files should preserve these fields.
+The lines in the @file{Entries} file can be in any order.
+
@cindex Entries.Log file, in CVS directory
@cindex CVS/Entries.Log file
@item Entries.Log
@@ -1492,6 +1595,9 @@ in @file{Entries.Log} is not a space, then it was
written by an older version of @sc{cvs} (not documented
here).
+Programs which are writing rather than reading can
+safely ignore @file{Entries.Log} if they so choose.
+
@cindex Entries.Backup file, in CVS directory
@cindex CVS/Entries.Backup file
@item Entries.Backup
@@ -1706,23 +1812,31 @@ to check out the working directory
(@pxref{Specifying a repository}).
The big advantage of having multiple repositories is
-that they can reside on different servers. The big
-disadvantage is that you cannot have a single @sc{cvs}
-command recurse into directories which comes from
-different repositories. Generally speaking, if you are
-thinking of setting up several repositories on the same
-machine, you might want to consider using several
-directories within the same repository.
-@c FIXCVS: the thing about recursing into diverse roots
-@c would be nice to fix. But it gets hairy if they are
-@c on diverse servers--it isn't clear this is really
-@c all that useful.
+that they can reside on different servers. With @sc{cvs}
+version 1.10, a single command cannot recurse into
+directories from different repositories. With development
+versions of @sc{cvs}, you can check out code from multiple
+servers into your working directory. @sc{cvs} will
+recurse and handle all the details of making
+connections to as many server machines as necessary to
+perform the requested command. Here is an example of
+how to set up a working directory:
+
+@example
+cvs -d server1:/cvs co dir1
+cd dir1
+cvs -d server2:/root co sdir
+cvs update
+@end example
+
+The @code{cvs co} commands set up the working
+directory, and then the @code{cvs update} command will
+contact server2, to update the dir1/sdir subdirectory,
+and server1, to update everything else.
+
@c FIXME: Does the FAQ have more about this? I have a
@c dim recollection, but I'm too lazy to check right now.
-None of the examples in this manual show multiple
-repositories.
-
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Creating a repository
@section Creating a repository
@@ -1755,7 +1869,7 @@ approximately one working directory for each developer
(either the entire tree or a portion of it, depending
on what each developer uses).
-The repository should be accessable
+The repository should be accessible
(directly or via a networked file system) from all
machines which want to use @sc{cvs} in server or local
mode; the client machines need not have any access to
@@ -1863,14 +1977,12 @@ see @ref{Working directory storage}, for information on
the @file{CVS/Repository} and @file{CVS/Root} files, but
unless you are sure you want to bother, it probably
isn't worth it.
-@c FIXME: This should be made unnecessary by:
-@c 1) a new -d should affect CVS/Root files throughout
-@c the tree, not just at the top level.
-@c 2) the RELATIVE_REPOS code should be fixed and made the
-@c default. I think that CVS already reads
-@c CVS/Repository files which are absolute or
-@c relative. FIXME: needs more investigation and
-@c documentation in "Working directory storage".
+@c FIXME: Surgery on CVS/Repository should be avoided
+@c by making RELATIVE_REPOS the default.
+@c FIXME-maybe: might want some documented way to
+@c change the CVS/Root files in some particular tree.
+@c But then again, I don't know, maybe just having
+@c people do this in perl/shell/&c isn't so bad...
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Remote repositories
@@ -1926,6 +2038,7 @@ described in @ref{Connecting via rsh}.
* Password authenticated:: Direct connections using passwords
* GSSAPI authenticated:: Direct connections using GSSAPI
* Kerberos authenticated:: Direct connections with kerberos
+* Connecting via fork:: Using a forked @code{cvs server} to connect
@end menu
@node Server requirements
@@ -2027,19 +2140,19 @@ operations, so the remote user host needs to have a
user.
For example, suppose you are the user @file{mozart} on
-the local machine @file{toe.grunge.com}, and the
-server machine is @file{chainsaw.yard.com}. On
-chainsaw, put the following line into the file
+the local machine @file{toe.example.com}, and the
+server machine is @file{faun.example.org}. On
+faun, put the following line into the file
@file{.rhosts} in @file{bach}'s home directory:
@example
-toe.grunge.com mozart
+toe.example.com mozart
@end example
Then test that @code{rsh} is working with
@example
-rsh -l bach chainsaw.yard.com 'echo $PATH'
+rsh -l bach faun.example.org 'echo $PATH'
@end example
@cindex CVS_SERVER, environment variable
@@ -2063,6 +2176,9 @@ There is no need to edit @code{inetd.conf} or start a
@cindex :server:, setting up
@cindex :ext:, setting up
+@cindex Kerberos, using kerberized rsh
+@cindex SSH (rsh replacement)
+@cindex rsh replacements (Kerberized, SSH, &c)
There are two access methods that you use in CVSROOT
for rsh. @code{:server:} specifies an internal rsh
client, which is supported only by some CVS ports.
@@ -2095,10 +2211,10 @@ replacement.
Continuing our example, supposing you want to access
the module @file{foo} in the repository
@file{/usr/local/cvsroot/}, on machine
-@file{chainsaw.yard.com}, you are ready to go:
+@file{faun.example.org}, you are ready to go:
@example
-cvs -d :ext:bach@@chainsaw.yard.com:/usr/local/cvsroot checkout foo
+cvs -d :ext:bach@@faun.example.org:/usr/local/cvsroot checkout foo
@end example
(The @file{bach@@} can be omitted if the username is
@@ -2167,6 +2283,11 @@ The @samp{--allow-root} option specifies the allowable
different @sc{cvsroot} directory will not be allowed to
connect. If there is more than one @sc{cvsroot}
directory which you want to allow, repeat the option.
+(Unfortunately, many versions of @code{inetd} have very small
+limits on the number of arguments and/or the total length
+of the command. The usual solution to this problem is
+to have @code{inetd} run a shell script which then invokes
+@sc{cvs} with the necessary arguments.)
If your @code{inetd} wants a symbolic service
name instead of a raw port number, then put this in
@@ -2183,14 +2304,8 @@ cvspserver 2401/tcp
@code{inetd}, or do whatever is necessary to force it
to reread its initialization files.
-@c FIXME: should be documenting how to troubleshoot
-@c this. One strange situation I ran into recently
-@c was that if inetd.conf specifies a non-existent
-@c cvs (e.g. /usr/local/bin/cvs doesn't exist in
-@c the above example), the client says
-@c cvs-1.8 [login aborted]: unrecognized auth response from harvey:
-@c which is a very unhelpful response (can it be
-@c improved? does inetd log somewhere?)
+If you are having trouble setting this up, see
+@ref{Connection}.
@cindex CVS passwd file
@cindex passwd (admin file)
@@ -2247,11 +2362,11 @@ anyone:1sOp854gDF3DY:spwang
@end example
Thus, someone remotely accessing the repository
-on @file{chainsaw.yard.com} with the following
+on @file{faun.example.org} with the following
command:
@example
-cvs -d :pserver:cvs@@chainsaw.yard.com:/usr/local/cvsroot checkout foo
+cvs -d :pserver:cvs@@faun.example.org:/usr/local/cvsroot checkout foo
@end example
would end up running the server under the
@@ -2274,6 +2389,9 @@ Right now, the only way to put a password in the
@sc{cvs} @file{passwd} file is to paste it there from
somewhere else. Someday, there may be a @code{cvs
passwd} command.
+Unlike many of the files in @file{$CVSROOT/CVSROOT},
+you edit the @file{passwd} file directly, rather than
+via @sc{cvs}.
@c We might also suggest using the @code{htpasswd} command
@c from freely available web servers as well, but that
@c would open up a can of worms in that the users next
@@ -2301,7 +2419,7 @@ argument or the @code{CVSROOT} environment variable.
password:
@example
-cvs -d :pserver:bach@@chainsaw.yard.com:/usr/local/cvsroot login
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot login
CVS password:
@end example
@@ -2314,7 +2432,7 @@ connect directly to the server and authenticate with
the stored password:
@example
-cvs -d :pserver:bach@@chainsaw.yard.com:/usr/local/cvsroot checkout foo
+cvs -d :pserver:bach@@faun.example.org:/usr/local/cvsroot checkout foo
@end example
The @samp{:pserver:} is necessary because without it,
@@ -2338,7 +2456,7 @@ administrator who happens to look at that file).
@c FIXME: seems to me this needs somewhat more
@c explanation.
@cindex Logout (subcommand)
-The password for the currently choosen remote repository
+The password for the currently chosen remote repository
can be removed from the CVS_PASSFILE by using the
@code{cvs logout} command.
@@ -2383,9 +2501,6 @@ but no one has done so as of this writing.
@c closes enough holes to recommend it (plus it is
@c *very* easy to accidentally screw up a setup of this
@c type).
-Furthermore, there may be other ways in which having
-access to @sc{cvs} allows people to gain more general
-access to the system; no one has done a careful audit.
Note that because the @file{$CVSROOT/CVSROOT} directory
contains @file{passwd} and other files which are used
@@ -2409,8 +2524,8 @@ using pserver.
@c someone who wants to play with it, document it, &c.
In summary, anyone who gets the password gets
-repository access, and some measure of general system
-access as well. The password is available to anyone
+repository access (which may imply some measure of general system
+access as well). The password is available to anyone
who can sniff network packets or read a protected
(i.e., user read-only) file. If you want real
security, get Kerberos.
@@ -2421,6 +2536,7 @@ security, get Kerberos.
@cindex GSSAPI
@cindex security, GSSAPI
@cindex :gserver:, setting up
+@cindex Kerberos, using :gserver:
GSSAPI is a generic interface to network security
systems such as Kerberos 5.
If you have a working GSSAPI library, you can have
@@ -2465,13 +2581,13 @@ To connect using GSSAPI, use @samp{:gserver:}. For
example,
@example
-cvs -d :gserver:chainsaw.yard.com:/usr/local/cvsroot checkout foo
+cvs -d :gserver:faun.example.org:/usr/local/cvsroot checkout foo
@end example
@node Kerberos authenticated
@subsection Direct connection with kerberos
-@cindex kerberos
+@cindex Kerberos, using :kserver:
@cindex security, kerberos
@cindex :kserver:, setting up
The easiest way to use kerberos is to use the kerberos
@@ -2513,12 +2629,47 @@ which allows you to log into the server machine. Then
you are ready to go:
@example
-cvs -d :kserver:chainsaw.yard.com:/usr/local/cvsroot checkout foo
+cvs -d :kserver:faun.example.org:/usr/local/cvsroot checkout foo
@end example
Previous versions of @sc{cvs} would fall back to a
connection via rsh; this version will not do so.
+@node Connecting via fork
+@subsection Connecting with fork
+
+@cindex fork, access method
+@cindex :fork:, setting up
+This access method allows you to connect to a
+repository on your local disk via the remote protocol.
+In other words it does pretty much the same thing as
+@code{:local:}, but various quirks, bugs and the like are
+those of the remote @sc{cvs} rather than the local
+@sc{cvs}.
+
+For day-to-day operations you might prefer either
+@code{:local:} or @code{:fork:}, depending on your
+preferences. Of course @code{:fork:} comes in
+particularly handy in testing or
+debugging @code{cvs} and the remote protocol.
+Specifically, we avoid all of the network-related
+setup/configuration, timeouts, and authentication
+inherent in the other remote access methods but still
+create a connection which uses the remote protocol.
+
+To connect using the @code{fork} method, use
+@samp{:fork:} and the pathname to your local
+repository. For example:
+
+@example
+cvs -d :fork:/usr/local/cvsroot checkout foo
+@end example
+
+@cindex CVS_SERVER, and :fork:
+As with @code{:ext:}, the server is called @samp{cvs}
+by default, or the value of the @code{CVS_SERVER}
+environment variable.
+
@c ---------------------------------------------------------------------
@node Read-only access
@section Read-only repository access
@@ -2778,7 +2929,7 @@ details). Then create the appropriate directories in
files into the appropriate directories in the @sc{cvs}
repository (the name in the repository must be the name
of the source file with @samp{,v} added; the files go
-directly in the appopriate directory of the repository,
+directly in the appropriate directory of the repository,
not in an @file{RCS} subdirectory). This is one of the
few times when it is a good idea to access the @sc{cvs}
repository directly, rather than using @sc{cvs}
@@ -2956,6 +3107,10 @@ numeric revision in each file.
* Versions revisions releases:: Terminology used in this manual
* Assigning revisions:: Assigning revisions
* Tags:: Tags--Symbolic revisions
+* Tagging the working directory:: The cvs tag command
+* Tagging by date/tag:: The cvs rtag command
+* Modifying tags:: Adding, renaming, and deleting tags
+* Tagging add/remove:: Tags with adding and removing files
* Sticky tags:: Certain tags are persistent
@end menu
@@ -3144,7 +3299,7 @@ taginfo file (@pxref{user-defined logging}).
@cindex tag, example
The following example shows how you can add a tag to a
file. The commands must be issued inside your working
-copy of the module. That is, you should issue the
+directory. That is, you should issue the
command in the directory where @file{backend.c}
resides.
@@ -3166,6 +3321,9 @@ File: backend.c Status: Up-to-date
@end example
+For a complete summary of the syntax of @code{cvs tag},
+including the various options, see @ref{Invoking CVS}.
+
There is seldom reason to tag a file in isolation. A more common use is
to tag all the files that constitute a module with the same tag at
strategic points in the development life-cycle, such as when a release
@@ -3201,7 +3359,9 @@ This is useful, for instance, if someone claims that there is a bug in
that release, but you cannot find the bug in the current working copy.
You can also check out a module as it was at any given date.
-@xref{checkout options}.
+@xref{checkout options}. When specifying @samp{-r} to
+any of these commands, you will need beware of sticky
+tags; see @ref{Sticky tags}.
When you tag more than one file with the same tag you
can think about the tag as "a curve drawn through a
@@ -3244,6 +3404,182 @@ like this:
@end group
@end example
+@node Tagging the working directory
+@section Specifying what to tag from the working directory
+
+@cindex Tag (subcommand)
+The example in the previous section demonstrates one of
+the most common ways to choose which revisions to tag.
+Namely, running the @code{cvs tag} command without
+arguments causes @sc{cvs} to select the revisions which
+are checked out in the current working directory. For
+example, if the copy of @file{backend.c} in working
+directory was checked out from revision 1.4, then
+@sc{cvs} will tag revision 1.4. Note that the tag is
+applied immediately to revision 1.4 in the repository;
+tagging is not like modifying a file, or other
+operations in which one first modifies the working
+directory and then runs @code{cvs commit} to transfer
+that modification to the repository.
+
+One potentially surprising aspect of the fact that
+@code{cvs tag} operates on the repository is that you
+are tagging the checked-in revisions, which may differ
+from locally modified files in your working directory.
+If you want to avoid doing this by mistake, specify the
+@samp{-c} option to @code{cvs tag}. If there are any
+locally modified files, @sc{cvs} will abort with an
+error before it tags any files:
+
+@example
+$ cvs tag -c rel-0-4
+cvs tag: backend.c is locally modified
+cvs [tag aborted]: correct the above errors first!
+@end example
+
+@node Tagging by date/tag
+@section Specifying what to tag by date or revision
+@cindex Rtag (subcommand)
+
+The @code{cvs rtag} command tags the repository as of a
+certain date or time (or can be used to tag the latest
+revision). @code{rtag} works directly on the
+repository contents (it requires no prior checkout and
+does not look for a working directory).
+
+The following options specify which date or revision to
+tag. See @ref{Common options}, for a complete
+description of them.
+
+@table @code
+@item -D @var{date}
+Tag the most recent revision no later than @var{date}.
+
+@item -f
+Only useful with the @samp{-D @var{date}} or @samp{-r @var{tag}}
+flags. If no matching revision is found, use the most
+recent revision (instead of ignoring the file).
+
+@item -r @var{tag}
+Only tag those files that contain existing tag @var{tag}.
+@end table
+
+The @code{cvs tag} command also allows one to specify
+files by revision or date, using the same @samp{-r},
+@samp{-D}, and @samp{-f} options. However, this
+feature is probably not what you want. The reason is
+that @code{cvs tag} chooses which files to tag based on
+the files that exist in the working directory, rather
+than the files which existed as of the given tag/date.
+Therefore, you are generally better off using @code{cvs
+rtag}. The exceptions might be cases like:
+
+@example
+cvs tag -r 1.4 backend.c
+@end example
+
+@node Modifying tags
+@section Deleting, moving, and renaming tags
+
+@c Also see:
+@c "How do I move or rename a magic branch tag?"
+@c in the FAQ (I think the issues it talks about still
+@c apply, but this could use some sanity.sh work).
+
+Normally one does not modify tags. They exist in order
+to record the history of the repository and so deleting
+them or changing their meaning would, generally, not be
+what you want.
+
+However, there might be cases in which one uses a tag
+temporarily or accidentally puts one in the wrong
+place. Therefore, one might delete, move, or rename a
+tag. Warning: the commands in this section are
+dangerous; they permanently discard historical
+information and it can difficult or impossible to
+recover from errors. If you are a @sc{cvs}
+administrator, you may consider restricting these
+commands with taginfo (@pxref{user-defined logging}).
+
+@cindex deleting tags
+@cindex removing tags
+@cindex tags, deleting
+To delete a tag, specify the @samp{-d} option to either
+@code{cvs tag} or @code{cvs rtag}. For example:
+
+@example
+cvs rtag -d rel-0-4 tc
+@end example
+
+deletes the tag @code{rel-0-4} from the module @code{tc}.
+
+@cindex moving tags
+@cindex tags, moving
+When we say @dfn{move} a tag, we mean to make the same
+name point to different revisions. For example, the
+@code{stable} tag may currently point to revision 1.4
+of @file{backend.c} and perhaps we want to make it
+point to revision 1.6. To move a tag, specify the
+@samp{-F} option to either @code{cvs tag} or @code{cvs
+rtag}. For example, the task just mentioned might be
+accomplished as:
+
+@example
+cvs tag -r 1.6 -F stable backend.c
+@end example
+
+@cindex renaming tags
+@cindex tags, renaming
+When we say @dfn{rename} a tag, we mean to make a
+different name point to the same revisions as the old
+tag. For example, one may have misspelled the tag name
+and want to correct it (hopefully before others are
+relying on the old spelling). To rename a tag, first
+create a new tag using the @samp{-r} option to
+@code{cvs rtag}, and then delete the old name. This
+leaves the new tag on exactly the same files as the old
+tag. For example:
+
+@example
+cvs rtag -r old-name-0-4 rel-0-4 tc
+cvs rtag -d old-name-0-4 tc
+@end example
+
+@node Tagging add/remove
+@section Tagging and adding and removing files
+
+The subject of exactly how tagging interacts with
+adding and removing files is somewhat obscure; for the
+most part @sc{cvs} will keep track of whether files
+exist or not without too much fussing. By default,
+tags are applied to only files which have a revision
+corresponding to what is being tagged. Files which did
+not exist yet, or which were already removed, simply
+omit the tag, and @sc{cvs} knows to treat the absence
+of a tag as meaning that the file didn't exist as of
+that tag.
+
+However, this can lose a small amount of information.
+For example, suppose a file was added and then removed.
+Then, if the tag is missing for that file, there is no
+way to know whether the tag refers to the time before
+the file was added, or the time after it was removed.
+If you specify the @samp{-r} option to @code{cvs rtag},
+then @sc{cvs} tags the files which have been removed,
+and thereby avoids this problem. For example, one
+might specify @code{-r HEAD} to tag the head.
+
+On the subject of adding and removing files, the
+@code{cvs rtag} command has a @samp{-a} option which
+means to clear the tag from removed files that would
+not otherwise be tagged. For example, one might
+specify this option in conjunction with @samp{-F} when
+moving a tag. If one moved a tag without @samp{-a},
+then the tag in the removed files might still refer to
+the old revision, rather than reflecting the fact that
+the file had been removed. I don't think this is
+necessary if @samp{-r} is specified, as noted above.
+
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Sticky tags
@section Sticky tags
@@ -3315,18 +3651,11 @@ tag with @code{cvs update -A}. Likewise, use of the
sets a @dfn{sticky date}, which, similarly, causes that
date to be used for future retrievals.
-@cindex Restoring old version of removed file
-@cindex Resurrecting old version of dead file
-Many times you will want to retrieve an old version of
-a file without setting a sticky tag. The way to do
-that is with the @samp{-p} option to @code{checkout} or
+People often want to retrieve an old version of
+a file without setting a sticky tag. This can
+be done with the @samp{-p} option to @code{checkout} or
@code{update}, which sends the contents of the file to
-standard output. For example, suppose you have a file
-named @file{file1} which existed as revision 1.1, and
-you then removed it (thus adding a dead revision 1.2).
-Now suppose you want to add it again, with the same
-contents it had previously. Here is how to do it:
-
+standard output. For example:
@example
$ cvs update -p -r 1.1 file1 >file1
===================================================================
@@ -3334,17 +3663,16 @@ Checking out file1
RCS: /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v
VERS: 1.1
***************
-$ cvs add file1
-cvs add: re-adding file file1 (in place of dead revision 1.2)
-cvs add: use 'cvs commit' to add this file permanently
-$ cvs commit -m test
-Checking in file1;
-/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
-new revision: 1.3; previous revision: 1.2
-done
$
@end example
+However, this isn't the easiest way, if you are asking
+how to undo a previous checkin (in this example, put
+@file{file1} back to the way it was as of revision
+1.1). In that case you are better off using the
+@samp{-j} option to @code{update}; for further
+discussion see @ref{Merging two revisions}.
+
@c ---------------------------------------------------------------------
@node Branching and merging
@chapter Branching and merging
@@ -3379,6 +3707,7 @@ copy the changes onto another branch.
* Merging more than once:: Merging from a branch several times
* Merging two revisions:: Merging differences between two revisions
* Merging adds and removals:: What if files are added or removed?
+* Merging and keywords:: Avoiding conflicts due to keyword substitution
@end menu
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -3610,12 +3939,16 @@ The following figure illustrates branching with an
example.
@example
+@c This example used to have a 1.2.2.4 revision, which
+@c might help clarify that development can continue on
+@c 1.2.2. Might be worth reinstating if it can be done
+@c without overfull hboxes.
@group
- +-------------+
- Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
- / +-------------+
- /
- /
+ +-------------+
+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 !
+ / +-------------+
+ /
+ /
+---------+ +---------+ +---------+
Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !
/ +---------+ +---------+ +---------+
@@ -3772,6 +4105,10 @@ A conflict can result from a merge operation. If that
happens, you should resolve it before committing the
new revision. @xref{Conflicts example}.
+If your source files contain keywords (@pxref{Keyword substitution}),
+you might be getting more conflicts than strictly necessary. See
+@ref{Merging and keywords}, for information on how to avoid this.
+
The @code{checkout} command also supports the @samp{-j @var{branch}} flag. The
same effect as above could be achieved with this:
@@ -3866,16 +4203,37 @@ $ cvs update -j 1.5 -j 1.3 backend.c
@end example
@noindent
-will @emph{remove} all changes made between revision
+will undo all changes made between revision
1.3 and 1.5. Note the order of the revisions!
If you try to use this option when operating on
multiple files, remember that the numeric revisions will
-probably be very different between the various files
-that make up a module. You almost always use symbolic
+probably be very different between the various files.
+You almost always use symbolic
tags rather than revision numbers when operating on
multiple files.
+@cindex Restoring old version of removed file
+@cindex Resurrecting old version of dead file
+Specifying two @samp{-j} options can also undo file
+removals or additions. For example, suppose you have
+a file
+named @file{file1} which existed as revision 1.1, and
+you then removed it (thus adding a dead revision 1.2).
+Now suppose you want to add it again, with the same
+contents it had previously. Here is how to do it:
+
+@example
+$ cvs update -j 1.2 -j 1.1 file1
+U file1
+$ cvs commit -m test
+Checking in file1;
+/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
+new revision: 1.3; previous revision: 1.2
+done
+$
+@end example
+
@node Merging adds and removals
@section Merging can add or remove files
@@ -3905,6 +4263,142 @@ After these commands are executed and a @samp{cvs commit} is done,
file @file{a} will be removed and file @file{d} added in the main branch.
@c (which was determined by trying it)
+@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+@node Merging and keywords
+@section Merging and keywords
+@cindex Merging, and keyword substitution
+@cindex Keyword substitution, and merging
+@cindex -j (merging branches), and keyword substitution
+@cindex -kk, to avoid conflicts during a merge
+
+If you merge files containing keywords (@pxref{Keyword
+substitution}), you will normally get numerous
+conflicts during the merge, because the keywords are
+expanded differently in the revisions which you are
+merging.
+
+Therefore, you will often want to specify the
+@samp{-kk} (@pxref{Substitution modes}) switch to the
+merge command line. By substituting just the name of
+the keyword, not the expanded value of that keyword,
+this option ensures that the revisions which you are
+merging will be the same as each other, and avoid
+spurious conflicts.
+
+For example, suppose you have a file like this:
+
+@example
+ +---------+
+ _! 1.1.2.1 ! <- br1
+ / +---------+
+ /
+ /
++-----+ +-----+
+! 1.1 !----! 1.2 !
++-----+ +-----+
+@end example
+
+and your working directory is currently on the trunk
+(revision 1.2). Then you might get the following
+results from a merge:
+
+@example
+$ cat file1
+key $@asis{}Revision: 1.2 $
+. . .
+$ cvs update -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+rcsmerge: warning: conflicts during merge
+$ cat file1
+@asis{}<<<<<<< file1
+key $@asis{}Revision: 1.2 $
+@asis{}=======
+key $@asis{}Revision: 1.1.2.1 $
+@asis{}>>>>>>> 1.1.2.1
+. . .
+@end example
+
+What happened was that the merge tried to merge the
+differences between 1.1 and 1.1.2.1 into your working
+directory. So, since the keyword changed from
+@code{Revision: 1.1} to @code{Revision: 1.1.2.1},
+@sc{cvs} tried to merge that change into your working
+directory, which conflicted with the fact that your
+working directory had contained @code{Revision: 1.2}.
+
+Here is what happens if you had used @samp{-kk}:
+
+@example
+$ cat file1
+key $@asis{}Revision: 1.2 $
+. . .
+$ cvs update -kk -j br1
+U file1
+RCS file: /cvsroot/first-dir/file1,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+Merging differences between 1.1 and 1.1.2.1 into file1
+$ cat file1
+key $@asis{}Revision$
+. . .
+@end example
+
+What is going on here is that revision 1.1 and 1.1.2.1
+both expand as plain @code{Revision}, and therefore
+merging the changes between them into the working
+directory need not change anything. Therefore, there
+is no conflict.
+
+There is, however, one major caveat with using
+@samp{-kk} on merges. Namely, it overrides whatever
+keyword expansion mode @sc{cvs} would normally have
+used. In particular, this is a problem if the mode had
+been @samp{-kb} for a binary file. Therefore, if your
+repository contains binary files, you will need to deal
+with the conflicts rather than using @samp{-kk}.
+
+@ignore
+The following seems rather confusing, possibly buggy,
+and in general, in need of much more thought before it
+is a recommended technique. For one thing, does it
+apply on Windows as well as on Unix?
+
+Unchanged binary files will undergo the same keyword substitution
+but will not be checked in on a subsequent
+@code{cvs commit}. Be aware that binary files containing keyword
+strings which are present in or below the working directory
+will most likely remain corrupt until repaired, however. A simple
+@code{cvs update -A} is sufficient to fix these otherwise unaltered binary files
+if the merge is being done to the main branch but
+this must be done after the merge has been committed or the merge itself
+will be lost.
+
+For Example:
+@example
+cvs update -Akk -jbranchtag
+cvs commit
+cvs update -A
+@end example
+
+@noindent
+will update the current directory from the main trunk of the
+repository, substituting the base keyword strings for keywords,
+and merge changes made on the branch @samp{branchtag} into the new
+work files, performing the same keyword substitution on that file set before
+comparing the two sets. The final @code{cvs update -A} will restore any
+corrupted binary files as well as resetting the sticky @samp{-kk} tags which
+were present on the files in and below the working directory.
+Unfortunately, this doesn't work as well with an arbitrary branch tag, as the
+@samp{-r @var{branchtag}} switch does not reset the sticky @samp{-kk}
+switches attached to the working files as @samp{-A} does. The workaround
+for this is to release the working directory after the merge has been
+committed and check it out again.
+@end ignore
+
@c ---------------------------------------------------------------------
@node Recursive behavior
@chapter Recursive behavior
@@ -3962,7 +4456,7 @@ subdirectories
@item
@samp{cvs update .} or just @samp{cvs update} updates
-all files in the @code{tc} module
+all files in the @code{tc} directory
@end itemize
If no arguments are given to @code{update} it will
@@ -4124,7 +4618,7 @@ later merge the additions to another branch if you want
@c be its own section, for example, as could the
@c various bits about undoing mistakes in adding and
@c removing).
-Modules change. New files are added, and old files
+Directories change. New files are added, and old files
disappear. Still, you want to be able to retrieve an
exact copy of old releases.
@@ -4375,7 +4869,7 @@ files inside the repository. Read this entire section
before trying it out!
@example
-$ cd $CVSROOT/@var{module}
+$ cd $CVSROOT/@var{dir}
$ mv @var{old},v @var{new},v
@end example
@@ -4395,7 +4889,7 @@ Disadvantages:
@itemize @bullet
@item
-Old releases of the module cannot easily be fetched from the
+Old releases cannot easily be fetched from the
repository. (The file will show up as @var{new} even
in revisions from the time before it was renamed).
@@ -4417,10 +4911,10 @@ repository. It is safe, but not without drawbacks.
@example
# @r{Copy the @sc{rcs} file inside the repository}
-$ cd $CVSROOT/@var{module}
+$ cd $CVSROOT/@var{dir}
$ cp @var{old},v @var{new},v
# @r{Remove the old file}
-$ cd ~/@var{module}
+$ cd ~/@var{dir}
$ rm @var{old}
$ cvs remove @var{old}
$ cvs commit @var{old}
@@ -4433,7 +4927,7 @@ $ cvs tag -d @var{tag2} @var{new}
@end example
By removing the tags you will be able to check out old
-revisions of the module.
+revisions.
@noindent
Advantages:
@@ -4492,16 +4986,16 @@ like this:
@enumerate
@item
-Inform everyone who has a copy of the module that the
+Inform everyone who has a checked out copy of the directory that the
directory will be renamed. They should commit all
-their changes, and remove their working copies of the
-module, before you take the steps below.
+their changes, and remove their working copies,
+before you take the steps below.
@item
Rename the directory inside the repository.
@example
-$ cd $CVSROOT/@var{module}
+$ cd $CVSROOT/@var{parent-dir}
$ mv @var{old-dir} @var{new-dir}
@end example
@@ -4510,12 +5004,12 @@ Fix the @sc{cvs} administrative files, if necessary (for
instance if you renamed an entire module).
@item
-Tell everyone that they can check out the module and continue
+Tell everyone that they can check out again and continue
working.
@end enumerate
-If someone had a working copy of the module the @sc{cvs} commands will
+If someone had a working copy the @sc{cvs} commands will
cease to work for him, until he removes the directory
that disappeared inside the repository.
@@ -5032,7 +5526,7 @@ is almost automatic.
@c FIXME? should probably use the word "watch" here, to
@c tie this into the text below and above.
@sc{Cvs} also supports mechanisms which facilitate
-various kinds of communcation, without actually
+various kinds of communication, without actually
enforcing rules like reserved checkouts do.
The rest of this chapter describes how these various
@@ -5293,8 +5787,7 @@ these options, see @ref{Invoking CVS}.
When you want to update or merge a file, use the @code{update}
command. For files that are not up to date this is roughly equivalent
to a @code{checkout} command: the newest revision of the file is
-extracted from the repository and put in your working copy of the
-module.
+extracted from the repository and put in your working directory.
Your modifications to a file are never lost when you
use @code{update}. If no newer revision exists,
@@ -5770,7 +6263,7 @@ files (@pxref{Intro administrative files}). This
file follows the usual conventions for administrative
files (@pxref{syntax}), where each line is a regular
expression followed by a command to execute. The
-command should contain a single ocurrence of @samp{%s}
+command should contain a single occurrence of @samp{%s}
which will be replaced by the user to notify; the rest
of the information regarding the notification will be
supplied to the command on standard input. The
@@ -5906,7 +6399,7 @@ repository since the last time you updated.
When using client/server @sc{cvs}, you can use the
@code{cvs edit} and @code{cvs unedit} commands even if
-@sc{cvs} is unable to succesfully communicate with the
+@sc{cvs} is unable to successfully communicate with the
server; the notifications will be sent upon the next
successful @sc{cvs} command.
@@ -6086,8 +6579,8 @@ goal, which is to get software written.
@comment version control, so we must not accidentally
@comment include a valid keyword in the running text.
-As long as you edit source files inside your working
-copy of a module you can always find out the state of
+As long as you edit source files inside a working
+directory you can always find out the state of
your files via @samp{cvs status} and @samp{cvs log}.
But as soon as you export the files from your
development environment it becomes harder to identify
@@ -6146,17 +6639,16 @@ filename is without a path.
@cindex Name keyword
@item $@asis{Name}$
-Tag name used to check out this file.
-@c FIXME: should supply an example (e.g. "if you use
-@c "cvs update -r foo" then Name expands to "foo"). Also
-@c should add Name to testsuite (best way to ensure
-@c that the example is correct!)
+Tag name used to check out this file. The keyword is
+expanded only if one checks out with an explicit tag
+name. For example, when running the command @code{cvs
+co -r first}, the keyword expands to @samp{Name: first}.
@cindex Locker keyword
@item $@asis{Locker}$
The login name of the user who locked the revision
-(empty if not locked, and thus almost always useless
-when you are using @sc{cvs}).
+(empty if not locked, which is the normal case unless
+@code{cvs admin -l} is in use).
@cindex Log keyword
@item $@asis{Log}$
@@ -6257,7 +6749,7 @@ It has a command, @code{what}, which is very similar to
without @sc{rcs} have @sc{sccs}. Since @code{what}
looks for the character sequence @code{@@(#)} it is
easy to include keywords that are detected by either
-command. Simply prefix the @sc{rcs} keyword with the
+command. Simply prefix the keyword with the
magic @sc{sccs} phrase, like this:
@example
@@ -6290,6 +6782,7 @@ and @code{troff} you can embed the null-character
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Substitution modes
@section Substitution modes
+@cindex Keyword substitution, changing modes
@cindex -k (keyword substitution)
@cindex Kflag
@@ -6302,7 +6795,7 @@ option to @code{cvs add} and @code{cvs admin}; the
latter is set by the @samp{-k} or @samp{-A} options to @code{cvs
checkout} or @code{cvs update}. @code{cvs diff} also
has a @samp{-k} option. For some examples,
-see @ref{Binary files}.
+see @ref{Binary files}, and @ref{Merging and keywords}.
@c The fact that -A is overloaded to mean both reset
@c sticky options and reset sticky tags/dates is
@c somewhat questionable. Perhaps there should be
@@ -6328,7 +6821,8 @@ keyword.
@item -kkvl
Like @samp{-kkv}, except that a locker's name is always
inserted if the given revision is currently locked.
-This option is normally not useful when @sc{cvs} is used.
+The locker's name is only relevant if @code{cvs admin
+-l} is in use.
@item -kk
Generate only keyword names in keyword strings; omit
@@ -6337,7 +6831,7 @@ keyword, generate the string @code{$@asis{}Revision$}
instead of @code{$@asis{}Revision: 5.7 $}. This option
is useful to ignore differences due to keyword
substitution when comparing different revisions of a
-file.
+file (@pxref{Merging and keywords}).
@item -ko
Generate the old keyword string, present in the working
@@ -6451,9 +6945,9 @@ placed on the main trunk, and made the `head'
revision.
@menu
-* First import:: Importing a module for the first time
-* Update imports:: Updating a module with the import command
-* Reverting local changes:: Reverting a module to the latest vendor release
+* First import:: Importing for the first time
+* Update imports:: Updating with the import command
+* Reverting local changes:: Reverting to the latest vendor release
* Binary files in imports:: Binary files require special handling
* Keywords in imports:: Keyword substitution might be undesirable
* Multiple vendor branches:: What if you get sources from several places?
@@ -6461,7 +6955,7 @@ revision.
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node First import
-@section Importing a module for the first time
+@section Importing for the first time
@cindex Importing modules
@c Should mention naming conventions for vendor tags,
@@ -6506,7 +7000,7 @@ example, and the only release tag assigned is
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Update imports
-@section Updating a module with the import command
+@section Updating with the import command
When a new release of the source arrives, you import it into the
repository with the same @code{import} command that you used to set up
@@ -6867,6 +7361,15 @@ reference to @sc{cvs} commands, @pxref{Invoking CVS}).
@c in the process reorganizing the manual to be
@c organized around what the user wants to do, not
@c organized around CVS commands.
+@c
+@c Note that many users do expect a manual which is
+@c organized by command. At least some users do.
+@c One good addition to the "organized by command"
+@c section (if any) would be "see also" links.
+@c The awk manual might be a good example; it has a
+@c reference manual which is more verbose than Invoking
+@c CVS but probably somewhat less verbose than CVS
+@c Commands.
@menu
* Structure:: Overall structure of CVS commands
@@ -6883,9 +7386,7 @@ reference to @sc{cvs} commands, @pxref{Invoking CVS}).
* import:: Import sources into CVS, using vendor branches
* log:: Show log messages for files
* rdiff:: 'patch' format diffs between releases
-* release:: Indicate that a Module is no longer in use
-* rtag:: Add a tag to a module
-* tag:: Add a tag to checked out version
+* release:: Indicate that a directory is no longer in use
* update:: Bring work tree in sync with repository
@end menu
@@ -7329,14 +7830,18 @@ are:
@c bizarre and it has lots of gratuitous multiple ways
@c to specify the same thing.
-For more details about ISO8601 dates, see:
+There are a lot more ISO8601 date formats, and CVS
+accepts many of them, but you probably don't want to
+hear the @emph{whole} long story :-).
-@example
-http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html
-@end example
-@c Perhaps we want to also cite other sources in
-@c case that page goes away. For example:
+@c Citing a URL here is kind of problematic given how
+@c much they change and people who have old versions of
+@c this manual, but in case we want to reinstate an
+@c ISO8601 URL, a few are:
@c http://www.saqqara.demon.co.uk/datefmt.htm
+@c http://www.cl.cam.ac.uk/~mgk25/iso-time.html
+@c Citing some other ISO8601 source is probably even
+@c worse :-).
In addition to the dates allowed in Internet e-mail
itself, @sc{cvs} also allows some of the fields to be
@@ -7398,6 +7903,11 @@ if you want files retrieved even when there is no match for the
tag or date. (The most recent revision of the file
will be used).
+Note that even with @samp{-f}, a tag that you specify
+must exist (that is, in some file, not necessary in
+every file). This is so that @sc{cvs} will continue to
+give an error if you mistype a tag name.
+
@need 800
@samp{-f} is available with these commands:
@code{annotate}, @code{checkout}, @code{export},
@@ -7499,7 +8009,7 @@ revision you last checked out into the current working directory.
@c special tags, ".thead" for the head of the trunk,
@c and ".bhead" for the head of the current branch.
@c Then deprecate HEAD. This has the advantage of
-@c not suprising people with a change to HEAD, and a
+@c not surprising people with a change to HEAD, and a
@c side benefit of also phasing out the poorly-named
@c HEAD (see discussion of reserved tag names in node
@c "Tags"). Of course, .thead and .bhead should be
@@ -7513,9 +8023,11 @@ The tag specification is sticky when you use this
with @code{checkout} or @code{update} to make your own
copy of a file: @sc{cvs} remembers the tag and continues to use it on
future update commands, until you specify otherwise (for more information
-on sticky tags/dates, @pxref{Sticky tags}). The
-tag can be either a symbolic or numeric tag.
-@xref{Tags}.
+on sticky tags/dates, @pxref{Sticky tags}).
+
+The tag can be either a symbolic or numeric tag, as
+described in @ref{Tags}, or the name of a branch, as
+described in @ref{Branching and merging}.
Specifying the @samp{-q} global option along with the
@samp{-r} command option is often useful, to suppress
@@ -7561,13 +8073,16 @@ are likely to disappear in the future. This command
@emph{does} work recursively, so extreme care should be
used.
+@cindex cvsadmin
On unix, if there is a group named @code{cvsadmin},
-only members of that group can run @code{cvs admin}.
-This group should exist on the server, or any system
-running the non-client/server @sc{cvs}. To disallow
-@code{cvs admin} for all users, create a group with no
-users in it. On NT, the @code{cvsadmin} feature does
-not exist and all users can run @code{cvs admin}.
+only members of that group can run @code{cvs admin}
+(except for the @code{cvs admin -k} command, which can
+be run by anybody). This group should exist on the
+server, or any system running the non-client/server
+@sc{cvs}. To disallow @code{cvs admin} for all users,
+create a group with no users in it. On NT, the
+@code{cvsadmin} feature does not exist and all users
+can run @code{cvs admin}.
@menu
* admin options:: admin options
@@ -7621,6 +8136,7 @@ Might not work together with @sc{cvs}. Erase the login
names appearing in the comma-separated list
@var{logins} from the access list of the RCS file. If
@var{logins} is omitted, erase the entire access list.
+There can be no space between @samp{-e} and its argument.
@item -I
Run interactively, even if the standard input is not a
@@ -8260,13 +8776,16 @@ invoking an editor.
@node commit examples
@appendixsubsec commit examples
+@c FIXME: this material wants to be somewhere
+@c in "Branching and merging".
+
@appendixsubsubsec Committing to a branch
You can commit to a branch revision (one that has an
even number of dots) with the @samp{-r} option. To
create a branch revision, use the @samp{-b} option
-of the @code{rtag} or @code{tag} commands (@pxref{tag}
-or @pxref{rtag}). Then, either @code{checkout} or
+of the @code{rtag} or @code{tag} commands
+(@pxref{Branching and merging}). Then, either @code{checkout} or
@code{update} can be used to base your sources on the
newly created branch. From that point on, all
@code{commit} changes made within these working sources
@@ -9239,8 +9758,7 @@ last change to a file was.
@item -u
Use the unidiff format for the context diffs.
-This option is not available if your @code{diff} does not
-support the unidiff format. Remember that old versions
+Remember that old versions
of the @code{patch} program can't handle the unidiff
format, so if you plan to post this patch to the net
you should probably not use @samp{-u}.
@@ -9257,14 +9775,14 @@ way that @sc{rcs} version 5 does.
@node rdiff examples
@appendixsubsec rdiff examples
-Suppose you receive mail from @t{foo@@bar.com} asking for an
+Suppose you receive mail from @t{foo@@example.net} asking for an
update from release 1.2 to 1.4 of the tc compiler. You
have no such patches on hand, but with @sc{cvs} that can
easily be fixed with a command such as this:
@example
$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \
-$$ Mail -s 'The patches you asked for' foo@@bar.com
+$$ Mail -s 'The patches you asked for' foo@@example.net
@end example
Suppose you have made release 1.3, and forked a branch
@@ -9395,7 +9913,7 @@ sources, this file will be lost.
@node release examples
@appendixsubsec release examples
-Release the module, and delete your local working copy
+Release the @file{tc} directory, and delete your local working copy
of the files.
@example
@@ -9403,244 +9921,10 @@ $ cd .. # @r{You must stand immediately above the}
# @r{sources when you issue @samp{cvs release}.}
$ cvs release -d tc
You have [0] altered files in this repository.
-Are you sure you want to release (and delete) module `tc': y
+Are you sure you want to release (and delete) directory `tc': y
$
@end example
-@node rtag
-@appendixsec rtag---Add a symbolic tag to a module
-@cindex Rtag (subcommand)
-
-@itemize @bullet
-@item
-rtag [-falnR] [-b] [-d] [-r tag | -Ddate] symbolic_tag modules@dots{}
-@item
-Requires: repository.
-@item
-Changes: repository.
-@item
-Synonym: rfreeze
-@end itemize
-
-You can use this command to assign symbolic tags to
-particular, explicitly specified source revisions in
-the repository. @code{rtag} works directly on the
-repository contents (and requires no prior checkout).
-Use @code{tag} instead (@pxref{tag}), to base the
-selection of revisions on the contents of your
-working directory.
-
-If you attempt to use a tag name that already exists,
-@sc{cvs} will complain and not overwrite that tag. Use
-the @samp{-F} option to force the new tag value.
-
-@menu
-* rtag options:: rtag options
-@end menu
-
-@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-@node rtag options
-@appendixsubsec rtag options
-
-These standard options are supported by @code{rtag}
-(@pxref{Common options}, for a complete description of
-them):
-
-@table @code
-@item -D @var{date}
-Tag the most recent revision no later than @var{date}.
-
-@item -f
-Only useful with the @samp{-D @var{date}} or @samp{-r @var{tag}}
-flags. If no matching revision is found, use the most
-recent revision (instead of ignoring the file).
-
-@item -F
-Overwrite an existing tag of the same name on a
-different revision.
-@c FIXME: Needs an example, and/or more explanation.
-@c Also needs to contrast this with the behavior if -F
-@c is not specified, and the description needs to be
-@c moved somewhere where it is shared between "tag" and
-@c "rtag" (probably some sub-node of Revisions and
-@c branches). Also should be clear about whether this
-@c applies to branch tags, non-branch tags, or both.
-@c Also this is *not* a common option.
-
-@item -l
-Local; run only in current working directory.
-
-@item -n
-Do not run any tag program that was specified with the
-@samp{-t} flag inside the @file{modules} file.
-(@pxref{modules}).
-
-@item -R
-Tag directories recursively. This is on by default.
-
-@c FIXME: this discussion is confusing. What part of
-@c the rename operation being discussed relates to
-@c "rtag -r" (that whole discussion needs an example,
-@c and probably to be moved somewhere else)?
-@item -r @var{tag}
-Only tag those files that contain @var{tag}. This can
-be used to rename a tag: tag only the files identified
-by the old tag, then delete the old tag, leaving the
-new tag on exactly the same files as the old tag.
-@end table
-
-In addition to the above common options, these options
-are available:
-
-@table @code
-@item -a
-@c FIXME: What does this option mean in terms of user
-@c concepts, not CVS internals?
-Use the @samp{-a} option to have @code{rtag} look in the
-@file{Attic} (@pxref{Attic}) for removed files
-that contain the specified tag. The tag is removed from
-these files, which makes it convenient to re-use a
-symbolic tag as development continues (and files get
-removed from the up-coming distribution).
-
-@item -b
-Make the tag a branch tag. @xref{Branching and merging}.
-
-@item -d
-Delete the tag instead of creating it.
-
-In general, tags (often the symbolic names of software
-distributions) should not be removed, but the @samp{-d}
-option is available as a means to remove completely
-obsolete symbolic names if necessary (as might be the
-case for an Alpha release, or if you mistagged a
-module).
-@end table
-
-@ignore
-@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-@c @node rtag examples
-@appendixsubsec rtag examples
-
-@c -- Examples here!
-@end ignore
-
-@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-@node tag
-@appendixsec tag---Add a symbolic tag to checked out versions of files
-@c -- //////// - unnecessary. Also
-@c -- in a lot of other
-@c -- places.
-@cindex Tag (subcommand)
-
-@itemize @bullet
-@item
-tag [-lR] [-b] [-c] [-d] symbolic_tag [files@dots{}]
-@item
-Requires: working directory, repository.
-@item
-Changes: repository.
-@item
-Synonym: freeze
-@end itemize
-
-Use this command to assign symbolic tags to the nearest
-repository versions to your working sources. The tags
-are applied immediately to the repository, as with
-@code{rtag}, but the versions are supplied implicitly by the
-@sc{cvs} records of your working files' history rather than
-applied explicitly.
-
-One use for tags is to record a snapshot of the
-current sources when the software freeze date of a
-project arrives. As bugs are fixed after the freeze
-date, only those changed sources that are to be part of
-the release need be re-tagged.
-
-The symbolic tags are meant to permanently record which
-revisions of which files were used in creating a
-software distribution. The @code{checkout} and
-@code{update} commands allow you to extract an exact
-copy of a tagged release at any time in the future,
-regardless of whether files have been changed, added,
-or removed since the release was tagged.
-
-This command can also be used to delete a symbolic tag,
-or to create a branch. See the options section below.
-
-If you attempt to use a tag name that already exists,
-@sc{cvs} will complain and not overwrite that tag. Use
-the @samp{-F} option to force the new tag value.
-
-
-@menu
-* tag options:: tag options
-@end menu
-
-@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-@node tag options
-@appendixsubsec tag options
-
-These standard options are supported by @code{tag}
-(@pxref{Common options}, for a complete description of
-them):
-
-@table @code
-@cindex renaming tags
-@cindex tags, renaming
-@cindex moving tags
-@c FIXME: Where does this talk about renaming tags?
-@c And what about rtag? This needs to be moved to
-@c the body of the manual.
-@c Also see:
-@c "How do I move or rename a magic branch tag?"
-@c in the FAQ (I think the issues it talks about still
-@c apply, but this could use some sanity.sh work).
-@item -F
-Overwrite an existing tag of the same name on a
-different revision.
-@c FIXME: See "rtag -F" for comments on this.
-
-@item -l
-Local; run only in current working directory.
-
-@item -R
-Tag directories recursively. This is on by default.
-@end table
-
-Two special options are available:
-
-@table @code
-@item -b
-Make the tag a branch tag
-(@pxref{Branching and merging}), allowing concurrent, isolated
-development. This is most useful for creating a patch
-to a previously released software distribution.
-
-@item -c
-Check that all files which are to be tagged are
-unmodified. This can be used to make sure that you can reconstruct the
-current file contents.
-
-@item -d
-Delete a tag.
-
-If you use @samp{cvs tag -d symbolic_tag}, the symbolic
-tag you specify is deleted instead of being added.
-Warning: Be very certain of your ground before you
-delete a tag; doing this permanently discards some
-historical information, which may later turn out to
-be valuable.
-@end table
-
-@ignore
-@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-@c @node tag examples
-@appendixsubsec tag examples
-
-@c -- FIXME
-@end ignore
-
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node update
@appendixsec update---Bring work tree in sync with repository
@@ -10277,7 +10561,7 @@ Operate recursively (default). @xref{Recursive
behavior}.
@item -r @var{tag}
-Checkout revision @var{tag} (is sticky). See @ref{Common options}.
+Checkout revision @var{tag}. See @ref{Common options}.
@end table
@item history [@var{options}] [@var{files}@dots{}]
@@ -10483,43 +10767,42 @@ behavior}.
@end table
@item rtag [@var{options}] @var{tag} @var{modules}@dots{}
-Add a symbolic tag to a module. See @ref{rtag}.
+Add a symbolic tag to a module.
+See @ref{Revisions} and @ref{Branching and merging}.
@table @code
-@c Is this one of those dumb options which used to
-@c work around the lack of death support?
@item -a
Clear tag from removed files that would not otherwise
-be tagged. See @ref{rtag options}.
+be tagged. See @ref{Tagging add/remove}.
@item -b
-Create a branch named @var{tag}. See @ref{rtag options}.
+Create a branch named @var{tag}. See @ref{Branching and merging}.
@item -D @var{date}
-Tag revisions as of @var{date}. See @ref{rtag options}.
+Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
@item -d
-Delete the given tag. See @ref{rtag options}.
+Delete @var{tag}. See @ref{Modifying tags}.
@item -F
-Move tag if it already exists. See @ref{rtag options}.
+Move @var{tag} if it already exists. See @ref{Modifying tags}.
@item -f
Force a head revision match if tag/date not found.
-See @ref{rtag options}.
+See @ref{Tagging by date/tag}.
@item -l
Local; run only in current working directory. See @ref{Recursive behavior}.
@item -n
-No execution of tag program. See @ref{rtag options}.
+No execution of tag program. See @ref{Common options}.
@item -R
Operate recursively (default). @xref{Recursive
behavior}.
-@item -r @var{tag}
-Tag existing tag @var{tag}. See @ref{rtag options}.
+@item -r @var{rev}
+Tag existing tag @var{rev}. See @ref{Tagging by date/tag}.
@end table
@item status [@var{options}] @var{files}@dots{}
@@ -10540,37 +10823,38 @@ Include tag information for file. See @ref{Tags}.
@item tag [@var{options}] @var{tag} [@var{files}@dots{}]
Add a symbolic tag to checked out version of files.
-See @ref{tag}.
+See @ref{Revisions} and @ref{Branching and merging}.
@table @code
@item -b
-Create a branch named @var{tag}. See @ref{tag options}.
+Create a branch named @var{tag}. See @ref{Branching and merging}.
+
+@item -c
+Check that working files are unmodified. See
+@ref{Tagging the working directory}.
@item -D @var{date}
-Tag revisions as of @var{date}. See @ref{tag options}.
+Tag revisions as of @var{date}. See @ref{Tagging by date/tag}.
@item -d
-Delete the given tag. See @ref{tag options}.
+Delete @var{tag}. See @ref{Modifying tags}.
@item -F
-Move tag if it already exists. See @ref{tag options}.
+Move @var{tag} if it already exists. See @ref{Modifying tags}.
@item -f
Force a head revision match if tag/date not found.
-See @ref{tag options}.
+See @ref{Tagging by date/tag}.
@item -l
Local; run only in current working directory. See @ref{Recursive behavior}.
-@item -n
-No execution of tag program. See @ref{tag options}.
-
@item -R
Operate recursively (default). @xref{Recursive
behavior}.
-@item -r @var{tag}
-Tag existing tag @var{tag}. See @ref{tag options}.
+@item -r @var{rev}
+Tag existing tag @var{rev}. See @ref{Tagging by date/tag}.
@end table
@item unedit [@var{options}] [@var{files}@dots{}]
@@ -10710,7 +10994,7 @@ file, which defines the modules inside the repository.
@menu
* modules:: Defining modules
-* Wrappers:: Treat directories as files
+* Wrappers:: Specify binary-ness based on file name
* commit files:: The commit support files
* commitinfo:: Pre-commit checking
* verifymsg:: How are log messages evaluated?
@@ -10719,6 +11003,7 @@ file, which defines the modules inside the repository.
* loginfo:: Where should log messages be sent?
* rcsinfo:: Templates for the log messages
* cvsignore:: Ignoring files via cvsignore
+* checkoutlist:: Adding your own administrative files
* history file:: History information
* Variables:: Various variables are expanded
* config:: Miscellaneous CVS configuration
@@ -11055,12 +11340,19 @@ this module.
@c should be better motivated (e.g. start with the
@c problems, then explain how the feature solves it).
+Wrappers refers to a @sc{cvs} feature which lets you
+control certain settings based on the name of the file
+which is being operated on. The settings are @samp{-k}
+for binary files, and @samp{-m} for nonmergeable text
+files.
+
+@ignore
Wrappers allow you to set a hook which transforms files on
their way in and out of @sc{cvs}.
The file @file{cvswrappers} defines the script that will be
run on a file when its name matches a regular
-expresion. There are two scripts that can be run on a
+expression. There are two scripts that can be run on a
file or directory. One script is executed on the file/directory
before being checked into the repository (this is denoted
with the @code{-t} flag) and the other when the file is
@@ -11071,9 +11363,10 @@ not work with client/server @sc{cvs}.
@c file converts to/from a single file, as opposed to
@c the file<->directory case. Could use more
@c investigation...
+@end ignore
-The @file{cvswrappers} also has a @samp{-m} option to
-specify the merge methodology that should be used when
+The @samp{-m} option
+specifies the merge methodology that should be used when
a non-binary file is updated. @code{MERGE} means the usual
@sc{cvs} behavior: try to merge the files. @code{COPY}
means that @code{cvs update} will refuse to merge
@@ -11104,14 +11397,17 @@ The basic format of the file @file{cvswrappers} is:
wildcard [option value][option value]...
where option is one of
+@ignore
-f from cvs filter value: path to filter
-t to cvs filter value: path to filter
+@end ignore
-m update methodology value: MERGE or COPY
-k keyword expansion value: expansion mode
and value is a single-quote delimited value.
@end example
+@ignore
@example
*.nib -f 'unwrap %s' -t 'wrap %s %s' -m 'COPY'
*.c -t 'indent %s %s'
@@ -11171,8 +11467,11 @@ options}).
@c This is, of course, a serious design flaw in -t/-f.
@c Probably the whole functionality needs to be
@c redesigned (starting from requirements) to fix this.
+@end ignore
-For another example, the following command imports a
+@c FIXME: We don't document -W or point to where it is
+@c documented. Or .cvswrappers.
+For example, the following command imports a
directory, treating files whose name ends in
@samp{.exe} as binary:
@@ -11346,9 +11645,11 @@ removed, and modified files).
@cindex exit status, of commitinfo
The first line with a regular expression matching the
-relative path to the module will be used. If the
+directory within the repository will be used. If the
command returns a non-zero exit status the commit will
be aborted.
+@c FIXME: need example(s) of what "directory within the
+@c repository" means.
@cindex DEFAULT in commitinfo
If the repository name does not match any of the
@@ -11356,7 +11657,7 @@ regular expressions in this file, the @samp{DEFAULT}
line is used, if it is specified.
@cindex ALL in commitinfo
-All occurances of the name @samp{ALL} appearing as a
+All occurrences of the name @samp{ALL} appearing as a
regular expression are used in addition to the first
matching regular expression or the name @samp{DEFAULT}.
@@ -11408,7 +11709,7 @@ One thing that should be noted is that the @samp{ALL}
keyword is not supported. If more than one matching
line is found, the first one is used. This can be
useful for specifying a default verification script in a
-module, and then overriding it in a subdirectory.
+directory, and then overriding it in a subdirectory.
@cindex DEFAULT in verifymsg
If the repository name does not match any of the
@@ -11462,7 +11763,7 @@ fi
The @file{verifymsg} file contains this line:
@example
-^tc /usr/cvssupport/bugid.edit
+^tc /usr/cvssupport/bugid.verify
@end example
The @file{rcsinfo} file contains this line:
@@ -11615,7 +11916,7 @@ If the repository name does not match any of the
regular expressions in this file, the @samp{DEFAULT}
line is used, if it is specified.
-All occurances of the name @samp{ALL} appearing as a
+All occurrences of the name @samp{ALL} appearing as a
regular expression are used in addition to the first
matching regular expression or @samp{DEFAULT}.
@@ -11780,7 +12081,7 @@ If the repository name does not match any of the
regular expressions in this file, the @samp{DEFAULT}
line is used, if it is specified.
-All occurances of the name @samp{ALL} appearing as a
+All occurrences of the name @samp{ALL} appearing as a
regular expression are used in addition to the first
matching regular expression or @samp{DEFAULT}.
@@ -11791,7 +12092,7 @@ matching regular expression or @samp{DEFAULT}.
@c whether it is hardwired into CVS or who creates
@c it or anything. In particular we should say
@c how to version control the template file. A
-@c probably better answer than the /usr/cvsssupport
+@c probably better answer than the /usr/cvssupport
@c stuff is to use checkoutlist (with xref to the
@c checkoutlist doc).
@c Also I am starting to see a connection between
@@ -11920,6 +12221,54 @@ way to specify comments.
@c changing it raises all the usual compatibility
@c issues and I'm also not sure what to change it to.
+@node checkoutlist
+@appendixsec The checkoutlist file
+@cindex checkoutlist
+
+It may be helpful to use @sc{cvs} to maintain your own
+files in the @file{CVSROOT} directory. For example,
+suppose that you have a script @file{logcommit.pl}
+which you run by including the following line in the
+@file{commitinfo} administrative file:
+
+@example
+ALL $CVSROOT/CVSROOT/logcommit.pl
+@end example
+
+To maintain @file{logcommit.pl} with @sc{cvs} you would
+add the following line to the @file{checkoutlist}
+administrative file:
+
+@example
+logcommit.pl
+@end example
+
+The format of @file{checkoutlist} is one line for each
+file that you want to maintain using @sc{cvs}, giving
+the name of the file.
+
+After setting up @file{checkoutlist} in this fashion,
+the files listed there will function just like
+@sc{cvs}'s built-in administrative files. For example,
+when checking in one of the files you should get a
+message such as:
+
+@example
+cvs commit: Rebuilding administrative file database
+@end example
+
+and the checked out copy in the @file{CVSROOT}
+directory should be updated.
+
+Note that listing @file{passwd} (@pxref{Password
+authentication server}) in @file{checkoutlist} is not
+recommended for security reasons.
+
+For information about keeping a checkout out copy in a
+more general context than the one provided by
+@file{checkoutlist}, see @ref{Keeping a checked out
+copy}.
+
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node history file
@appendixsec The history file
@@ -11964,7 +12313,7 @@ One may want to know about various pieces of
information internal to @sc{cvs}. A @sc{cvs} internal
variable has the syntax @code{$@{@var{variable}@}},
where @var{variable} starts with a letter and consists
-of alphanumberic characters and @samp{_}. If the
+of alphanumeric characters and @samp{_}. If the
character following @var{variable} is a
non-alphanumeric character other than @samp{_}, the
@samp{@{} and @samp{@}} can be omitted. The @sc{cvs}
@@ -12069,7 +12418,7 @@ The default is @samp{yes}. For more on pserver, see
Enable support for saving special device files,
symbolic links, file permissions and ownerships in the
repository. The default value is @samp{no}.
-@xref{Special Files} for the full implications of using
+@xref{Special Files}, for the full implications of using
this keyword.
@cindex TopLevelAdmin, in CVSROOT/config
@@ -12089,6 +12438,28 @@ each command. It also provides a place for the
@samp{CVS/Template} file (@pxref{Working directory
storage}).
+@cindex LockDir, in CVSROOT/config
+@item LockDir=@var{directory}
+Put CVS lock files in @var{directory} rather than
+directly in the repository. This is useful if you want
+to let users read from the repository while giving them
+write access only to @var{directory}, not to the
+repository. You need to create @var{directory}, but
+CVS will create subdirectories of @var{directory} as it
+needs them. For information on CVS locks, see
+@ref{Concurrency}.
+
+@c Mention this in Compatibility section?
+Before enabling the LockDir option, make sure that you
+have tracked down and removed any copies of CVS 1.9 or
+older. Such versions neither support LockDir, nor will
+give an error indicating that they don't support it.
+The result, if this is allowed to happen, is that some
+CVS users will put the locks one place, and others will
+put them another place, and therefore the repository
+could become corrupted. CVS 1.10 does not support
+LockDir but it will print a warning if run on a
+repository with LockDir enabled.
@end table
@c ---------------------------------------------------------------------
@@ -12138,6 +12509,7 @@ directory.
@item $EDITOR
@itemx $CVSEDITOR
+@itemx $VISUAL
Specifies the program to use for recording log messages
during commit. @code{$CVSEDITOR} overrides
@code{$EDITOR}. See @ref{Committing your changes}.
@@ -12209,7 +12581,12 @@ seconds so that you can attach to it with a debugger.
@cindex CVS_IGNORE_REMOTE_ROOT, environment variable
@item $CVS_IGNORE_REMOTE_ROOT
-(What is the purpose of this variable?)
+For @sc{cvs} 1.10 and older, setting this variable
+prevents @sc{cvs} from overwriting the @file{CVS/Root}
+file when the @samp{-d} global option is specified.
+Later versions of @sc{cvs} do not rewrite
+@file{CVS/Root}, so CVS_IGNORE_REMOTE_ROOT has no
+effect.
@cindex COMSPEC, environment variable
@item $COMSPEC
@@ -12424,6 +12801,20 @@ produced it should work fine.
@c so it doesn't seem particularly specific to any one
@c test.
+@item cvs [server aborted]: Cannot check out files into the repository itself
+The obvious cause for this message (especially for
+non-client/server @sc{cvs}) is that the @sc{cvs} root
+is, for example, @file{/usr/local/cvsroot} and you try
+to check out files when you are in a subdirectory, such
+as @file{/usr/local/cvsroot/test}. However, there is a
+more subtle cause, which is that the temporary
+directory on the server is set to a subdirectory of the
+root (which is also not allowed). If this is the
+problem, set the temporary directory to somewhere else,
+for example @file{/var/tmp}; see @code{TMPDIR} in
+@ref{Environment variables}, for how to set the
+temporary directory.
+
@c For one example see basica-1a10 in the testsuite
@c For another example, "cvs co ." on NT; see comment
@c at windows-NT/filesubr.c (expand_wild).
@@ -12539,6 +12930,22 @@ have printed a message, which will appear before the
above message. For more information on setting up a
@sc{cvs} client and server, see @ref{Remote repositories}.
+@item cvs [update aborted]: EOF in key in RCS file @var{file},v
+@itemx cvs [checkout aborted]: EOF while looking for end of string in RCS file @var{file},v
+This means that there is a syntax error in the given
+@sc{rcs} file. Note that this might be true even if @sc{rcs} can
+read the file OK; @sc{cvs} does more error checking of
+errors in the RCS file. That is why you may see this
+message when upgrading from @sc{cvs} 1.9 to @sc{cvs}
+1.10. The likely cause for the original corruption is
+hardware, the operating system, or the like. Of
+course, if you find a case in which @sc{cvs} seems to
+corrupting the file, by all means report it,
+(@pxref{BUGS}).
+There are quite a few variations of this error message,
+depending on exactly where in the @sc{rcs} file @sc{cvs}
+finds the syntax error.
+
@cindex mkmodules
@item cvs commit: Executing 'mkmodules'
This means that your repository is set up for a version
@@ -12557,7 +12964,7 @@ every place it appears in your @code{modules}
file. For more information on the @code{modules} file,
see @ref{modules}.
-@c This messsage comes from "co", and I believe is
+@c This message comes from "co", and I believe is
@c possible only with older versions of CVS which call
@c co. The problem with being able to create the bogus
@c RCS file still exists, though (and I think maybe
@@ -12575,6 +12982,22 @@ set to a non-empty value and re-create the RCS file.
@c variables the system login name, &c, and it depends
@c on the version of CVS.
+@item cvs [checkout aborted]: no such tag @var{tag}
+This message means that @sc{cvs} isn't familiar with
+the tag @var{tag}. Usually this means that you have
+mistyped a tag name; however there are (relatively
+obscure) cases in which @sc{cvs} will require you to
+@c Search sanity.sh for "no such tag" to see some of
+@c the relatively obscure cases.
+try a few other @sc{cvs} commands involving that tag,
+before you find one which will cause @sc{cvs} to update
+the @file{val-tags} file; see discussion of val-tags in
+@ref{File permissions}. You only need to worry about
+this once for a given tag; when a tag is listed in
+@file{val-tags}, it stays there. Note that using
+@samp{-f} to not require tag matches does not override
+this check; see @ref{Common options}.
+
@item *PANIC* administration files missing
This typically means that there is a directory named
CVS but it does not contain the administrative files
@@ -12621,6 +13044,18 @@ logfile to be specified with a @samp{-f} option. Of
course, if you don't need @file{log.pl} you can just
comment it out of @file{loginfo}.
+@item cvs [update aborted]: unexpected EOF reading @var{file},v
+See @samp{EOF in key in RCS file}.
+
+@item cvs [login aborted]: unrecognized auth response from @var{server}
+This message typically means that the server is not set
+up properly. For example, if @file{inetd.conf} points
+to a nonexistent cvs executable. To debug it further,
+find the log file which inetd writes
+(@file{/var/log/messages} or whatever inetd uses on
+your system). For details, see @ref{Connection}, and
+@ref{Password authentication server}.
+
@item cvs commit: Up-to-date check failed for `@var{file}'
This means that someone else has committed a change to
that file since the last time that you did a @code{cvs
@@ -12665,6 +13100,10 @@ for setting up the CVS server.
@c FIXCVS: should be printing CR as \r or \015 or some
@c such, probably.
+@item cvs commit: [@var{time}] waiting for @var{user}'s lock in @var{directory}
+This is a normal message, not an error. See
+@ref{Concurrency}, for more details.
+
@item cvs commit: warning: editor session failed
@cindex exit status, of editor
This means that the editor which @sc{cvs} is using exits with a nonzero
@@ -12746,6 +13185,10 @@ program trying to use port 2401. This is AIX's problem
in the sense that port 2401 is registered for use with
@sc{cvs}. I hear that there is an AIX patch available
to address this problem.
+
+Another good debugging tool is the @samp{-d}
+(debugging) option to inetd. Consult your system
+documentation for more information.
@end table
@node Other problems
@@ -12756,6 +13199,17 @@ above categories. They are in no particular order.
@itemize @bullet
@item
+On Windows, if there is a 30 second or so delay when
+you run a @sc{cvs} command, it may mean that you have
+your home directory set to @file{C:/}, for example (see
+@code{HOMEDRIVE} and @code{HOMEPATH} in
+@ref{Environment variables}). CVS expects the home
+directory to not end in a slash, for example @file{C:}
+or @file{C:\cvs}.
+@c FIXCVS: CVS should at least detect this and print an
+@c error, presumably.
+
+@item
If you are running @sc{cvs} 1.9.18 or older, and
@code{cvs update} finds a conflict and tries to
merge, as described in @ref{Conflicts example}, but
diff --git a/contrib/cvs/doc/cvsclient.texi b/contrib/cvs/doc/cvsclient.texi
index 6f01399..394c0ca 100644
--- a/contrib/cvs/doc/cvsclient.texi
+++ b/contrib/cvs/doc/cvsclient.texi
@@ -217,6 +217,10 @@ The @var{text} should be supplied to the
user. Compatibility note: @sc{cvs} 1.9.10 and older clients will print
@code{unrecognized auth response} and @var{text}, and then exit, upon
receiving this response.
+Note that @var{text} for this response, or the @var{text} in an @code{E}
+response, is not designed for machine parsing. More vigorous use of
+@var{code}, or future extensions, will be needed to prove a cleaner
+machine-parseable indication of what the error was.
@end table
@c If you are thinking of putting samp or code around BEGIN AUTH REQUEST
@@ -479,7 +483,7 @@ For the @samp{-D} option to the @code{annotate}, @code{co}, @code{diff},
and @code{update} requests, the server should support two formats:
@example
-26 May 1997 13:01:40 GMT ; @r{RFC 822 as modified by RFC 1123}
+26 May 1997 13:01:40 -0000 ; @r{RFC 822 as modified by RFC 1123}
5/26/1997 13:01:40 GMT ; @r{traditional}
@end example
@@ -491,7 +495,9 @@ least support RFC 822/1123 format. Clients are encouraged to use this
format too (traditionally the command line CVS client has just passed
along the date format specified by the user, however).
-For @code{Mod-time}, see the description of that response.
+The @code{Mod-time} response and @code{Checkin-time} request use RFC
+822/1123 format (see the descriptions of that response and request for
+details).
For @code{Notify}, see the description of that request.
@@ -504,6 +510,16 @@ exception is @samp{gzip-file-contents}. Unrecognized requests will
always elicit a response from the server, even if that request begins
with a capital letter.
+The term @dfn{command} means a request which expects a response (except
+@code{valid-requests}). The general model is that the client transmits
+a great number of requests, but nothing happens until the very end when
+the client transmits a command. Although the intention is that
+transmitting several commands in one connection should be legal,
+existing servers probably have some bugs with some combinations of more
+than one command, and so clients may find it necessary to make several
+connections in some cases. This should be thought of as a workaround
+rather than a desired attribute of the protocol.
+
@node Requests
@section Requests
@@ -521,7 +537,7 @@ in use, connection, authentication, etc., are already taken care of.
The @code{Root} request must be sent only once, and it must be sent
before any requests other than @code{Valid-responses},
-@code{valid-requests}, @code{UseUnchanged}, or @code{init}.
+@code{valid-requests}, @code{UseUnchanged}, @code{Set} or @code{init}.
@item Valid-responses @var{request-list} \n
Response expected: no.
@@ -606,6 +622,99 @@ Each @code{Directory} request specifies a brand-new
@var{local-directory} and @var{repository} are never relative to paths
specified in any previous @code{Directory} request.
+Here's a more complex example, in which we request an update of a
+working directory which has been checked out from multiple places in the
+repository.
+
+@example
+C: Argument dir1
+C: Directory dir1
+C: /home/foo/repos/mod1
+. . .
+C: Argument dir2
+C: Directory dir2
+C: /home/foo/repos/mod2
+. . .
+C: Argument dir3
+C: Directory dir3/subdir3
+C: /home/foo/repos/mod3
+. . .
+C: update
+@end example
+
+While directories @code{dir1} and @code{dir2} will be handled in similar
+fashion to the other examples given above, @code{dir3} is slightly
+different from the server's standpoint. Notice that module @code{mod3}
+is actually checked out into @code{dir3/subdir3}, meaning that directory
+@code{dir3} is either empty or does not contain data checked out from
+this repository.
+
+The above example will work correctly in @sc{cvs} 1.10.1 and later. The
+server will descend the tree starting from all directories mentioned in
+@code{Argument} requests and update those directories specifically
+mentioned in @code{Directory} requests.
+
+Previous versions of @sc{cvs} (1.10 and earlier) do not behave the same
+way. While the descent of the tree begins at all directories mentioned
+in @code{Argument} requests, descent into subdirectories only occurs if
+a directory has been mentioned in a @code{Directory} request.
+Therefore, the above example would succeed in updating @code{dir1} and
+@code{dir2}, but would skip @code{dir3} because that directory was not
+specifically mentioned in a @code{Directory} request. A functional
+version of the above that would run on a 1.10 or earlier server is as
+follows:
+
+@example
+C: Argument dir1
+C: Directory dir1
+C: /home/foo/repos/mod1
+. . .
+C: Argument dir2
+C: Directory dir2
+C: /home/foo/repos/mod2
+. . .
+C: Argument dir3
+C: Directory dir3
+C: /home/foo/repos/.
+. . .
+C: Directory dir3/subdir3
+C: /home/foo/repos/mod3
+. . .
+C: update
+@end example
+
+Note the extra @code{Directory dir3} request. It might be better to use
+@code{Emptydir} as the repository for the @code{dir3} directory, but the
+above will certainly work.
+
+One more peculiarity of the 1.10 and earlier protocol is the ordering of
+@code{Directory} arguments. In order for a subdirectory to be
+registered correctly for descent by the recursion processor, its parent
+must be sent first. For example, the following would not work to update
+@code{dir3/subdir3}:
+
+@example
+. . .
+C: Argument dir3
+C: Directory dir3/subdir3
+C: /home/foo/repos/mod3
+. . .
+C: Directory dir3
+C: /home/foo/repos/.
+. . .
+C: update
+@end example
+
+The implementation of the server in 1.10 and earlier writes the
+administration files for a given directory at the time of the
+@code{Directory} request. It also tries to register the directory with
+its parent to mark it for recursion. In the above example, at the time
+@code{dir3/subdir3} is created, the physical directory for @code{dir3}
+will be created on disk, but the administration files will not have been
+created. Therefore, when the server tries to register
+@code{dir3/subdir3} for recursion, the operation will silently fail
+because the administration files do not yet exist for @code{dir3}.
+
@item Max-dotdot @var{level} \n
Response expected: no.
Tell the server that @var{level} levels of directories above the
@@ -627,9 +736,10 @@ responses.
@item Sticky @var{tagspec} \n
Response expected: no. Tell the server that the directory most recently
specified with @code{Directory} has a sticky tag or date @var{tagspec}.
-The first character of @var{tagspec} is @samp{T} for a tag, or @samp{D}
-for a date. The remainder of @var{tagspec} contains the actual tag or
-date.
+The first character of @var{tagspec} is @samp{T} for a tag, @samp{D}
+for a date, or some other character supplied by a Set-sticky response
+from a previous request to the server. The remainder of @var{tagspec}
+contains the actual tag or date, again as supplied by Set-sticky.
The server should remember @code{Static-directory} and @code{Sticky}
requests for a particular directory; the client need not resend them
@@ -672,10 +782,34 @@ Typically this will be a file being added via an @code{add} or
@code{import} request. The client may not send both @code{Kopt} and
@code{Entry} for the same file.
+@item Checkin-time @var{time} \n
+For the file specified by the next @code{Modified} request, use
+@var{time} as the time of the checkin. The @var{time} is in the format
+specified by RFC822 as modified by RFC1123. The client may specify any
+timezone it chooses; servers will want to convert that to their own
+timezone as appropriate. An example of this format is:
+
+@example
+26 May 1997 13:01:40 -0400
+@end example
+
+There is no requirement that the client and server clocks be
+synchronized. The client just sends its recommendation for a timestamp
+(based on file timestamps or whatever), and the server should just believe
+it (this means that the time might be in the future, for example).
+
+Note that this is not a general-purpose way to tell the server about the
+timestamp of a file; that would be a separate request (if there are
+servers which can maintain timestamp and time of checkin separately).
+
+This request should affect the @code{import} request, and may optionally
+affect the @code{ci} request or other relevant requests if any.
+
@item Modified @var{filename} \n
Response expected: no. Additional data: mode, \n, file transmission.
Send the server a copy of one locally modified file. @var{filename} is
-relative to the most recent repository sent with @code{Directory}. If
+a file within the most recent directory sent with @code{Directory}; it
+must not contain @samp{/}. If
the user is operating on only some files in a directory, only those
files need to be included. This can also be sent without @code{Entry},
if there is no entry for the file.
@@ -717,8 +851,9 @@ investigation, the more conservative course of action is to stick to
@item Unchanged @var{filename} \n
Response expected: no. Tell the server that @var{filename} has not been
-modified in the checked out directory. The name is relative to the most
-recent repository sent with @code{Directory}.
+modified in the checked out directory. The @var{filename} is
+a file within the most recent directory sent with @code{Directory}; it
+must not contain @samp{/}.
@item UseUnchanged \n
Response expected: no. To specify the version of the protocol described
@@ -727,10 +862,13 @@ not do anything) and clients must issue it.
@item Notify @var{filename} \n
Response expected: no.
-Tell the server that a @code{edit} or @code{unedit} command has taken
+Tell the server that an @code{edit} or @code{unedit} command has taken
place. The server needs to send a @code{Notified} response, but such
response is deferred until the next time that the server is sending
-responses. Response expected: no. Additional data:
+responses.
+The @var{filename} is a file within the most recent directory sent with
+@code{Directory}; it must not contain @samp{/}.
+Additional data:
@example
@var{notification-type} \t @var{time} \t @var{clienthost} \t
@var{working-dir} \t @var{watches} \n
@@ -748,9 +886,17 @@ time as an opaque string rather than interpreting it).
@var{clienthost} is the name of the host on which the edit or unedit
took place, and @var{working-dir} is the pathname of the working
directory where the edit or unedit took place. @var{watches} are the
-temporary watches to set. If @var{watches} is followed by \t then the
+temporary watches, zero or more of the following characters in the
+following order: @samp{E} for edit, @samp{U} for unedit, @samp{C} for
+commit, and all other letters should be silently ignored for future
+expansion. If @var{notification-type} is @samp{E} the temporary watches
+are set; if it is @samp{U} they are cleared.
+If @var{watches} is followed by \t then the
\t and the rest of the line should be ignored, for future expansion.
+The @var{time}, @var{clienthost}, and @var{working-dir} fields may not
+contain the characters @samp{+}, @samp{,}, @samp{>}, @samp{;}, or @samp{=}.
+
Note that a client may be capable of performing an @code{edit} or
@code{unedit} operation without connecting to the server at that time,
and instead connecting to the server when it is convenient (for example,
@@ -982,7 +1128,9 @@ Response expected: yes. Actually do a @code{cvs import} command. This
uses any previous @code{Argument}, @code{Directory}, @code{Entry}, or
@code{Modified} requests, if they have been sent. The
last @code{Directory} sent specifies the working directory at the time
-of the operation. The files to be imported are sent in @code{Modified}
+of the operation - unlike most commands, the repository field of each
+@code{Directory} request is ignored (it merely must point somewhere
+within the root). The files to be imported are sent in @code{Modified}
requests (files which the client knows should be ignored are not sent;
the server must still process the CVSROOT/cvsignore file unless -I ! is
sent). A log message must have been specified with a @code{-m}
@@ -1134,7 +1282,7 @@ Response expected: yes.
Any unrecognized request expects a response, and does not
contain any additional data. The response will normally be something like
@samp{error unrecognized request}, but it could be a different error if
-a previous command which doesn't expect a response produced an error.
+a previous request which doesn't expect a response produced an error.
@end table
When the client is done, it drops the connection.
@@ -1330,6 +1478,11 @@ synchronized. The server just sends its recommendation for a timestamp
(based on its own clock, presumably), and the client should just believe
it (this means that the time might be in the future, for example).
+If the server does not send @code{Mod-time} for a given file, the client
+should pick a modification time in the usual way (usually, just let the
+operating system set the modification time to the time that the CVS
+command is running).
+
@item Checksum @var{checksum}\n
The @var{checksum} applies to the next file sent (that is,
@code{Checksum} is a file update modifying response
@@ -1433,6 +1586,13 @@ extending this one, for graceful handling of @code{Valid-responses}).
@item M @var{text} \n
A one-line message for the user.
+Note that the format of @var{text} is not designed for machine parsing.
+Although sometimes scripts and clients will have little choice, the
+exact text which is output is subject to vary at the discretion of the
+server and the example output given in this document is just that,
+example output. Servers are encouraged to use the @samp{MT} response,
+and future versions of this document will hopefully standardize more of
+the @samp{MT} tags; see @ref{Text tags}.
@item Mbinary \n
Additional data: file transmission (note: compressed file transmissions
@@ -1530,6 +1690,12 @@ feature, or if it's not appropriate for this particular message, it just
omits the errno-code (in that case there are two spaces after
@samp{error}). Text is an error message such as that provided by
strerror(), or any other message the server wants to use.
+The @var{text} is like the @code{M} response, in the sense that it is
+not particularly intended to be machine-parsed; servers may wish to
+print an error message with @code{MT} responses, and then issue a
+@code{error} response without @var{text} (although it should be noted
+that @code{MT} currently has no way of flagging the output as intended
+for standard error, the way that the @code{E} response does).
@item ok \n
The command completed successfully.
@@ -1564,6 +1730,23 @@ MT fname @var{name}
MT -updated
@end example
+The @code{importmergecmd} tag is used when doing an import which has
+conflicts. The client can use it to report how to merge in the newly
+imported changes. The @var{count} is the number of conflicts. The
+newly imported changes can be merged by running the following command:
+@smallexample
+cvs checkout -j @var{tag1} -j @var{tag2} @var{repository}
+@end smallexample
+
+@example
+MT +importmergecmd
+MT conflicts @var{count}
+MT mergetag1 @var{tag1}
+MT mergetag2 @var{tag2}
+MT repository @var{repository}
+MT -importmergecmd
+@end example
+
@node Example
@section Example
@@ -1751,6 +1934,8 @@ working directory, and the meaning of sending @code{Entries} without
A number of enhancements are possible. Also see the file @sc{todo} in
the @sc{cvs} source distribution, which has further ideas concerning
various aspects of @sc{cvs}, some of which impact the protocol.
+Similarly, the @code{http://www.cyclic.com} site, in particular the
+@cite{Development of CVS} page.
@itemize @bullet
@item
@@ -1762,18 +1947,6 @@ could be handled by a package like VC for emacs). This would also allow
local operation of @code{cvs diff} without arguments.
@item
-The current procedure for @code{cvs update} is highly sub-optimal if
-there are many modified files. One possible alternative would be to
-have the client send a first request without the contents of every
-modified file, then have the server tell it what files it needs. Note
-the server needs to do the what-needs-to-be-updated check twice (or
-more, if changes in the repository mean it has to ask the client for
-more files), because it can't keep locks open while waiting for the
-network. Perhaps this whole thing is irrelevant if there is a multisite
-capability (as noted in @sc{todo}), and therefore the rcsmerge can be
-done with a repository which is connected via a fast connection.
-
-@item
The fact that @code{pserver} requires an extra network turnaround in
order to perform authentication would be nice to avoid. This relates to
the issue of reporting errors; probably the clean solution is to defer
diff --git a/contrib/cvs/lib/ChangeLog b/contrib/cvs/lib/ChangeLog
index 264b7ac..37cc6ab 100644
--- a/contrib/cvs/lib/ChangeLog
+++ b/contrib/cvs/lib/ChangeLog
@@ -1,3 +1,45 @@
+1999-03-26 Jim Kingdon <http://www.cyclic.com>
+
+ * getopt.h: Don't declare the arguments to getopt.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * vasprintf.c: Removed; there is apparently no clean, portable
+ solution to the VA_LIST_IS_ARRAY problem (C9X drafts have va_copy,
+ but we aren't even assuming C90 yet!).
+ * Makefile.in (SOURCES): Remove vasprintf.c.
+ * build_lib.com: Remove vasprintf.c and vasprintf.obj.
+
+1999-01-26 Jim Kingdon <http://www.cyclic.com>
+ and Joerg Bullmann <http://www.glink.net.hk/~jb/MacCVSClient/>
+
+ * fnmatch.c: Use FOLD_FN_CHAR in two cases where it had been
+ omitted.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * fnmatch.c: Include system.h; FOLD_FN_CHAR has moved there from
+ config.h (from Alexey Milov). Don't define our own FOLD_FN_CHAR;
+ that just masks cases in which we got the includes tangled up.
+
+1999-01-12 Jim Kingdon <http://www.cyclic.com>
+
+ * memmove.c: Remove paragraph which contained the FSF's old
+ snail mail address; it has changed.
+
+1999-01-05 Jim Kingdon <http://www.cyclic.com>
+
+ * md5.c, md5.h: Rename all the external interfaces to start with
+ cvs_* to avoid namespace pollution problems. Include string.h
+ unconditionally, to avoid gcc -Wall warnings on memset.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * getdate.y (RelativeMonth): Add 1900 to tm_year, so that in 2000,
+ we pass 2000, not 100, to Convert.
+ (Convert): Add comment about Year argument.
+ * getdate.c: Regenerated using byacc.
+
Tue Mar 24 16:08:00 1998 Ian Lance Taylor <ian@cygnus.com>
* Makefile.in (CFLAGS): Set to @CFLAGS@, not -g.
diff --git a/contrib/cvs/lib/Makefile.in b/contrib/cvs/lib/Makefile.in
index 99d816b..f35baae 100644
--- a/contrib/cvs/lib/Makefile.in
+++ b/contrib/cvs/lib/Makefile.in
@@ -46,7 +46,6 @@ SOURCES = \
stripslash.c \
strtoul.c \
valloc.c \
- vasprintf.c \
waitpid.c \
xgetwd.c \
yesno.c
diff --git a/contrib/cvs/lib/fnmatch.c b/contrib/cvs/lib/fnmatch.c
index cf0f124..a41c0dc 100644
--- a/contrib/cvs/lib/fnmatch.c
+++ b/contrib/cvs/lib/fnmatch.c
@@ -18,14 +18,7 @@ Library General Public License for more details. */
#include "config.h"
#endif
-/* Some file systems are case-insensitive. If FOLD_FN_CHAR is
- #defined, it maps the character C onto its "canonical" form. In a
- case-insensitive system, it would map all alphanumeric characters
- to lower case. Under Windows NT, / and \ are both path component
- separators, so FOLD_FN_CHAR would map them both to /. */
-#ifndef FOLD_FN_CHAR
-#define FOLD_FN_CHAR(c) (c)
-#endif
+#include "system.h"
/* IGNORE(@ */
/* #include <ansidecl.h> */
@@ -75,7 +68,7 @@ fnmatch (pattern, string, flags)
case '\\':
if (!(flags & FNM_NOESCAPE))
c = *p++;
- if (*n != c)
+ if (FOLD_FN_CHAR (*n) != FOLD_FN_CHAR (c))
return FNM_NOMATCH;
break;
@@ -95,7 +88,7 @@ fnmatch (pattern, string, flags)
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
for (--p; *n != '\0'; ++n)
- if ((c == '[' || *n == c1) &&
+ if ((c == '[' || FOLD_FN_CHAR (*n) == FOLD_FN_CHAR (c1)) &&
fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
return 0;
return FNM_NOMATCH;
diff --git a/contrib/cvs/lib/getdate.y b/contrib/cvs/lib/getdate.y
index fdb177d..9a4a8fa 100644
--- a/contrib/cvs/lib/getdate.y
+++ b/contrib/cvs/lib/getdate.y
@@ -619,6 +619,10 @@ ToSeconds(Hours, Minutes, Seconds, Meridian)
}
+/* Year is either
+ * A negative number, which means to use its absolute value (why?)
+ * A number from 0 to 99, which means a year from 1900 to 1999, or
+ * The actual year (>=100). */
static time_t
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
time_t Month;
@@ -710,7 +714,7 @@ RelativeMonth(Start, RelMonth)
if (RelMonth == 0)
return 0;
tm = localtime(&Start);
- Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
Year = Month / 12;
Month = Month % 12 + 1;
return DSTcorrect(Start,
diff --git a/contrib/cvs/lib/getopt.h b/contrib/cvs/lib/getopt.h
index c872f414..7fc2cca 100644
--- a/contrib/cvs/lib/getopt.h
+++ b/contrib/cvs/lib/getopt.h
@@ -91,14 +91,14 @@ struct option
#define optional_argument 2
#if __STDC__
-#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
- differences in the consts, in stdlib.h. To avoid compilation
- errors, only prototype getopt for the GNU C library. */
-extern int getopt (int argc, char *const *argv, const char *shortopts);
-#else /* not __GNU_LIBRARY__ */
+ differences in the consts, in stdlib.h. We used to try to prototype
+ it if __GNU_LIBRARY__ but that wasn't problem free either (I'm not sure
+ exactly why), and there is no particular need to prototype it.
+ We really shouldn't be trampling on the system's namespace at all by
+ declaring getopt() but that is a bigger issue. */
extern int getopt ();
-#endif /* not __GNU_LIBRARY__ */
+
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
diff --git a/contrib/cvs/lib/md5.c b/contrib/cvs/lib/md5.c
index 1003a40..f9a3cad 100644
--- a/contrib/cvs/lib/md5.c
+++ b/contrib/cvs/lib/md5.c
@@ -23,13 +23,16 @@
copyright in any changes I have made; this code remains in the
public domain. */
+/* Note regarding cvs_* namespace: this avoids potential conflicts
+ with libraries such as some versions of Kerberos. No particular
+ need to worry about whether the system supplies an MD5 library, as
+ this file is only about 3k of object code. */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#if HAVE_STRING_H || STDC_HEADERS
-#include <string.h> /* for memcpy() */
-#endif
+#include <string.h> /* for memcpy() and memset() */
/* Add prototype support. */
#ifndef PROTO
@@ -43,12 +46,12 @@
#include "md5.h"
/* Little-endian byte-swapping routines. Note that these do not
- depend on the size of datatypes such as uint32, nor do they require
+ depend on the size of datatypes such as cvs_uint32, nor do they require
us to detect the endianness of the machine we are running on. It
is possible they should be macros for speed, but I would be
surprised if they were a performance bottleneck for MD5. */
-static uint32
+static cvs_uint32
getu32 (addr)
const unsigned char *addr;
{
@@ -58,7 +61,7 @@ getu32 (addr)
static void
putu32 (data, addr)
- uint32 data;
+ cvs_uint32 data;
unsigned char *addr;
{
addr[0] = (unsigned char)data;
@@ -72,8 +75,8 @@ putu32 (data, addr)
* initialization constants.
*/
void
-MD5Init(ctx)
- struct MD5Context *ctx;
+cvs_MD5Init (ctx)
+ struct cvs_MD5Context *ctx;
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
@@ -89,17 +92,17 @@ MD5Init(ctx)
* of bytes.
*/
void
-MD5Update(ctx, buf, len)
- struct MD5Context *ctx;
+cvs_MD5Update (ctx, buf, len)
+ struct cvs_MD5Context *ctx;
unsigned char const *buf;
unsigned len;
{
- uint32 t;
+ cvs_uint32 t;
/* Update bitcount */
t = ctx->bits[0];
- if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
+ if ((ctx->bits[0] = (t + ((cvs_uint32)len << 3)) & 0xffffffff) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
@@ -116,7 +119,7 @@ MD5Update(ctx, buf, len)
return;
}
memcpy(p, buf, t);
- MD5Transform(ctx->buf, ctx->in);
+ cvs_MD5Transform (ctx->buf, ctx->in);
buf += t;
len -= t;
}
@@ -125,7 +128,7 @@ MD5Update(ctx, buf, len)
while (len >= 64) {
memcpy(ctx->in, buf, 64);
- MD5Transform(ctx->buf, ctx->in);
+ cvs_MD5Transform (ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
@@ -140,9 +143,9 @@ MD5Update(ctx, buf, len)
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
-MD5Final(digest, ctx)
+cvs_MD5Final (digest, ctx)
unsigned char digest[16];
- struct MD5Context *ctx;
+ struct cvs_MD5Context *ctx;
{
unsigned count;
unsigned char *p;
@@ -162,7 +165,7 @@ MD5Final(digest, ctx)
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
- MD5Transform(ctx->buf, ctx->in);
+ cvs_MD5Transform (ctx->buf, ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
@@ -175,7 +178,7 @@ MD5Final(digest, ctx)
putu32(ctx->bits[0], ctx->in + 56);
putu32(ctx->bits[1], ctx->in + 60);
- MD5Transform(ctx->buf, ctx->in);
+ cvs_MD5Transform (ctx->buf, ctx->in);
putu32(ctx->buf[0], digest);
putu32(ctx->buf[1], digest + 4);
putu32(ctx->buf[2], digest + 8);
@@ -203,12 +206,12 @@ MD5Final(digest, ctx)
* the data and converts bytes into longwords for this routine.
*/
void
-MD5Transform(buf, inraw)
- uint32 buf[4];
+cvs_MD5Transform (buf, inraw)
+ cvs_uint32 buf[4];
const unsigned char inraw[64];
{
- register uint32 a, b, c, d;
- uint32 in[16];
+ register cvs_uint32 a, b, c, d;
+ cvs_uint32 in[16];
int i;
for (i = 0; i < 16; ++i)
@@ -302,7 +305,7 @@ MD5Transform(buf, inraw)
int
main (int argc, char **argv)
{
- struct MD5Context context;
+ struct cvs_MD5Context context;
unsigned char checksum[16];
int i;
int j;
@@ -315,9 +318,9 @@ main (int argc, char **argv)
for (j = 1; j < argc; ++j)
{
printf ("MD5 (\"%s\") = ", argv[j]);
- MD5Init (&context);
- MD5Update (&context, argv[j], strlen (argv[j]));
- MD5Final (checksum, &context);
+ cvs_MD5Init (&context);
+ cvs_MD5Update (&context, argv[j], strlen (argv[j]));
+ cvs_MD5Final (checksum, &context);
for (i = 0; i < 16; i++)
{
printf ("%02x", (unsigned int) checksum[i]);
diff --git a/contrib/cvs/lib/md5.h b/contrib/cvs/lib/md5.h
index 65bac1f..876b632 100644
--- a/contrib/cvs/lib/md5.h
+++ b/contrib/cvs/lib/md5.h
@@ -8,22 +8,19 @@
bits instead of 64 is not important; speed is considerably more
important. ANSI guarantees that "unsigned long" will be big enough,
and always using it seems to have few disadvantages. */
-typedef unsigned long uint32;
+typedef unsigned long cvs_uint32;
-struct MD5Context {
- uint32 buf[4];
- uint32 bits[2];
+struct cvs_MD5Context {
+ cvs_uint32 buf[4];
+ cvs_uint32 bits[2];
unsigned char in[64];
};
-void MD5Init PROTO((struct MD5Context *context));
-void MD5Update PROTO((struct MD5Context *context, unsigned char const *buf, unsigned len));
-void MD5Final PROTO((unsigned char digest[16], struct MD5Context *context));
-void MD5Transform PROTO((uint32 buf[4], const unsigned char in[64]));
-
-/*
- * This is needed to make RSAREF happy on some MS-DOS compilers.
- */
-typedef struct MD5Context MD5_CTX;
+void cvs_MD5Init PROTO ((struct cvs_MD5Context *context));
+void cvs_MD5Update PROTO ((struct cvs_MD5Context *context,
+ unsigned char const *buf, unsigned len));
+void cvs_MD5Final PROTO ((unsigned char digest[16],
+ struct cvs_MD5Context *context));
+void cvs_MD5Transform PROTO ((cvs_uint32 buf[4], const unsigned char in[64]));
#endif /* !MD5_H */
diff --git a/contrib/cvs/lib/memmove.c b/contrib/cvs/lib/memmove.c
index 8818d46..047a5a0 100644
--- a/contrib/cvs/lib/memmove.c
+++ b/contrib/cvs/lib/memmove.c
@@ -12,10 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
-You should have received a copy of the GNU Library General Public
-License along with libiberty; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+*/
/*
diff --git a/contrib/cvs/man/ChangeLog b/contrib/cvs/man/ChangeLog
index f131d3e..38cc91b 100644
--- a/contrib/cvs/man/ChangeLog
+++ b/contrib/cvs/man/ChangeLog
@@ -1,3 +1,7 @@
+1999-01-19 Vitaly V Fedrushkov <willy@snowyowl.csu.ac.ru>
+
+ * Makefile.in (INSTALL_DATA): Wrong manpage permissions fixed.
+
1998-06-28 Jim Kingdon <kingdon@harvey.cyclic.com>
* cvs.1: Update various items which were out of date. Mostly
diff --git a/contrib/cvs/man/Makefile.in b/contrib/cvs/man/Makefile.in
index ffc3613..d92d494 100644
--- a/contrib/cvs/man/Makefile.in
+++ b/contrib/cvs/man/Makefile.in
@@ -25,7 +25,7 @@ MANFILES = $(MAN1FILES) $(MAN5FILES) $(MAN8FILES)
DISTFILES = .cvsignore ChangeLog Makefile.in $(MANFILES)
INSTALL = @INSTALL@
-INSTALL_DATA = $(INSTALL)
+INSTALL_DATA = @INSTALL_DATA@
prefix = @prefix@
mandir = $(prefix)/man
man1dir = $(mandir)/man1
diff --git a/contrib/cvs/src/ChangeLog b/contrib/cvs/src/ChangeLog
index 8077ce8..0d18891 100644
--- a/contrib/cvs/src/ChangeLog
+++ b/contrib/cvs/src/ChangeLog
@@ -1,3 +1,1517 @@
+1999-07-28 Eric Sink <eric@sourcegear.com>
+
+ * sanity.sh: before running basicc-11, we need to see if
+ the cwd has been deleted (by basicc-8). If so, we
+ recreate it to allow basicc-11 to proceed. This may be
+ something that only happens under the Linux 2.2 kernel.
+
+1999-07-18 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * edit.c (notify_do): chop newline, if any, from the value
+ obtained from CVSROOT/users. Otherwise it just gets passed along
+ in the argument to the notification program (usually mail), which
+ will misinterpret it as signifying the end of the command.
+
+1999-07-19 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c (RCS_delete_revs): In the WIN32 kludge, be sure that the result
+ of RCS_getexpand is not NULL before trying to use what it points to.
+ (Patch submitted by Timothy L. Taylor <ttaylor@mitre.org>.)
+
+1999-07-16 Tom Tromey <tromey@cygnus.com>
+
+ * admin.c (admin): Allow `-k' options to be used unrestricted.
+
+1999-06-23 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (symlinks2): New test, for symlinks in working
+ directory without PreservePermissions. This test (modulo a few
+ details not relevant to testing whether we are following symlinks)
+ worked remote as of now, or either remote or local for CVS 1.9.
+ * subr.c (get_file): Revert 1998-02-15 change to special-case
+ symlinks. This makes the above test work local too.
+ * rcs.c (RCS_checkin): Move the logic to handle special-case
+ symlinks (and other files other than regular files) here, and make
+ it only happen if PreservePermissions is on.
+
+1999-06-18 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (devcom3-9a): Be less specific about the expected
+ error message (BSD/OS 4.0 has a bug that can cause exec* to fail
+ with EACCES instead of ENOENT).
+
+1999-06-08 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (diff-4, dirs2-10, tagf-13, importc-7, conflicts2-142b8):
+ Use ${PROG} instead of "cvs".
+
+1999-06-05 Jim Kingdon <http://www.cyclic.com>
+
+ * recurse.c (do_recursion, do_dir_proc): Make the SERVER_ACTIVE
+ #ifdef be only around the check for server_active. Modulo a few
+ cosmetic tweaks, same as a patch submitted by Johannes Stezenbach
+ of propack-data.de.
+
+1999-06-01 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh: Add comment about rcs2-7 failures on certain days.
+
+ Make "cvs status -v" on a removed file work:
+ * status.c (cvsstatus): Reindent the client code.
+ (status_fileproc): Don't need a CVS/Entries listing to show the
+ tags.
+ * sanity.sh (rmadd2): New test rmadd2-16 tests the existing
+ behavior with "cvs log"; new test rmadd2-17 tests the new behavior
+ with "cvs status".
+
+ * sanity.sh (basicc): To match no output in dotest, put the empty
+ regexp first. Remove tests which check that first-dir exists,
+ since that isn't true in the case where the OS let us delete it.
+ (dotest_internal): Fix so that things work with two regexps, with
+ an empty one first.
+
+1999-05-28 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (server-4): Replace bogus directory with real one since
+ the server now checks it.
+
+1999-05-27 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (spacefiles): Clean up -c, top, and -b at end.
+ (spacefiles, files): Fix bad references to CVSROOT_DIRNAME.
+
+ Fix two problems pointed out by Olaf Kirch of swb.de/caldera.de:
+ * server.c (outside_root): New function, contains expanded version
+ of code from serve_directory.
+ (serve_directory): Call outside_root.
+ (outside_dir): New function
+ (serve_modified, serve_is_modified, serve_notify,
+ serve_questionable, serve_unchanged): Call outside_dir.
+ * sanity.sh (server2): New tests, for these fixes.
+
+1999-05-26 Jim Kingdon <http://www.cyclic.com>
+
+ * cvs.h, subr.c (xmalloc): Return void* not char*, like xrealloc
+ has done for some time.
+ * modules.c (do_module): If we find the module as a directory/file
+ (rather than in the modules file), skip a bunch of processing
+ which was unnecessary and also broken in most of the cases
+ now tested for by the spacefiles sanity.sh test.
+ * sanity.sh (spacefiles): New test, for specifying filenames
+ (containing spaces, or starting with '-', or starting with '/') to
+ "cvs co".
+
+1999-05-25 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (update_entries): Make the old DONT_USE_PATCH code the
+ only code. This means that if people are still on CVS 1.9
+ servers, then CVS will fall back to transferring entire files.
+ This is better than looking for an external "patch" program which
+ causes no end of troubles (especially on Windows, but someone just
+ posted to info-cvs about a problem with the Solaris patch). (This
+ change was run by devel-cvs and feedback was positive).
+
+ * subr.c (xmalloc, xrealloc): The new error.c does not support
+ %lu; use sprintf instead.
+
+1999-05-25 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (server): Escaped a few more newlines in
+ another awk script. Solaris awk still don't like 'em.
+
+1999-05-25 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * log.c: Remove comment which said "you can delete [this line]"
+ and which stuck around for over 3 years.
+ * sanity.sh (errmsg2 & tagdate): Added tests to prove the
+ current functionality with respect to combining -r and -D.
+
+1999-05-20 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (pserver_authenticate_connection): Previous changes
+ broke verify_and_exit (reported by Robert Fitzsimons, thanks).
+ * sanity.sh (pserver): New tests pserver-7 and pserver-8 for this.
+
+1999-05-18 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (keyword2): Escaped a newline in an awk script.
+ Apparently Solaris awk don't like 'em.
+
+1999-05-18 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (basicc): Allow the behavior whereby unlink(".")
+ succeeds. Reported by Jeremy Buhler and Pavel Roskin.
+
+1999-05-17 Steve Cameron of Compaq
+
+ * sanity.sh: Modified to no longer use "test -e" for existence
+ test as it has turned out to be not portable enough. Instead use
+ "test -f", "test -d", etc.
+ [SCO Unixware 7 apparently doesn't always support it -kingdon]
+
+1999-05-17 Jim Kingdon <http://www.cyclic.com>
+
+ * version.c: Push version number to 1.10.6.1.
+
+ * version.c: Version 1.10.6.
+
+1999-05-16 Jim Kingdon <http://www.cyclic.com>
+
+ * update.c (patch_file): When we are passing vn_rcs to
+ RCS_checkout, pass vn_tag as well.
+ * sanity.sh (keyword): In test keyword-22, test for the fixed
+ behavior rather than the buggy behavior. Adjust keyword-23. Add
+ test keyword-24, to see whether keyword-23 really worked.
+
+1999-05-12 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (pserver-4, pserver-5): Bogus error messages from
+ non-root initgroups on some 4.4BSD derived systems now show up
+ in different places in the output.
+
+1999-05-12 Jim Kingdon <http://www.cyclic.com>
+
+ * import.c (import): Don't allow the user to supply a repository
+ directory which takes us out of the cvsroot.
+ * sanity.sh (importc): New tests importc-10 to importc-12, for this.
+
+1999-05-11 Larry Jones <larry.jones@sdrc.com>
+
+ * server.c (serve_notify): Allocate enough memory to hold the
+ "misformed Notify request" message in pending_error_text.
+
+1999-05-11 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (switch_to_user): Ignore EPERM from initgroups. Fixes
+ pserver-4 in testsuite.
+ (pserver_authenticate_connection): Only print "I LOVE YOU" after
+ switch_to_user has come back successfully.
+
+ * server.c (pserver_authenticate_connection): Call error_exit
+ rather than reinventing the wheel ourselves.
+ (switch_to_user): Check for errors from setuid, setgid, and
+ initgroups. Fix the #ifdef's (the previous code would skip the
+ setuid call if SETXID_SUPPORT).
+
+1999-05-10 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (serve_notify), edit.c (notify_do): Check for
+ and reject characters which will get confused with delimiters.
+ * sanity.sh (server): New tests server-7 through server-15 test
+ for this and for other notify behaviors.
+
+ * rcs.c (RCS_tag2rev): Also look for a physical branch with
+ RCS_getversion.
+ * sanity.sh (tagf): Adjust tagf-12 and following tests to test for
+ the fixed behavior rather than the broken behavior.
+
+1999-05-07 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (server_notify): Also set last_node to NULL.
+ * sanity.sh (server): New tests server-6 and server-7, for this.
+
+1999-05-05 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (rcs_internal_lockfile): Remove unused variable lockfile.
+
+ * add.c (add): Look for directories with the same name in a
+ different case where appropriate (analogous to fopen_case).
+ In client code, add comment about how this doesn't do quite
+ everything.
+
+1999-05-03 Jim Meyering <meyering@ascend.com>
+
+ Remove rcs-style ,file, lock files upon signal.
+ * rcs.c (rcs_lockfile): New file-scoped global.
+ (rcs_cleanup): New function (similar to patch_cleanup).
+ (rcs_internal_lockfile): Register rcs_cleanup the first time this
+ function is called. Rename uses of local `lockfile' to refer to new
+ global, `rcs_lockfile'. Don't free the lock file name string, now
+ that it's global.
+ (rcs_internal_unlockfile): Rename `lockfile', as above, and carefully
+ free and NULL-out the global, rcs_lockfile.
+
+1999-04-30 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (annotate_fileproc): Don't cast NULL in passing it to
+ RCS_deltas. Because there is a prototype in scope the cast is
+ unnecessary (per HACKING's ANSI C or SunOS4 rule), and in fact it
+ was causing failures on UNICOS because it cast to size_t instead
+ of size_t*. (Thanks to Dean Kopesky for reporting this).
+
+1999-04-29 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh: If invoked without any arguments, print a usage
+ message (thanks to Pavel Roskin for a report/patch).
+
+ * run.c (piped_child): Make the error messages more verbose.
+ (close_on_exec): Reindent.
+ * sanity.sh (devcom3): Several errors are possible in devcom3-9a.
+ Adjust for change to piped_child error message.
+
+1999-04-28 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (devcom3): Add some tests of the CVS/Notify file and
+ disconnected "cvs edit".
+
+ * main.c (opt_usage): Remove -b.
+
+1999-04-20 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * rcs.c (RCS_delete_revs): RCS_delete_revs uses an
+ RCS_checkout call to get a new copy of a revision to be
+ used internally after old revisions were deleted and it was
+ performing keyword substitutions. This munged all the
+ the revisions of the file on the branch containing the
+ deleted revisions and its sub-branches, as the original they
+ were being patched from was incorrect. Corrected this by
+ passing in "-ko" as an option to RCS_checkout.
+ * sanity.sh (keywordlog): modified this test to verify the
+ correct behavior of 'cvs admin -o'.
+ [Fixed use of \$ in keywordlog test; added code in RCS_delete_revs
+ to abort on binary file on Windows -kingdon]
+
+1999-04-21 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * tag.c (tag_check_valid): A bug was causing CVS to spin
+ indefinately when -j:<date> was specified. CVS now returns
+ an error.
+ * sanity.sh: Added a test (tagdate-12) to test this.
+
+1999-04-19 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (backuprecover): Clean up the repository at the end.
+
+1999-04-18 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh added a test (backuprecover) to test cvs behavior
+ with a repository that is out of date relative to the
+ developer's workspaces.
+ [Fix --keep code; move test to "Repository Storage" section since
+ it doesn't really exercise the diff/diff3 library. -kingdon]
+
+1999-04-13 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh (diff): Tests to verify correct operation of
+ the --ifdef parameter to cvs diff.
+ [indentation fixed -kingdon].
+
+1999-04-13 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ for Noah Friedman <friedman@splode.com>
+
+ * diff.c (diff): Put "--ifdef=" in opts string, not "-D"; the
+ latter is confused by pserver for a date spec.
+
+1999-04-14 Jim Kingdon <http://www.cyclic.com>
+
+ * fileattr.h: Adjust comments to reflect the official version of
+ the fileattr format now being in cvs.texinfo.
+
+1999-04-05 Jim Kingdon
+
+ * sanity.sh (watch5): Remove nonstandard --keep code. Don't pass
+ -f to rm when cleaning up (that tends to mask bugs). Add watch5
+ to list of tests at start. Add comment explaining why we consider
+ the behavior we test for the right one. Rename a few tests which
+ had been erroneously named watch6* instead of watch5*.
+ * client.c (update_entries): Add comment with brief discussion of
+ whether there is a better way.
+
+1999-04-05 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * client.c (update_entries): Only call mark_up_to_date
+ (which deletes the CVS/Base/<filename> file for watched
+ and edited files) on commit.
+ * sanity.sh: Make sure the CVS/Base/<filename> file for
+ a watched and edited file is not removed on a status or
+ update of a touched/unmodfied file.
+
+1999-03-30 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (get_responses_and_close), commit.c (commit),
+ update.c (do_update): If the sleep(1) call returns prematurely
+ (due to the way wakeup is scheduled or receiving a signal), do
+ it again.
+
+1999-03-26 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (server): Add comment about Gzip-stream vs. RQ_ROOTLESS.
+
+ * sanity.sh (modules3-11b): Adjust exact text of error message to
+ reflect 1999-03-24 change to dirswitch.
+
+1999-03-25 Jim Kingdon <http://www.cyclic.com>
+
+ * admin.c (admin): Make argument to -e optional, to match the
+ documentation.
+ * sanity.sh (admin-19a-2): Test for this.
+
+ * server.c (serve_root): Update comment about checking for missing
+ Root request.
+
+1999-03-24 Jim Kingdon <http://www.cyclic.com>
+
+ * server.c (dirswitch): Also check dir here, similar to
+ what server_pathname_check does for other cases.
+ * sanity.sh (files): Adjust files-14 to test for this.
+
+1999-03-24 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+ and Jim Kingdon
+
+ * sanity.sh: added a test (files-13) to test .. indirection
+ in a path and another (files-14) to make sure we still fail
+ out when the '..' indirection takes us into the $CVSROOT
+ directory or beyond.
+
+1999-03-24 Larry Jones <larry.jones@sdrc.com>
+
+ * rcs.c: Change enum constants ADD and DELETE to something less
+ likely to run into conflicts.
+
+1999-03-21 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (tagf): New test, tests for moving a branch tag to a
+ non-branch tag and trying to recover.
+
+1999-03-12 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (branches): Tweak test branches-5 to test the case in
+ which one modifies a file and then branches it.
+
+1999-03-09 John Bley of duke.edu
+
+ * mkmodules.c (filelist): Missed a NULL in this struct (should
+ have 3 members, only had 2).
+
+1999-03-07 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (Index): Rename new test from rm_CVS/Root to rmroot
+ (we don't have a formal rule about funky punctuation in test names
+ but both underscore and a slash is too funky for me :-)).
+ Reindent a few tests which were off.
+
+ * root.c: Remove the sentence which had the improper English;
+ there isn't really a need for that sentence and it isn't
+ particularly accurate any more.
+
+1999-02-27 Derek Price
+ <http://www-personal.engin.umich.edu/~oberon/resume.html>
+
+ * sanity.sh: Added rm_CVS/Root test to test that CVS uses
+ $CVSROOT rather than dumping core when running remotely and
+ the admin file CVS/Root is deleted from the workspace.
+
+ Also, altered a few 'cvs commit' 's in regular expressions to
+ fit the .${PROG} commit. portability syntax.
+
+ * recurse.c: Stopped CVS from dumping core in the case tested
+ above.
+
+ * root.c: Fixed somebody's improper english.
+
+1999-02-25 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (keyword2-12): Use ${QUESTION} instead of ? in the
+ expected result.
+
+1999-02-24 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (keyword2): Restore the original \\\$ instead of $.
+ The latter ends up working due to various kludgy semantics in the
+ shell and regular expressions, but the former is cleaner.
+
+ * sanity.sh (keyword2): Protect keywords against accidental
+ expansion in sanity.sh itself (most occurrences had this, but not
+ all).
+
+1999-02-23 Derek Price <http://www.cyclic.com>
+ and Jim Kingdon.
+
+ * sanity.sh (keyword2): New test, tests for merging with -kk.
+
+1999-02-22 Jim Kingdon <http://www.cyclic.com>
+
+ * version.c: Ease version number to 1.10.5.1.
+
+ * version.c: Version 1.10.5.
+
+1999-02-18 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (files): New test, for a relatively obscure spurious
+ "Up-to-date check failed" in client/server.
+
+ * main.c (lookup_command_attribute): Don't check for "history"
+ twice.
+
+1999-02-17 Jim Kingdon <http://www.cyclic.com>
+ and Hallvard B Furuseth
+
+ * root.c (parse_cvsroot): Rearrange ifdefs to squelch possible
+ warnings about statement not reached.
+
+1999-02-16 Jim Kingdon <http://www.cyclic.com>
+
+ * recurse.c (start_recursion): If we are skipping the current
+ directory (due to it being from the wrong repository), also adjust
+ the arguments we send to the server accordingly (like we already
+ do for the case in which there is no CVS directory).
+ * sanity.sh (multiroot4): New test, for this. All these tests had
+ passed locally, but remote multiroot4-12 tests for this fix.
+ (multiroot): Adjust multiroot-diff-1, multiroot-update-2,
+ multiroot-tag-1, multiroot-status-1, multiroot-update-3, and
+ multiroot-log-1 to reflect the cosmetic change this produces (one
+ less "Diffing ." message).
+ (multiroot2): multiroot2-8 likewise.
+
+1999-02-10 Jim Kingdon <http://www.cyclic.com>
+
+ * tag.c (cvstag): Don't pass SEND_NO_CONTENTS if -c specified.
+ * sanity.sh (tagc): New test, for various tag -c behaviors.
+ Test tagc-6 tests for this fix.
+
+1999-02-09 Jim Kingdon <http://www.cyclic.com>
+
+ * error.c (error): Rewrite to no longer use vasprintf (see
+ ../lib/ChangeLog for rationale). Note the slight change in
+ interface - callers which want %8.8s or similar formats need to
+ call sprintf.
+ * lock.c (lock_wait, lock_obtained): Use sprintf.
+
+1999-02-08 Jim Kingdon <http://www.cyclic.com>
+
+ * rcs.c (RCS_delete_revs): Pass -a to diff_exec.
+ * sanity.sh (binfiles3): New tests binfiles3-9 through
+ binfiles3-13 test for this fix.
+ * sanity.sh (binfiles): New tests binfiles-o4 and binfiles-o5
+ (which don't test this bug, just on general principles).
+
+1999-02-04 Jim Kingdon <http://www.cyclic.com>
+
+ * lock.c (lock_name): Permissions of directories in LockDir
+ shouldn't depend on the umask.
+ * sanity.sh (lockfiles): Set umask and CVSUMASK, to test for this.
+
+1999-02-01 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (keywordlog): New tests keywordlog-22 and
+ keywordlog-23 test keyword expansion and $Log. Adjust other tests
+ so that revisions differ more from each other, so this is a
+ better test.
+
+1999-01-29 Jim Kingdon <http://www.cyclic.com>
+
+ * commit.c (checkaddfile): If options is "", treat it the same as
+ NULL. Centralize this check, and the one for it starting with
+ "-k", at the start of the function.
+
+ * rcs.c, rcs.h (RCS_setexpand): New function.
+ * admin.c (admin_fileproc): Access keyword expansion field via
+ RCS_getexpand and RCS_setexpand, rather than directly.
+ * commit.c (checkaddfile): When resurrecting, set the keyword
+ expansion mode.
+ * sanity.sh (binfiles3): Adjust tests binfiles3-7 and binfiles3-8
+ for the new behavior.
+
+1999-01-27 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (multiroot3): Add new variant of multiroot3-10 test
+ for RELATIVE_REPOS. Move multiroot3-11 test out of the
+ conditionals; it works the same for remote or local,
+ RELATIVE_REPOS or no.
+
+ * options.h.in: Make RELATIVE_REPOS the default, as has been
+ announced as a future direction since 1997-10-11.
+ * sanity.sh (multiroot): Tweak multiroot-update-1a and
+ multiroot-update-1b tests to work with either RELATIVE_REPOS or
+ non-RELATIVE_REPOS.
+
+ * sanity.sh (client-9): Don't assume the time zone.
+
+1999-01-26 Jim Kingdon <http://www.cyclic.com>
+
+ Fix one facet of the "cvs add -kb" re-adding problem (the other
+ known facet is tested for by binfiles3-8).
+ * add.c (add): When re-adding a file, set the keyword expansion
+ as we normally would.
+ * sanity.sh (binfiles3): New test binfiles3-6a tests for this.
+
+1999-01-22 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rmadd2): New tests, for undoing a commit.
+
+1999-01-21 Eric Mumpower <nocturne@cygnus.com>
+
+ * sanity.sh (reposmv): Actually modify CVSROOT in current
+ environment when calling functions, rather than trying to achieve
+ the same effect with "CVSROOT=foo functionname". (Many common
+ bourne shells, including those in SunOS and Solaris 2.4-2.7,
+ do not properly handle "ENVVAR=foo command" when "command" is
+ a user-defined shell function rather than an actual executable.)
+
+1999-01-15 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rcs3): Redirect awk's stdin to /dev/null like all the
+ other awk invocations. GNU awk seems not to read stdin in this
+ case, but that behavior is hard to reconcile with the Single Unix
+ Spec and some awks don't do it.
+
+ * sanity.sh (binfiles, binfiles2, binfiles3, server): Use the same
+ tr trick as in rcs3. People don't seem to have been complaining,
+ and this should fix server-4 for HPUX.
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (recv_line): If the line we are reading contains a
+ character which would sign-extend to EOF, don't treat it as end of
+ file. recv() doesn't report end of file this way and this might
+ fix bugs with 0xff characters.
+
+1999-01-14 Larry Jones <larry.jones@sdrc.com>
+
+ * client.c (recv_line): Handle EOF from server.
+
+ * sanity.sh (importc-8, importc-9): Accept anything in the seconds
+ fields of the timestamps since touch doesn't set it reliably.
+ (This isn't great, but it's better than nothing.)
+
+1999-01-14 Jim Kingdon <http://www.cyclic.com>
+
+ * run.c (run_exec): Adjust comment about vfork; this isn't the place
+ to get into a treatise about fork performance vs. vfork
+ performance but it isn't quite as simple as whether one has
+ copy-on-write.
+
+1999-01-13 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (dotest_fail): Handle spurrious output from assert better.
+
+ * sanity.sh (rcs3-4, rcs3-5a): Handle even more variants of the
+ assertion failure message.
+
+1999-01-12 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (mtfr-3): ls behavior varies wildly on nonexistant files,
+ just use echo instead.
+
+1999-01-11 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (mkmodules-temp-file-removal): New test, for this.
+ * mkmodules.c (mkmodules): Remove each `CVSROOT/.#[0-9]*' temporary
+ file that's used to check out files listed in CVSROOT/checkoutlist.
+ Remove extra semicolon at end of line.
+
+1999-01-11 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rcs3-5a): Allow for multiple lines of output before the
+ assertion failure message.
+
+ * sanity.sh (lockfiles-6, client-8): Work around bug in HP-UX chmod
+ (doesn't allow anything to follow omitted permissions).
+
+1999-01-09 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (set_sticky): Nonfatal error if we can't write it.
+ * sanity.sh (dirs2-8 through dirs2-14): New tests, for this.
+
+ * sanity.sh (rcs3): Write NUL character with tr not awk, in
+ accordance with Single Unix Specification. Hopefully will fix
+ rcs3-7 for HPUX. Will not work on SunOS4, but then again neither
+ did the old syntax.
+
+1999-01-05 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c, update.c: Rename MD5* functions to cvs_MD5* per
+ corresponding change to ../lib/md5.h.
+
+1999-01-03 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (client): Give file1 a predictable mode so that the
+ output in client-9 will not depend on the umask of the user
+ running the tests.
+
+1998-12-29 Jim Kingdon <http://www.cyclic.com>
+
+ * client.c (client_senddate): Use date_to_internet rather than
+ using our own "5/26/1997 13:01:40 GMT" date format.
+ * main.c (date_to_internet): Check for errors from sscanf. Always
+ send a four digit year. Send hours, minutes, and seconds as two
+ digits per RFC822.
+ * sanity.sh (client): New tests client-8 and client-9 test for this.
+
+ * sanity.sh (rcs2): New tests rcs2-6 through rcs2-8 test for fix
+ to lib/getdate.y (before the fix, "100 months" or "8 years" would
+ tend to mean the year 1969, thus the tests would give "cvs update:
+ file1 is no longer in the repository").
+
+1998-12-28 Larry Jones <larry.jones@sdrc.com>
+
+ * entries.c (Register): Return if unable to open log file to avoid
+ referencing the invalid file pointer.
+ * sanity.sh (dirs2-7): With above change, no longer fails.
+ * sanity.sh (rcs3-5a): Another assertion failure message.
+ * sanity.sh (pserver-4, pserver-5): Some 4.4BSD derived systems spit
+ out bogus error messages when initgroups is called as non-root.
+
+1998-12-23 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (rcs3, dotest_fail): The assertion failure message varies
+ wildly between different systems and the resulting abort call can
+ even result in spurrious output. Fix the regexp to accept nearly
+ anything containing some kind of assertion failure and ensure that
+ any spurrious output ends up in the output file instead of on the
+ terminal.
+
+1998-12-23 Jim Kingdon <http://www.cyclic.com>
+
+ * admin.c, checkout.c, commit.c, cvsrc.c, expand_path.c,
+ history.c, ignore.c, import.c, log.c, mkmodules.c, modules.c,
+ myndbm.c, parseinfo.c, rcs.c, remove.c, rtag.c, status.c, subr.c,
+ tag.c, wrapper.c: Cast all char's to unsigned char before passing
+ them to ctype.h functions (isalpha, isgraph, isalnum, isspace,
+ isdigit, isprint, isupper). Whether using ctype.h is the right
+ thing at all is unclear to me (having the server depend on locale
+ seems wrong, as we don't necessarily have any good way to set the
+ right locale, if there even is such a concept as 'right' locale in
+ this context), but as long as we use ctype.h we might as use it
+ according to the standards (this affects systems where plain char
+ is signed but users supply characters with the 8th bit set).
+ Thanks to Paul Eggert for suggesting this.
+
+1998-12-22 Jim Kingdon <http://www.cyclic.com>
+
+ * sanity.sh (rcs3): Oops, the earlier fix for srcdir only fixed
+ the non-remote case, not the remote case. Fix the other occurrence.
+
+1998-12-22 Jim Kingdon
+
+ * sanity.sh (rcs3): The assertion failure message varies slightly
+ depending on whether CVS was built with srcdir != ".". Fix regexp.
+
+1998-12-21 Jim Kingdon
+
+ * rcs.c (RCS_getdate): Reindent Jim Meyering's change; remove
+ unused variable x_vers.
+
+ * rcs.c: When printing an unexpected character we found in the RCS
+ file, print it in hex rather than as a character (see comment for
+ rationale).
+ * sanity.sh (rcs3): Adjust rcs3-2 and rcs3-7 tests accordingly.
+
+ * sanity.sh (rcs3): New test, for some error handling cases
+ involving parsing RCS files.
+
+1998-12-16 Jim Meyering <meyering@ascend.com>
+
+ * rcs.c (RCS_getdate): Handle the case in which a file is first
+ imported after its initial version has been created.
+ * sanity.sh (import-after-initial): New test for that.
+
+1998-12-17 Jim Kingdon
+
+ * server.c (serve_root): Pserver_Repos only exists if
+ AUTH_SERVER_SUPPORT is defined.
+
+1998-12-12 Jim Kingdon, and Derek R. Price of Stortek.
+
+ * sanity.sh (multiroot): Change + to ${PLUS}.
+
+1998-12-12 Jim Kingdon, and Gary Young of Motorola
+
+ * sanity.sh (admin): In tests admin-13, admin-25, and admin-29,
+ allow 4 digit year in addition to 2 digit year.
+
+1998-12-12 Jim Kingdon
+
+ * sanity.sh (log): New tests log-14a and log-14b test for -rHEAD
+ and for HEAD as (nonexistent) file name.
+
+1998-12-02 Jim Kingdon
+
+ * version.c: Squish version number to 1.10.4.1.
+
+ * version.c: Version 1.10.4.
+
+1998-11-24 Jim Kingdon
+
+ * recurse.c (do_file_proc): Check for errors from RCS_parse.
+ * sanity.sh (rcslib-symlink-7 through rcslib-symlink-10): New
+ tests, test for this.
+
+ * sanity.sh (reposmv-2): Adjust for 22-Nov change to Find_Names.
+
+ * entries.c (Register): If we can't write Entries.Log, make it a
+ nonfatal error.
+ * sanity.sh (dirs2): Test for this fix.
+
+ * sanity.sh (dirs2): Clean up working directory at end of test.
+
+1998-11-23 Jim Kingdon
+
+ * sanity.sh (dirs2): New test, for some more cases involving
+ deleting directories and such.
+
+ * sanity.sh (dirs): Update for yesterday's change in Find_Names
+ error handling. The error in dirs-4 is fairly different now; in
+ dirs-3 and dirs-3a it is the obvious change.
+
+1998-11-22 Jim Kingdon
+
+ * sanity.sh (release): Move the commments listing "cvs release"
+ tests from modules2-6 to here.
+ * release.c (release): Update comment to reflect "? foo" case.
+
+ * find_names.c (Find_Names): If we can't read the repository, make
+ it a nonfatal error. Tell the caller whether this happened.
+ (find_rcs): Add comment regarding this behavior.
+ * recurse.c (do_recursion): If Find_Names gives an error, skip
+ the directory and print a message saying so.
+ * sanity.sh (modes3): New test, for this.
+
+1998-11-18 Jim Kingdon
+
+ * rtag.c (rtag_usage), tag.c (tag_usage): Use "-r rev"
+ consistently.
+
+ * sanity.sh (conflicts3): Tests conflicts3-24 through
+ conflicts3-28 test for another case similar to conflicts3-22.
+
+1998-11-14 Jim Kingdon
+
+ * sanity.sh (diff): New test, for now just tests for the "I know
+ nothing" message.
+
+ * sanity.sh (conflicts2-142b7 through conflicts2-142b11): New
+ tests; resurrecting doesn't work from one level up.
+
+ * sanity.sh (mwrap-7): Remote prints the messages in a different
+ order.
+
+1998-11-13 Jim Kingdon
+
+ * tag.c (check_fileproc): Log tag deletions.
+ * rtag.c (check_fileproc): Likewise.
+ * sanity.sh (taginfo-14 through taginfo-18): New tests, for
+ these behaviors.
+
+1998-11-12 Jim Kingdon
+
+ * sanity.sh (mwrap-7): Update for the noexec fix.
+
+ * server.c (server_copy_file): Add comment about noexec.
+
+ * update.c (checkout_file): Handle noexec case involving revbuf
+ and modes.
+ (update_fileproc): In case T_NEEDS_MERGE, let merge_file take care
+ of noexec, so it can tell the user if there would be conflicts.
+ (merge_file): Print "conflicts found in FILE" message
+ regardless of noexec. Add comment about checking for whether the
+ file already contained the changes, and noexec.
+ * sanity.sh (conflicts-192a): New test, for this.
+
+1998-10-20 Jim Kingdon
+
+ Use the gzip library on the server. Probably doesn't speed things
+ up as currently implemented, but does avoid hassles in terms of
+ finding an external gzip program.
+ * zlib.c, server.h (gunzip_and_write, read_and_gzip): Now returns
+ whether a fatal error occurred, rather than expecting error (1,
+ ...) to work.
+ * client.c (update_entries, send_modified): Change callers.
+ * server.c (receive_file): Rewrite gzip code to use
+ gunzip_and_write rather than filter_through_gunzip.
+ (server_updated): Likewise, use read_and_gzip rather than
+ filter_through_gzip.
+ * client.c, client.h (filter_through_gzip, filter_through_gunzip),
+ run.c, cvs.h (filter_stream_through_program): Removed; no longer used.
+ * sanity.sh (server): New tests server-4 and server-5 test
+ this feature (note that CVS 1.10 also passes these tests; the
+ behavior is supposed to be unchanged).
+
+1998-10-19 Jim Kingdon
+
+ * sanity.sh (multiroot3): New test, tests for a few more
+ multiroot cases.
+
+ * lock.c (lock_name): Set the permissions on each directory we
+ create to that of the parent directory.
+ * sanity.sh (lockfiles): New chmod and tests lockfiles-7a and
+ lockfiles-7b test for this. Adjust lockfiles-5 for new text of
+ error message.
+
+1998-10-15 Jim Kingdon
+
+ * server.c (requests): Set RQ_ROOTLESS for "Set".
+ * sanity.sh (info): Also clean up $HOME/.cvsrc.
+ (server): Test that we can send Set before Root (had been tested
+ by crerepos-6b, but only if you ran the info test first). Tests
+ for this fix.
+
+1998-10-14 Jim Kingdon
+
+ * subr.c (expand_string): Tweak the algorithm so that the size
+ that it allocates is generally a power of two.
+
+1998-10-14 Eivind Eklund and Jim Kingdon
+
+ * commit.c (commit): For the client, don't worry about whether we
+ are root.
+
+1998-10-13 Jim Kingdon
+
+ * server.h (struct request): Change status field to flags and add
+ RQ_ROOTLESS.
+ * client.c (handle_valid_requests, supported_request): Change
+ status to flags.
+ * server.c (requests): Change status to flags. Add RQ_ROOTLESS.
+ * server.c (server): If not RQ_ROOTLESS, and we haven't gotten a
+ Root request, give an error.
+
+1998-10-12 Jim Kingdon
+
+ * version.c: Slide version number to 1.10.3.1.
+
+ * Version 1.10.3.
+
+ * sanity.sh (modules2-17): Update for 9 Oct 1998 change to
+ update_dirent_proc.
+
+1998-10-11 Jim Kingdon
+
+ * commit.c (checkaddfile, commit_fileproc): A numeric value for
+ 'tag' does not mean that we are adding on a branch.
+ * sanity.sh (keywordlog): Adjust this test, to test for this
+ (replaces comment saying we should be doing it).
+ (rmadd): Likewise.
+
+ * sanity.sh (rmadd): New test, tests for various existing
+ behaviors with "cvs ci -r".
+
+1998-10-09 Jim Kingdon
+
+ * update.c (update_dirent_proc): For local CVS, if the directory
+ does not exist in the working directory nor in the repository,
+ just skip it.
+ * sanity.sh (dirs): New tests dirs-3a, dirs-7 and dirs-8 test for
+ this and related behaviors. Note that the new behavior was also
+ the previous behavior for remote; we are only changing it for local.
+
+ * wrapper.c, cvsrc.c, ignore.c: Add comments about ignoring .cvsrc
+ and friends if we can't find a home directory.
+ * expand_path.c (expand_path): If we can't find the home
+ directory, give an error rather than a coredump (or worse).
+ * login.c (construct_cvspass_filename): Don't use errno in error
+ message; get_homedir doesn't set it. Add comment about this
+ message.
+
+1998-10-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * diff.c (diff): Set variables to NULL at the start, and free
+ memory at the end.
+ * sanity.sh (multiroot2): Add tests for this (before the fix,
+ multiroot2-12 would abort with "no more than two revisions/dates
+ can be specified").
+
+1998-10-06 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Makefile.in (installcheck check): Remove references to RCSBIN;
+ they don't do anything now that RCSBIN is ignored.
+
+ * client.c: Clean up horrible confusion about whether stored_mode
+ or stored_mode_valid (or nothing :-)) indicates whether
+ stored_mode is allocated. Should fix crashes (for example, on NT
+ when the server has renamed multiple files from uppercase to
+ lowercase).
+
+ * sanity.sh (dirs): New tests, tests for some cases involving
+ admins who do surgery on the repository.
+
+1998-10-03 Johannes Stezenbach <johannes.stezenbach@propack-data.de>
+
+ * vers_ts.c (Version_TS): If UTIME_EXPECTS_WRITABLE, if
+ necessary change the file to be writable temporarily to set its
+ modification time.
+
+1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (handle_error): Add comment about indicating which
+ errors are from the server.
+
+1998-10-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (devcom-180): Allow one digit day.
+
+1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * main.c (main): Don't call Name_Root if -d specified.
+ * recurse.c (do_recursion, do_dir_proc): Don't check CVS/Root
+ if -d was specified.
+ * import.c (import): Indentation fix.
+ * sanity.sh (multiroot): Update for this change.
+ (reposmv): New test, tests for this.
+
+1998-09-28 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot2): New test, tests some nested directory
+ cases.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot): Change a few comments which said modules
+ when they meant directories.
+
+1998-09-25 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (devcom-180): Add 0-9 to the range of characters allowed
+ in hostname regexp.
+
+1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (log2): New test log2-7a tests for one error handling
+ case. Add a comment about another.
+
+1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Change crerepos test back to :ext: (for several
+ reasons; see comments).
+
+1998-09-24 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (rcslib-symlink-5, rcslib-symlink-6): new tests to
+ check the operation of "tag" when there are symlinks in the
+ repository.
+
+ * rcs.c (RCS_checkin): remove old code that resolved the symlink
+ and call resolve_symlink instead.
+ (RCS_rewrite): call resolve_symlink before doing anything else to
+ make sure we're operating on the file and not the symlink.
+
+ * subr.c (resolve_symlink): new routine -- resolves a symbolic
+ link chain to its destination.
+ * cvs.h: add prototype.
+
+ * sanity.sh (basica-6.2, basica-6.3): changed match expressions to
+ reflect new diff output.
+
+ * rcs.c (make_file_label): generate labels for files that include
+ the pathname so that output from "cvs diff" is useable by patch.
+ Looks like I came up with the mods as Andy Piper
+ <andyp@parallax.co.uk>; his patch was on the Cyclic unofficial
+ patches page.
+
+ * sanity.sh: change remote access method from ext to fork. This
+ results in a significant speed improvement when running the
+ testsuite. The ext method on my machine (i586 120MHz Linux 2.0.35
+ with TCP wrappers installed) runs in 450% of the time of the local
+ method while the fork method runs in only 150% of the time of the
+ local method! Yow! Am I SWAPPING yet?!
+ (crerepos-6a, crerepos-6b): change to reflect different error
+ messages for fork method.
+ (modes-15): same.
+
+ * client.c (connect_to_forked_server): new routine.
+ (start_server): call the above when method is fork_method.
+
+ * root.c: add a new method named "fork". This method uses the
+ remote protocol, but does so by forking a "cvs server" process
+ directly rather than doing "rsh host cvs server" (for example).
+ This new method has few advantages for day-to-day use, but has
+ three important benefits for debugging:
+
+ 1) Most secure installations these days don't allow rsh access.
+ With this new method, we can still test the remote protocol on
+ these machines because we don't need to be able to make a local
+ TCP connection.
+
+ 2) Even if installations allow rsh access, they almost always
+ have TCP wrappers to check permissions by IP/hostname. This
+ causes a short delay for every connection. For invocations from
+ the command line, this doesn't matter much, but it adds up to a
+ significant amount of time when running the testsuite.
+
+ 3) On machines that can't (or do not usually) provide rshd
+ access (I'm thinking of WNT/W95 in particular), we can now run
+ tests of the remote protocol using this method. Indeed, we can
+ run remote protocol tests on any machine that has an
+ implementation of piped_child().
+
+ (parse_cvsroot): handle new method.
+ (error_exit, xstrdup, isabsolute): new stub functions to use when
+ compiling root.c with the DEBUG option.
+ (main): fix a few typos.
+ * cvs.h (CVSmethod): add fork_method.
+
+ * server.c (create_adm_p): use Emptydir as the placeholder
+ directory instead of "." to avoid problems with "cvs update -d" et
+ al.
+
+1998-09-22 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (devcom-180): fixed typo in regexp.
+
+ * main.c (main): remove need_to_create_root and related code
+ (including CVS_IGNORE_REMOTE_ROOT environment variable). The
+ current implementation (just removed) of rewriting the contents of
+ the CVS/Root file isn't desirable for a number of reasons:
+
+ 1) Only the top-level CVS/Root directory is updated. If we're
+ really interested in pointing our WD at another CVSROOT, we
+ should have a separate command.
+
+ 2) With the new multiroot mods, we don't ever want to rewrite
+ CVS/Root files in the way the removed code did. Consider:
+
+ cvs -d repository1 co a
+ cd a
+ cvs -d repository2 co b
+ cvs -d repository2 update b
+
+ The update command would rewrite the contents of a/CVS/Root to
+ the incorrect value. Bad. We then wouldn't be talking to the
+ correct repository for files in a.
+
+ 3) The removed code seems to be a quick hack to support working
+ directories checked out from multiple repositories. With the
+ CVS_IGNORE_REMOTE_ROOT variable set, one could perform commands
+ as in example 2, above, without worring about updating CVS/Root
+ files. While in pre-1.10.1 recursive commands wouldn't handle
+ that working directory hierarchy, one could use commands like
+ "cvs foo -l" instead. While not great, this allows you (with a
+ lot of manual interaction) to have a multiroot WD. Since we now
+ have multiroot mods checked in, we don't need this code.
+
+ (lookup_command_attribute): while we don't need the
+ CVS_CMD_USES_WORK_DIR flag anymore (since it only was supporting
+ the need_to_create_root code), I'm leaving it in. It may come in
+ handy at some later date.
+
+1998-09-18 Jim Kingdon <kingdon@pennington.cyclic.com>
+
+ * version.c: Advance version number to 1.10.2.1.
+
+ * Version 1.10.2.
+
+1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c: Refuse to Copy-file to another directory
+ * sanity.sh (client): New test, tests for this.
+
+ * edit.c (editors_fileproc), watch.c (watchers_fileproc): Use
+ cvs_output rather than writing to stdout.
+ * sanity.sh (devcom): Use dotest for tests 178, 180, and 183
+ (tests that we preserve existing behavior on "cvs editors").
+
+ * commit.c (check_fileproc): Don't allow commits in Emptydir.
+ * sanity.sh (emptydir-8): Test for this change in behavior.
+
+ * sanity.sh: Add some compatibility tests to TODO comments at end.
+
+1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * wrapper.c (wrap_add): Remove obsolete comment about -m.
+
+ * server.c (server_updated): Check for error from CVS_UNLINK.
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * server.c (serve_root): Allocate with malloc, not xmalloc.
+
+ * root.c (set_local_cvsroot): Move memory allocation from here...
+ * server.c (serve_root): ...to here. Fixes error handling.
+
+ * root.c (parse_cvsroot): Don't call check_root_consistent;
+ parse_cvsroot is only used for local and client.
+ * root.c (set_local_cvsroot): Move check_root_consistent
+ functionality from here...
+ * server.c (serve_root): ...to here. Fixes error handling. Also
+ made the error more explicit, while I am at it.
+ * server.c (Pserver_Repos): Now static.
+ * cvs.h: Don't declare it.
+ * root.c (check_root_consistent): Removed; no longer needed.
+ * sanity.sh (pserver): New test, tests for this behavior and some
+ other basic pserver stuff.
+
+ * update.c (merge_file): Use cvs_output for "already contains the
+ differences" message. Found this one when I actually observed the
+ out-of-order bug in Real Life(TM).
+
+1998-09-09 Jim Kingdon
+
+ * find_names.c (find_dirs): Make sure to zero errno before
+ going around the loop again.
+ * find_names.c (find_rcs): Make sure to set save_errno.
+ (thanks to Alexandre Parenteau for reporting both problems).
+
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> and Michael Pakovic
+
+ * edit.c (notify_do): Only free line if it is not NULL.
+
+1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h: dirs_sent_to_server should not be inside
+ AUTH_SERVER_SUPPORT (reported by both Richard Levitte and Murray
+ Bishop, thanks).
+
+ * lock.c, cvs.h: New variable lock_dir.
+ * parseinfo.c (parse_config): New option LockDir.
+ * lock.c (lock_name): New function, abstracts out lock file naming
+ and also supports LockDir.
+ * lock.c (lock_simple_remove, Reader_Lock, write_lock, set_lock):
+ Call it (6 places, to create/remove read/write/master locks).
+ (Lock_Cleanup): Refuse to reenter this function.
+ * sanity.sh (lockfiles): New test, tests for this feature.
+
+1998-09-03 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (multiroot): Expect ${TESTDIR} in output instead of
+ assuming it is /tmp/cvs-sanity (thanks to Mark D. Baushke of Cisco).
+ Clean up working directory when done (fixes apparent thinko).
+
+ * server.c (create_adm_p): Fix one "return" which didn't return a
+ value.
+ (dirswitch): Check for errors from create_adm_p.
+
+ * sanity.sh: Set LC_ALL rather than just LC_COLLATE.
+
+Wed Sep 2 02:30:22 1998 Jim Kingdon <kingdon@pennington.cyclic.com>
+
+ * version.c: Bump version number to 1.10.1.1.
+
+ * Version 1.10.1.
+
+1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Administrative note regarding Noel's changes to allow one to
+ switch from one CVS root to another in a single command: The
+ ChangeLog entries for the changes which Noel just checked in
+ appear for 1998-09-01, 1998-08-28, 1998-08-25, 1998-08-19, and
+ 1998-08-18, rather than being all together.
+
+ * main.c (set_root_directory): Fix whitespace.
+ (main): Nuke new -m option and just have that message controlled
+ by -t.
+ * server.c (server): Revert the CVS_SERVER_SLEEP code back the way
+ it was in CVS 1.10. Attaching to the parent process is relatively
+ boring (you can just run "cvs server" under a debugger instead),
+ but connecting to the child process is what the old code was for.
+ * recurse.c, server.c: Remove DEBUG_NJC code.
+
+1998-09-01 Noel Cragg <noel@swish.red-bean.com>
+
+ * server.c (do_cvs_command): add another environment variable,
+ CVS_SERVER_SLEEP2, after forking to pause the program so one can
+ attach a debugger.
+
+ * sanity.sh (crerepos): clean up crerepos-18 now that multiroot
+ works in this case.
+ (multiroot): finalize tests for local vs. remote operation.
+
+ * recurse.c (start_recursion): near the beginning, save the list
+ of directories to spoof as command-line arguments, if necessary.
+ Use that list near the end and call send_file_names to send those
+ arguments to the server.
+ (do_argument_proc): removed, since we call send_file_names now.
+
+ * main.c (main): re-initialize dirs_sent_to_server on each pass
+ through the loop for each CVSROOT.
+
+ * cvs.h: add proto for global variable which keeps track of which
+ directories have been sent to the server when in client mode.
+
+ * client.c (is_arg_a_parent_or_listed_dir): new function.
+ (arg_should_not_be_sent_to_server): new function. Tries to decide
+ whether the given argument should be sent to the server, based on
+ the current CVSROOT and the list of directories sent to the
+ server.
+ (send_repository): add the directory name to the list of
+ directories sent to the server.
+ (send_file_names): call arg_should_not_be_sent_to_server.
+
+ * add.c (add): switch the order of send_files and send_file_names
+ to make multiple repository support possible. send_files needs to
+ create a list of directories being requested so that
+ send_file_names can decide which command-line arguments to send to
+ the server for the given current CVSROOT.
+ * admin.c (admin): same.
+ * commit.c (commit): same.
+ * diff.c (diff): same.
+ * edit.c (editors): same.
+ * log.c (cvslog): same.
+ * rcs.c (annotate): same.
+ * remove.c (cvsremove): same.
+ * status.c (cvsstatus): same.
+ * tag.c (cvstag): same.
+ * update.c (update): same.
+ * watch.c (watch_addremove): same.
+ (watchers): same.
+
+1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Remove "debug" function; it was apparently checked
+ in accidentally by Norbert Kiesel's change.
+
+1998-08-31 Norbert Kiesel <nk@iname.com>
+
+ * release.c (release): modify last patch to release so that
+ save_cwd is called only once and restore_cwd is always called when
+ neccessary. Also fixed a tiny memory leak.
+
+ * sanity.sh (release): added some more tests for "cvs release"
+ including a test with two dirs and a "no" for the first one (which
+ fails without the above patch).
+
+1998-08-28 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (crerepos-18): add new comment and change test
+ slightly to support multiroot.
+ (multiroot): add more tests.
+
+ * server.c (create_adm_p): new function.
+ (dirswitch): call create_adm_p. Modify the code to always write a
+ new CVSADM_REP file, since create_adm_p might have put a
+ placeholder there and our value is guaranteed to be correct.
+ (server): move the CVS_SERVER_SLEEP check here so we can debug
+ things at an earlier stage.
+
+ * recurse.c (start_recursion): add large comment about the ideal
+ solution to the "Argument xxx" problem.
+
+ * main.c (main): move position of debugging comment for -m flag.
+
+ * diff.c (diff): clear a static variable.
+
+ * client.c (send_file_names): check to see if we should send this
+ argument to the server based on the contents of the appropriate
+ CVSADM directory. This avoids "nothing known about foo" messages
+ and problems with duplicate modules names in multiple
+ repositories.
+ (send_a_repository): change method of calculating toplevel_repos
+ to support multiple CVSROOTs.
+ (start_server): clear some static variables.
+
+1998-08-28 Jim Meyering <meyering@ascend.com>
+
+ * sanity.sh (basicc-8, basicc-11): Use `.*' instead of explicit
+ `Operation not permitted'. Solaris2.5.1 gets a different error:
+ `Invalid argument'.
+
+1998-08-26 Eric M. Hopper
+
+ * sanity.sh: Set LC_COLLATE to "C".
+
+1998-08-25 Noel Cragg <noel@swish.red-bean.com>
+
+ * sanity.sh (multiroot): new set of tests to check the behavior of
+ multiroot.
+
+ * diff.c (diff): set options value to NULL after freeing to reset
+ the state for the next time around.
+
+1998-08-25 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Fix problems with trying to rename an open file:
+ * rcs.c, rcs.h (RCS_setattic): New function.
+ * commit.c (remove_file, checkaddfile): Call it.
+
+1998-08-24 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * release.c (release): Use save_cwd and restore_cwd to get back to
+ where we started, rather than hoping that CVS_CHDIR ("..") will do
+ something useful. This removes the need for most of
+ release_delete, so remove that function and inline what is left.
+ * sanity.sh (basicc): Adjust tests for this fix, also some tests
+ with multiple arguments to "cvs release" (in the non-"-d"-case, it
+ would seem like the old code would CVS_CHDIR into directories and not
+ CVS_CHDIR back, but I'm not going to investigate this and it
+ should be a moot point with this fix.).
+
+ * sanity.sh (basicc): Add tests for a serious bug in "cvs release
+ -d .".
+
+ More error handling fixes:
+ * ignore.c (ignore_files): Check for errors from opendir and
+ readdir.
+ * find_names.c (Find_Names): Check for errors from find_rcs.
+ (find_rcs, find_dirs): Comment error handling better; also return
+ an error if we got one from readdir.
+ * filesubr.c (deep_remove_dir): Also check for errors from readdir.
+ * import.c (import_descend): Print message on error from opendir
+ or readdir.
+ * commit.c (remove_file): Check for errors from CVS_MKDIR and
+ CVS_RENAME.
+ (remove_file): No need to remove the file in the temporary
+ directory; server.c now informs time_stamp_server of what is going
+ on via CVS/Entries rather than a file with a kludged up timestamp.
+ * client.c, entries.c, login.c, logmsg.c, mkmodules.c, patch.c,
+ remove.c, update.c: Check for errors from unlink_file.
+ * mkmodules.c (write_dbmfile, rename_dbfile, rename_rcsfile):
+ Check for errors from fclose, CVS_RENAME, and CVS_STAT.
+ * mkmodules.c (checkout_file): Clarify error handling convention.
+ * mkmodules.c (mkmodules): Call checkout_file accordingly.
+ * entries.c (Entries_Open): Check for errors from fclose.
+
+1998-08-21 Ian Lance Taylor <ian@cygnus.com>
+
+ * import.c (import): Output suggested merge command using
+ cvs_output_tagged rather than just cvs_output. Don't put
+ CVSroot_cmdline in the log file.
+ * client.c (importmergecmd): New static struct.
+ (handle_mt): Handle +importmergecmd tag.
+ * sanity.sh (import): Use an explicit -d in importb-2, to test
+ whether it is reported in the suggested merge command.
+
+1998-08-20 Ian Lance Taylor <ian@cygnus.com>
+
+ * sanity.sh (import): Rewrite tests to use dotest.
+
+1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Add comments about binary files and cvs import.
+
+1998-08-19 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (importc): Use ${username} in one place where I had
+ missed it.
+
+ Make import -d work client/server:
+ * client.c, client.h (client_process_import_file): Take new
+ argument, for whether -d is specified, and send Checkin-time
+ request if it is set.
+ * import.c (import_descend): Pass it.
+ * main.c, cvs.h (date_to_internet): New function.
+ * server.c (server_modtime): Call date_to_internet.
+ * server.c (serve_checkin_time): New function.
+ (requests): Add "Checkin-time" request.
+ (serve_modified): If it was sent, set the timestamp in the
+ temporary directory.
+ * import.c (import): If the client sends a -d option, complain.
+ (import): For the server, always use the timestamps from the temp
+ directory.
+ (import): Don't send a -d option to the server.
+ * sanity.sh (importc): Add tests for import -d.
+
+Wed Aug 19 15:19:13 1998 Larry Jones <larry.jones@sdrc.com>
+
+ * sanity.sh (unedit-without-baserev-5): use ${DOTSTAR} instead
+ of .* since we expect to match multiple lines.
+
+1998-08-19 Ian Lance Taylor <ian@cygnus.com>
+
+ * cvs.h (CVSroot_cmdline): Declare.
+ * root.c (CVSroot_cmdline): Define.
+ * main.c (main): Set CVSroot_cmdline if the -d option is used.
+ * import.c (import): If CVSroot_cmdline is not NULL, then mention
+ an explicit -d option in the suggested merge command line.
+
+Wed Aug 19 00:28:50 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * recurse.c (do_dir_proc): don't muck with CVS/Root directories
+ when running in server mode.
+ (do_recursion): same.
+
+ * main.c (main): add the command-line option `m' to help debug the
+ multiroot environment; it prints out the value of CVSROOT for each
+ iteration through the main loop. Also, changed the main loop so
+ that it gets executed only once when running in server mode (the
+ server will only deal with a single CVSROOT).
+
+ * recurse.c (do_recursion): change default for
+ PROCESS_THIS_DIRECTORY to true; we should always process a
+ directory's contents unless there's an existing CVS/Root file with
+ a different root than the current root to tell us otherwise.
+ (do_dir_proc): same.
+
+Tue Aug 18 14:30:59 1998 Noel Cragg <noel@swish.red-bean.com>
+
+ * recurse.c (do_recursion): check the current value of CVS/Root
+ and add it to our list of CVSROOTs if it doesn't exist. Decide
+ whether or not to process files in this directory based based on
+ the value of CURRENT_ROOT.
+ (do_dir_proc): same.
+
+ * main.c: add two new globals -- root_directories and current_root
+ -- which keep track of the values of CVSROOT we've seen and which
+ value of CVSROOT we're currently processing.
+ (main): put the main loop for stepping through cvsroot values
+ here, since we might need to send command-specific arguments for
+ every unique non-local cvsroot. Moved blocks of code around so
+ that one-time initializations happen first (outside the loop) and
+ the other stuff happens inside the loop.
+ (set_root_directory): helper function.
+
+ * cvs.h: add prototypes for root_directories and current_root, two
+ new globals for keeping track of multiple CVSROOT information.
+
+1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: Don't assume that the shell leaves $^ unexpanded in
+ an unquoted here-document (suggested by Bart Schaefer to help when
+ zsh is the shell).
+
+1998-08-17 Ian Lance Taylor <ian@cygnus.com>
+
+ * commit.c (checkaddfile): Don't call fix_rcs_modes.
+ (fix_rcs_modes): Remove.
+
+1998-08-16 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * create_adm.c (Create_Admin): Don't condition traces on
+ SERVER_SUPPORT; SERVER_SUPPORT shouldn't do (much of) anything
+ independent of server_active.
+
+ * sanity.sh (binfiles3): New test, for yet another binary file
+ bug (sigh). Thanks to Jason Aten for reporting this one.
+
+1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (call_diff_write_output): Update to reflect new
+ calling convention for the write_output callback.
+
+1998-08-15 Jim Meyering <meyering@ascend.com>
+
+ * update.c (merge_file): Warn about failed unlink when not due
+ to ENOENT.
+
+ * server.h (CLIENT_SERVER_STR): New macro
+ * create_adm.c (Create_Admin): Use it.
+ * entries.c (Scratch_Entry, Register): Use it.
+ * filesubr.c (copy_file, xchmod, rename_file, unlink_file): Use it.
+ * history.c (history_write): Use it.
+ * modules.c (do_module): Use it.
+ * no_diff.c (No_Difference): Use it.
+ * run.c (run_popen): Use it.
+ * server.c (server_register): Use it.
+
+1998-08-14 Jim Meyering <meyering@ascend.com>
+
+ * hardlink.c (lookup_file_by_inode): Use existence_error rather than
+ comparing errno to ENOENT directly.
+
+ * client.c (copy_a_file): Unlink destination before doing copy.
+ * sanity.sh (join-readonly-conflict): New test for this -- it would
+ fail only in client/server mode.
+
+ * sanity.sh (rcsmerge-symlink-4): Don't use `test -L', it's not
+ portable. Instead, match against the output of `ls -l'.
+ (dotest tag8k-16): Simplify tag-construction code and at the same
+ time, avoid using expr's `length' and `substr' operators. Not
+ all versions of expr support those.
+
+1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * version.c: Bump version number to 1.10.0.1.
+
Thu Aug 13 11:15:24 1998 Noel Cragg <noel@swish.red-bean.com>
* version.c: Change version number to 1.10 and name to `Halibut'.
@@ -67,14 +1581,14 @@ Sun Jul 26 05:14:41 1998 Noel Cragg <noel@swish.red-bean.com>
does not create CVS directories at top-level (except for the
obvious "cvs co ."). Added a new configuration option to switch
between 1.9 and 1.9.2 behavior.
-
+
* recurse.c (do_argument_proc): new function.
(start_recursion): in the case that we've done a command from
top-level but have no CVS directory there, the behavior should be
the same as "cvs <cmd> dir1 dir2 dir3...". Make sure that the
appropriate "Argument" commands are sent to the server by calling
walklist with do_argument_proc.
-
+
* client.c (call_in_directory): only create the top-level CVS
directory when we're checking out "." explicitly. The server will
force creation of this directory in all other cases.
diff --git a/contrib/cvs/src/Makefile.in b/contrib/cvs/src/Makefile.in
index 2c93ec2..7cbdca7 100644
--- a/contrib/cvs/src/Makefile.in
+++ b/contrib/cvs/src/Makefile.in
@@ -97,14 +97,10 @@ installdirs:
.PHONY: install installdirs
installcheck:
- RCSBIN=$(bindir) ; export RCSBIN ; $(SHELL) $(srcdir)/sanity.sh $(bindir)/cvs
+ $(SHELL) $(srcdir)/sanity.sh $(bindir)/cvs
.PHONY: installcheck
check: all
- if [ -x ../../rcs/src/rcs ] ; then \
- RCSBIN=`pwd`/../../rcs/src ; \
- export RCSBIN ; \
- fi ; \
$(SHELL) $(srcdir)/sanity.sh `pwd`/cvs
.PHONY: check
diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c
index a4eed40..db1f527 100644
--- a/contrib/cvs/src/add.c
+++ b/contrib/cvs/src/add.c
@@ -172,9 +172,20 @@ add (argc, argv)
}
for (i = 0; i < argc; ++i)
+ {
/* FIXME: Does this erroneously call Create_Admin in error
conditions which are only detected once the server gets its
hands on things? */
+ /* FIXME-also: if filenames are case-insensitive on the
+ client, and the directory in the repository already
+ exists and is named "foo", and the command is "cvs add
+ FOO", this call to Create_Admin puts the wrong thing in
+ CVS/Repository and so a subsequent "cvs update" will
+ give an error. The fix will be to have the server report
+ back what it actually did (e.g. use tagged text for the
+ "Directory %s added" message), and then Create_Admin,
+ which should also fix the error handling concerns. */
+
if (isdir (argv[i]))
{
char *tag;
@@ -240,8 +251,9 @@ add (argc, argv)
free (repository);
free (filedir);
}
- send_file_names (argc, argv, SEND_EXPAND_WILD);
+ }
send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("add\012", 0);
if (message)
free (message);
@@ -258,6 +270,9 @@ add (argc, argv)
#endif
struct file_info finfo;
char *p;
+#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
+ char *found_name;
+#endif
memset (&finfo, 0, sizeof finfo);
@@ -294,6 +309,60 @@ add (argc, argv)
finfo.repository = repository;
finfo.entries = entries;
+#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
+ if (ign_case)
+ {
+ /* Need to check whether there is a directory with the
+ same name but different case. We'll check for files
+ with the same name later (when Version_TS calls
+ RCS_parse which calls fopen_case). If CVS some day
+ records directories in the RCS files, then we should be
+ able to skip the separate check here, which would be
+ cleaner. */
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = CVS_OPENDIR (finfo.repository);
+ if (dirp == NULL)
+ error (1, errno, "cannot read directory %s", finfo.repository);
+ found_name = NULL;
+ errno = 0;
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (cvs_casecmp (dp->d_name, finfo.file) == 0)
+ {
+ if (found_name != NULL)
+ error (1, 0, "%s is ambiguous; could mean %s or %s",
+ finfo.file, dp->d_name, found_name);
+ found_name = xstrdup (dp->d_name);
+ }
+ }
+ if (errno != 0)
+ error (1, errno, "cannot read directory %s", finfo.repository);
+ closedir (dirp);
+
+ if (found_name != NULL)
+ {
+ /* OK, we are about to patch up the name, so patch up
+ the temporary directory too to match. The isdir
+ should "always" be true (since files have ,v), but
+ I guess we might as well make some attempt to not
+ get confused by stray files in the repository. */
+ if (isdir (finfo.file))
+ {
+ if (CVS_MKDIR (found_name, 0777) < 0
+ && errno != EEXIST)
+ error (0, errno, "cannot create %s", finfo.file);
+ }
+
+ /* OK, we found a directory with the same name, maybe in
+ a different case. Treat it as if the name were the
+ same. */
+ finfo.file = found_name;
+ }
+ }
+#endif
+
/* We pass force_tag_match as 1. If the directory has a
sticky branch tag, and there is already an RCS file which
does not have that tag, then the head revision is
@@ -420,7 +489,7 @@ file `%s' will be added on branch `%s' from version %s",
re-adding file %s (in place of dead revision %s)",
finfo.fullname, vers->vn_rcs);
Register (entries, finfo.file, "0", vers->ts_user,
- NULL,
+ vers->options,
vers->tag, NULL, NULL);
++added_files;
}
@@ -538,6 +607,10 @@ cannot resurrect %s; RCS file removed by second party", finfo.fullname);
free_cwd (&cwd);
free (finfo.fullname);
+#if defined (SERVER_SUPPORT) && !defined (FILENAMES_CASE_INSENSITIVE)
+ if (ign_case && found_name != NULL)
+ free (found_name);
+#endif
}
if (added_files)
error (0, 0, "use '%s commit' to add %s permanently",
diff --git a/contrib/cvs/src/admin.c b/contrib/cvs/src/admin.c
index 72cddac..c5af96e 100644
--- a/contrib/cvs/src/admin.c
+++ b/contrib/cvs/src/admin.c
@@ -120,35 +120,11 @@ admin (argc, argv)
struct admin_data admin_data;
int c;
int i;
+ int only_k_option;
if (argc <= 1)
usage (admin_usage);
-#ifdef CVS_ADMIN_GROUP
- grp = getgrnam(CVS_ADMIN_GROUP);
- /* skip usage right check if group CVS_ADMIN_GROUP does not exist */
- if (grp != NULL)
- {
- char *me = getcaller();
- char **grnam = grp->gr_mem;
- int denied = 1;
-
- while (*grnam)
- {
- if (strcmp(*grnam, me) == 0)
- {
- denied = 0;
- break;
- }
- grnam++;
- }
-
- if (denied)
- error (1, 0, "usage is restricted to members of the group %s",
- CVS_ADMIN_GROUP);
- }
-#endif
-
wrap_setup ();
memset (&admin_data, 0, sizeof admin_data);
@@ -157,9 +133,13 @@ admin (argc, argv)
example, admin_data->branch should be not `-bfoo' but simply `foo'. */
optind = 0;
+ only_k_option = 1;
while ((c = getopt (argc, argv,
- "+ib::c:a:A:e:l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
+ "+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
{
+ if (c != 'k')
+ only_k_option = 0;
+
switch (c)
{
case 'i':
@@ -211,6 +191,11 @@ admin (argc, argv)
break;
case 'e':
+ if (optarg == NULL)
+ {
+ error (1, 0,
+ "removing entire access list not yet implemented");
+ }
arg_add (&admin_data, 'e', optarg);
break;
@@ -353,6 +338,33 @@ admin (argc, argv)
argc -= optind;
argv += optind;
+#ifdef CVS_ADMIN_GROUP
+ grp = getgrnam(CVS_ADMIN_GROUP);
+ /* skip usage right check if group CVS_ADMIN_GROUP does not exist */
+ if (grp != NULL)
+ {
+ char *me = getcaller();
+ char **grnam = grp->gr_mem;
+ /* The use of `cvs admin -k' is unrestricted. However, any
+ other option is restricted. */
+ int denied = ! only_k_option;
+
+ while (*grnam)
+ {
+ if (strcmp(*grnam, me) == 0)
+ {
+ denied = 0;
+ break;
+ }
+ grnam++;
+ }
+
+ if (denied)
+ error (1, 0, "usage is restricted to members of the group %s",
+ CVS_ADMIN_GROUP);
+ }
+#endif
+
for (i = 0; i < admin_data.ac; ++i)
{
assert (admin_data.av[i][0] == '-');
@@ -375,9 +387,9 @@ admin (argc, argv)
check_numeric (admin_data.delete_revs + 2, argc, argv);
p = strchr (admin_data.delete_revs + 2, ':');
- if (p != NULL && isdigit (p[1]))
+ if (p != NULL && isdigit ((unsigned char) p[1]))
check_numeric (p + 1, argc, argv);
- else if (p != NULL && p[1] == ':' && isdigit(p[2]))
+ else if (p != NULL && p[1] == ':' && isdigit ((unsigned char) p[2]))
check_numeric (p + 2, argc, argv);
}
@@ -414,8 +426,8 @@ admin (argc, argv)
for (i = 0; i < admin_data.ac; ++i)
send_arg (admin_data.av[i]);
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, 0, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("admin\012", 0);
err = get_responses_and_close ();
goto return_it;
@@ -492,7 +504,7 @@ admin_fileproc (callerdat, finfo)
if (admin_data->branch != NULL)
{
char *branch = &admin_data->branch[2];
- if (*branch != '\0' && ! isdigit (*branch))
+ if (*branch != '\0' && ! isdigit ((unsigned char) *branch))
{
branch = RCS_whatbranch (rcs, admin_data->branch + 2);
if (branch == NULL)
@@ -604,12 +616,9 @@ admin_fileproc (callerdat, finfo)
if (admin_data->kflag != NULL)
{
char *kflag = admin_data->kflag + 2;
- if (!rcs->expand || strcmp (rcs->expand, kflag) != 0)
- {
- if (rcs->expand)
- free (rcs->expand);
- rcs->expand = xstrdup (kflag);
- }
+ char *oldexpand = RCS_getexpand (rcs);
+ if (oldexpand == NULL || strcmp (oldexpand, kflag) != 0)
+ RCS_setexpand (rcs, kflag);
}
/* Handle miscellaneous options. TODO: decide whether any or all
diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c
index c6a8122..a7d942f 100644
--- a/contrib/cvs/src/checkout.c
+++ b/contrib/cvs/src/checkout.c
@@ -238,7 +238,7 @@ checkout (argc, argv)
if (!tag && !date)
error (1, 0, "must specify a tag or date");
- if (tag && isdigit (tag[0]))
+ if (tag && isdigit ((unsigned char) tag[0]))
error (1, 0, "tag `%s' must be a symbolic tag", tag);
}
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index 222e7f2..748132a 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -148,6 +148,139 @@ static void handle_notified PROTO((char *, int));
static size_t try_read_from_server PROTO ((char *, size_t));
#endif /* CLIENT_SUPPORT */
+#ifdef CLIENT_SUPPORT
+
+/* We need to keep track of the list of directories we've sent to the
+ server. This list, along with the current CVSROOT, will help us
+ decide which command-line arguments to send. */
+List *dirs_sent_to_server = NULL;
+
+static int is_arg_a_parent_or_listed_dir PROTO((Node *, void *));
+
+static int
+is_arg_a_parent_or_listed_dir (n, d)
+ Node *n;
+ void *d;
+{
+ char *directory = n->key; /* name of the dir sent to server */
+ char *this_argv_elem = (char *) d; /* this argv element */
+
+ /* Say we should send this argument if the argument matches the
+ beginning of a directory name sent to the server. This way,
+ the server will know to start at the top of that directory
+ hierarchy and descend. */
+
+ if (strncmp (directory, this_argv_elem, strlen (this_argv_elem)) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int arg_should_not_be_sent_to_server PROTO((char *));
+
+/* Return nonzero if this argument should not be sent to the
+ server. */
+
+static int
+arg_should_not_be_sent_to_server (arg)
+ char *arg;
+{
+ /* Decide if we should send this directory name to the server. We
+ should always send argv[i] if:
+
+ 1) the list of directories sent to the server is empty (as it
+ will be for checkout, etc.).
+
+ 2) the argument is "."
+
+ 3) the argument is a file in the cwd and the cwd is checked out
+ from the current root
+
+ 4) the argument lies within one of the paths in
+ dirs_sent_to_server.
+
+ 4) */
+
+ if (list_isempty (dirs_sent_to_server))
+ return 0; /* always send it */
+
+ if (strcmp (arg, ".") == 0)
+ return 0; /* always send it */
+
+ /* We should send arg if it is one of the directories sent to the
+ server or the parent of one; this tells the server to descend
+ the hierarchy starting at this level. */
+ if (isdir (arg))
+ {
+ if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg))
+ return 0;
+
+ /* If arg wasn't a parent, we don't know anything about it (we
+ would have seen something related to it during the
+ send_files phase). Don't send it. */
+ return 1;
+ }
+
+ /* Try to decide whether we should send arg to the server by
+ checking the contents of the corresponding CVSADM directory. */
+ {
+ char *t, *this_root;
+
+ /* Calculate "dirname arg" */
+ for (t = arg + strlen (arg) - 1; t >= arg; t--)
+ {
+ if (ISDIRSEP(*t))
+ break;
+ }
+
+ /* Now we're either poiting to the beginning of the
+ string, or we found a path separator. */
+ if (t >= arg)
+ {
+ /* Found a path separator. */
+ char c = *t;
+ *t = '\0';
+
+ /* First, check to see if we sent this directory to the
+ server, because it takes less time than actually
+ opening the stuff in the CVSADM directory. */
+ if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir,
+ arg))
+ {
+ *t = c; /* make sure to un-truncate the arg */
+ return 0;
+ }
+
+ /* Since we didn't find it in the list, check the CVSADM
+ files on disk. */
+ this_root = Name_Root (arg, (char *) NULL);
+ *t = c;
+ }
+ else
+ {
+ /* We're at the beginning of the string. Look at the
+ CVSADM files in cwd. */
+ this_root = Name_Root ((char *) NULL, (char *) NULL);
+ }
+
+ /* Now check the value for root. */
+ if (this_root && current_root
+ && (strcmp (this_root, current_root) != 0))
+ {
+ /* Don't send this, since the CVSROOTs don't match. */
+ free (this_root);
+ return 1;
+ }
+ free (this_root);
+ }
+
+ /* OK, let's send it. */
+ return 0;
+}
+
+
+#endif /* CLIENT_SUPPORT */
+
#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
/* Shared with server. */
@@ -710,25 +843,6 @@ int gzip_level;
*/
int file_gzip_level;
-int filter_through_gzip (fd, dir, level, pidp)
- int fd, dir, level;
- pid_t *pidp;
-{
- static char buf[5] = "-";
- static char *gzip_argv[3] = { "gzip", buf };
-
- sprintf (buf+1, "%d", level);
- return filter_stream_through_program (fd, dir, &gzip_argv[0], pidp);
-}
-
-int filter_through_gunzip (fd, dir, pidp)
- int fd, dir;
- pid_t *pidp;
-{
- static char *gunzip_argv[3] = { "gzip", "-d" };
- return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp);
-}
-
#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
#ifdef CLIENT_SUPPORT
@@ -737,7 +851,7 @@ int filter_through_gunzip (fd, dir, pidp)
* The Repository for the top level of this command (not necessarily
* the CVSROOT, just the current directory at the time we do it).
*/
-static char *toplevel_repos;
+static char *toplevel_repos = NULL;
/* Working directory when we first started. Note: we could speed things
up on some systems by using savecwd.h here instead of just always
@@ -770,6 +884,13 @@ handle_error (args, len)
return;
}
++p;
+
+ /* Next we print the text of the message from the server. We
+ probably should be prefixing it with "server error" or some
+ such, because if it is something like "Out of memory", the
+ current behavior doesn't say which machine is out of
+ memory. */
+
len -= p - args;
something_printed = 0;
for (; len > 0; --len)
@@ -807,7 +928,7 @@ handle_valid_requests (args, len)
;
else
{
- if (rq->status == rq_enableme)
+ if (rq->flags & RQ_ENABLEME)
{
/*
* Server wants to know if we have this, to enable the
@@ -817,16 +938,17 @@ handle_valid_requests (args, len)
send_to_server ("\012", 0);
}
else
- rq->status = rq_supported;
+ rq->flags |= RQ_SUPPORTED;
}
p = q;
} while (q != NULL);
for (rq = requests; rq->name != NULL; ++rq)
{
- if (rq->status == rq_essential)
+ if ((rq->flags & RQ_SUPPORTED)
+ || (rq->flags & RQ_ENABLEME))
+ continue;
+ if (rq->flags & RQ_ESSENTIAL)
error (1, 0, "request `%s' not supported by server", rq->name);
- else if (rq->status == rq_optional)
- rq->status = rq_not_supported;
}
}
@@ -1210,7 +1332,14 @@ copy_a_file (data, ent_list, short_pathname, filename)
for(p = newname; *p; p++)
if(*p == '.' || *p == '#') *p = '_';
#endif
-
+ /* cvsclient.texi has said for a long time that newname must be in the
+ same directory. Wouldn't want a malicious or buggy server overwriting
+ ~/.profile, /etc/passwd, or anything like that. */
+ if (last_component (newname) != newname)
+ error (1, 0, "protocol error: Copy-file tried to specify directory");
+
+ if (unlink_file (newname) && !existence_error (errno))
+ error (0, errno, "unable to remove %s", newname);
copy_file (filename, newname);
free (newname);
}
@@ -1317,6 +1446,23 @@ static int updated_seen;
/* Filename from an "fname" tagged response within +updated/-updated. */
static char *updated_fname;
+/* This struct is used to hold data when reading the +importmergecmd
+ and -importmergecmd tags. We put the variables in a struct only
+ for namespace issues. FIXME: As noted above, we need to develop a
+ more systematic approach. */
+static struct
+{
+ /* Nonzero if we have seen +importmergecmd and not -importmergecmd. */
+ int seen;
+ /* Number of conflicts, from a "conflicts" tagged response. */
+ int conflicts;
+ /* First merge tag, from a "mergetag1" tagged response. */
+ char *mergetag1;
+ /* Second merge tag, from a "mergetag2" tagged response. */
+ char *mergetag2;
+ /* Repository, from a "repository" tagged response. */
+ char *repository;
+} importmergecmd;
/* Nonzero if we should arrange to return with a failure exit status. */
static int failure_exit;
@@ -1367,7 +1513,7 @@ handle_checksum (args, len)
stored_checksum_valid = 1;
}
-static int stored_mode_valid;
+/* Mode that we got in a "Mode" response (malloc'd), or NULL if none. */
static char *stored_mode;
static void handle_mode PROTO ((char *, int));
@@ -1377,12 +1523,9 @@ handle_mode (args, len)
char *args;
int len;
{
- if (stored_mode_valid)
- error (1, 0, "protocol error: duplicate Mode");
if (stored_mode != NULL)
- free (stored_mode);
+ error (1, 0, "protocol error: duplicate Mode");
stored_mode = xstrdup (args);
- stored_mode_valid = 1;
}
/* Nonzero if time was specified in Mod-time. */
@@ -1547,8 +1690,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
free (size_string);
/* Note that checking this separately from writing the file is
- a race condition: if the existing or lack thereof of the
- file changes between now and the actually calls which
+ a race condition: if the existence or lack thereof of the
+ file changes between now and the actual calls which
operate on it, we lose. However (a) there are so many
cases, I'm reluctant to try to fix them all, (b) in some
cases the system might not even have a system call which
@@ -1622,9 +1765,11 @@ update_entries (data_arg, ent_list, short_pathname, filename)
/* The Mode, Mod-time, and Checksum responses should not carry
over to a subsequent Created (or whatever) response, even
in the error case. */
- stored_mode_valid = 0;
if (stored_mode != NULL)
+ {
free (stored_mode);
+ stored_mode = NULL;
+ }
stored_modtime_valid = 0;
stored_checksum_valid = 0;
@@ -1701,7 +1846,10 @@ update_entries (data_arg, ent_list, short_pathname, filename)
read_from_server (buf, size);
if (use_gzip)
- gunzip_and_write (fd, short_pathname, buf, size);
+ {
+ if (gunzip_and_write (fd, short_pathname, buf, size))
+ error (1, 0, "aborting due to compression error");
+ }
else if (write (fd, buf, size) != size)
error (1, errno, "writing %s", short_pathname);
}
@@ -1734,82 +1882,14 @@ update_entries (data_arg, ent_list, short_pathname, filename)
}
else if (data->contents == UPDATE_ENTRIES_PATCH)
{
-#ifdef DONT_USE_PATCH
- /* Hmm. We support only Rcs-diff, and the server supports
- only Patched (or else it would have sent Rcs-diff instead).
+ /* You might think we could just leave Patched out of
+ Valid-responses and not get this response. However, if
+ memory serves, the CVS 1.9 server bases this on -u
+ (update-patches), and there is no way for us to send -u
+ or not based on whether the server supports "Rcs-diff".
+
Fall back to transmitting entire files. */
patch_failed = 1;
-#else /* Use patch. */
- int retcode;
- char *backup;
- struct stat s;
-
- backup = xmalloc (strlen (filename) + 5);
- strcpy (backup, filename);
- strcat (backup, "~");
- (void) unlink_file (backup);
- if (!isfile (filename))
- error (1, 0, "patch original file %s does not exist",
- short_pathname);
- if ( CVS_STAT (temp_filename, &s) < 0)
- error (1, errno, "can't stat patch file %s", temp_filename);
- if (s.st_size == 0)
- retcode = 0;
- else
- {
- /* This behavior (in which -b takes an argument) is
- supported by GNU patch 2.1. Apparently POSIX.2
- specifies a -b option without an argument. GNU
- patch 2.1.5 implements this and therefore won't
- work here. GNU patch versions after 2.1.5 are said
- to have a kludge which checks if the last 4 args
- are `-b SUFFIX ORIGFILE PATCHFILE' and if so emit a
- warning (I think -s suppresses it), and then behave
- as CVS expects.
-
- Of course this is yet one more reason why in the long
- run we want Rcs-diff to replace Patched. */
-
- run_setup (PATCH_PROGRAM);
- run_arg ("-f");
- run_arg ("-s");
- run_arg ("-b");
- run_arg ("~");
- run_arg (filename);
- run_arg (temp_filename);
- retcode = run_exec (DEVNULL, RUN_TTY, RUN_TTY, RUN_NORMAL);
- }
- /* FIXME: should we really be silently ignoring errors? */
- (void) unlink_file (temp_filename);
- if (retcode == 0)
- {
- /* FIXME: should we really be silently ignoring errors? */
- (void) unlink_file (backup);
- }
- else
- {
- int old_errno = errno;
- char *path_tmp;
-
- if (isfile (backup))
- rename_file (backup, filename);
-
- /* Get rid of the patch reject file. */
- path_tmp = xmalloc (strlen (filename) + 10);
- strcpy (path_tmp, filename);
- strcat (path_tmp, ".rej");
- /* FIXME: should we really be silently ignoring errors? */
- (void) unlink_file (path_tmp);
- free (path_tmp);
-
- error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
- "could not patch %s%s", filename,
- retcode == -1 ? "" : "; will refetch");
-
- patch_failed = 1;
- }
- free (backup);
-#endif /* Use patch. */
}
else
{
@@ -1842,15 +1922,16 @@ update_entries (data_arg, ent_list, short_pathname, filename)
{
if (stored_checksum_valid)
{
- struct MD5Context context;
+ struct cvs_MD5Context context;
unsigned char checksum[16];
/* We have a checksum. Check it before writing
the file out, so that we don't have to read it
back in again. */
- MD5Init (&context);
- MD5Update (&context, (unsigned char *) patchedbuf, patchedlen);
- MD5Final (checksum, &context);
+ cvs_MD5Init (&context);
+ cvs_MD5Update (&context,
+ (unsigned char *) patchedbuf, patchedlen);
+ cvs_MD5Final (checksum, &context);
if (memcmp (checksum, stored_checksum, 16) != 0)
{
error (0, 0,
@@ -1887,7 +1968,7 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (stored_checksum_valid && ! patch_failed)
{
FILE *e;
- struct MD5Context context;
+ struct cvs_MD5Context context;
unsigned char buf[8192];
unsigned len;
unsigned char checksum[16];
@@ -1906,12 +1987,12 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (e == NULL)
error (1, errno, "could not open %s", short_pathname);
- MD5Init (&context);
+ cvs_MD5Init (&context);
while ((len = fread (buf, 1, sizeof buf, e)) != 0)
- MD5Update (&context, buf, len);
+ cvs_MD5Update (&context, buf, len);
if (ferror (e))
error (1, errno, "could not read %s", short_pathname);
- MD5Final (checksum, &context);
+ cvs_MD5Final (checksum, &context);
fclose (e);
@@ -1958,10 +2039,13 @@ update_entries (data_arg, ent_list, short_pathname, filename)
free (buf);
}
- if (stored_mode_valid)
+ if (stored_mode != NULL)
+ {
change_mode (filename, stored_mode, 1);
- stored_mode_valid = 0;
-
+ free (stored_mode);
+ stored_mode = NULL;
+ }
+
if (stored_modtime_valid)
{
struct utimbuf t;
@@ -2020,7 +2104,17 @@ update_entries (data_arg, ent_list, short_pathname, filename)
else if (local_timestamp == NULL)
{
local_timestamp = file_timestamp;
- mark_up_to_date (filename);
+
+ /* Checking for command_name of "commit" doesn't seem like
+ the cleanest way to handle this, but it seem to roughly
+ parallel what the :local: code which calls
+ mark_up_to_date ends up amounting to. Some day, should
+ think more about what the Checked-in response means
+ vis-a-vis both Entries and Base and clarify
+ cvsclient.texi accordingly. */
+
+ if (!strcmp (command_name, "commit"))
+ mark_up_to_date (filename);
}
Register (ent_list, filename, vn, local_timestamp,
@@ -2263,7 +2357,20 @@ set_sticky (data, ent_list, short_pathname, filename)
FILE *f;
read_line (&tagspec);
- f = open_file (CVSADM_TAG, "w+");
+
+ /* FIXME-update-dir: error messages should include the directory. */
+ f = CVS_FOPEN (CVSADM_TAG, "w+");
+ if (f == NULL)
+ {
+ /* Making this non-fatal is a bit of a kludge (see dirs2
+ in testsuite). A better solution would be to avoid having
+ the server tell us about a directory we shouldn't be doing
+ anything with anyway (e.g. by handling directory
+ addition/removal better). */
+ error (0, errno, "cannot open %s", CVSADM_TAG);
+ free (tagspec);
+ return;
+ }
if (fprintf (f, "%s\n", tagspec) < 0)
error (1, errno, "writing %s", CVSADM_TAG);
if (fclose (f) == EOF)
@@ -2568,6 +2675,22 @@ send_repository (dir, repos, update_dir)
if (client_prune_dirs)
add_prune_candidate (update_dir);
+ /* Add a directory name to the list of those sent to the
+ server. */
+ if (update_dir && (*update_dir != '\0')
+ && (strcmp (update_dir, ".") != 0)
+ && (findnode (dirs_sent_to_server, update_dir) == NULL))
+ {
+ Node *n;
+ n = getnode ();
+ n->type = UNKNOWN;
+ n->key = xstrdup (update_dir);
+ n->data = NULL;
+
+ if (addnode (dirs_sent_to_server, n))
+ error (1, 0, "cannot add directory %s to list", n->key);
+ }
+
/* 80 is large enough for any of CVSADM_*. */
adm_name = xmalloc (strlen (dir) + 80);
@@ -2762,47 +2885,55 @@ send_a_repository (dir, repository, update_dir)
* directories (and cvs invoked on the containing
* directory). I'm not sure the latter case needs to
* work.
+ *
+ * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it
+ * does need to work after all. When we are using the
+ * client in a multi-cvsroot environment, it will be
+ * fairly common that we have the above case (e.g.,
+ * cwd checked out from one repository but
+ * subdirectory checked out from another). We can't
+ * assume that by walking up a directory in our wd we
+ * necessarily walk up a directory in the repository.
*/
/*
* This gets toplevel_repos wrong for "cvs update ../foo"
* but I'm not sure toplevel_repos matters in that case.
*/
- int slashes_in_update_dir;
- int slashes_skipped;
- char *p;
- /*
- * Strip trailing slashes from the name of the update directory.
- * Otherwise, running `cvs update dir/' provokes the failure
- * `protocol error: illegal directory syntax in dir/' when
- * running in client/server mode.
- */
- strip_trailing_slashes (update_dir);
+ int repository_len, update_dir_len;
- slashes_in_update_dir = 0;
- for (p = update_dir; *p != '\0'; ++p)
- if (*p == '/')
- ++slashes_in_update_dir;
+ strip_trailing_slashes (update_dir);
- slashes_skipped = 0;
- p = repository + strlen (repository);
- while (1)
+ repository_len = strlen (repository);
+ update_dir_len = strlen (update_dir);
+
+ /* Try to remove the path components in UPDATE_DIR
+ from REPOSITORY. If the path elements don't exist
+ in REPOSITORY, or the removal of those path
+ elements mean that we "step above"
+ CVSroot_directory, set toplevel_repos to
+ CVSroot_directory. */
+ if ((repository_len > update_dir_len)
+ && (strcmp (repository + repository_len - update_dir_len,
+ update_dir) == 0)
+ /* TOPLEVEL_REPOS shouldn't be above CVSroot_directory */
+ && ((repository_len - update_dir_len)
+ > strlen (CVSroot_directory)))
{
- if (p == repository)
- error (1, 0,
- "internal error: not enough slashes in %s",
- repository);
- if (*p == '/')
- ++slashes_skipped;
- if (slashes_skipped < slashes_in_update_dir + 1)
- --p;
- else
- break;
+ /* The repository name contains UPDATE_DIR. Set
+ toplevel_repos to the repository name without
+ UPDATE_DIR. */
+
+ toplevel_repos = xmalloc (repository_len - update_dir_len);
+ /* Note that we don't copy the trailing '/'. */
+ strncpy (toplevel_repos, repository,
+ repository_len - update_dir_len - 1);
+ toplevel_repos[repository_len - update_dir_len - 1] = '\0';
+ }
+ else
+ {
+ toplevel_repos = xstrdup (CVSroot_directory);
}
- toplevel_repos = xmalloc (p - repository + 1);
- /* Note that we don't copy the trailing '/'. */
- strncpy (toplevel_repos, repository, p - repository);
- toplevel_repos[p - repository] = '\0';
}
}
}
@@ -3047,10 +3178,61 @@ handle_mt (args, len)
case '+':
if (strcmp (tag, "+updated") == 0)
updated_seen = 1;
+ else if (strcmp (tag, "+importmergecmd") == 0)
+ importmergecmd.seen = 1;
break;
case '-':
if (strcmp (tag, "-updated") == 0)
updated_seen = 0;
+ else if (strcmp (tag, "-importmergecmd") == 0)
+ {
+ char buf[80];
+
+ /* Now that we have gathered the information, we can
+ output the suggested merge command. */
+
+ if (importmergecmd.conflicts == 0
+ || importmergecmd.mergetag1 == NULL
+ || importmergecmd.mergetag2 == NULL
+ || importmergecmd.repository == NULL)
+ {
+ error (0, 0,
+ "invalid server: incomplete importmergecmd tags");
+ break;
+ }
+
+ sprintf (buf, "\n%d conflicts created by this import.\n",
+ importmergecmd.conflicts);
+ cvs_output (buf, 0);
+ cvs_output ("Use the following command to help the merge:\n\n",
+ 0);
+ cvs_output ("\t", 1);
+ cvs_output (program_name, 0);
+ if (CVSroot_cmdline != NULL)
+ {
+ cvs_output (" -d ", 0);
+ cvs_output (CVSroot_cmdline, 0);
+ }
+ cvs_output (" checkout -j", 0);
+ cvs_output (importmergecmd.mergetag1, 0);
+ cvs_output (" -j", 0);
+ cvs_output (importmergecmd.mergetag2, 0);
+ cvs_output (" ", 1);
+ cvs_output (importmergecmd.repository, 0);
+ cvs_output ("\n\n", 0);
+
+ /* Clear the static variables so that everything is
+ ready for any subsequent importmergecmd tag. */
+ importmergecmd.conflicts = 0;
+ free (importmergecmd.mergetag1);
+ importmergecmd.mergetag1 = NULL;
+ free (importmergecmd.mergetag2);
+ importmergecmd.mergetag2 = NULL;
+ free (importmergecmd.repository);
+ importmergecmd.repository = NULL;
+
+ importmergecmd.seen = 0;
+ }
break;
default:
if (updated_seen)
@@ -3073,6 +3255,21 @@ handle_mt (args, len)
or they reflect future extensions that we can
safely ignore. */
}
+ else if (importmergecmd.seen)
+ {
+ if (strcmp (tag, "conflicts") == 0)
+ importmergecmd.conflicts = atoi (text);
+ else if (strcmp (tag, "mergetag1") == 0)
+ importmergecmd.mergetag1 = xstrdup (text);
+ else if (strcmp (tag, "mergetag2") == 0)
+ importmergecmd.mergetag2 = xstrdup (text);
+ else if (strcmp (tag, "repository") == 0)
+ importmergecmd.repository = xstrdup (text);
+ /* Swallow all other tags. Either they are text for
+ which we are going to print our own version when we
+ see -importmergecmd, or they are future extensions
+ we can safely ignore. */
+ }
else if (strcmp (tag, "newline") == 0)
printf ("\n");
else if (text != NULL)
@@ -3404,9 +3601,12 @@ get_responses_and_close ()
{
time_t now;
- (void) time (&now);
- if (now == last_register_time)
+ for (;;)
+ {
+ (void) time (&now);
+ if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
+ }
}
return errs;
@@ -3424,7 +3624,7 @@ supported_request (name)
for (rq = requests; rq->name; rq++)
if (!strcmp (rq->name, name))
- return rq->status == rq_supported;
+ return (rq->flags & RQ_SUPPORTED) != 0;
error (1, 0, "internal error: testing support for unknown option?");
/* NOTREACHED */
return 0;
@@ -3490,7 +3690,6 @@ recv_line (sock, resultp)
int sock;
char **resultp;
{
- int c;
char *result;
size_t input_index = 0;
size_t result_size = 80;
@@ -3500,23 +3699,16 @@ recv_line (sock, resultp)
while (1)
{
char ch;
- if (recv (sock, &ch, 1, 0) < 0)
+ int n;
+ n = recv (sock, &ch, 1, 0);
+ if (n <= 0)
error (1, 0, "recv() from server %s: %s", CVSroot_hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- c = ch;
+ n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
- if (c == EOF)
- {
- free (result);
-
- /* It's end of file. */
- error (1, 0, "end of file from server");
- }
-
- if (c == '\012')
+ if (ch == '\012')
break;
- result[input_index++] = c;
+ result[input_index++] = ch;
while (input_index + 1 >= result_size)
{
result_size *= 2;
@@ -3535,6 +3727,28 @@ recv_line (sock, resultp)
return input_index;
}
+/* Connect to a forked server process. */
+
+void
+connect_to_forked_server (tofdp, fromfdp)
+ int *tofdp, *fromfdp;
+{
+ /* This is pretty simple. All we need to do is choose the correct
+ cvs binary and call piped_child. */
+
+ char *command[3];
+
+ command[0] = getenv ("CVS_SERVER");
+ if (! command[0])
+ command[0] = "cvs";
+
+ command[1] = "server";
+ command[2] = NULL;
+
+ if (! piped_child (command, tofdp, fromfdp))
+ error (1, 0, "could not fork server process");
+}
+
/* Connect to the authenticating server.
If VERIFY_ONLY is non-zero, then just verify that the password is
@@ -3960,6 +4174,13 @@ start_server ()
int tofd, fromfd;
char *log = getenv ("CVS_CLIENT_LOG");
+
+ /* Clear our static variables for this invocation. */
+ if (toplevel_repos != NULL)
+ free (toplevel_repos);
+ toplevel_repos = NULL;
+
+
/* Note that generally speaking we do *not* fall back to a different
way of connecting if the first one does not work. This is slow
(*really* slow on a 14.4kbps link); the clean way to have a CVS
@@ -4020,6 +4241,10 @@ the :server: access method is not supported by this port of CVS");
#endif
break;
+ case fork_method:
+ connect_to_forked_server (&tofd, &fromfd);
+ break;
+
default:
error (1, 0, "\
(start_server internal error): unknown access method");
@@ -4119,7 +4344,11 @@ the :server: access method is not supported by this port of CVS");
free (last_update_dir);
last_update_dir = NULL;
stored_checksum_valid = 0;
- stored_mode_valid = 0;
+ if (stored_mode != NULL)
+ {
+ free (stored_mode);
+ stored_mode = NULL;
+ }
if (strcmp (command_name, "init") != 0)
{
@@ -4648,9 +4877,10 @@ send_modified (file, short_pathname, vers)
{
size_t newsize = 0;
- read_and_gzip (fd, short_pathname, (unsigned char **)&buf,
- &bufsize, &newsize,
- file_gzip_level);
+ if (read_and_gzip (fd, short_pathname, (unsigned char **)&buf,
+ &bufsize, &newsize,
+ file_gzip_level))
+ error (1, 0, "aborting due to compression error");
if (close (fd) < 0)
error (0, errno, "warning: can't close %s", short_pathname);
@@ -5050,7 +5280,7 @@ send_file_names (argc, argv, flags)
int i;
int level;
int max_level;
-
+
/* The fact that we do this here as well as start_recursion is a bit
of a performance hit. Perhaps worth cleaning up someday. */
if (flags & SEND_EXPAND_WILD)
@@ -5091,6 +5321,9 @@ send_file_names (argc, argv, flags)
char *p = argv[i];
char *line = NULL;
+ if (arg_should_not_be_sent_to_server (argv[i]))
+ continue;
+
#ifdef FILENAMES_CASE_INSENSITIVE
/* We want to send the file name as it appears
in CVS/Entries. We put this inside an ifdef
@@ -5224,7 +5457,7 @@ client_import_setup (repository)
*/
int
client_process_import_file (message, vfile, vtag, targc, targv, repository,
- all_files_binary)
+ all_files_binary, modtime)
char *message;
char *vfile;
char *vtag;
@@ -5232,6 +5465,9 @@ client_process_import_file (message, vfile, vtag, targc, targv, repository,
char *targv[];
char *repository;
int all_files_binary;
+
+ /* Nonzero for "import -d". */
+ int modtime;
{
char *update_dir;
char *fullname;
@@ -5281,6 +5517,28 @@ client_process_import_file (message, vfile, vtag, targc, targv, repository,
error (0, 0,
"warning: ignoring -k options due to server limitations");
}
+ if (modtime)
+ {
+ if (supported_request ("Checkin-time"))
+ {
+ struct stat sb;
+ char *rcsdate;
+ char netdate[MAXDATELEN];
+
+ if (CVS_STAT (vfile, &sb) < 0)
+ error (1, errno, "cannot stat %s", fullname);
+ rcsdate = date_from_time_t (sb.st_mtime);
+ date_to_internet (netdate, rcsdate);
+ free (rcsdate);
+
+ send_to_server ("Checkin-time ", 0);
+ send_to_server (netdate, 0);
+ send_to_server ("\012", 1);
+ }
+ else
+ error (0, 0,
+ "warning: ignoring -d option due to server limitations");
+ }
send_modified (vfile, fullname, &vers);
if (vers.options != NULL)
free (vers.options);
@@ -5466,27 +5724,15 @@ option_with_arg (option, arg)
We then convert that to the format required in the protocol
(including the "-D" option) and send it. According to
- cvsclient.texi, RFC 822/1123 format is preferred, but for now we
- use the format that we always have, for
- conservatism/laziness/paranoia. As far as I know all servers
- support the RFC 822/1123 format, so probably there would be no
- particular danger in switching. */
+ cvsclient.texi, RFC 822/1123 format is preferred. */
void
client_senddate (date)
const char *date;
{
- int year, month, day, hour, minute, second;
- char buf[100];
-
- if (sscanf (date, SDATEFORM, &year, &month, &day, &hour, &minute, &second)
- != 6)
- {
- error (1, 0, "client_senddate: sscanf failed on date");
- }
+ char buf[MAXDATELEN];
- sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year,
- hour, minute, second);
+ date_to_internet (buf, (char *)date);
option_with_arg ("-D", buf);
}
diff --git a/contrib/cvs/src/client.h b/contrib/cvs/src/client.h
index 996dc63..c323cf3 100644
--- a/contrib/cvs/src/client.h
+++ b/contrib/cvs/src/client.h
@@ -6,8 +6,6 @@ extern int change_mode PROTO((char *, char *, int));
extern int gzip_level;
extern int file_gzip_level;
-extern int filter_through_gzip PROTO((int, int, int, pid_t *));
-extern int filter_through_gunzip PROTO((int, int, pid_t *));
#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
@@ -195,7 +193,8 @@ extern char *toplevel_wd;
extern void client_import_setup PROTO((char *repository));
extern int client_process_import_file
PROTO((char *message, char *vfile, char *vtag,
- int targc, char *targv[], char *repository, int all_files_binary));
+ int targc, char *targv[], char *repository, int all_files_binary,
+ int modtime));
extern void client_import_done PROTO((void));
extern void client_notify PROTO((char *, char *, char *, int, char *));
#endif /* CLIENT_SUPPORT */
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 75d2e5ae..c4cbd24 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -49,7 +49,6 @@ static int precommit_list_proc PROTO((Node * p, void *closure));
static int precommit_proc PROTO((char *repository, char *filter));
static int remove_file PROTO ((struct file_info *finfo, char *tag,
char *message));
-static void fix_rcs_modes PROTO((char *rcs, char *user));
static void fixaddfile PROTO((char *file, char *repository));
static void fixbranch PROTO((RCSNode *, char *branch));
static void unlockrcs PROTO((RCSNode *rcs));
@@ -340,7 +339,12 @@ commit (argc, argv)
/* FIXME: Shouldn't this check be much more closely related to the
readonly user stuff (CVSROOT/readers, &c). That is, why should
root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
- if (geteuid () == (uid_t) 0)
+ if (geteuid () == (uid_t) 0
+# ifdef CLIENT_SUPPORT
+ /* Who we are on the client side doesn't affect logging. */
+ && !client_active
+# endif
+ )
{
struct passwd *pw;
@@ -406,7 +410,7 @@ commit (argc, argv)
argv += optind;
/* numeric specified revision means we ignore sticky tags... */
- if (saved_tag && isdigit (*saved_tag))
+ if (saved_tag && isdigit ((unsigned char) *saved_tag))
{
aflag = 1;
/* strip trailing dots */
@@ -561,13 +565,6 @@ commit (argc, argv)
send_arg("-n");
option_with_arg ("-r", saved_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
- check on those files. This is different from local CVS and
- previous versions of client/server CVS, but it probably is a Good
- Thing, or at least Not Such A Bad Thing. */
- send_file_names (find_args.argc, find_args.argv, 0);
-
/* FIXME: This whole find_args.force/SEND_FORCE business is a
kludge. It would seem to be a server bug that we have to
say that files are modified when they are not. This makes
@@ -580,6 +577,13 @@ commit (argc, argv)
send_files (find_args.argc, find_args.argv, local, 0,
find_args.force ? SEND_FORCE : 0);
+ /* Sending only the names of the files which were modified, added,
+ or removed means that the server will only do an up-to-date
+ check on those files. This is different from local CVS and
+ previous versions of client/server CVS, but it probably is a Good
+ Thing, or at least Not Such A Bad Thing. */
+ send_file_names (find_args.argc, find_args.argv, 0);
+
send_to_server ("ci\012", 0);
err = get_responses_and_close ();
if (err != 0 && use_editor && saved_message != NULL)
@@ -672,9 +676,10 @@ commit (argc, argv)
{
time_t now;
- (void) time (&now);
- if (now == last_register_time)
+ for (;;)
{
+ (void) time (&now);
+ if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
}
}
@@ -703,7 +708,7 @@ classify_file_internal (finfo, vers)
noexec = quiet = really_quiet = 1;
/* handle specified numeric revision specially */
- if (saved_tag && isdigit (*saved_tag))
+ if (saved_tag && isdigit ((unsigned char) *saved_tag))
{
/* If the tag is for the trunk, make sure we're at the head */
if (numdots (saved_tag) < 2)
@@ -787,6 +792,19 @@ check_fileproc (callerdat, finfo)
struct commit_info *ci;
struct logfile_info *li;
+ size_t cvsroot_len = strlen (CVSroot_directory);
+
+ if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0
+ && ISDIRSEP (finfo->repository[cvsroot_len])
+ && strncmp (finfo->repository + cvsroot_len + 1,
+ CVSROOTADM,
+ sizeof (CVSROOTADM) - 1) == 0
+ && ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
+ && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
+ CVSNULLREPOS) == 0
+ )
+ error (1, 0, "cannot check in to %s", finfo->repository);
+
status = classify_file_internal (finfo, &vers);
/*
@@ -825,7 +843,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 (!saved_tag || !isdigit ((unsigned char) *saved_tag))
{
if (vers->date)
{
@@ -897,7 +915,9 @@ warning: file `%s' seems to still contain conflict indicators",
}
}
- if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
+ if (status == T_REMOVED
+ && vers->tag
+ && isdigit ((unsigned char) *vers->tag))
{
/* Remove also tries to forbid this, but we should check
here. I'm only _sure_ about somewhat obscure cases
@@ -936,7 +956,7 @@ warning: file `%s' seems to still contain conflict indicators",
}
free (rcs);
}
- if (vers->tag && isdigit (*vers->tag) &&
+ if (vers->tag && isdigit ((unsigned char) *vers->tag) &&
numdots (vers->tag) > 1)
{
error (0, 0,
@@ -996,7 +1016,7 @@ warning: file `%s' seems to still contain conflict indicators",
ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
ci->status = status;
if (vers->tag)
- if (isdigit (*vers->tag))
+ if (isdigit ((unsigned char) *vers->tag))
ci->rev = xstrdup (vers->tag);
else
ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
@@ -1115,7 +1135,7 @@ precommit_proc (repository, filter)
s = xstrdup (filter);
for (cp = s; *cp; cp++)
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
{
*cp = '\0';
break;
@@ -1262,7 +1282,11 @@ commit_fileproc (callerdat, finfo)
Since the branch test was done in check_fileproc for
modified files, we need to stub it in again here. */
- if (ci->tag)
+ if (ci->tag
+
+ /* If numeric, it is on the trunk; check_fileproc enforced
+ this. */
+ && !isdigit ((unsigned char) ci->tag[0]))
{
if (finfo->rcs == NULL)
error (1, 0, "internal error: no parsed RCS file");
@@ -1596,16 +1620,16 @@ findmaxrev (p, closure)
* XXX - if removing a ,v file that is a relative symbolic link to
* another ,v file, we probably should add a ".." component to the
* link to keep it relative after we move it into the attic.
- */
+
+ Return value is 0 on success, or >0 on error (in which case we have
+ printed an error message). */
static int
remove_file (finfo, tag, message)
struct file_info *finfo;
char *tag;
char *message;
{
- mode_t omask;
int retcode;
- char *tmp;
int branch;
int lockflag;
@@ -1695,16 +1719,6 @@ remove_file (finfo, tag, message)
RCS_rewrite (finfo->rcs, NULL, NULL);
}
-#ifdef SERVER_SUPPORT
- if (server_active) {
- /* If this is the server, there will be a file sitting in the
- temp directory which is the kludgy way in which server.c
- tells time_stamp that the file is no longer around. Remove
- it so we can create temp files with that name (ignore errors). */
- unlink_file (finfo->file);
- }
-#endif
-
/* check something out. Generally this is the head. If we have a
particular rev, then name it. */
retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
@@ -1741,34 +1755,9 @@ remove_file (finfo, tag, message)
if (rev != NULL)
free (rev);
- old_path = finfo->rcs->path;
+ old_path = xstrdup (finfo->rcs->path);
if (!branch)
- {
- /* this was the head; really move it into the Attic */
- tmp = xmalloc(strlen(finfo->repository) +
- sizeof('/') +
- sizeof(CVSATTIC) +
- sizeof('/') +
- strlen(finfo->file) +
- sizeof(RCSEXT) + 1);
- (void) sprintf (tmp, "%s/%s", finfo->repository, CVSATTIC);
- omask = umask (cvsumask);
- (void) CVS_MKDIR (tmp, 0777);
- (void) umask (omask);
- (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)))
- {
- free(tmp);
- return (1);
- }
- /* The old value of finfo->rcs->path is in old_path, and is
- freed below. */
- finfo->rcs->path = tmp;
- }
+ RCS_setattic (finfo->rcs, 1);
/* Print message that file was removed. */
cvs_output (old_path, 0);
@@ -1779,8 +1768,7 @@ remove_file (finfo, tag, message)
cvs_output ("\ndone\n", 0);
free(prev_rev);
- if (old_path != finfo->rcs->path)
- free (old_path);
+ free (old_path);
Scratch_Entry (finfo->entries, finfo->file);
return (0);
@@ -1806,7 +1794,9 @@ finaladd (finfo, rev, tag, options)
char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
+ sizeof (CVSEXT_LOG) + 10);
(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
- (void) unlink_file (tmp);
+ if (unlink_file (tmp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmp);
free (tmp);
}
else
@@ -1850,7 +1840,10 @@ fixaddfile (file, repository)
save_really_quiet = really_quiet;
really_quiet = 1;
if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
- (void) unlink_file (rcs);
+ {
+ if (unlink_file (rcs) < 0)
+ error (0, errno, "cannot remove %s", rcs);
+ }
else
freercsnode (&rcsfile);
really_quiet = save_really_quiet;
@@ -1897,8 +1890,20 @@ checkaddfile (file, repository, tag, options, rcsnode)
int newfile = 0;
RCSNode *rcsfile = NULL;
int retval;
+ int adding_on_branch;
+
+ /* Callers expect to be able to use either "" or NULL to mean the
+ default keyword expansion. */
+ if (options != NULL && options[0] == '\0')
+ options = NULL;
+ if (options != NULL)
+ assert (options[0] == '-' && options[1] == 'k');
- if (tag)
+ /* If numeric, it is on the trunk; check_fileproc enforced
+ this. */
+ adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
+
+ if (adding_on_branch)
{
rcs = xmalloc (strlen (repository) + strlen (file)
+ sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
@@ -1921,6 +1926,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
{
/* file has existed in the past. Prepare to resurrect. */
char *rev;
+ char *oldexpand;
if ((rcsfile = *rcsnode) == NULL)
{
@@ -1929,41 +1935,38 @@ checkaddfile (file, repository, tag, options, rcsnode)
goto out;
}
- if (tag == NULL)
+ oldexpand = RCS_getexpand (rcsfile);
+ if ((oldexpand != NULL
+ && options != NULL
+ && strcmp (options + 2, oldexpand) != 0)
+ || (oldexpand == NULL && options != NULL))
{
- char *oldfile;
-
- /* we are adding on the trunk, so move the file out of the
- Attic. */
- oldfile = xstrdup (rcs);
- sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+ /* We tell the user about this, because it means that the
+ old revisions will no longer retrieve the way that they
+ used to. */
+ error (0, 0, "changing keyword expansion mode to %s", options);
+ RCS_setexpand (rcsfile, options + 2);
+ }
- if (strcmp (oldfile, rcs) == 0)
+ if (!adding_on_branch)
+ {
+ /* We are adding on the trunk, so move the file out of the
+ Attic. */
+ if (!(rcsfile->flags & INATTIC))
{
error (0, 0, "internal error: confused about attic for %s",
- oldfile);
- out1:
- free (oldfile);
+ rcsfile->path);
retval = 1;
goto out;
}
- if (CVS_RENAME (oldfile, rcs) != 0)
- {
- error (0, errno, "failed to move `%s' out of the attic",
- oldfile);
- goto out1;
- }
- if (isreadable (oldfile)
- || !isreadable (rcs))
+
+ sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
+
+ if (RCS_setattic (rcsfile, 0))
{
- error (0, 0, "\
-internal error: `%s' didn't move out of the attic",
- oldfile);
- goto out1;
+ retval = 1;
+ goto out;
}
- free (oldfile);
- free (rcsfile->path);
- rcsfile->path = xstrdup (rcs);
}
rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
@@ -2016,7 +2019,7 @@ internal error: `%s' didn't move out of the attic",
}
/* Set RCS keyword expansion options. */
- if (options && options[0] == '-' && options[1] == 'k')
+ if (options != NULL)
opt = options + 2;
else
opt = NULL;
@@ -2045,7 +2048,7 @@ internal error: `%s' didn't move out of the attic",
/* when adding a file for the first time, and using a tag, we need
to create a dead revision on the trunk. */
- if (tag && newfile)
+ if (adding_on_branch && newfile)
{
char *tmp;
FILE *fp;
@@ -2107,7 +2110,7 @@ internal error: `%s' didn't move out of the attic",
}
}
- if (tag != NULL)
+ if (adding_on_branch)
{
/* when adding with a tag, we need to stub a branch, if it
doesn't already exist. */
@@ -2171,13 +2174,22 @@ internal error: `%s' didn't move out of the attic",
fileattr_newfile (file);
- /* I don't think fix_rcs_modes is needed any more. In the
- add_rcs_file case, the algorithms used by add_rcs_file and
- fix_rcs_modes are the same, so there is no need to go through
- it all twice. In the other cases, I think we want to just
- preserve the mode that the file had before we started. That is
- a behavior change, but I would think a desirable one. */
- fix_rcs_modes (rcs, file);
+ /* At this point, we used to set the file mode of the RCS file
+ based on the mode of the file in the working directory. If we
+ are creating the RCS file for the first time, add_rcs_file does
+ this already. If we are re-adding the file, then perhaps it is
+ consistent to preserve the old file mode, just as we preserve
+ the old keyword expansion mode.
+
+ If we decide that we should change the modes, then we can't do
+ it here anyhow. At this point, the RCS file may be owned by
+ somebody else, so a chmod will fail. We need to instead do the
+ chmod after rewriting it.
+
+ FIXME: In general, I think the file mode (and the keyword
+ expansion mode) should be associated with a particular revision
+ of the file, so that it is possible to have different revisions
+ of a file have different modes. */
retval = 0;
@@ -2211,7 +2223,8 @@ lock_RCS (user, rcs, rev, repository)
* the head points to the trunk, not a branch... and as such, it's not
* necessary to move the head in this case.
*/
- if (rev == NULL || (rev && isdigit (*rev) && numdots (rev) < 2))
+ if (rev == NULL
+ || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
{
branch = xstrdup (rcs->branch);
if (branch != NULL)
@@ -2268,69 +2281,6 @@ lock_RCS (user, rcs, rev, repository)
return (1);
}
-/* Called when "add"ing files to the RCS respository. It doesn't seem to
- be possible to get RCS to use the right mode, so we change it after
- the fact. TODO: now that RCS has been librarified, we have the power
- to change this. */
-
-static void
-fix_rcs_modes (rcs, user)
- char *rcs;
- char *user;
-{
- struct stat sb;
- mode_t rcs_mode;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Do ye nothing to the modes on a symbolic link. */
- if (preserve_perms && islink (user))
- return;
-#endif
-
- if (CVS_STAT (user, &sb) < 0)
- {
- /* FIXME: Should be ->fullname. */
- error (0, errno, "warning: cannot stat %s", user);
- return;
- }
-
- /* Now we compute the new mode.
-
- TODO: decide whether this whole thing can/should be skipped
- when `preserve_perms' is set. Almost certainly so. -twp
-
- The algorithm that we use is:
-
- Write permission is always off (this is what RCS and CVS have always
- done).
-
- If S_IRUSR is on (user read), then the read permission of
- the RCS file will be on. It would seem that if this is off,
- then other users can't do "cvs update" and such, so perhaps this
- should be hardcoded to being on (it is a strange case, though--the
- case in which a user file doesn't have user read permission on).
-
- If S_IXUSR is on (user execute), then set execute permission
- on the RCS file. This allows other users who check out the file
- to get the right setting for whether a shell script (for example)
- has the executable bit set.
-
- The result of that calculation is modified by CVSUMASK. The
- reason, of course, that the read and execute settings take the
- user bit and copy it to all three bits (user, group, other), is
- that it should be CVSUMASK, not the umask of individual users,
- which is the sole determiner of modes in the repository. */
-
- rcs_mode = 0;
- if (sb.st_mode & S_IRUSR)
- rcs_mode |= S_IRUSR | S_IRGRP | S_IROTH;
- if (sb.st_mode & S_IXUSR)
- rcs_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
- rcs_mode &= ~cvsumask;
- if (chmod (rcs, rcs_mode) < 0)
- error (0, errno, "warning: cannot change mode of %s", rcs);
-}
-
/*
* free an UPDATE node's data
*/
diff --git a/contrib/cvs/src/create_adm.c b/contrib/cvs/src/create_adm.c
index c51785c..7f8f581 100644
--- a/contrib/cvs/src/create_adm.c
+++ b/contrib/cvs/src/create_adm.c
@@ -36,15 +36,13 @@ Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn)
char *reposcopy;
char *tmp;
-#ifdef SERVER_SUPPORT
if (trace)
{
- fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s, %d, %d)\n",
- (server_active) ? 'S' : ' ',
+ fprintf (stderr, "%s-> Create_Admin (%s, %s, %s, %s, %s, %d, %d)\n",
+ CLIENT_SERVER_STR,
dir, update_dir, repository, tag ? tag : "",
date ? date : "", nonbranch, warn);
}
-#endif
if (noexec)
return 0;
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index f8b1552..8a1501c 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -367,11 +367,16 @@ extern mode_t cvsumask;
/* Access method specified in CVSroot. */
typedef enum {
local_method, server_method, pserver_method, kserver_method, gserver_method,
- ext_method
+ ext_method, fork_method
} CVSmethod;
extern char *method_names[]; /* change this in root.c if you change
the enum above */
+/* This global variable holds the global -d option. It is NULL if -d
+ was not used, which means that we must get the CVSroot information
+ from the CVSROOT environment variable or from a CVS/Root file. */
+extern char *CVSroot_cmdline;
+
extern char *CVSroot_original; /* the active, complete CVSroot string */
extern int client_active; /* nonzero if we are doing remote access */
extern CVSmethod CVSroot_method; /* one of the enum values above */
@@ -379,6 +384,11 @@ extern char *CVSroot_username; /* the username or NULL if method == local */
extern char *CVSroot_hostname; /* the hostname or NULL if method == local */
extern char *CVSroot_directory; /* the directory name */
+/* These variables keep track of all of the CVSROOT directories that
+ have been seen by the client and the current one of those selected. */
+extern List *root_directories;
+extern char *current_root;
+
extern char *emptydir_name PROTO ((void));
extern int trace; /* Show all commands */
@@ -387,11 +397,11 @@ extern int logoff; /* Don't write history entry */
extern int top_level_admin;
-#ifdef AUTH_SERVER_SUPPORT
-extern char *Pserver_Repos; /* used to check that same repos is
- transmitted in pserver auth and in
- CVS protocol. */
-#endif /* AUTH_SERVER_SUPPORT */
+#ifdef CLIENT_SUPPORT
+extern List *dirs_sent_to_server; /* used to decide which "Argument
+ xxx" commands to send to each
+ server in multiroot mode. */
+#endif
extern char hostname[];
@@ -432,6 +442,7 @@ void Subdir_Deregister PROTO((List *, const char *, const char *));
char *Make_Date PROTO((char *rawdate));
char *date_from_time_t PROTO ((time_t));
+void date_to_internet PROTO ((char *, char *));
char *Name_Repository PROTO((char *dir, char *update_dir));
char *Short_Repository PROTO((char *repository));
@@ -450,7 +461,7 @@ extern void check_numeric PROTO ((const char *, int, char **));
char *getcaller PROTO((void));
char *time_stamp PROTO((char *file));
-char *xmalloc PROTO((size_t bytes));
+void *xmalloc PROTO((size_t bytes));
void *xrealloc PROTO((void *ptr, size_t bytes));
void expand_string PROTO ((char **, size_t *, size_t));
char *xstrdup PROTO((const char *str));
@@ -502,6 +513,9 @@ void lock_tree_for_write PROTO ((int argc, char **argv, int local, int aflag));
/* See lock.c for description. */
extern void lock_dir_for_write PROTO ((char *));
+
+/* LockDir setting from CVSROOT/config. */
+extern char *lock_dir;
void Scratch_Entry PROTO((List * list, char *fname));
void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp));
@@ -628,6 +642,7 @@ char *make_message_rcslegal PROTO((char *message));
extern int file_has_markers PROTO ((const struct file_info *));
extern void get_file PROTO ((const char *, const char *, const char *,
char **, size_t *, size_t *));
+extern void resolve_symlink PROTO ((char **filename));
/* flags for run_exec(), the fast system() for CVS */
#define RUN_NORMAL 0x0000 /* no special behaviour */
@@ -648,7 +663,6 @@ int run_exec PROTO((const char *stin, const char *stout, const char *sterr,
FILE *run_popen PROTO((const char *, const char *));
int piped_child PROTO((char **, int *, int *));
void close_on_exec PROTO((int));
-int filter_stream_through_program PROTO((int, int, char **, pid_t *));
pid_t waitpid PROTO((pid_t, int *, int));
diff --git a/contrib/cvs/src/cvsrc.c b/contrib/cvs/src/cvsrc.c
index e35ec21..accc53f 100644
--- a/contrib/cvs/src/cvsrc.c
+++ b/contrib/cvs/src/cvsrc.c
@@ -65,6 +65,11 @@ read_cvsrc (argc, argv, cmdname)
/* determine filename for ~/.cvsrc */
homedir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvsrc. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvsrc (and many users won't even know what
+ .cvsrc is). */
if (!homedir)
return;
@@ -96,7 +101,7 @@ read_cvsrc (argc, argv, cmdname)
/* stop if we match the current command */
if (!strncmp (line, cmdname, command_len)
- && isspace (*(line + command_len)))
+ && isspace ((unsigned char) *(line + command_len)))
{
found = 1;
break;
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c
index 341c04c..e98938d 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -40,7 +40,13 @@ static enum diff_file diff_file_nodiff PROTO ((struct file_info *finfo,
static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static void diff_mark_errors PROTO((int err));
+
+/* Global variables. Would be cleaner if we just put this stuff in a
+ struct like log.c does. */
+
+/* Command line tags, from -r option. Points into argv. */
static char *diff_rev1, *diff_rev2;
+/* Command line dates, from -D option. Malloc'd. */
static char *diff_date1, *diff_date2;
static char *use_rev1, *use_rev2;
static int have_rev1_label, have_rev2_label;
@@ -224,15 +230,19 @@ diff (argc, argv)
* non-recursive/recursive diff.
*/
- /* For server, need to be able to do this command more than once
- (according to the protocol spec, even if the current client
- doesn't use it). */
+ /* Clean out our global variables (multiroot can call us multiple
+ times and the server can too, if the client sends several
+ diff commands). */
if (opts == NULL)
{
opts_allocated = 1;
opts = xmalloc (opts_allocated);
}
opts[0] = '\0';
+ diff_rev1 = NULL;
+ diff_rev2 = NULL;
+ diff_date1 = NULL;
+ diff_date2 = NULL;
optind = 0;
while ((c = getopt_long (argc, argv,
@@ -267,7 +277,7 @@ diff (argc, argv)
break;
case 131:
/* --ifdef. */
- strcat_and_allocate (&opts, &opts_allocated, " -D");
+ strcat_and_allocate (&opts, &opts_allocated, " --ifdef=");
strcat_and_allocate (&opts, &opts_allocated, optarg);
break;
case 129: case 130: case 132: case 133: case 134:
@@ -353,17 +363,18 @@ diff (argc, argv)
if (diff_date2)
client_senddate (diff_date2);
- send_file_names (argc, argv, SEND_EXPAND_WILD);
-
/* Send the current files unless diffing two revs from the archive */
if (diff_rev2 == NULL && diff_date2 == NULL)
send_files (argc, argv, local, 0, 0);
else
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+
send_to_server ("diff\012", 0);
err = get_responses_and_close ();
free (options);
+ options = NULL;
return (err);
}
#endif
@@ -386,6 +397,13 @@ diff (argc, argv)
/* clean up */
free (options);
+ options = NULL;
+
+ if (diff_date1 != NULL)
+ free (diff_date1);
+ if (diff_date2 != NULL)
+ free (diff_date2);
+
return (err);
}
diff --git a/contrib/cvs/src/edit.c b/contrib/cvs/src/edit.c
index aa0f4c4..59d363c 100644
--- a/contrib/cvs/src/edit.c
+++ b/contrib/cvs/src/edit.c
@@ -89,8 +89,8 @@ watch_onoff (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0);
return get_responses_and_close ();
}
@@ -722,6 +722,9 @@ notify_proc (repository, filter)
return (pclose (pipefp));
}
+/* FIXME: this function should have a way to report whether there was
+ an error so that server.c can know whether to report Notified back
+ to the client. */
void
notify_do (type, filename, who, val, watches, repository)
int type;
@@ -743,6 +746,11 @@ notify_do (type, filename, who, val, watches, repository)
switch (type)
{
case 'E':
+ if (strpbrk (val, ",>;=\n") != NULL)
+ {
+ error (0, 0, "invalid character in editor value");
+ return;
+ }
editor_set (filename, who, val);
break;
case 'U':
@@ -864,7 +872,14 @@ notify_do (type, filename, who, val, watches, repository)
{
char *cp;
args.notifyee = xstrdup (line + len + 1);
- cp = strchr (args.notifyee, ':');
+
+ /* There may or may not be more
+ colon-separated fields added to this in the
+ future; in any case, we ignore them right
+ now, and if there are none we make sure to
+ chop off the final newline, if any. */
+ cp = strpbrk (args.notifyee, ":\n");
+
if (cp != NULL)
*cp = '\0';
break;
@@ -876,7 +891,8 @@ notify_do (type, filename, who, val, watches, repository)
error (0, errno, "cannot close %s", usersname);
}
free (usersname);
- free (line);
+ if (line != NULL)
+ free (line);
if (args.notifyee == NULL)
{
@@ -1008,29 +1024,29 @@ editors_fileproc (callerdat, finfo)
if (them == NULL)
return 0;
- fputs (finfo->fullname, stdout);
+ cvs_output (finfo->fullname, 0);
p = them;
while (1)
{
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (*p != '>' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
/* Only happens if attribute is misformed. */
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (1)
{
while (*p != '+' && *p != ',' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
goto out;
}
if (*p == ',')
@@ -1039,9 +1055,9 @@ editors_fileproc (callerdat, finfo)
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
}
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
}
out:;
return 0;
@@ -1086,8 +1102,8 @@ editors (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("editors\012", 0);
return get_responses_and_close ();
}
diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c
index aeab313..7e258a9 100644
--- a/contrib/cvs/src/entries.c
+++ b/contrib/cvs/src/entries.c
@@ -157,7 +157,9 @@ write_entries (list)
rename_file (entfilename, CVSADM_ENT);
/* now, remove the log file */
- unlink_file (CVSADM_ENTLOG);
+ if (unlink_file (CVSADM_ENTLOG) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
}
/*
@@ -171,12 +173,8 @@ Scratch_Entry (list, fname)
Node *node;
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n",
- (server_active) ? 'S' : ' ', fname);
-#else
- (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
-#endif
+ (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n",
+ CLIENT_SERVER_STR, fname);
/* hashlookup to see if it is there */
if ((node = findnode_fn (list, fname)) != NULL)
@@ -231,18 +229,11 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict)
if (trace)
{
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
- (server_active) ? 'S' : ' ',
+ (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
+ CLIENT_SERVER_STR,
fname, vn, ts ? ts : "",
ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
options, tag ? tag : "", date ? date : "");
-#else
- (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
- fname, vn, ts ? ts : "",
- ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
- options, tag ? tag : "", date ? date : "");
-#endif
}
entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
@@ -252,7 +243,15 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict)
if (!noexec)
{
entfilename = CVSADM_ENTLOG;
- entfile = open_file (entfilename, "a");
+ entfile = CVS_FOPEN (entfilename, "a");
+
+ if (entfile == NULL)
+ {
+ /* Warning, not error, as in write_entries. */
+ /* FIXME-update-dir: should be including update_dir in message. */
+ error (0, errno, "cannot open %s", entfilename);
+ return;
+ }
if (fprintf (entfile, "A ") < 0)
error (1, errno, "cannot write %s", entfilename);
@@ -507,7 +506,9 @@ Entries_Open (aflag, update_dir)
(void) AddEntryNode (entries, ent);
}
- fclose (fpin);
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENT);
}
fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
@@ -535,7 +536,9 @@ Entries_Open (aflag, update_dir)
}
}
do_rewrite = 1;
- fclose (fpin);
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENTLOG);
}
/* Update the list private data to indicate whether subdirectory
diff --git a/contrib/cvs/src/error.c b/contrib/cvs/src/error.c
index 9dcc162..64b686c 100644
--- a/contrib/cvs/src/error.c
+++ b/contrib/cvs/src/error.c
@@ -61,8 +61,6 @@ void exit ();
extern char *strerror ();
#endif
-extern int vasprintf ();
-
void
error_exit PROTO ((void))
{
@@ -80,7 +78,10 @@ error_exit PROTO ((void))
}
/* Print the program name and error message MESSAGE, which is a printf-style
- format string with optional args.
+ format string with optional args. This is a very limited printf subset:
+ %s, %d, %c, %x and %% only (without anything between the % and the s,
+ d, &c). Callers who want something fancier can use sprintf.
+
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status EXIT_FAILURE if STATUS is nonzero. If MESSAGE is "",
no need to print a message.
@@ -100,7 +101,7 @@ error_exit PROTO ((void))
/* VARARGS */
void
-#if defined (HAVE_VPRINTF) && defined (__STDC__)
+#if defined (__STDC__)
error (int status, int errnum, const char *message, ...)
#else
error (status, errnum, message, va_alist)
@@ -110,116 +111,84 @@ error (status, errnum, message, va_alist)
va_dcl
#endif
{
- /* Prevent strtoul (via int_vasprintf) from clobbering it. */
int save_errno = errno;
-#ifdef HAVE_VPRINTF
if (message[0] != '\0')
{
va_list args;
- char *mess = NULL;
- char *entire;
- size_t len;
-
- VA_START (args, message);
- vasprintf (&mess, message, args);
- va_end (args);
-
- if (mess == NULL)
+ const char *p;
+ char *q;
+ char *str;
+ int num;
+ unsigned int unum;
+ int ch;
+ unsigned char buf[100];
+
+ cvs_outerr (program_name, 0);
+ if (command_name && *command_name)
{
- entire = NULL;
- status = 1;
+ cvs_outerr (" ", 1);
+ if (status != 0)
+ cvs_outerr ("[", 1);
+ cvs_outerr (command_name, 0);
+ if (status != 0)
+ cvs_outerr (" aborted]", 0);
}
- else
+ cvs_outerr (": ", 2);
+
+ VA_START (args, message);
+ p = message;
+ while ((q = strchr (p, '%')) != NULL)
{
- len = strlen (mess) + strlen (program_name) + 80;
- if (command_name != NULL)
- len += strlen (command_name);
- if (errnum != 0)
- len += strlen (strerror (errnum));
- entire = malloc (len);
- if (entire == NULL)
- {
- free (mess);
- status = 1;
- }
- else
+ static const char msg[] =
+ "\ninternal error: bad % in error()\n";
+ if (q - p > 0)
+ cvs_outerr (p, q - p);
+
+ switch (q[1])
{
- strcpy (entire, program_name);
- if (command_name != NULL && command_name[0] != '\0')
- {
- strcat (entire, " ");
- if (status != 0)
- strcat (entire, "[");
- strcat (entire, command_name);
- if (status != 0)
- strcat (entire, " aborted]");
- }
- strcat (entire, ": ");
- strcat (entire, mess);
- if (errnum != 0)
- {
- strcat (entire, ": ");
- strcat (entire, strerror (errnum));
- }
- strcat (entire, "\n");
- free (mess);
+ case 's':
+ str = va_arg (args, char *);
+ cvs_outerr (str, strlen (str));
+ break;
+ case 'd':
+ num = va_arg (args, int);
+ sprintf (buf, "%d", num);
+ cvs_outerr (buf, strlen (buf));
+ break;
+ case 'x':
+ unum = va_arg (args, unsigned int);
+ sprintf (buf, "%x", unum);
+ cvs_outerr (buf, strlen (buf));
+ break;
+ case 'c':
+ ch = va_arg (args, int);
+ buf[0] = ch;
+ cvs_outerr (buf, 1);
+ break;
+ case '%':
+ cvs_outerr ("%", 1);
+ break;
+ default:
+ cvs_outerr (msg, sizeof (msg) - 1);
+ /* Don't just keep going, because q + 1 might point to the
+ terminating '\0'. */
+ goto out;
}
+ p = q + 2;
}
- cvs_outerr (entire ? entire : "out of memory\n", 0);
- if (entire != NULL)
- free (entire);
- }
-
-#else /* No HAVE_VPRINTF */
- /* I think that all relevant systems have vprintf these days. But
- just in case, I'm leaving this code here. */
-
- if (message[0] != '\0')
- {
- FILE *out = stderr;
+ cvs_outerr (p, strlen (p));
+ out:
+ va_end (args);
- if (error_use_protocol)
+ if (errnum != 0)
{
- out = stdout;
- printf ("E ");
+ cvs_outerr (": ", 2);
+ cvs_outerr (strerror (errnum), 0);
}
-
- if (command_name && *command_name)
- {
- if (status)
- fprintf (out, "%s [%s aborted]: ", program_name, command_name);
- else
- fprintf (out, "%s %s: ", program_name, command_name);
- }
- else
- fprintf (out, "%s: ", program_name);
-
-#ifdef HAVE_VPRINTF
- VA_START (args, message);
- vfprintf (out, message, args);
- va_end (args);
-#else
-#ifdef HAVE_DOPRNT
- _doprnt (message, &args, out);
-#else
- fprintf (out, message, a1, a2, a3, a4, a5, a6, a7, a8);
-#endif
-#endif
- if (errnum)
- fprintf (out, ": %s", strerror (errnum));
- putc ('\n', out);
-
- /* In the error_use_protocol case, this probably does
- something useful. In most other cases, I suspect it is a
- noop (either stderr is line buffered or we haven't written
- anything to stderr) or unnecessary (if stderr is not line
- buffered, maybe there is a reason....). */
- fflush (out);
+ cvs_outerr ("\n", 1);
}
-#endif /* No HAVE_VPRINTF */
-
if (status)
error_exit ();
errno = save_errno;
diff --git a/contrib/cvs/src/expand_path.c b/contrib/cvs/src/expand_path.c
index 5cf414e..25e561c 100644
--- a/contrib/cvs/src/expand_path.c
+++ b/contrib/cvs/src/expand_path.c
@@ -43,7 +43,7 @@ variable_set (nameval)
Node *node;
p = nameval;
- while (isalnum (*p) || *p == '_')
+ while (isalnum ((unsigned char) *p) || *p == '_')
++p;
if (*p != '=')
error (1, 0, "illegal character in user variable name in %s", nameval);
@@ -133,7 +133,7 @@ expand_path (name, file, line)
{
if (flag
? *s =='}'
- : isalnum (*s) == 0 && *s != '_')
+ : isalnum ((unsigned char) *s) == 0 && *s != '_')
break;
doff = d - mybuf;
expand_string (&mybuf, &mybuf_size, doff + 1);
@@ -214,6 +214,9 @@ expand_path (name, file, line)
t = ps->pw_dir;
#endif
}
+ if (t == NULL)
+ error (1, 0, "cannot find home directory");
+
doff = d - buf;
expand_string (&buf, &buf_size, doff + 1);
d = buf + doff;
@@ -283,7 +286,7 @@ expand_variable (name, file, line)
return Editor;
else if (strcmp (name, "USER") == 0)
return getcaller ();
- else if (isalpha (name[0]))
+ else if (isalpha ((unsigned char) name[0]))
{
/* These names are reserved for future versions of CVS,
so that is why it is an error. */
diff --git a/contrib/cvs/src/fileattr.h b/contrib/cvs/src/fileattr.h
index 7e02b3a..046b975 100644
--- a/contrib/cvs/src/fileattr.h
+++ b/contrib/cvs/src/fileattr.h
@@ -12,28 +12,24 @@
#ifndef FILEATTR_H
-/* File containing per-file attributes. Format is a series of entries:
+/* File containing per-file attributes. The format of this file is in
+ cvs.texinfo but here is a quick summary. The file contains a
+ series of entries:
ENT-TYPE FILENAME <tab> ATTRNAME = ATTRVAL
{; ATTRNAME = ATTRVAL} <linefeed>
- ENT-TYPE is 'F' for a file, in which case the entry specifies the
- attributes for that file.
+ ENT-TYPE is 'F' for a file.
- ENT-TYPE is 'D', and FILENAME empty, to specify default attributes
- to be used for newly added files.
+ ENT-TYPE is 'D', and FILENAME empty, for default attributes.
- Other ENT-TYPE are reserved for future expansion. CVS 1.9 and older
- will delete them any time it writes file attributes. Current versions
- of CVS will preserve them.
+ Other ENT-TYPE are reserved for future expansion.
Note that the order of the line is not significant; CVS is free to
rearrange them at its convenience.
- There is currently no way of quoting tabs or linefeeds in the
- filename, '=' in ATTRNAME, ';' in ATTRVAL, etc. I'm not sure
- whether I think we need one. Note: the current implementation also
- doesn't handle '\0' in any of the fields.
+ FIXME: this implementation doesn't handle '\0' in any of the
+ fields. We are encouraged to fix this (by cvs.texinfo).
By convention, ATTRNAME starting with '_' is for an attribute given
special meaning by CVS; other ATTRNAMEs are for user-defined attributes
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c
index 1c24b2f..f3da62a 100644
--- a/contrib/cvs/src/filesubr.c
+++ b/contrib/cvs/src/filesubr.c
@@ -34,12 +34,8 @@ copy_file (from, to)
int fdin, fdout;
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
- (server_active) ? 'S' : ' ', from, to);
-#else
- (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
-#endif
+ (void) fprintf (stderr, "%s-> copy(%s,%s)\n",
+ CLIENT_SERVER_STR, from, to);
if (noexec)
return;
@@ -377,14 +373,9 @@ xchmod (fname, writable)
}
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
- (server_active) ? 'S' : ' ', fname,
+ (void) fprintf (stderr, "%s-> chmod(%s,%o)\n",
+ CLIENT_SERVER_STR, fname,
(unsigned int) mode);
-#else
- (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
- (unsigned int) mode);
-#endif
if (noexec)
return;
@@ -401,12 +392,8 @@ rename_file (from, to)
const char *to;
{
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
- (server_active) ? 'S' : ' ', from, to);
-#else
- (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
-#endif
+ (void) fprintf (stderr, "%s-> rename(%s,%s)\n",
+ CLIENT_SERVER_STR, from, to);
if (noexec)
return;
@@ -422,12 +409,8 @@ unlink_file (f)
const char *f;
{
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> unlink(%s)\n",
- (server_active) ? 'S' : ' ', f);
-#else
- (void) fprintf (stderr, "-> unlink(%s)\n", f);
-#endif
+ (void) fprintf (stderr, "%s-> unlink(%s)\n",
+ CLIENT_SERVER_STR, f);
if (noexec)
return (0);
@@ -506,6 +489,7 @@ deep_remove_dir (path)
*/
return -1;
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
char *buf;
@@ -539,6 +523,15 @@ deep_remove_dir (path)
}
}
free (buf);
+
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ int save_errno = errno;
+ closedir (dirp);
+ errno = save_errno;
+ return -1;
}
closedir (dirp);
return rmdir (path);
diff --git a/contrib/cvs/src/find_names.c b/contrib/cvs/src/find_names.c
index 4fa795a..6fb927b 100644
--- a/contrib/cvs/src/find_names.c
+++ b/contrib/cvs/src/find_names.c
@@ -50,6 +50,11 @@ add_entries_proc (node, closure)
return (0);
}
+/* Find files in the repository and/or working directory. On error,
+ may either print a nonfatal error and return NULL, or just give
+ a fatal error. On success, return non-NULL (even if it is an empty
+ list). */
+
List *
Find_Names (repository, which, aflag, optentries)
char *repository;
@@ -85,7 +90,10 @@ Find_Names (repository, which, aflag, optentries)
{
/* search the repository */
if (find_rcs (repository, files) != 0)
- error (1, errno, "cannot open directory %s", repository);
+ {
+ error (0, errno, "cannot open directory %s", repository);
+ goto error_exit;
+ }
/* search the attic too */
if (which & W_ATTIC)
@@ -93,7 +101,11 @@ Find_Names (repository, which, aflag, optentries)
char *dir;
dir = xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10);
(void) sprintf (dir, "%s/%s", repository, CVSATTIC);
- (void) find_rcs (dir, files);
+ if (find_rcs (dir, files) != 0
+ && !existence_error (errno))
+ /* For now keep this a fatal error, seems less useful
+ for access control than the case above. */
+ error (1, errno, "cannot open directory %s", dir);
free (dir);
}
}
@@ -101,6 +113,9 @@ Find_Names (repository, which, aflag, optentries)
/* sort the list into alphabetical order and return it */
sortlist (files, fsortcmp);
return (files);
+ error_exit:
+ dellist (&files);
+ return NULL;
}
/*
@@ -235,7 +250,9 @@ Find_Directories (repository, which, entries)
/*
* Finds all the ,v files in the argument directory, and adds them to the
* files list. Returns 0 for success and non-zero if the argument directory
- * cannot be opened.
+ * cannot be opened, in which case errno is set to indicate the error.
+ * In the error case LIST is left in some reasonable state (unchanged, or
+ * containing the files which were found before the error occurred).
*/
static int
find_rcs (dir, list)
@@ -251,6 +268,7 @@ find_rcs (dir, list)
return (1);
/* read the dir, grabbing the ,v files */
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
@@ -265,6 +283,14 @@ find_rcs (dir, list)
if (addnode (list, p) != 0)
freenode (p);
}
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ int save_errno = errno;
+ (void) closedir (dirp);
+ errno = save_errno;
+ return 1;
}
(void) closedir (dirp);
return (0);
@@ -275,7 +301,7 @@ find_rcs (dir, list)
* the specified list. Sub-directories without a CVS administration
* directory are optionally ignored. If ENTRIES is not NULL, all
* files on the list are ignored. Returns 0 for success or 1 on
- * error.
+ * error, in which case errno is set to indicate the error.
*/
static int
find_dirs (dir, list, checkadm, entries)
@@ -305,6 +331,7 @@ find_dirs (dir, list, checkadm, entries)
return (1);
/* read the dir, grabbing sub-dirs */
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
@@ -312,34 +339,34 @@ find_dirs (dir, list, checkadm, entries)
strcmp (dp->d_name, CVSATTIC) == 0 ||
strcmp (dp->d_name, CVSLCK) == 0 ||
strcmp (dp->d_name, CVSREP) == 0)
- continue;
+ goto do_it_again;
/* findnode() is going to be significantly faster than stat()
because it involves no system calls. That is why we bother
with the entries argument, and why we check this first. */
if (entries != NULL && findnode (entries, dp->d_name) != NULL)
- continue;
+ goto do_it_again;
if (skip_emptydir
&& strcmp (dp->d_name, CVSNULLREPOS) == 0)
- continue;
+ goto do_it_again;
#ifdef DT_DIR
if (dp->d_type != DT_DIR)
{
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
- continue;
+ goto do_it_again;
#endif
/* don't bother stating ,v files */
if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
- continue;
+ goto do_it_again;
expand_string (&tmp,
&tmp_size,
strlen (dir) + strlen (dp->d_name) + 10);
sprintf (tmp, "%s/%s", dir, dp->d_name);
if (!isdir (tmp))
- continue;
+ goto do_it_again;
#ifdef DT_DIR
}
@@ -354,12 +381,12 @@ find_dirs (dir, list, checkadm, entries)
{
/* we're either unknown or a symlink at this point */
if (dp->d_type == DT_LNK)
- continue;
+ goto do_it_again;
#endif
/* Note that we only get here if we already set tmp
above. */
if (islink (tmp))
- continue;
+ goto do_it_again;
#ifdef DT_DIR
}
#endif
@@ -371,7 +398,7 @@ find_dirs (dir, list, checkadm, entries)
+ sizeof (CVSADM) + 10));
(void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
if (!isdir (tmp))
- continue;
+ goto do_it_again;
}
/* put it in the list */
@@ -380,6 +407,16 @@ find_dirs (dir, list, checkadm, entries)
p->key = xstrdup (dp->d_name);
if (addnode (list, p) != 0)
freenode (p);
+
+ do_it_again:
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ int save_errno = errno;
+ (void) closedir (dirp);
+ errno = save_errno;
+ return 1;
}
(void) closedir (dirp);
if (tmp != NULL)
diff --git a/contrib/cvs/src/hardlink.c b/contrib/cvs/src/hardlink.c
index b279aa9..046cf3a 100644
--- a/contrib/cvs/src/hardlink.c
+++ b/contrib/cvs/src/hardlink.c
@@ -66,7 +66,7 @@ lookup_file_by_inode (filepath)
inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1);
if (stat (file, &sb) < 0)
{
- if (errno == ENOENT)
+ if (existence_error (errno))
{
/* The file doesn't exist; we may be doing an update on a
file that's been removed. A nonexistent file has no
diff --git a/contrib/cvs/src/history.c b/contrib/cvs/src/history.c
index 8f1e254..bc7d1a6 100644
--- a/contrib/cvs/src/history.c
+++ b/contrib/cvs/src/history.c
@@ -719,12 +719,8 @@ history_write (type, update_dir, revs, name, repository)
}
if (trace)
-#ifdef SERVER_SUPPORT
- fprintf (stderr, "%c-> fopen(%s,a)\n",
- (server_active) ? 'S' : ' ', fname);
-#else
- fprintf (stderr, "-> fopen(%s,a)\n", fname);
-#endif
+ fprintf (stderr, "%s-> fopen(%s,a)\n",
+ CLIENT_SERVER_STR, fname);
if (noexec)
goto out;
fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
@@ -971,7 +967,7 @@ expand_modules ()
* Return a pointer to the character following the newline.
*/
-#define NEXT_BAR(here) do { while (isspace(*line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0)
+#define NEXT_BAR(here) do { while (isspace((unsigned char) *line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0)
static char *
fill_hrec (line, hr)
@@ -985,7 +981,7 @@ fill_hrec (line, hr)
unsigned long date;
memset ((char *) hr, 0, sizeof (*hr));
- while (isspace (*line))
+ while (isspace ((unsigned char) *line))
line++;
if (!(rtn = strchr (line, '\n')))
return ("");
@@ -1062,7 +1058,7 @@ read_hrecs (fname)
*(cp + i) = '\0';
for (cp2 = cp; cp2 - cp < i; cp2++)
{
- if (*cp2 != '\n' && !isprint (*cp2))
+ if (*cp2 != '\n' && !isprint ((unsigned char) *cp2))
*cp2 = ' ';
}
diff --git a/contrib/cvs/src/ignore.c b/contrib/cvs/src/ignore.c
index 5d7ca61..df08017 100644
--- a/contrib/cvs/src/ignore.c
+++ b/contrib/cvs/src/ignore.c
@@ -82,6 +82,11 @@ ign_setup ()
/* Then add entries found in home dir, (if user has one) and file exists */
home_dir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvsignore. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvsignore (and many users won't even know what
+ .cvsignore is). */
if (home_dir)
{
char *file = xmalloc (strlen (home_dir) + sizeof (CVSDOTIGNORE) + 10);
@@ -176,7 +181,7 @@ ign_add (ign, hold)
char save;
/* ignore whitespace before the token */
- if (isspace (*ign))
+ if (isspace ((unsigned char) *ign))
continue;
/*
@@ -184,7 +189,8 @@ ign_add (ign, hold)
* (saving it if necessary). We also catch * as a special case in a
* global ignore file as an optimization
*/
- if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
+ if ((!*(ign+1) || isspace ((unsigned char) *(ign+1)))
+ && (*ign == '!' || *ign == '*'))
{
if (!hold)
{
@@ -233,7 +239,7 @@ ign_add (ign, hold)
}
/* find the end of this token */
- for (mark = ign; *mark && !isspace (*mark); mark++)
+ for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++)
/* do nothing */ ;
save = *mark;
@@ -395,11 +401,15 @@ ignore_files (ilist, entries, update_dir, proc)
dirp = CVS_OPENDIR (".");
if (dirp == NULL)
+ {
+ error (0, errno, "cannot open current directory");
return;
+ }
ign_add_file (CVSDOTIGNORE, 1);
wrap_add_file (CVSDOTWRAPPER, 1);
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
file = dp->d_name;
@@ -476,6 +486,9 @@ ignore_files (ilist, entries, update_dir, proc)
}
(*proc) (file, xdir);
+ errno = 0;
}
+ if (errno != 0)
+ error (0, errno, "error reading current directory");
(void) closedir (dirp);
}
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 77c617a..57ff619 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -94,6 +94,17 @@ import (argc, argv)
command_name);
break;
case 'd':
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ {
+ /* CVS 1.10 and older clients will send this, but it
+ doesn't do any good. So tell the user we can't
+ cope, rather than silently losing. */
+ error (0, 0,
+ "warning: not setting the time of import from the file");
+ error (0, 0, "due to client limitations");
+ }
+#endif
use_file_modtime = 1;
break;
case 'b':
@@ -132,6 +143,20 @@ import (argc, argv)
if (argc < 3)
usage (import_usage);
+#ifdef SERVER_SUPPORT
+ /* This is for handling the Checkin-time request. It might seem a
+ bit odd to enable the use_file_modtime code even in the case
+ where Checkin-time was not sent for a particular file. The
+ effect is that we use the time of upload, rather than the time
+ when we call RCS_checkin. Since those times are both during
+ CVS's run, that seems OK, and it is easier to implement than
+ putting the "was Checkin-time sent" flag in CVS/Entries or some
+ such place. */
+
+ if (server_active)
+ use_file_modtime = 1;
+#endif
+
for (i = 1; i < argc; i++) /* check the tags for validity */
{
int j;
@@ -143,7 +168,8 @@ import (argc, argv)
}
/* XXX - this should be a module, not just a pathname */
- if (! isabsolute (argv[0]))
+ if (! isabsolute (argv[0])
+ && pathname_levels (argv[0]) == 0)
{
if (CVSroot_directory == NULL)
{
@@ -158,9 +184,11 @@ import (argc, argv)
}
else
{
- repository = xmalloc (strlen (argv[0]) + 5);
- (void) strcpy (repository, argv[0]);
- repos_len = 0;
+ /* It is somewhere between a security hole and "unexpected" to
+ let the client start mucking around outside the cvsroot
+ (wouldn't get the right CVSROOT configuration, &c). */
+ error (1, 0, "directory %s not relative within the repository",
+ argv[0]);
}
/*
@@ -170,7 +198,7 @@ import (argc, argv)
* must only have two dots in it (like "1.1.1").
*/
for (cp = vbranch; *cp != '\0'; cp++)
- if (!isdigit (*cp) && *cp != '.')
+ if (!isdigit ((unsigned char) *cp) && *cp != '.')
error (1, 0, "%s is not a numeric branch", vbranch);
if (numdots (vbranch) != 2)
error (1, 0, "Only branches with two dots are supported: %s", vbranch);
@@ -212,9 +240,6 @@ import (argc, argv)
{
int err;
- if (use_file_modtime)
- send_arg("-d");
-
if (vbranch[0] != '\0')
option_with_arg ("-b", vbranch);
if (message)
@@ -275,29 +300,52 @@ import (argc, argv)
{
if (!really_quiet)
{
- char buf[80];
- sprintf (buf, "\n%d conflicts created by this import.\n",
- conflicts);
- cvs_output (buf, 0);
- cvs_output ("Use the following command to help the merge:\n\n",
- 0);
- cvs_output ("\t", 1);
- cvs_output (program_name, 0);
- cvs_output (" checkout -j", 0);
- cvs_output (argv[1], 0);
- cvs_output (":yesterday -j", 0);
- cvs_output (argv[1], 0);
- cvs_output (" ", 1);
- cvs_output (argv[0], 0);
- cvs_output ("\n\n", 0);
+ char buf[20];
+ char *buf2;
+
+ cvs_output_tagged ("+importmergecmd", NULL);
+ cvs_output_tagged ("newline", NULL);
+ sprintf (buf, "%d", conflicts);
+ cvs_output_tagged ("conflicts", buf);
+ cvs_output_tagged ("text", " conflicts created by this import.");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text",
+ "Use the following command to help the merge:");
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("text", "\t");
+ cvs_output_tagged ("text", program_name);
+ if (CVSroot_cmdline != NULL)
+ {
+ cvs_output_tagged ("text", " -d ");
+ cvs_output_tagged ("text", CVSroot_cmdline);
+ }
+ cvs_output_tagged ("text", " checkout -j");
+ buf2 = xmalloc (strlen (argv[1]) + 20);
+ sprintf (buf2, "%s:yesterday", argv[1]);
+ cvs_output_tagged ("mergetag1", buf2);
+ free (buf2);
+ cvs_output_tagged ("text", " -j");
+ cvs_output_tagged ("mergetag2", argv[1]);
+ cvs_output_tagged ("text", " ");
+ cvs_output_tagged ("repository", argv[0]);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("newline", NULL);
+ cvs_output_tagged ("-importmergecmd", NULL);
}
+ /* FIXME: I'm not sure whether we need to put this information
+ into the loginfo. If we do, then note that it does not
+ report any required -d option. There is no particularly
+ clean way to tell the server about the -d option used by
+ the client. */
(void) fprintf (logfp, "\n%d conflicts created by this import.\n",
conflicts);
(void) fprintf (logfp,
"Use the following command to help the merge:\n\n");
- (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
- program_name, argv[1], argv[1], argv[0]);
+ (void) fprintf (logfp, "\t%s checkout ", program_name);
+ (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n",
+ argv[1], argv[1], argv[0]);
}
else
{
@@ -340,9 +388,9 @@ import (argc, argv)
return (err);
}
-/*
- * process all the files in ".", then descend into other directories.
- */
+/* Process all the files in ".", then descend into other directories.
+ Returns 0 for success, or >0 on error (in which case a message
+ will have been printed). */
static int
import_descend (message, vtag, targc, targv)
char *message;
@@ -361,25 +409,27 @@ import_descend (message, vtag, targc, targv)
if ((dirp = CVS_OPENDIR (".")) == NULL)
{
+ error (0, errno, "cannot open directory");
err++;
}
else
{
+ errno = 0;
while ((dp = readdir (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
- continue;
+ goto one_more_time_boys;
#ifdef SERVER_SUPPORT
/* CVS directories are created in the temp directory by
server.c because it doesn't special-case import. So
don't print a message about them, regardless of -I!. */
if (server_active && strcmp (dp->d_name, CVSADM) == 0)
- continue;
+ goto one_more_time_boys;
#endif
if (ign_name (dp->d_name))
{
add_log ('I', dp->d_name);
- continue;
+ goto one_more_time_boys;
}
if (
@@ -418,12 +468,20 @@ import_descend (message, vtag, targc, targv)
vtag, targc, targv,
repository,
keyword_opt != NULL &&
- keyword_opt[0] == 'b');
+ keyword_opt[0] == 'b',
+ use_file_modtime);
else
#endif
err += process_import_file (message, dp->d_name,
vtag, targc, targv);
}
+ one_more_time_boys:
+ errno = 0;
+ }
+ if (errno != 0)
+ {
+ error (0, errno, "cannot read directory");
+ ++err;
}
(void) closedir (dirp);
}
@@ -874,7 +932,7 @@ get_comment (user)
*/
(void) strcpy (suffix_path, cp);
for (cp = suffix_path; *cp; cp++)
- if (isupper (*cp))
+ if (isupper ((unsigned char) *cp))
*cp = tolower (*cp);
suffix = suffix_path;
}
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 72818f3..3776b2c 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -73,6 +73,7 @@
unneeded complication although it presumably would be faster). */
#include "cvs.h"
+#include <assert.h>
struct lock {
/* This is the directory in which we may have a lock named by the
@@ -134,12 +135,161 @@ static List *lock_tree_list;
static char *locked_dir;
static List *locked_list;
+/* LockDir from CVSROOT/config. */
+char *lock_dir;
+
+static char *lock_name PROTO ((char *repository, char *name));
+
+/* Return a newly malloc'd string containing the name of the lock for the
+ repository REPOSITORY and the lock file name within that directory
+ NAME. Also create the directories in which to put the lock file
+ if needed (if we need to, could save system call(s) by doing
+ that only if the actual operation fails. But for now we'll keep
+ things simple). */
+static char *
+lock_name (repository, name)
+ char *repository;
+ char *name;
+{
+ char *retval;
+ char *p;
+ char *q;
+ char *short_repos;
+ mode_t save_umask;
+ int saved_umask = 0;
+
+ if (lock_dir == NULL)
+ {
+ /* This is the easy case. Because the lock files go directly
+ in the repository, no need to create directories or anything. */
+ retval = xmalloc (strlen (repository) + strlen (name) + 10);
+ (void) sprintf (retval, "%s/%s", repository, name);
+ }
+ else
+ {
+ struct stat sb;
+ mode_t new_mode = 0;
+
+ /* The interesting part of the repository is the part relative
+ to CVSROOT. */
+ assert (CVSroot_directory != NULL);
+ assert (strncmp (repository, CVSroot_directory,
+ strlen (CVSroot_directory)) == 0);
+ short_repos = repository + strlen (CVSroot_directory);
+ assert (*short_repos++ == '/');
+
+ retval = xmalloc (strlen (lock_dir)
+ + strlen (short_repos)
+ + strlen (name)
+ + 10);
+ strcpy (retval, lock_dir);
+ q = retval + strlen (retval);
+ *q++ = '/';
+
+ strcpy (q, short_repos);
+
+ /* In the common case, where the directory already exists, let's
+ keep it to one system call. */
+ if (CVS_STAT (retval, &sb) < 0)
+ {
+ /* If we need to be creating more than one directory, we'll
+ get the existence_error here. */
+ if (!existence_error (errno))
+ error (1, errno, "cannot stat directory %s", retval);
+ }
+ else
+ {
+ if (S_ISDIR (sb.st_mode))
+ goto created;
+ else
+ error (1, 0, "%s is not a directory", retval);
+ }
+
+ /* Now add the directories one at a time, so we can create
+ them if needed.
+
+ The idea behind the new_mode stuff is that the directory we
+ end up creating will inherit permissions from its parent
+ directory (we re-set new_mode with each EEXIST). CVSUMASK
+ isn't right, because typically the reason for LockDir is to
+ use a different set of permissions. We probably want to
+ inherit group ownership also (but we don't try to deal with
+ that, some systems do it for us either always or when g+s is on).
+
+ We don't try to do anything about the permissions on the lock
+ files themselves. The permissions don't really matter so much
+ because the locks will generally be removed by the process
+ which created them. */
+
+ if (CVS_STAT (lock_dir, &sb) < 0)
+ error (1, errno, "cannot stat %s", lock_dir);
+ new_mode = sb.st_mode;
+ save_umask = umask (0000);
+ saved_umask = 1;
+
+ p = short_repos;
+ while (1)
+ {
+ while (!ISDIRSEP (*p) && *p != '\0')
+ ++p;
+ if (ISDIRSEP (*p))
+ {
+ strncpy (q, short_repos, p - short_repos);
+ q[p - short_repos] = '\0';
+ if (!ISDIRSEP (q[p - short_repos - 1])
+ && CVS_MKDIR (retval, new_mode) < 0)
+ {
+ int saved_errno = errno;
+ if (saved_errno != EEXIST)
+ error (1, errno, "cannot make directory %s", retval);
+ else
+ {
+ if (CVS_STAT (retval, &sb) < 0)
+ error (1, errno, "cannot stat %s", retval);
+ new_mode = sb.st_mode;
+ }
+ }
+ ++p;
+ }
+ else
+ {
+ strcpy (q, short_repos);
+ if (CVS_MKDIR (retval, new_mode) < 0
+ && errno != EEXIST)
+ error (1, errno, "cannot make directory %s", retval);
+ goto created;
+ }
+ }
+ created:;
+
+ strcat (retval, "/");
+ strcat (retval, name);
+
+ if (saved_umask)
+ {
+ assert (umask (save_umask) == 0000);
+ saved_umask = 0;
+ }
+ }
+ return retval;
+}
+
/*
* Clean up all outstanding locks
*/
void
Lock_Cleanup ()
{
+ /* FIXME: error handling here is kind of bogus; we sometimes will call
+ error, which in turn can call us again. For the moment work around
+ this by refusing to reenter this function (this is a kludge). */
+ /* FIXME-reentrancy: the workaround isn't reentrant. */
+ static int in_lock_cleanup = 0;
+
+ if (in_lock_cleanup)
+ return;
+ in_lock_cleanup = 1;
+
remove_locks ();
dellist (&lock_tree_list);
@@ -151,6 +301,7 @@ Lock_Cleanup ()
locked_dir = NULL;
locked_list = NULL;
}
+ in_lock_cleanup = 0;
}
/*
@@ -199,8 +350,7 @@ lock_simple_remove (lock)
existence_error here. */
if (readlock != NULL)
{
- tmp = xmalloc (strlen (lock->repository) + strlen (readlock) + 10);
- (void) sprintf (tmp, "%s/%s", lock->repository, readlock);
+ tmp = lock_name (lock->repository, readlock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
free (tmp);
@@ -212,8 +362,7 @@ lock_simple_remove (lock)
existence_error here. */
if (writelock != NULL)
{
- tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10);
- (void) sprintf (tmp, "%s/%s", lock->repository, writelock);
+ tmp = lock_name (lock->repository, writelock);
if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
error (0, errno, "failed to remove lock %s", tmp);
free (tmp);
@@ -221,8 +370,7 @@ lock_simple_remove (lock)
if (lock->have_lckdir)
{
- tmp = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10);
- (void) sprintf (tmp, "%s/%s", lock->repository, CVSLCK);
+ tmp = lock_name (lock->repository, CVSLCK);
SIG_beginCrSect ();
if (CVS_RMDIR (tmp) < 0)
error (0, errno, "failed to remove lock dir %s", tmp);
@@ -283,8 +431,7 @@ Reader_Lock (xrepository)
}
/* write a read-lock */
- tmp = xmalloc (strlen (xrepository) + strlen (readlock) + 10);
- (void) sprintf (tmp, "%s/%s", xrepository, readlock);
+ tmp = lock_name (xrepository, readlock);
if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
error (0, errno, "cannot create read lock in repository `%s'",
@@ -432,8 +579,7 @@ write_lock (lock)
}
/* write the write-lock file */
- tmp = xmalloc (strlen (lock->repository) + strlen (writelock) + 10);
- (void) sprintf (tmp, "%s/%s", lock->repository, writelock);
+ tmp = lock_name (lock->repository, writelock);
if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
{
int xerrno = errno;
@@ -577,8 +723,7 @@ set_lock (lock, will_wait)
if (masterlock != NULL)
free (masterlock);
- masterlock = xmalloc (strlen (lock->repository) + sizeof (CVSLCK) + 10);
- (void) sprintf (masterlock, "%s/%s", lock->repository, CVSLCK);
+ masterlock = lock_name (lock->repository, CVSLCK);
/*
* Note that it is up to the callers of set_lock() to arrange for signal
@@ -675,13 +820,17 @@ lock_wait (repos)
char *repos;
{
time_t now;
+ char *msg;
(void) time (&now);
- error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
- lockers_name, repos);
+ msg = xmalloc (100 + strlen (lockers_name) + strlen (repos));
+ sprintf (msg, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11,
+ lockers_name, repos);
+ error (0, 0, "%s", msg);
/* Call cvs_flusherr to ensure that the user sees this message as
soon as possible. */
cvs_flusherr ();
+ free (msg);
(void) sleep (CVSLCKSLEEP);
}
@@ -693,12 +842,16 @@ lock_obtained (repos)
char *repos;
{
time_t now;
+ char *msg;
(void) time (&now);
- error (0, 0, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos);
+ msg = xmalloc (100 + strlen (repos));
+ sprintf (msg, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos);
+ error (0, 0, "%s", msg);
/* Call cvs_flusherr to ensure that the user sees this message as
soon as possible. */
cvs_flusherr ();
+ free (msg);
}
static int lock_filesdoneproc PROTO ((void *callerdat, int err,
diff --git a/contrib/cvs/src/log.c b/contrib/cvs/src/log.c
index 4502e26..398d650 100644
--- a/contrib/cvs/src/log.c
+++ b/contrib/cvs/src/log.c
@@ -7,9 +7,6 @@
*
* Print Log Information
*
- * This line exists solely to test some pcl-cvs/ChangeLog stuff. You
- * can delete it, if indeed it's still here when you read it. -Karl
- *
* Prints the RCS "log" (rlog) information for the specified files. With no
* argument, prints the log information for all the files in the directory
* (recursive by default).
@@ -233,8 +230,8 @@ cvslog (argc, argv)
for (i = 1; i < argc && argv[i][0] == '-'; i++)
send_arg (argv[i]);
- send_file_names (argc - i, argv + i, SEND_EXPAND_WILD);
send_files (argc - i, argv + i, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc - i, argv + i, SEND_EXPAND_WILD);
send_to_server ("log\012", 0);
err = get_responses_and_close ();
@@ -591,11 +588,11 @@ log_fileproc (callerdat, finfo)
cvs_output ("\n\t", 2);
cp2 = cp;
- while (! isspace (*cp2) && *cp2 != '\0')
+ while (! isspace ((unsigned char) *cp2) && *cp2 != '\0')
++cp2;
cvs_output (cp, cp2 - cp);
cp = cp2;
- while (isspace (*cp) && *cp != '\0')
+ while (isspace ((unsigned char) *cp) && *cp != '\0')
++cp;
}
}
@@ -734,7 +731,7 @@ log_expand_revlist (rcs, revlist, default_branch)
char *branch;
/* Print just the head of the branch. */
- if (isdigit (r->first[0]))
+ if (isdigit ((unsigned char) r->first[0]))
nr->first = RCS_getbranch (rcs, r->first, 1);
else
{
@@ -761,7 +758,7 @@ log_expand_revlist (rcs, revlist, default_branch)
}
else
{
- if (r->first == NULL || isdigit (r->first[0]))
+ if (r->first == NULL || isdigit ((unsigned char) r->first[0]))
nr->first = xstrdup (r->first);
else
{
@@ -780,7 +777,7 @@ log_expand_revlist (rcs, revlist, default_branch)
if (r->last == r->first)
nr->last = xstrdup (nr->first);
- else if (r->last == NULL || isdigit (r->last[0]))
+ else if (r->last == NULL || isdigit ((unsigned char) r->last[0]))
nr->last = xstrdup (r->last);
else
{
@@ -1356,12 +1353,12 @@ version_compare (v1, v2, len)
while (*v1 == '0')
++v1;
- for (d1 = 0; isdigit (v1[d1]); ++d1)
+ for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1)
;
while (*v2 == '0')
++v2;
- for (d2 = 0; isdigit (v2[d2]); ++d2)
+ for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2)
;
if (d1 != d2)
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
index 4ffce36..46707e2 100644
--- a/contrib/cvs/src/login.c
+++ b/contrib/cvs/src/login.c
@@ -48,7 +48,14 @@ construct_cvspass_filename ()
homedir = get_homedir ();
if (! homedir)
{
- error (1, errno, "could not find out home directory");
+ /* FIXME? This message confuses a lot of users, at least
+ on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like
+ NT does). I suppose the answer for Win95 is to store the
+ passwords in the registry or something (??). And .cvsrc
+ and such too? Wonder what WinCVS does (about .cvsrc, the
+ right thing for a GUI is to just store the password in
+ memory only)... */
+ error (1, 0, "could not find out home directory");
return (char *) NULL;
}
@@ -246,7 +253,8 @@ login (argc, argv)
/* FIXME: rename_file would make more sense (e.g. almost
always faster). */
copy_file (tmp_name, passfile);
- unlink_file (tmp_name);
+ if (unlink_file (tmp_name) < 0)
+ error (0, errno, "cannot remove %s", tmp_name);
chmod (passfile, 0600);
free (tmp_name);
@@ -437,6 +445,8 @@ logout (argc, argv)
*/
passfile = construct_cvspass_filename ();
+ /* FIXME: This should not be in /tmp; that is almost surely a security
+ hole. Probably should just keep it in memory. */
tmp_name = cvs_temp_name ();
if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL)
{
@@ -476,14 +486,16 @@ logout (argc, argv)
if (! found)
{
printf ("Entry not found for %s\n", CVSroot_original);
- unlink_file (tmp_name);
+ if (unlink_file (tmp_name) < 0)
+ error (0, errno, "cannot remove %s", tmp_name);
}
else
{
/* FIXME: rename_file would make more sense (e.g. almost
always faster). */
copy_file (tmp_name, passfile);
- unlink_file (tmp_name);
+ if (unlink_file (tmp_name) < 0)
+ error (0, errno, "cannot remove %s", tmp_name);
chmod (passfile, 0600);
}
return 0;
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index 67194be..6d45ca3 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -446,7 +446,8 @@ do_verify (message, repository)
{
/* Since following error() exits, delete the temp file
now. */
- unlink_file (fname);
+ if (unlink_file (fname) < 0)
+ error (0, errno, "cannot remove %s", fname);
error (1, retcode == -1 ? errno : 0,
"Message verification failed");
@@ -455,7 +456,8 @@ do_verify (message, repository)
/* Delete the temp file */
- unlink_file (fname);
+ if (unlink_file (fname) < 0)
+ error (0, errno, "cannot remove %s", fname);
free (fname);
}
}
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index 68513df..e211db6 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -12,6 +12,7 @@
*
*/
+#include <assert.h>
#include "cvs.h"
#ifdef HAVE_WINSOCK_H
@@ -57,6 +58,16 @@ char *CurDir;
char *Tmpdir = TMPDIR_DFLT;
char *Editor = EDITOR_DFLT;
+
+/* When our working directory contains subdirectories with different
+ values in CVS/Root files, we maintain a list of them. */
+List *root_directories = NULL;
+
+/* We step through the above values. This variable is set to reflect
+ the currently active value. */
+char *current_root = NULL;
+
+
static const struct cmd
{
char *fullname; /* Full name of the function (e.g. "commit") */
@@ -209,6 +220,7 @@ static const char *const cmd_usage[] =
static const char *const opt_usage[] =
{
+ /* Omit -b because it is just for compatibility. */
"CVS global options (specified before the command name) are:\n",
" -H Displays usage information for command.\n",
" -Q Cause CVS to be really quiet.\n",
@@ -219,7 +231,6 @@ static const char *const opt_usage[] =
" -n Do not execute anything that will change the disk.\n",
" -t Show trace of program execution -- try with -n.\n",
" -v CVS version and copyright.\n",
- " -b bindir Find RCS programs in 'bindir'.\n",
" -T tmpdir Use 'tmpdir' for temporary files.\n",
" -e editor Use 'editor' for editing log information.\n",
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
@@ -236,6 +247,21 @@ static const char *const opt_usage[] =
NULL
};
+
+static int
+set_root_directory (p, ignored)
+ Node *p;
+ void *ignored;
+{
+ if (current_root == NULL && p->data == NULL)
+ {
+ current_root = p->key;
+ return 1;
+ }
+ return 0;
+}
+
+
static const char * const*
cmd_synonyms ()
{
@@ -311,7 +337,6 @@ lookup_command_attribute (cmd_name)
(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) &&
(strcmp (cmd_name, "export") != 0) &&
(strcmp (cmd_name, "history") != 0) &&
@@ -406,7 +431,6 @@ main (argc, argv)
/* `getopt_long' stores the option index here, but right now we
don't use it. */
int option_index = 0;
- int need_to_create_root = 0;
#ifdef SYSTEM_INITIALIZE
/* Hook for OS-specific behavior, for example socket subsystems on
@@ -562,6 +586,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
free_Editor = 1;
break;
case 'd':
+ if (CVSroot_cmdline != NULL)
+ free (CVSroot_cmdline);
+ CVSroot_cmdline = xstrdup (optarg);
CVSroot = xstrdup (optarg);
free_CVSroot = 1;
cvs_update_env = 1; /* need to update environment */
@@ -644,7 +671,10 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
}
if (help)
+ {
argc = -1; /* some functions only check for this */
+ err = (*(cm->func)) (argc, argv);
+ }
else
{
/* The user didn't ask for help, so go ahead and authenticate,
@@ -701,10 +731,79 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
#ifdef SERVER_SUPPORT
server_active = strcmp (command_name, "server") == 0;
+#endif
+
+ /* This is only used for writing into the history file. For
+ remote connections, it might be nice to have hostname
+ and/or remote path, on the other hand I'm not sure whether
+ it is worth the trouble. */
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ CurDir = xstrdup ("<remote>");
+ else
+#endif
+ {
+ CurDir = xgetwd ();
+ if (CurDir == NULL)
+ error (1, errno, "cannot get working directory");
+ }
+
+ if (Tmpdir == NULL || Tmpdir[0] == '\0')
+ Tmpdir = "/tmp";
+
+#ifdef HAVE_PUTENV
+ if (tmpdir_update_env)
+ {
+ char *env;
+ env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1);
+ (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir);
+ (void) putenv (env);
+ /* do not free env, as putenv has control of it */
+ }
+#endif
+
+#ifndef DONT_USE_SIGNALS
+ /* make sure we clean up on error */
+#ifdef SIGHUP
+ (void) SIG_register (SIGHUP, main_cleanup);
+ (void) SIG_register (SIGHUP, Lock_Cleanup);
+#endif
+#ifdef SIGINT
+ (void) SIG_register (SIGINT, main_cleanup);
+ (void) SIG_register (SIGINT, Lock_Cleanup);
+#endif
+#ifdef SIGQUIT
+ (void) SIG_register (SIGQUIT, main_cleanup);
+ (void) SIG_register (SIGQUIT, Lock_Cleanup);
+#endif
+#ifdef SIGPIPE
+ (void) SIG_register (SIGPIPE, main_cleanup);
+ (void) SIG_register (SIGPIPE, Lock_Cleanup);
+#endif
+#ifdef SIGTERM
+ (void) SIG_register (SIGTERM, main_cleanup);
+ (void) SIG_register (SIGTERM, Lock_Cleanup);
+#endif
+#endif /* !DONT_USE_SIGNALS */
+
+ gethostname(hostname, sizeof (hostname));
+
+#ifdef KLUDGE_FOR_WNT_TESTSUITE
+ /* Probably the need for this will go away at some point once
+ we call fflush enough places (e.g. fflush (stdout) in
+ cvs_outerr). */
+ (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
+ (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
+#endif /* KLUDGE_FOR_WNT_TESTSUITE */
+
+ if (use_cvsrc)
+ read_cvsrc (&argc, &argv, command_name);
+
+#ifdef SERVER_SUPPORT
/* Fiddling with CVSROOT doesn't make sense if we're running
- in server mode, since the client will send the repository
- directory after the connection is made. */
+ in server mode, since the client will send the repository
+ directory after the connection is made. */
if (!server_active)
#endif
@@ -721,11 +820,15 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
specify a different repository than the one we are
importing to. */
- if (lookup_command_attribute (command_name)
- & CVS_CMD_IGNORE_ADMROOT)
- {
+ if ((lookup_command_attribute (command_name)
+ & CVS_CMD_IGNORE_ADMROOT)
+
+ /* -d overrides CVS/Root, so don't give an error if the
+ latter points to a nonexistent repository. */
+ && CVSroot_cmdline == NULL)
+ {
CVSADM_Root = Name_Root((char *) NULL, (char *) NULL);
- }
+ }
if (CVSADM_Root != NULL)
{
@@ -734,39 +837,11 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
CVSroot = CVSADM_Root;
cvs_update_env = 1; /* need to update environment */
}
- /* Let -d override CVS/Root file. The user might want
- to change the access method, use a different server
- (if there are two server machines which share the
- repository using a networked file system), etc. */
- else if (
-#ifdef CLIENT_SUPPORT
- !getenv ("CVS_IGNORE_REMOTE_ROOT") &&
-#endif
- strcmp (CVSroot, CVSADM_Root) != 0)
- {
- /* Once we have verified that this root is usable,
- we will want to write it into CVS/Root.
-
- Don't do it for the "login" command, however.
- Consider: if the user executes "cvs login" with
- the working directory inside an already checked
- out module, we'd incorrectly change the
- CVS/Root file to reflect the CVSROOT of the
- "cvs login" command. Ahh, the things one
- discovers. */
-
- if (lookup_command_attribute (command_name)
- & CVS_CMD_USES_WORK_DIR)
- {
- need_to_create_root = 1;
- }
-
- }
}
/* Now we've reconciled CVSROOT from the command line, the
- CVS/Root file, and the environment variable. Do the
- last sanity checks on the variable. */
+ CVS/Root file, and the environment variable. Do the
+ last sanity checks on the variable. */
if (! CVSroot)
{
@@ -788,172 +863,180 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
error (1, 0,
"CVS/Root file (if any).");
}
+ }
+
+ /* Here begins the big loop over unique cvsroot values. We
+ need to call do_recursion once for each unique value found
+ in CVS/Root. Prime the list with the current value. */
+
+ /* Create the list. */
+ assert (root_directories == NULL);
+ root_directories = getlist ();
+
+ /* Prime it. */
+ if (CVSroot != NULL)
+ {
+ Node *n;
+ n = getnode ();
+ n->type = UNKNOWN;
+ n->key = xstrdup (CVSroot);
+ n->data = NULL;
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add initial CVSROOT %s", n->key);
+ }
- /* Now we're 100% sure that we have a valid CVSROOT
- variable. Parse it to see if we're supposed to do
- remote accesses or use a special access method. */
+ assert (current_root == NULL);
- if (parse_cvsroot (CVSroot))
- error (1, 0, "Bad CVSROOT.");
+ /* If we're running the server, we want to execute this main
+ loop once and only once (we won't be serving multiple roots
+ from this connection, so there's no need to do it more than
+ once). To get out of the loop, we perform a "break" at the
+ end of things. */
- /*
- * Check to see if we can write into the history file. If not,
- * we assume that we can't work in the repository.
- * BUT, only if the history file exists.
- */
+ while (
+#ifdef SERVER_SUPPORT
+ server_active ||
+#endif
+ walklist (root_directories, set_root_directory, NULL)
+ )
+ {
+#ifdef SERVER_SUPPORT
+ /* Fiddling with CVSROOT doesn't make sense if we're running
+ in server mode, since the client will send the repository
+ directory after the connection is made. */
- if (!client_active)
+ if (!server_active)
+#endif
{
- char *path;
- int save_errno;
-
- path = xmalloc (strlen (CVSroot_directory)
- + sizeof (CVSROOTADM)
- + 20
- + sizeof (CVSROOTADM_HISTORY));
- (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
- if (!isaccessible (path, R_OK | X_OK))
+ /* Now we're 100% sure that we have a valid CVSROOT
+ variable. Parse it to see if we're supposed to do
+ remote accesses or use a special access method. */
+
+ if (parse_cvsroot (current_root))
+ error (1, 0, "Bad CVSROOT.");
+
+ if (trace)
+ error (0, 0, "notice: main loop with CVSROOT=%s",
+ current_root);
+
+ /*
+ * Check to see if we can write into the history file. If not,
+ * we assume that we can't work in the repository.
+ * BUT, only if the history file exists.
+ */
+
+ if (!client_active)
{
- save_errno = errno;
- /* If this is "cvs init", the root need not exist yet. */
- if (strcmp (command_name, "init") != 0)
+ char *path;
+ int save_errno;
+
+ path = xmalloc (strlen (CVSroot_directory)
+ + sizeof (CVSROOTADM)
+ + 20
+ + sizeof (CVSROOTADM_HISTORY));
+ (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
+ if (!isaccessible (path, R_OK | X_OK))
+ {
+ save_errno = errno;
+ /* If this is "cvs init", the root need not exist yet. */
+ if (strcmp (command_name, "init") != 0)
+ {
+ error (1, save_errno, "%s", path);
+ }
+ }
+ (void) strcat (path, "/");
+ (void) strcat (path, CVSROOTADM_HISTORY);
+ if (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");
error (1, save_errno, "%s", path);
}
+ free (path);
}
- (void) strcat (path, "/");
- (void) strcat (path, CVSROOTADM_HISTORY);
- if (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");
- error (1, save_errno, "%s", path);
- }
- free (path);
- }
#ifdef HAVE_PUTENV
- /* Update the CVSROOT environment variable if necessary. */
-
- if (cvs_update_env)
- {
- char *env;
- env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
- + 1 + 1);
- (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
- (void) putenv (env);
- /* do not free env, as putenv has control of it */
- }
+ /* Update the CVSROOT environment variable if necessary. */
+ /* FIXME (njc): should we always set this with the CVSROOT from the command line? */
+ if (cvs_update_env)
+ {
+ char *env;
+ env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot)
+ + 1 + 1);
+ (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
+ (void) putenv (env);
+ /* do not free env, as putenv has control of it */
+ }
#endif
- }
+ }
- /* This is only used for writing into the history file. For
- remote connections, it might be nice to have hostname
- and/or remote path, on the other hand I'm not sure whether
- it is worth the trouble. */
-
+ /* Parse the CVSROOT/config file, but only for local. For the
+ server, we parse it after we know $CVSROOT. For the
+ client, it doesn't get parsed at all, obviously. The
+ presence of the parse_config call here is not mean to
+ predetermine whether CVSROOT/config overrides things from
+ read_cvsrc and other such places or vice versa. That sort
+ of thing probably needs more thought. */
+ if (1
#ifdef SERVER_SUPPORT
- if (server_active)
- CurDir = xstrdup ("<remote>");
- else
+ && !server_active
#endif
- {
- CurDir = xgetwd ();
- if (CurDir == NULL)
- error (1, errno, "cannot get working directory");
- }
-
- if (Tmpdir == NULL || Tmpdir[0] == '\0')
- Tmpdir = "/tmp";
-
-#ifdef HAVE_PUTENV
- if (tmpdir_update_env)
- {
- char *env;
- env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1);
- (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir);
- (void) putenv (env);
- /* do not free env, as putenv has control of it */
- }
+#ifdef CLIENT_SUPPORT
+ && !client_active
#endif
+ )
+ {
+ /* If there was an error parsing the config file, parse_config
+ already printed an error. We keep going. Why? Because
+ if we didn't, then there would be no way to check in a new
+ CVSROOT/config file to fix the broken one! */
+ parse_config (CVSroot_directory);
+ }
-#ifndef DONT_USE_SIGNALS
- /* make sure we clean up on error */
-#ifdef SIGHUP
- (void) SIG_register (SIGHUP, main_cleanup);
- (void) SIG_register (SIGHUP, Lock_Cleanup);
-#endif
-#ifdef SIGINT
- (void) SIG_register (SIGINT, main_cleanup);
- (void) SIG_register (SIGINT, Lock_Cleanup);
-#endif
-#ifdef SIGQUIT
- (void) SIG_register (SIGQUIT, main_cleanup);
- (void) SIG_register (SIGQUIT, Lock_Cleanup);
-#endif
-#ifdef SIGPIPE
- (void) SIG_register (SIGPIPE, main_cleanup);
- (void) SIG_register (SIGPIPE, Lock_Cleanup);
-#endif
-#ifdef SIGTERM
- (void) SIG_register (SIGTERM, main_cleanup);
- (void) SIG_register (SIGTERM, Lock_Cleanup);
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ /* Create a new list for directory names that we've
+ sent to the server. */
+ if (dirs_sent_to_server != NULL)
+ dellist (&dirs_sent_to_server);
+ dirs_sent_to_server = getlist ();
+ }
#endif
-#endif /* !DONT_USE_SIGNALS */
-
- gethostname(hostname, sizeof (hostname));
-#ifdef KLUDGE_FOR_WNT_TESTSUITE
- /* Probably the need for this will go away at some point once
- we call fflush enough places (e.g. fflush (stdout) in
- cvs_outerr). */
- (void) setvbuf (stdout, (char *) NULL, _IONBF, 0);
- (void) setvbuf (stderr, (char *) NULL, _IONBF, 0);
-#endif /* KLUDGE_FOR_WNT_TESTSUITE */
+ err = (*(cm->func)) (argc, argv);
+
+ /* Mark this root directory as done. When the server is
+ active, current_root will be NULL -- don't try and
+ remove it from the list. */
- if (use_cvsrc)
- read_cvsrc (&argc, &argv, command_name);
+ if (current_root != NULL)
+ {
+ Node *n = findnode (root_directories, current_root);
+ assert (n != NULL);
+ n->data = (void *) 1;
+ current_root = NULL;
+ }
+
+#if 0
+ /* This will not work yet, since it tries to free (void *) 1. */
+ dellist (&root_directories);
+#endif
- /* Parse the CVSROOT/config file, but only for local. For the
- server, we parse it after we know $CVSROOT. For the
- client, it doesn't get parsed at all, obviously. The
- presence of the parse_config call here is not mean to
- predetermine whether CVSROOT/config overrides things from
- read_cvsrc and other such places or vice versa. That sort
- of thing probably needs more thought. */
- if (1
#ifdef SERVER_SUPPORT
- && !server_active
-#endif
-#ifdef CLIENT_SUPPORT
- && !client_active
+ if (server_active)
+ break;
#endif
- )
- {
- /* If there was an error parsing the config file, parse_config
- already printed an error. We keep going. Why? Because
- if we didn't, then there would be no way to check in a new
- CVSROOT/config file to fix the broken one! */
- parse_config (CVSroot_directory);
- }
- } /* end of stuff that gets done if the user DOESN'T ask for help */
+ } /* end of loop for cvsroot values */
- err = (*(cm->func)) (argc, argv);
-
- if (need_to_create_root)
- {
- /* Update the CVS/Root file. We might want to do this in
- all directories that we recurse into, but currently we
- don't. Note that if there is an error writing the file,
- we give an error/warning. This is so if users try to rewrite
- CVS/Root with the -d option (a documented feature), they will
- either succeed, or be told why it didn't work. */
- Create_Root (NULL, CVSroot);
- }
+ } /* end of stuff that gets done if the user DOESN'T ask for help */
Lock_Cleanup ();
free (program_path);
+ if (CVSroot_cmdline != NULL)
+ free (CVSroot_cmdline);
if (free_CVSroot)
free (CVSroot);
if (free_Editor)
@@ -1020,6 +1103,43 @@ date_from_time_t (unixtime)
return (ret);
}
+/* Convert a date to RFC822/1123 format. This is used in contexts like
+ dates to send in the protocol; it should not vary based on locale or
+ other such conventions for users. We should have another routine which
+ does that kind of thing.
+
+ The SOURCE date is in our internal RCS format. DEST should point to
+ storage managed by the caller, at least MAXDATELEN characters. */
+void
+date_to_internet (dest, source)
+ char *dest;
+ char *source;
+{
+ int year, month, day, hour, minute, second;
+
+ /* Just to reiterate, these strings are from RFC822 and do not vary
+ according to locale. */
+ static const char *const month_names[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ if (sscanf (source, SDATEFORM,
+ &year, &month, &day, &hour, &minute, &second)
+ != 6)
+ /* Is there a better way to handle errors here? I made this
+ non-fatal in case we are called from the code which can't
+ deal with fatal errors. */
+ error (0, 0, "internal error: bad date %s", source);
+
+ /* Always send a four digit year. */
+ if (year < 100)
+ year += 1900;
+
+ sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", day,
+ month < 1 || month > 12 ? "???" : month_names[month - 1],
+ year, hour, minute, second);
+}
+
void
usage (cpp)
register const char *const *cpp;
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index e716222..4244258 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -353,7 +353,7 @@ static const struct admin_file filelist[] = {
{CVSROOTADM_CONFIG,
"a %s file configures various behaviors",
config_contents},
- {NULL, NULL}
+ {NULL, NULL, NULL}
};
/* Rebuild the checked out administrative files in directory DIR. */
@@ -397,11 +397,6 @@ mkmodules (dir)
rename_rcsfile (temp, CVSROOTADM_MODULES);
break;
- case -1: /* fork failed */
- (void) unlink_file (temp);
- error (1, errno, "cannot check out %s", CVSROOTADM_MODULES);
- /* NOTREACHED */
-
default:
error (0, 0,
"'cvs checkout' is less functional without a %s file",
@@ -409,7 +404,9 @@ mkmodules (dir)
break;
} /* switch on checkout_file() */
- (void) unlink_file (temp);
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
free (temp);
/* Checkout the files that need it in CVSROOT dir */
@@ -430,7 +427,9 @@ mkmodules (dir)
else if (fileptr->errormsg)
error (0, 0, fileptr->errormsg, fileptr->filename);
#endif
- (void) unlink_file (temp);
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
free (temp);
}
@@ -453,11 +452,13 @@ mkmodules (dir)
*last = '\0'; /* strip the newline */
/* Skip leading white space. */
- for (fname = line; *fname && isspace(*fname); fname++)
+ for (fname = line;
+ *fname && isspace ((unsigned char) *fname);
+ fname++)
;
/* Find end of filename. */
- for (cp = fname; *cp && !isspace(*cp); cp++)
+ for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++)
;
*cp = '\0';
@@ -468,11 +469,16 @@ mkmodules (dir)
}
else
{
- for (cp++; cp < last && *last && isspace(*last); cp++)
+ for (cp++;
+ cp < last && *last && isspace ((unsigned char) *last);
+ cp++)
;
if (cp < last && *cp)
error (0, 0, cp, fname);
}
+ if (unlink_file (temp) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", temp);
free (temp);
}
if (line)
@@ -522,6 +528,10 @@ make_tempfile ()
return temp;
}
+/* Get a file. If the file does not exist, return 1 silently. If
+ there is an error, print a message and return 1 (FIXME: probably
+ not a very clean convention). On success, return 0. */
+
static int
checkout_file (file, temp)
char *file;
@@ -547,6 +557,8 @@ checkout_file (file, temp)
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
{
+ /* Probably not necessary (?); RCS_checkout already printed a
+ message. */
error (0, 0, "failed to check out %s file",
file);
}
@@ -607,7 +619,7 @@ write_dbmfile (temp)
if (value[0] == '#')
continue; /* comment line */
vp = value;
- while (*vp && isspace (*vp))
+ while (*vp && isspace ((unsigned char) *vp))
vp++;
if (*vp == '\0')
continue; /* empty line */
@@ -618,11 +630,11 @@ write_dbmfile (temp)
if (!cont)
{
key.dptr = vp;
- while (*vp && !isspace (*vp))
+ while (*vp && !isspace ((unsigned char) *vp))
vp++;
key.dsize = vp - key.dptr;
*vp++ = '\0'; /* NULL terminate the key */
- while (*vp && isspace (*vp))
+ while (*vp && isspace ((unsigned char) *vp))
vp++; /* skip whitespace to value */
if (*vp == '\0')
{
@@ -639,17 +651,28 @@ write_dbmfile (temp)
}
}
dbm_close (db);
- (void) fclose (fp);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", temp);
if (err)
{
+ /* I think that the size of the buffer needed here is
+ just determined by sizeof (CVSROOTADM_MODULES), the
+ filenames created by make_tempfile, and other things that won't
+ overflow. */
char dotdir[50], dotpag[50], dotdb[50];
(void) sprintf (dotdir, "%s.dir", temp);
(void) sprintf (dotpag, "%s.pag", temp);
(void) sprintf (dotdb, "%s.db", temp);
- (void) unlink_file (dotdir);
- (void) unlink_file (dotpag);
- (void) unlink_file (dotdb);
+ if (unlink_file (dotdir) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotdir);
+ if (unlink_file (dotpag) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotpag);
+ if (unlink_file (dotdb) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", dotdb);
error (1, 0, "DBM creation failed; correct above errors");
}
}
@@ -658,10 +681,18 @@ static void
rename_dbmfile (temp)
char *temp;
{
+ /* I think that the size of the buffer needed here is
+ just determined by sizeof (CVSROOTADM_MODULES), the
+ filenames created by make_tempfile, and other things that won't
+ overflow. */
char newdir[50], newpag[50], newdb[50];
char dotdir[50], dotpag[50], dotdb[50];
char bakdir[50], bakpag[50], bakdb[50];
+ int dir1_errno = 0, pag1_errno = 0, db1_errno = 0;
+ int dir2_errno = 0, pag2_errno = 0, db2_errno = 0;
+ int dir3_errno = 0, pag3_errno = 0, db3_errno = 0;
+
(void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
(void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
(void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES);
@@ -679,18 +710,59 @@ rename_dbmfile (temp)
/* don't mess with me */
SIG_beginCrSect ();
- (void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
- (void) unlink_file (bakpag);
- (void) unlink_file (bakdb);
- (void) CVS_RENAME (dotdir, bakdir); /* mv modules.dir .#modules.dir */
- (void) CVS_RENAME (dotpag, bakpag); /* mv modules.pag .#modules.pag */
- (void) CVS_RENAME (dotdb, bakdb); /* mv modules.db .#modules.db */
- (void) CVS_RENAME (newdir, dotdir); /* mv "temp".dir modules.dir */
- (void) CVS_RENAME (newpag, dotpag); /* mv "temp".pag modules.pag */
- (void) CVS_RENAME (newdb, dotdb); /* mv "temp".db modules.db */
+ /* rm .#modules.dir .#modules.pag */
+ if (unlink_file (bakdir) < 0)
+ dir1_errno = errno;
+ if (unlink_file (bakpag) < 0)
+ pag1_errno = errno;
+ if (unlink_file (bakdb) < 0)
+ db1_errno = errno;
+
+ /* mv modules.dir .#modules.dir */
+ if (CVS_RENAME (dotdir, bakdir) < 0)
+ dir2_errno = errno;
+ /* mv modules.pag .#modules.pag */
+ if (CVS_RENAME (dotpag, bakpag) < 0)
+ pag2_errno = errno;
+ /* mv modules.db .#modules.db */
+ if (CVS_RENAME (dotdb, bakdb) < 0)
+ db2_errno = errno;
+
+ /* mv "temp".dir modules.dir */
+ if (CVS_RENAME (newdir, dotdir) < 0)
+ dir3_errno = errno;
+ /* mv "temp".pag modules.pag */
+ if (CVS_RENAME (newpag, dotpag) < 0)
+ pag3_errno = errno;
+ /* mv "temp".db modules.db */
+ if (CVS_RENAME (newdb, dotdb) < 0)
+ db3_errno = errno;
/* OK -- make my day */
SIG_endCrSect ();
+
+ /* I didn't want to call error() when we had signals blocked
+ (unnecessary?), but do it now. */
+ if (dir1_errno && !existence_error (dir1_errno))
+ error (0, dir1_errno, "cannot remove %s", bakdir);
+ if (pag1_errno && !existence_error (pag1_errno))
+ error (0, pag1_errno, "cannot remove %s", bakpag);
+ if (db1_errno && !existence_error (db1_errno))
+ error (0, db1_errno, "cannot remove %s", bakdb);
+
+ if (dir2_errno && !existence_error (dir2_errno))
+ error (0, dir2_errno, "cannot remove %s", bakdir);
+ if (pag2_errno && !existence_error (pag2_errno))
+ error (0, pag2_errno, "cannot remove %s", bakpag);
+ if (db2_errno && !existence_error (db2_errno))
+ error (0, db2_errno, "cannot remove %s", bakdb);
+
+ if (dir3_errno && !existence_error (dir3_errno))
+ error (0, dir3_errno, "cannot remove %s", bakdir);
+ if (pag3_errno && !existence_error (pag3_errno))
+ error (0, pag3_errno, "cannot remove %s", bakpag);
+ if (db3_errno && !existence_error (db3_errno))
+ error (0, db3_errno, "cannot remove %s", bakdb);
}
#endif /* !MY_NDBM */
@@ -708,16 +780,31 @@ rename_rcsfile (temp, real)
rcs = xmalloc (strlen (real) + sizeof (RCSEXT) + 10);
(void) sprintf (rcs, "%s%s", real, RCSEXT);
statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */
- (void) CVS_STAT (rcs, &statbuf);
+ if (CVS_STAT (rcs, &statbuf) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot stat %s", rcs);
free (rcs);
if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0)
error (0, errno, "warning: cannot chmod %s", temp);
bak = xmalloc (strlen (real) + sizeof (BAKPREFIX) + 10);
(void) sprintf (bak, "%s%s", BAKPREFIX, real);
- (void) unlink_file (bak); /* rm .#loginfo */
- (void) CVS_RENAME (real, bak); /* mv loginfo .#loginfo */
- (void) CVS_RENAME (temp, real); /* mv "temp" loginfo */
+
+ /* rm .#loginfo */
+ if (unlink_file (bak) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", bak);
+
+ /* mv loginfo .#loginfo */
+ if (CVS_RENAME (real, bak) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot rename %s to %s", real, bak);
+
+ /* mv "temp" loginfo */
+ if (CVS_RENAME (temp, real) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot rename %s to %s", temp, real);
+
free (bak);
}
diff --git a/contrib/cvs/src/modules.c b/contrib/cvs/src/modules.c
index de95f7e..9907cc8 100644
--- a/contrib/cvs/src/modules.c
+++ b/contrib/cvs/src/modules.c
@@ -20,6 +20,7 @@
* command line.
*/
+#include <assert.h>
#include "cvs.h"
#include "savecwd.h"
@@ -120,7 +121,8 @@ do_module (db, mname, m_type, msg, callback_proc, where,
int xmodargc;
char **modargv;
char **xmodargv;
- char *value;
+ /* Found entry from modules file, including options and such. */
+ char *value = NULL;
char *zvalue = NULL;
char *mwhere = NULL;
char *mfile = NULL;
@@ -147,8 +149,8 @@ do_module (db, mname, m_type, msg, callback_proc, where,
+ strlen (msg)
+ (where ? strlen (where) : 0)
+ (extra_arg ? strlen (extra_arg) : 0));
- sprintf (buf, "%c-> do_module (%s, %s, %s, %s)\n",
- (server_active) ? 'S' : ' ',
+ sprintf (buf, "%s-> do_module (%s, %s, %s, %s)\n",
+ CLIENT_SERVER_STR,
mname, msg, where ? where : "",
extra_arg ? extra_arg : "");
cvs_outerr (buf, 0);
@@ -192,13 +194,13 @@ do_module (db, mname, m_type, msg, callback_proc, where,
{
do
*cp-- = '\0';
- while (isspace (*cp));
+ while (isspace ((unsigned char) *cp));
}
else
{
/* Always strip trailing spaces */
cp = strchr (val.dptr, '\0');
- while (cp > val.dptr && isspace(*--cp))
+ while (cp > val.dptr && isspace ((unsigned char) *--cp))
*cp = '\0';
}
@@ -231,7 +233,9 @@ do_module (db, mname, m_type, msg, callback_proc, where,
if (isdir (file))
{
- value = mname;
+ modargv = xmalloc (sizeof (*modargv));
+ modargv[0] = xstrdup (mname);
+ modargc = 1;
is_found = 1;
}
else
@@ -242,14 +246,12 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* if mname was a file, we have to split it into "dir file" */
if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
{
- char *slashp;
-
- /* put the ' ' in a copy so we don't mess up the
- original */
- xvalue = xmalloc (strlen (mname) + 2);
- value = strcpy (xvalue, mname);
- slashp = strrchr (value, '/');
- *slashp = ' ';
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xmalloc (strlen (mname) + 2);
+ strncpy (modargv[0], mname, cp - mname);
+ modargv[0][cp - mname] = '\0';
+ modargv[1] = xstrdup (cp + 1);
+ modargc = 2;
}
else
{
@@ -261,31 +263,54 @@ do_module (db, mname, m_type, msg, callback_proc, where,
if (cp == mname)
{
/* drop the leading / if specified */
- xvalue = xmalloc (strlen (mname) + 10);
- value = strcpy (xvalue, ". ");
- (void) strcat (xvalue, mname + 1);
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname + 1);
+ modargc = 2;
}
else
{
/* otherwise just copy it */
- xvalue = xmalloc (strlen (mname) + 10);
- value = strcpy (xvalue, ". ");
- (void) strcat (xvalue, mname);
+ modargv = xmalloc (2 * sizeof (*modargv));
+ modargv[0] = xstrdup (".");
+ modargv[1] = xstrdup (mname);
+ modargc = 2;
}
}
is_found = 1;
}
- else
- {
- /* This initialization suppresses a warning from gcc -Wall. */
- value = NULL;
- }
}
free (attic_file);
free (file);
if (is_found)
- goto found;
+ {
+ assert (value == NULL);
+
+ /* OK, we have now set up modargv with the actual
+ file/directory we want to work on. We duplicate a
+ small amount of code here because the vast majority of
+ the code after the "found" label does not pertain to
+ the case where we found a file/directory rather than
+ finding an entry in the modules file. */
+ if (save_cwd (&cwd))
+ error_exit ();
+ cwd_saved = 1;
+
+ err += callback_proc (&modargc, modargv, where, mwhere, mfile,
+ shorten,
+ local_specified, mname, msg);
+
+ free_names (&modargc, modargv);
+
+ /* cd back to where we started. */
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
+ cwd_saved = 0;
+
+ goto do_module_return;
+ }
}
/* look up everything to the first / as a module */
@@ -315,7 +340,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
{
do
*cp2-- = '\0';
- while (isspace (*cp2));
+ while (isspace ((unsigned char) *cp2));
}
value = val.dptr;
@@ -352,6 +377,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* copy value to our own string since if we go recursive we'll be
really screwed if we do another dbm lookup */
+ assert (value != NULL);
zvalue = xstrdup (value);
value = zvalue;
@@ -362,7 +388,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
spec_opt = cp + 1; /* save the options for later */
if (cp != value) /* strip whitespace if necessary */
- while (isspace (*--cp))
+ while (isspace ((unsigned char) *--cp))
*cp = '\0';
if (cp == value)
@@ -609,13 +635,13 @@ module `%s' is a request for a file in a module which is not a directory",
/* strip whitespace off the end */
do
*cp = '\0';
- while (isspace (*--cp));
+ while (isspace ((unsigned char) *--cp));
}
else
next_opt = NULL;
/* strip whitespace from front */
- while (isspace (*spec_opt))
+ while (isspace ((unsigned char) *spec_opt))
spec_opt++;
if (*spec_opt == '\0')
@@ -836,15 +862,15 @@ save_d (k, ks, d, ds)
cp = d;
*(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
/* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
while (*cp)
{
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
{
*cp2++ = ' ';
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
}
else
diff --git a/contrib/cvs/src/myndbm.c b/contrib/cvs/src/myndbm.c
index 6b15e77..f674ac1 100644
--- a/contrib/cvs/src/myndbm.c
+++ b/contrib/cvs/src/myndbm.c
@@ -263,7 +263,7 @@ mydbm_load_file (fp, list)
if (value[0] == '#')
continue; /* comment line */
vp = value;
- while (*vp && isspace (*vp))
+ while (*vp && isspace ((unsigned char) *vp))
vp++;
if (*vp == '\0')
continue; /* empty line */
@@ -277,12 +277,12 @@ mydbm_load_file (fp, list)
char *kp;
kp = vp;
- while (*vp && !isspace (*vp))
+ while (*vp && !isspace ((unsigned char) *vp))
vp++;
*vp++ = '\0'; /* NULL terminate the key */
p->type = NDBMNODE;
p->key = xstrdup (kp);
- while (*vp && isspace (*vp))
+ while (*vp && isspace ((unsigned char) *vp))
vp++; /* skip whitespace to value */
if (*vp == '\0')
{
diff --git a/contrib/cvs/src/no_diff.c b/contrib/cvs/src/no_diff.c
index 078343e..dfca372 100644
--- a/contrib/cvs/src/no_diff.c
+++ b/contrib/cvs/src/no_diff.c
@@ -82,13 +82,8 @@ No_Difference (finfo, vers)
/* Need to call unlink myself because the noexec variable
* has been set to 1. */
if (trace)
- (void) fprintf (stderr, "%c-> unlink (%s)\n",
-#ifdef SERVER_SUPPORT
- (server_active) ? 'S' : ' ',
-#else
- ' ',
-#endif
- tocvsPath);
+ (void) fprintf (stderr, "%s-> unlink (%s)\n",
+ CLIENT_SERVER_STR, tocvsPath);
if ( CVS_UNLINK (tocvsPath) < 0)
error (0, errno, "could not remove %s", tocvsPath);
}
diff --git a/contrib/cvs/src/options.h.in b/contrib/cvs/src/options.h.in
index 67e8c40..a3ee047 100644
--- a/contrib/cvs/src/options.h.in
+++ b/contrib/cvs/src/options.h.in
@@ -88,13 +88,12 @@
* repository, change the contents of CVS/Root files in your
* checked-out code, and CVS will work without problems.
*
- * This is likely to be the default in the future, but we want to give
- * people who may be relying on absolute pathnames time to update
- * their scripts/software.
+ * Therefore, RELATIVE_REPOS is now the default. In the future, this
+ * is likely to disappear entirely as a compile-time (or other) option,
+ * so if you have other software which relies on absolute pathnames,
+ * update them.
*/
-#ifndef RELATIVE_REPOS
-/* #define RELATIVE_REPOS */
-#endif
+#define RELATIVE_REPOS 1
/*
* When committing or importing files, you must enter a log message.
diff --git a/contrib/cvs/src/parseinfo.c b/contrib/cvs/src/parseinfo.c
index 9847ab9..1c1ab70 100644
--- a/contrib/cvs/src/parseinfo.c
+++ b/contrib/cvs/src/parseinfo.c
@@ -77,7 +77,7 @@ Parse_Info (infofile, repository, callproc, all)
continue;
/* skip whitespace at beginning of line */
- for (cp = line; *cp && isspace (*cp); cp++)
+ for (cp = line; *cp && isspace ((unsigned char) *cp); cp++)
;
/* if *cp is null, the whole line was blank */
@@ -85,13 +85,13 @@ Parse_Info (infofile, repository, callproc, all)
continue;
/* the regular expression is everything up to the first space */
- for (exp = cp; *cp && !isspace (*cp); cp++)
+ for (exp = cp; *cp && !isspace ((unsigned char) *cp); cp++)
;
if (*cp != '\0')
*cp++ = '\0';
/* skip whitespace up to the start of the matching value */
- while (*cp && isspace (*cp))
+ while (*cp && isspace ((unsigned char) *cp))
cp++;
/* no value to match with the regular expression is an error */
@@ -358,6 +358,15 @@ warning: this CVS does not support PreservePermissions");
goto error_return;
}
}
+ else if (strcmp (line, "LockDir") == 0)
+ {
+ if (lock_dir != NULL)
+ free (lock_dir);
+ lock_dir = xstrdup (p);
+ /* Could try some validity checking, like whether we can
+ opendir it or something, but I don't see any particular
+ reason to do that now rather than waiting until lock.c. */
+ }
else
{
/* We may be dealing with a keyword which was added in a
diff --git a/contrib/cvs/src/patch.c b/contrib/cvs/src/patch.c
index 9f56b62..f16a331 100644
--- a/contrib/cvs/src/patch.c
+++ b/contrib/cvs/src/patch.c
@@ -763,19 +763,29 @@ patch_dirproc (callerdat, dir, repos, update_dir, entries)
static RETSIGTYPE
patch_cleanup ()
{
+ /* Note that the checks for existence_error are because we are
+ called from a signal handler, without SIG_begincrsect, so
+ we don't know whether the files got created. */
+
if (tmpfile1 != NULL)
{
- (void) unlink_file (tmpfile1);
+ if (unlink_file (tmpfile1) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile1);
free (tmpfile1);
}
if (tmpfile2 != NULL)
{
- (void) unlink_file (tmpfile2);
+ if (unlink_file (tmpfile2) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile2);
free (tmpfile2);
}
if (tmpfile3 != NULL)
{
- (void) unlink_file (tmpfile3);
+ if (unlink_file (tmpfile3) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile3);
free (tmpfile3);
}
tmpfile1 = tmpfile2 = tmpfile3 = NULL;
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 951736e..64524b1 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -153,6 +153,26 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
+static char *rcs_lockfile;
+
+/* A few generic thoughts on error handling, in particular the
+ printing of unexpected characters that we find in the RCS file
+ (that is, why we use '\x%x' rather than %c or some such).
+
+ * Avoiding %c means we don't have to worry about what is printable
+ and other such stuff. In error handling, often better to keep it
+ simple.
+
+ * Hex rather than decimal or octal because character set standards
+ tend to use hex.
+
+ * Saying "character 0x%x" might make it sound like we are printing
+ a file offset. So we use '\x%x'.
+
+ * Would be nice to print the offset within the file, but I can
+ imagine various portability hassles (in particular, whether
+ unsigned long is always big enough to hold file offsets). */
+
/* Parse an rcsfile given a user file name and a repository. If there is
an error, we print an error message and return NULL. If the file
does not exist, we return NULL without printing anything (I'm not
@@ -364,7 +384,9 @@ RCS_parsercsfile_i (fp, rcsfile)
break;
}
- for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
/* do nothing */ ;
if (*cp == '\0')
break;
@@ -498,7 +520,9 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
* revision or `desc', we are done with the headers and are down to the
* revision deltas, so we break out of the loop
*/
- for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK
@@ -583,6 +607,98 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
rdata->flags &= ~PARTIAL;
}
+/* Move RCS into or out of the Attic, depending on TOATTIC. If the
+ file is already in the desired place, return without doing
+ anything. At some point may want to think about how this relates
+ to RCS_rewrite but that is a bit hairy (if one wants renames to be
+ atomic, or that kind of thing). If there is an error, print a message
+ and return 1. On success, return 0. */
+int
+RCS_setattic (rcs, toattic)
+ RCSNode *rcs;
+ int toattic;
+{
+ char *newpath;
+ char *p;
+ char *q;
+
+ /* Some systems aren't going to let us rename an open file. */
+ rcsbuf_cache_close ();
+
+ /* Could make the pathname computations in this file, and probably
+ in other parts of rcs.c too, easier if the REPOS and FILE
+ arguments to RCS_parse got stashed in the RCSNode. */
+
+ if (toattic)
+ {
+ mode_t omask;
+
+ if (rcs->flags & INATTIC)
+ return 0;
+
+ /* Example: rcs->path is "/foo/bar/baz,v". */
+ newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5);
+ p = last_component (rcs->path);
+ strncpy (newpath, rcs->path, p - rcs->path);
+ strcpy (newpath + (p - rcs->path), CVSATTIC);
+
+ /* Create the Attic directory if it doesn't exist. */
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST)
+ error (0, errno, "cannot make directory %s", newpath);
+ (void) umask (omask);
+
+ strcat (newpath, "/");
+ strcat (newpath, p);
+
+ if (CVS_RENAME (rcs->path, newpath) < 0)
+ {
+ int save_errno = errno;
+
+ /* The checks for isreadable look awfully fishy, but
+ I'm going to leave them here for now until I
+ can think harder about whether they take care of
+ some cases which should be handled somehow. */
+
+ if (isreadable (rcs->path) || !isreadable (newpath))
+ {
+ error (0, save_errno, "cannot rename %s to %s",
+ rcs->path, newpath);
+ free (newpath);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ if (!(rcs->flags & INATTIC))
+ return 0;
+
+ newpath = xmalloc (strlen (rcs->path));
+
+ /* Example: rcs->path is "/foo/bar/Attic/baz,v". */
+ p = last_component (rcs->path);
+ strncpy (newpath, rcs->path, p - rcs->path - 1);
+ newpath[p - rcs->path - 1] = '\0';
+ q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1);
+ assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0);
+ strcpy (q, p);
+
+ if (CVS_RENAME (rcs->path, newpath) < 0)
+ {
+ error (0, errno, "failed to move `%s' out of the attic",
+ rcs->path);
+ free (newpath);
+ return 1;
+ }
+ }
+
+ free (rcs->path);
+ rcs->path = newpath;
+
+ return 0;
+}
+
/*
* Fully parse the RCS file. Store all keyword/value pairs, fetch the
* log messages for each revision, and fetch add and delete counts for
@@ -671,7 +787,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
op = *cp++;
if (op != 'a' && op != 'd')
- error (1, 0, "unrecognized operation '%c' in %s",
+ error (1, 0, "\
+unrecognized operation '\\x%x' in %s",
op, rcs->path);
(void) strtoul (cp, (char **) &cp, 10);
if (*cp++ != ' ')
@@ -1479,7 +1596,8 @@ rcsbuf_getstring (rcsbuf, strp)
/* PTR should now point to the start of a string. */
if (c != '@')
- error (1, 0, "expected @-string at `%c' in %s", c, rcsbuf->filename);
+ error (1, 0, "expected @-string at '\\x%x' in %s",
+ c, rcsbuf->filename);
/* Optimize the common case of a value composed of a single
'@' string. */
@@ -1736,7 +1854,7 @@ rcsbuf_getword (rcsbuf, wordp)
printing character that is not a special.' This test ought
to do the trick. */
c = *ptr;
- if (isprint (c) &&
+ if (isprint ((unsigned char) c) &&
c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
{
++ptr;
@@ -1804,9 +1922,10 @@ rcsbuf_getrevnum (rcsbuf, revp)
++ptr;
}
- if (! isdigit (c) && c != '.')
+ if (! isdigit ((unsigned char) c) && c != '.')
error (1, 0,
- "unexpected `%c' reading revision number in RCS file %s",
+ "\
+unexpected '\\x%x' reading revision number in RCS file %s",
c, rcsbuf->filename);
*revp = ptr;
@@ -1826,10 +1945,11 @@ rcsbuf_getrevnum (rcsbuf, revp)
c = *ptr;
}
- while (isdigit (c) || c == '.');
+ while (isdigit ((unsigned char) c) || c == '.');
if (! whitespace (c))
- error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
+ error (1, 0, "\
+unexpected '\\x%x' reading revision number in RCS file %s",
c, rcsbuf->filename);
*ptr = '\0';
@@ -2337,7 +2457,7 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag)
}
/* Work out the branch. */
- if (! isdigit (tag[0]))
+ if (! isdigit ((unsigned char) tag[0]))
branch = RCS_whatbranch (rcs, tag);
else
branch = xstrdup (tag);
@@ -2402,6 +2522,16 @@ RCS_tag2rev (rcs, tag)
}
}
+ /* Try for a real (that is, exists in the RCS deltas) branch
+ (RCS_exist_rev just checks for real revisions and revisions
+ which have tags pointing to them). */
+ pa = RCS_getbranch (rcs, rev, 1);
+ if (pa != NULL)
+ {
+ free (pa);
+ return rev;
+ }
+
/* Tag is branch, but does not exist, try corresponding
* magic branch tag.
*
@@ -2425,7 +2555,7 @@ RCS_tag2rev (rcs, 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))
+ if (tag && STREQ (tag, TAG_HEAD))
return (RCS_head (rcs));
/* If valid tag let translate_symtag say yea or nay. */
@@ -2478,7 +2608,7 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
#endif
return (RCS_head (rcs));
- if (!isdigit (tag[0]))
+ if (!isdigit ((unsigned char) tag[0]))
{
char *version;
@@ -2675,7 +2805,7 @@ RCS_isbranch (rcs, rev)
const char *rev;
{
/* numeric revisions are easy -- even number of dots is a branch */
- if (isdigit (*rev))
+ if (isdigit ((unsigned char) *rev))
return ((numdots (rev) & 1) == 0);
/* assume a revision if you can't find the RCS info */
@@ -2702,7 +2832,7 @@ RCS_nodeisbranch (rcs, rev)
assert (rcs != NULL);
/* numeric revisions are easy -- even number of dots is a branch */
- if (isdigit (*rev))
+ if (isdigit ((unsigned char) *rev))
return ((numdots (rev) & 1) == 0);
version = translate_symtag (rcs, rev);
@@ -2929,7 +3059,7 @@ RCS_branch_head (rcs, rev)
if (RCS_nodeisbranch (rcs, rev))
return RCS_getbranch (rcs, rev, 1);
- if (isdigit (*rev))
+ if (isdigit ((unsigned char) *rev))
num = xstrdup (rev);
else
{
@@ -3101,8 +3231,23 @@ RCS_getdate (rcs, date, force_tag_match)
*/
/* if we found what we're looking for, and it's not 1.1 return it */
- if (cur_rev != NULL && ! STREQ (cur_rev, "1.1"))
- return (xstrdup (cur_rev));
+ if (cur_rev != NULL)
+ {
+ if (! STREQ (cur_rev, "1.1"))
+ return (xstrdup (cur_rev));
+
+ /* This is 1.1; if the date of 1.1 is not the same as that for the
+ 1.1.1.1 version, then return 1.1. This happens when the first
+ version of a file is created by a regular cvs add and commit,
+ and there is a subsequent cvs import of the same file. */
+ p = findnode (rcs->versions, "1.1.1.1");
+ if (p)
+ {
+ vers = (RCSVers *) p->data;
+ if (RCS_datecmp (vers->date, date) != 0)
+ return xstrdup ("1.1");
+ }
+ }
/* look on the vendor branch */
retval = RCS_getdatebranch (rcs, date, CVSBRANCH);
@@ -3454,11 +3599,11 @@ RCS_check_tag (tag)
* characters cannot be non-visible graphic characters, and must not be
* in the set of "invalid" RCS identifier characters.
*/
- if (isalpha (*tag))
+ if (isalpha ((unsigned char) *tag))
{
for (cp = tag; *cp; cp++)
{
- if (!isgraph (*cp))
+ if (!isgraph ((unsigned char) *cp))
error (1, 0, "tag `%s' has non-visible graphic characters",
tag);
if (strchr (invalid, *cp))
@@ -3485,7 +3630,7 @@ RCS_valid_rev (rev)
{
char last, c;
last = *rev++;
- if (!isdigit (last))
+ if (!isdigit ((unsigned char) last))
return 0;
while ((c = *rev++)) /* Extra parens placate -Wall gcc option */
{
@@ -3496,10 +3641,10 @@ RCS_valid_rev (rev)
continue;
}
last = c;
- if (!isdigit (c))
+ if (!isdigit ((unsigned char) c))
return 0;
}
- if (!isdigit (last))
+ if (!isdigit ((unsigned char) last))
return 0;
return 1;
}
@@ -3535,10 +3680,26 @@ char *
RCS_getexpand (rcs)
RCSNode *rcs;
{
+ /* Since RCS_parsercsfile_i now reads expand, don't need to worry
+ about RCS_reparsercsfile. */
assert (rcs != NULL);
return rcs->expand;
}
+/* Set keyword expansion mode to EXPAND. For example "b" for binary. */
+void
+RCS_setexpand (rcs, expand)
+ RCSNode *rcs;
+ char *expand;
+{
+ /* Since RCS_parsercsfile_i now reads expand, don't need to worry
+ about RCS_reparsercsfile. */
+ assert (rcs != NULL);
+ if (rcs->expand != NULL)
+ free (rcs->expand);
+ rcs->expand = xstrdup (expand);
+}
+
/* RCS keywords, and a matching enum. */
struct rcs_keyword
{
@@ -3740,7 +3901,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
/* Look for the first non alphabetic character after the '$'. */
send = srch + srch_len;
for (s = srch; s < send; s++)
- if (! isalpha (*s))
+ if (! isalpha ((unsigned char) *s))
break;
/* If the first non alphabetic character is not '$' or ':',
@@ -3843,7 +4004,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
break;
case KEYWORD_NAME:
- if (name != NULL && ! isdigit (*name))
+ if (name != NULL && ! isdigit ((unsigned char) *name))
value = (char *) name;
else
value = NULL;
@@ -4186,7 +4347,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
: (sout != RUN_TTY ? sout : "(stdout)"))));
}
- assert (rev == NULL || isdigit (*rev));
+ assert (rev == NULL || isdigit ((unsigned char) *rev));
if (noexec && workfile != NULL)
return 0;
@@ -4434,9 +4595,9 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
error (1, 0, "%s:%s has bad `special' newphrase %s",
workfile, vers->version, info->data);
devnum = devnum_long;
- if (strcmp (devtype, "character") == 0)
+ if (STREQ (devtype, "character"))
special_file = S_IFCHR;
- else if (strcmp (devtype, "block") == 0)
+ else if (STREQ (devtype, "block"))
special_file = S_IFBLK;
else
error (0, 0, "%s is a special file of unsupported type `%s'",
@@ -4997,6 +5158,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
struct tm *ftm;
time_t modtime;
int adding_branch = 0;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ struct stat sb;
+#endif
commitpt = NULL;
@@ -5017,40 +5181,11 @@ 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;
- }
- }
+ /* If the filename is a symbolic link, follow it and replace it
+ with the destination of the link. We need to do this before
+ calling rcs_internal_lockfile, or else we won't put the lock in
+ the right place. */
+ resolve_symlink (&(rcs->path));
checkin_quiet = flags & RCS_FLAGS_QUIET;
if (!checkin_quiet)
@@ -5096,7 +5231,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (preserve_perms)
{
Node *np;
- struct stat sb;
char buf[64]; /* static buffer should be safe: see usage. -twp */
delta->other_delta = getlist();
@@ -5195,6 +5329,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
dtext->version = xstrdup (newrev);
bufsize = 0;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms && !S_ISREG (sb.st_mode))
+ /* Pretend file is empty. */
+ bufsize = 0;
+ else
+#endif
get_file (workfile, workfile,
rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
&dtext->text, &bufsize, &dtext->len);
@@ -5277,7 +5417,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
char *branch, *tip, *newrev, *p;
int dots, isrevnum;
- assert (isdigit(*rev));
+ assert (isdigit ((unsigned char) *rev));
newrev = xstrdup (rev);
dots = numdots (newrev);
@@ -5432,6 +5572,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
/* If this revision is being inserted on the trunk, the change text
for the new delta should be the contents of the working file ... */
bufsize = 0;
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ if (preserve_perms && !S_ISREG (sb.st_mode))
+ /* Pretend file is empty. */
+ ;
+ else
+#endif
get_file (workfile, workfile,
rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
&dtext->text, &bufsize, &dtext->len);
@@ -6506,8 +6652,23 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
char *diffbuf;
size_t bufsize, len;
+#if defined (__CYGWIN32__) || defined (_WIN32)
+ /* FIXME: This is an awful kludge, but at least until I have
+ time to work on it a little more and test it, I'd rather
+ give a fatal error than corrupt the file. I think that we
+ need to use "-kb" and "--binary" and "rb" to get_file
+ (probably can do it always, not just for binary files, if
+ we are consistent between the RCS_checkout and the diff). */
+ {
+ char *expand = RCS_getexpand (rcs);
+ if (expand != NULL && STREQ (expand, "b"))
+ error (1, 0,
+ "admin -o not implemented yet for binary on this system");
+ }
+#endif
+
afterfile = cvs_temp_name();
- status = RCS_checkout (rcs, NULL, after, NULL, NULL, afterfile,
+ status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile,
(RCSCHECKOUTPROC)0, NULL);
if (status > 0)
goto delrev_done;
@@ -6535,13 +6696,13 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
else
{
beforefile = cvs_temp_name();
- status = RCS_checkout (rcs, NULL, before, NULL, NULL, beforefile,
+ status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile,
(RCSCHECKOUTPROC)0, NULL);
if (status > 0)
goto delrev_done;
outfile = cvs_temp_name();
- status = diff_exec (beforefile, afterfile, "-n", outfile);
+ status = diff_exec (beforefile, afterfile, "-an", outfile);
if (status == 2)
{
@@ -6991,7 +7152,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
we define a deltafrag as an add or a delete) need to be applied
in reverse order. So we stick them into a linked list. */
struct deltafrag {
- enum {ADD, DELETE} type;
+ enum {FRAG_ADD, FRAG_DELETE} type;
unsigned long pos;
unsigned long nlines;
const char *new_lines;
@@ -7008,7 +7169,8 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
if (op != 'a' && op != 'd')
/* Can't just skip over the deltafrag, because the value
of op determines the syntax. */
- error (1, 0, "unrecognized operation '%c' in %s", op, name);
+ error (1, 0, "unrecognized operation '\\x%x' in %s",
+ op, name);
df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
df->next = dfhead;
dfhead = df;
@@ -7030,7 +7192,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
{
unsigned int i;
- df->type = ADD;
+ df->type = FRAG_ADD;
i = df->nlines;
/* The text we want is the number of lines specified, or
until the end of the value, whichever comes first (it
@@ -7060,7 +7222,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
--df->pos;
assert (op == 'd');
- df->type = DELETE;
+ df->type = FRAG_DELETE;
}
}
@@ -7070,12 +7232,12 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
switch (df->type)
{
- case ADD:
+ case FRAG_ADD:
if (! linevector_add (lines, df->new_lines, df->len, addvers,
df->pos))
return 0;
break;
- case DELETE:
+ case FRAG_DELETE:
if (df->pos > lines->nlines
|| df->pos + df->nlines > lines->nlines)
return 0;
@@ -7534,7 +7696,9 @@ getdelta (rcsbuf, rcsfile, keyp, valp)
/* Make sure that it is a revision number and not a cabbage
or something. */
- for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK since
@@ -7718,7 +7882,9 @@ unable to parse %s; `state' not in the expected place", rcsfile);
continue;
}
/* if we have a new revision number, we're done with this delta */
- for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
+ for (cp = key;
+ (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
+ cp++)
/* do nothing */ ;
/* Note that when comparing with RCSDATE, we are not massaging
VALUE from the string found in the RCS file. This is OK
@@ -8300,6 +8466,30 @@ count_delta_actions (np, ignore)
return 0;
}
+/*
+ * Clean up temporary files
+ */
+static RETSIGTYPE
+rcs_cleanup ()
+{
+ /* Note that the checks for existence_error are because we are
+ called from a signal handler, so we don't know whether the
+ files got created. */
+
+ /* FIXME: Do not perform buffered I/O from an interrupt handler like
+ this (via error). However, I'm leaving the error-calling code there
+ in the hope that on the rare occasion the error call is actually made
+ (e.g., a fluky I/O error or permissions problem prevents the deletion
+ of a just-created file) reentrancy won't be an issue. */
+ if (rcs_lockfile != NULL)
+ {
+ if (unlink_file (rcs_lockfile) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", rcs_lockfile);
+ }
+ rcs_lockfile = NULL;
+}
+
/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
locking on the specified RCSFILE: for a file called `foo,v', open
for writing a file called `,foo,'.
@@ -8324,10 +8514,6 @@ count_delta_actions (np, ignore)
processes from stomping all over each other's laundry. Hence,
they are `internal' locking functions.
- Note that we don't clean up the ,foo, file on ^C. We probably should.
- I'm not completely sure whether RCS does or not (I looked at the code
- a little, and didn't find it).
-
If there is an error, give a fatal error; if we return we always
return a non-NULL value. */
@@ -8335,13 +8521,35 @@ static FILE *
rcs_internal_lockfile (rcsfile)
char *rcsfile;
{
- char *lockfile;
int fd;
struct stat rstat;
FILE *fp;
+ static int first_call = 1;
+
+ if (first_call)
+ {
+ first_call = 0;
+ /* clean up if we get a signal */
+#ifdef SIGHUP
+ (void) SIG_register (SIGHUP, rcs_cleanup);
+#endif
+#ifdef SIGINT
+ (void) SIG_register (SIGINT, rcs_cleanup);
+#endif
+#ifdef SIGQUIT
+ (void) SIG_register (SIGQUIT, rcs_cleanup);
+#endif
+#ifdef SIGPIPE
+ (void) SIG_register (SIGPIPE, rcs_cleanup);
+#endif
+#ifdef SIGTERM
+ (void) SIG_register (SIGTERM, rcs_cleanup);
+#endif
+ }
/* Get the lock file name: `,file,' for RCS file `file,v'. */
- lockfile = rcs_lockfilename (rcsfile);
+ assert (rcs_lockfile == NULL);
+ rcs_lockfile = rcs_lockfilename (rcsfile);
/* Use the existing RCS file mode, or read-only if this is a new
file. (Really, this is a lie -- if this is a new file,
@@ -8367,12 +8575,13 @@ rcs_internal_lockfile (rcsfile)
rely on O_EXCL these days. This might be true for unix (I
don't really know), but I am still pretty skeptical in the case
of the non-unix systems. */
- fd = open (lockfile, OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
+ fd = open (rcs_lockfile,
+ OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
S_IRUSR | S_IRGRP | S_IROTH);
if (fd < 0)
{
- error (1, errno, "could not open lock file `%s'", lockfile);
+ error (1, errno, "could not open lock file `%s'", rcs_lockfile);
}
/* Force the file permissions, and return a stream object. */
@@ -8380,13 +8589,11 @@ rcs_internal_lockfile (rcsfile)
this in the non-HAVE_FCHMOD case. */
#ifdef HAVE_FCHMOD
if (fchmod (fd, rstat.st_mode) < 0)
- error (1, errno, "cannot change mode for %s", lockfile);
+ error (1, errno, "cannot change mode for %s", rcs_lockfile);
#endif
fp = fdopen (fd, FOPEN_BINARY_WRITE);
if (fp == NULL)
- error (1, errno, "cannot fdopen %s", lockfile);
-
- free (lockfile);
+ error (1, errno, "cannot fdopen %s", rcs_lockfile);
return fp;
}
@@ -8396,10 +8603,7 @@ rcs_internal_unlockfile (fp, rcsfile)
FILE *fp;
char *rcsfile;
{
- char *lockfile;
-
- /* Get the lock file name: `,file,' for RCS file `file,v'. */
- lockfile = rcs_lockfilename (rcsfile);
+ assert (rcs_lockfile != NULL);
/* Abort if we could not write everything successfully to LOCKFILE.
This is not a great error-handling mechanism, but should prevent
@@ -8412,12 +8616,21 @@ rcs_internal_unlockfile (fp, rcsfile)
fragile even if it happens to sometimes be true. The real
solution is to check each call to fprintf rather than waiting
until the end like this. */
- error (1, 0, "error writing to lock file %s", lockfile);
+ error (1, 0, "error writing to lock file %s", rcs_lockfile);
if (fclose (fp) == EOF)
- error (1, errno, "error closing lock file %s", lockfile);
+ error (1, errno, "error closing lock file %s", rcs_lockfile);
- rename_file (lockfile, rcsfile);
- free (lockfile);
+ rename_file (rcs_lockfile, rcsfile);
+
+ {
+ /* Use a temporary to make sure there's no interval
+ (after rcs_lockfile has been freed but before it's set to NULL)
+ during which the signal handler's use of rcs_lockfile would
+ reference freed memory. */
+ char *tmp = rcs_lockfile;
+ rcs_lockfile = NULL;
+ free (tmp);
+ }
}
static char *
@@ -8460,6 +8673,9 @@ RCS_rewrite (rcs, newdtext, insertpt)
if (noexec)
return;
+ /* Make sure we're operating on an actual file and not a symlink. */
+ resolve_symlink (&(rcs->path));
+
fout = rcs_internal_lockfile (rcs->path);
RCS_putadmin (rcs, fout);
@@ -8538,8 +8754,8 @@ annotate_fileproc (callerdat, finfo)
cvs_outerr (finfo->fullname, 0);
cvs_outerr ("\n***************\n", 0);
- RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, (char **) NULL,
- (size_t) NULL, (char **) NULL, (size_t *) NULL);
+ RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL,
+ NULL, NULL, NULL);
free (version);
return 0;
}
@@ -8612,8 +8828,8 @@ annotate (argc, argv)
option_with_arg ("-r", tag);
if (date)
client_senddate (date);
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("annotate\012", 0);
return get_responses_and_close ();
}
@@ -8649,7 +8865,7 @@ make_file_label (path, rev, rcs)
char *file;
file = last_component (path);
- label = (char *) xmalloc (strlen (file)
+ label = (char *) xmalloc (strlen (path)
+ (rev == NULL ? 0 : strlen (rev))
+ 50);
@@ -8658,7 +8874,7 @@ make_file_label (path, rev, rcs)
char *date;
RCS_getrevtime (rcs, rev, datebuf, 0);
date = printable_date (datebuf);
- (void) sprintf (label, "-L%s\t%s\t%s", file, date, rev);
+ (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev);
free (date);
}
else
@@ -8675,9 +8891,8 @@ make_file_label (path, rev, rcs)
wm->tm_year + 1900, wm->tm_mon + 1,
wm->tm_mday, wm->tm_hour,
wm->tm_min, wm->tm_sec);
- (void) sprintf (label, "-L%s\t%s", file, datebuf);
+ (void) sprintf (label, "-L%s\t%s", path, datebuf);
}
}
return label;
}
-
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index f92988f..0a28161 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -184,6 +184,7 @@ RCSNode *RCS_parse PROTO((const char *file, const char *repos));
RCSNode *RCS_parsercsfile PROTO((char *rcsfile));
void RCS_fully_parse PROTO((RCSNode *));
void RCS_reparsercsfile PROTO((RCSNode *, FILE **, struct rcsbuffer *));
+extern int RCS_setattic PROTO ((RCSNode *, int));
char *RCS_check_kflag PROTO((const char *arg));
char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
@@ -211,6 +212,7 @@ char *RCS_branch_head PROTO ((RCSNode *rcs, char *rev));
int RCS_isdead PROTO((RCSNode *, const char *));
char *RCS_getexpand PROTO ((RCSNode *));
+void RCS_setexpand PROTO ((RCSNode *, char *));
int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *,
RCSCHECKOUTPROC, void *));
int RCS_checkin PROTO ((RCSNode *rcs, char *workfile, char *message,
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index f889233..ab94e40 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -147,7 +147,8 @@ call_diff_write_output (text, len)
const char *text;
size_t len;
{
- cvs_output (text, len);
+ if (len > 0)
+ cvs_output (text, len);
}
/* Call back function for the diff library to flush the output file.
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index d88bf2b..e93afbf 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,23 +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.
@@ -127,6 +107,9 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
int dosrcs;
{
int i, err = 0;
+#ifdef CLIENT_SUPPORT
+ List *args_to_send_when_finished = NULL;
+#endif
List *files_by_dir = NULL;
struct recursion_frame frame;
@@ -169,6 +152,29 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
if (argc == 0)
{
+ int just_subdirs = (which & W_LOCAL) && !isdir (CVSADM);
+
+#ifdef CLIENT_SUPPORT
+ if (!just_subdirs
+ && CVSroot_cmdline == NULL
+ && client_active)
+ {
+ char *root = Name_Root (NULL, update_dir);
+ if (root && strcmp (root, current_root) != 0)
+ /* We're skipping this directory because it is for
+ a different root. Therefore, we just want to
+ do the subdirectories only. Processing files would
+ cause a working directory from one repository to be
+ processed against a different repository, which could
+ cause all kinds of spurious conflicts and such.
+
+ Question: what about the case of "cvs update foo"
+ where we process foo/bar and not foo itself? That
+ seems to be handled somewhere (else) but why should
+ it be a separate case? Needs investigation... */
+ just_subdirs = 1;
+ }
+#endif
/*
* There were no arguments, so we'll probably just recurse. The
@@ -177,7 +183,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
* process each of the sub-directories, so we pretend like we were
* called with the list of sub-dirs of the current dir as args
*/
- if ((which & W_LOCAL) && !isdir (CVSADM))
+ if (just_subdirs)
{
dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL);
/* If there are no sub-directories, there is a certain logic in
@@ -204,17 +210,21 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
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);
+ generalizes to other commands. */
+
+ /* This is the same call to Find_Directories as above.
+ FIXME: perhaps it would be better to write a
+ function that duplicates a list. */
+ args_to_send_when_finished = Find_Directories ((char *) NULL,
+ W_LOCAL,
+ (List *) NULL);
}
#endif
}
else
addlist (&dirlist, ".");
- err += do_recursion (&frame);
- goto out;
+ goto do_the_work;
}
@@ -335,14 +345,146 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
/* then do_recursion on the dirlist. */
if (dirlist != NULL)
+ {
+ do_the_work:
err += do_recursion (&frame);
-
+ }
+
/* Free the data which expand_wild allocated. */
free_names (&argc, argv);
- out:
free (update_dir);
update_dir = NULL;
+
+#ifdef CLIENT_SUPPORT
+ if (args_to_send_when_finished != NULL)
+ {
+ /* FIXME (njc): in the multiroot case, we don't want to send
+ argument commands for those top-level directories which do
+ not contain any subdirectories which have files checked out
+ from current_root. If we do, and two repositories have a
+ module with the same name, nasty things could happen.
+
+ This is hard. Perhaps we should send the Argument commands
+ later in this procedure, after we've had a chance to notice
+ which directores we're using (after do_recursion has been
+ called once). This means a _lot_ of rewriting, however.
+
+ What we need to do for that to happen is descend the tree
+ and construct a list of directories which are checked out
+ from current_cvsroot. Now, we eliminate from the list all
+ of those directories which are immediate subdirectories of
+ another directory in the list. To say that the opposite
+ way, we keep the directories which are not immediate
+ subdirectories of any other in the list. Here's a picture:
+
+ a
+ / \
+ B C
+ / \
+ D e
+ / \
+ F G
+ / \
+ H I
+
+ The node in capitals are those directories which are
+ checked out from current_cvsroot. We want the list to
+ contain B, C, F, and G. D, H, and I are not included,
+ because their parents are also checked out from
+ current_cvsroot.
+
+ The algorithm should be:
+
+ 1) construct a tree of all directory names where each
+ element contains a directory name and a flag which notes if
+ that directory is checked out from current_cvsroot
+
+ a0
+ / \
+ B1 C1
+ / \
+ D1 e0
+ / \
+ F1 G1
+ / \
+ H1 I1
+
+ 2) Recursively descend the tree. For each node, recurse
+ before processing the node. If the flag is zero, do
+ nothing. If the flag is 1, check the node's parent. If
+ the parent's flag is one, change the current entry's flag
+ to zero.
+
+ a0
+ / \
+ B1 C1
+ / \
+ D0 e0
+ / \
+ F1 G1
+ / \
+ H0 I0
+
+ 3) Walk the tree and spit out "Argument" commands to tell
+ the server which directories to munge.
+
+ Yuck. It's not clear this is worth spending time on, since
+ we might want to disable cvs commands entirely from
+ directories that do not have CVSADM files...
+
+ Anyways, the solution as it stands has modified server.c
+ (dirswitch) to create admin files [via server.c
+ (create_adm_p)] in all path elements for a client's
+ "Directory xxx" command, which forces the server to descend
+ and serve the files there. client.c (send_file_names) has
+ also been modified to send only those arguments which are
+ appropriate to current_root.
+
+ */
+
+ /* Construct a fake argc/argv pair. */
+
+ int our_argc = 0, i;
+ char **our_argv = NULL;
+
+ if (! list_isempty (args_to_send_when_finished))
+ {
+ Node *head, *p;
+
+ head = args_to_send_when_finished->list;
+
+ /* count the number of nodes */
+ i = 0;
+ for (p = head->next; p != head; p = p->next)
+ i++;
+ our_argc = i;
+
+ /* create the argument vector */
+ our_argv = (char **) xmalloc (sizeof (char *) * our_argc);
+
+ /* populate it */
+ i = 0;
+ for (p = head->next; p != head; p = p->next)
+ our_argv[i++] = xstrdup (p->key);
+ }
+
+ /* We don't want to expand widcards, since we've just created
+ a list of directories directly from the filesystem. */
+ send_file_names (our_argc, our_argv, 0);
+
+ /* Free our argc/argv. */
+ if (our_argv != NULL)
+ {
+ for (i = 0; i < our_argc; i++)
+ free (our_argv[i]);
+ free (our_argv);
+ }
+
+ dellist (&args_to_send_when_finished);
+ }
+#endif
+
return (err);
}
@@ -359,6 +501,7 @@ do_recursion (frame)
char *srepository;
List *entries = NULL;
int should_readlock;
+ int process_this_directory = 1;
/* do nothing if told */
if (frame->flags == R_SKIP_ALL)
@@ -410,6 +553,57 @@ do_recursion (frame)
server_pause_check();
#endif
+ /* Check the value in CVSADM_ROOT and see if it's in the list. If
+ not, add it to our lists of CVS/Root directories and do not
+ process the files in this directory. Otherwise, continue as
+ usual. THIS_ROOT might be NULL if we're doing an initial
+ checkout -- check before using it. The default should be that
+ we process a directory's contents and only skip those contents
+ if a CVS/Root file exists.
+
+ If we're running the server, we want to process all
+ directories, since we're guaranteed to have only one CVSROOT --
+ our own. */
+
+ if (
+ /* If -d was specified, it should override CVS/Root.
+
+ In the single-repository case, it is long-standing CVS behavior
+ and makes sense - the user might want another access method,
+ another server (which mounts the same repository), &c.
+
+ In the multiple-repository case, -d overrides all CVS/Root
+ files. That is the only plausible generalization I can
+ think of. */
+ CVSroot_cmdline == NULL
+
+#ifdef SERVER_SUPPORT
+ && ! server_active
+#endif
+ )
+ {
+ char *this_root = Name_Root ((char *) NULL, update_dir);
+ if (this_root != NULL)
+ {
+ if (findnode (root_directories, this_root) == NULL)
+ {
+ /* Add it to our list. */
+
+ Node *n = getnode ();
+ n->type = UNKNOWN;
+ n->key = xstrdup (this_root);
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add new CVSROOT %s", this_root);
+
+ }
+
+ process_this_directory = (strcmp (current_root, this_root) == 0);
+
+ free (this_root);
+ }
+ }
+
/*
* Fill in repository with the current repository
*/
@@ -468,12 +662,26 @@ do_recursion (frame)
repository = Name_Repository ((char *) NULL, update_dir);
/* find the files and fill in entries if appropriate */
- filelist = Find_Names (repository, lwhich, frame->aflag, &entries);
+ if (process_this_directory)
+ {
+ filelist = Find_Names (repository, lwhich, frame->aflag,
+ &entries);
+ if (filelist == NULL)
+ {
+ error (0, 0, "skipping directory %s", update_dir);
+ /* Note that Find_Directories and the filesdoneproc
+ in particular would do bad things ("? foo.c" in
+ the case of some filesdoneproc's). */
+ goto skip_directory;
+ }
+ }
}
/* find sub-directories if we will recurse */
if (frame->flags != R_SKIP_DIRS)
- dirlist = Find_Directories (repository, frame->which, entries);
+ dirlist = Find_Directories (
+ process_this_directory ? repository : NULL,
+ frame->which, entries);
}
else
{
@@ -487,7 +695,7 @@ do_recursion (frame)
}
/* process the files (if any) */
- if (filelist != NULL && frame->fileproc)
+ if (process_this_directory && filelist != NULL && frame->fileproc)
{
struct file_info finfo_struct;
struct frame_and_file frfile;
@@ -525,11 +733,12 @@ do_recursion (frame)
}
/* call-back files done proc (if any) */
- if (dodoneproc && frame->filesdoneproc != NULL)
+ if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL)
err = frame->filesdoneproc (frame->callerdat, err, repository,
update_dir[0] ? update_dir : ".",
entries);
+ skip_directory:
fileattr_write ();
fileattr_free ();
@@ -589,7 +798,24 @@ do_file_proc (p, closure)
strcat (finfo->fullname, finfo->file);
if (frfile->frame->dosrcs && repository)
+ {
finfo->rcs = RCS_parse (finfo->file, repository);
+
+ /* OK, without W_LOCAL the error handling becomes relatively
+ simple. The file names came from readdir() on the
+ repository and so we know any ENOENT is an error
+ (e.g. symlink pointing to nothing). Now, the logic could
+ be simpler - since we got the name from readdir, we could
+ just be calling RCS_parsercsfile. */
+ if (finfo->rcs == NULL
+ && !(frfile->frame->which & W_LOCAL))
+ {
+ error (0, 0, "could not read RCS file for %s", finfo->fullname);
+ free (finfo->fullname);
+ cvs_flushout ();
+ return 0;
+ }
+ }
else
finfo->rcs = (RCSNode *) NULL;
ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo);
@@ -625,6 +851,7 @@ do_dir_proc (p, closure)
int err = 0;
struct saved_cwd cwd;
char *saved_update_dir;
+ int process_this_directory = 1;
if (fncmp (dir, CVSADM) == 0)
{
@@ -760,12 +987,62 @@ but CVS uses %s for its own purposes; skipping %s directory",
free (cvsadmdir);
}
+ /* Only process this directory if the root matches. This nearly
+ duplicates code in do_recursion. */
+
+ if (
+ /* If -d was specified, it should override CVS/Root.
+
+ In the single-repository case, it is long-standing CVS behavior
+ and makes sense - the user might want another access method,
+ another server (which mounts the same repository), &c.
+
+ In the multiple-repository case, -d overrides all CVS/Root
+ files. That is the only plausible generalization I can
+ think of. */
+ CVSroot_cmdline == NULL
+
+#ifdef SERVER_SUPPORT
+ && ! server_active
+#endif
+ )
+ {
+ char *this_root = Name_Root (dir, update_dir);
+ if (this_root != NULL)
+ {
+ if (findnode (root_directories, this_root) == NULL)
+ {
+ /* Add it to our list. */
+
+ Node *n = getnode ();
+ n->type = UNKNOWN;
+ n->key = xstrdup (this_root);
+
+ if (addnode (root_directories, n))
+ error (1, 0, "cannot add new CVSROOT %s", this_root);
+
+ }
+
+ process_this_directory = (strcmp (current_root, this_root) == 0);
+ free (this_root);
+ }
+ }
+
/* call-back dir entry proc (if any) */
if (dir_return == R_SKIP_ALL)
;
else if (frame->direntproc != NULL)
- dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
- update_dir, frent->entries);
+ {
+ /* If we're doing the actual processing, call direntproc.
+ Otherwise, assume that we need to process this directory
+ and recurse. FIXME. */
+
+ if (process_this_directory)
+ dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
+ update_dir, frent->entries);
+ else
+ dir_return = R_PROCESS;
+ }
else
{
/* Generic behavior. I don't see a reason to make the caller specify
@@ -811,7 +1088,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
(void) strcpy (update_dir, ".");
/* call-back dir leave proc (if any) */
- if (frame->dirleaveproc != NULL)
+ if (process_this_directory && frame->dirleaveproc != NULL)
err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
frent->entries);
diff --git a/contrib/cvs/src/release.c b/contrib/cvs/src/release.c
index 82429e0..ca7945b 100644
--- a/contrib/cvs/src/release.c
+++ b/contrib/cvs/src/release.c
@@ -6,10 +6,9 @@
*/
#include "cvs.h"
+#include "savecwd.h"
#include "getline.h"
-static void release_delete PROTO((char *dir));
-
static const char *const release_usage[] =
{
"Usage: %s %s [-d] directories...\n",
@@ -76,6 +75,7 @@ release (argc, argv)
int arg_start_idx;
int err = 0;
short delete_flag = 0;
+ struct saved_cwd cwd;
#ifdef SERVER_SUPPORT
if (server_active)
@@ -111,6 +111,10 @@ release (argc, argv)
/* We're going to run "cvs -n -q update" and check its output; if
* the output is sufficiently unalarming, then we release with no
* questions asked. Else we prompt, then maybe release.
+ * (Well, actually we ask no matter what. Our notion of "sufficiently
+ * unalarming" doesn't take into account "? foo.c" files, so it is
+ * up to the user to take note of them, at least currently
+ * (ignore-193 in testsuite)).
*/
/* Construct the update command. */
update_cmd = xmalloc (strlen (program_path)
@@ -128,6 +132,12 @@ release (argc, argv)
}
#endif /* CLIENT_SUPPORT */
+ /* Remember the directory where "cvs release" was invoked because
+ all args are relative to this directory and we chdir around.
+ */
+ if (save_cwd (&cwd))
+ error_exit ();
+
arg_start_idx = 0;
for (i = arg_start_idx; i < argc; i++)
@@ -146,6 +156,8 @@ release (argc, argv)
{
if (!really_quiet)
error (0, 0, "no repository directory: %s", thisarg);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
continue;
}
}
@@ -190,6 +202,9 @@ release (argc, argv)
if ((pclose (fp)) != 0)
{
error (0, 0, "unable to release `%s'", thisarg);
+ free (repository);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
continue;
}
@@ -203,6 +218,8 @@ release (argc, argv)
(void) fprintf (stderr, "** `%s' aborted by user choice.\n",
command_name);
free (repository);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
continue;
}
}
@@ -239,7 +256,19 @@ release (argc, argv)
}
free (repository);
- if (delete_flag) release_delete (thisarg);
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+
+ if (delete_flag)
+ {
+ /* FIXME? Shouldn't this just delete the CVS-controlled
+ files and, perhaps, the files that would normally be
+ ignored and leave everything else? */
+
+ if (unlink_file_dir (thisarg) < 0)
+ error (0, errno, "deletion of directory %s failed", thisarg);
+ }
#ifdef CLIENT_SUPPORT
if (client_active)
@@ -247,6 +276,10 @@ release (argc, argv)
#endif /* CLIENT_SUPPORT */
}
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
+
#ifdef CLIENT_SUPPORT
if (client_active)
{
@@ -264,37 +297,3 @@ release (argc, argv)
free (line);
return err;
}
-
-
-/* We want to "rm -r" the working directory, but let us be a little
- paranoid. */
-static void
-release_delete (dir)
- char *dir;
-{
- struct stat st;
- ino_t ino;
-
- (void) CVS_STAT (".", &st);
- ino = st.st_ino;
- (void) CVS_CHDIR ("..");
- (void) CVS_STAT (dir, &st);
- if (ino != st.st_ino)
- {
- /* This test does not work on cygwin32, because under cygwin32
- the st_ino field is not the same when you refer to a file
- by a different name. This is a cygwin32 bug, but then I
- don't see what the point of this test is anyhow. */
-#ifndef __CYGWIN32__
- error (0, 0,
- "Parent dir on a different disk, delete of %s aborted", dir);
- return;
-#endif
- }
- /*
- * XXX - shouldn't this just delete the CVS-controlled files and, perhaps,
- * the files that would normally be ignored and leave everything else?
- */
- if (unlink_file_dir (dir) < 0)
- error (0, errno, "deletion of directory %s failed", dir);
-}
diff --git a/contrib/cvs/src/remove.c b/contrib/cvs/src/remove.c
index 9ed32d7..2dacdf1 100644
--- a/contrib/cvs/src/remove.c
+++ b/contrib/cvs/src/remove.c
@@ -100,9 +100,9 @@ cvsremove (argc, argv)
ign_setup ();
if (local)
send_arg("-l");
- send_file_names (argc, argv, 0);
/* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */
send_files (argc, argv, local, 0, 0);
+ send_file_names (argc, argv, 0);
send_to_server ("remove\012", 0);
return get_responses_and_close ();
}
@@ -200,7 +200,9 @@ remove_fileproc (callerdat, finfo)
+ sizeof (CVSEXT_LOG)
+ 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
- (void) unlink_file (fname);
+ if (unlink_file (fname) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", CVSEXT_LOG);
if (!quiet)
error (0, 0, "removed `%s'", finfo->fullname);
@@ -216,7 +218,7 @@ remove_fileproc (callerdat, finfo)
error (0, 0, "file `%s' already scheduled for removal",
finfo->fullname);
}
- else if (vers->tag != NULL && isdigit (*vers->tag))
+ else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag))
{
/* Commit will just give an error, and so there seems to be
little reason to allow the remove. I mean, conflicts that
diff --git a/contrib/cvs/src/root.c b/contrib/cvs/src/root.c
index 050e168..d88c6f4 100644
--- a/contrib/cvs/src/root.c
+++ b/contrib/cvs/src/root.c
@@ -7,8 +7,6 @@
* Name of Root
*
* Determine the path to the CVSROOT and set "Root" accordingly.
- * If this looks like of modified clone of Name_Repository() in
- * repos.c, it is...
*/
#include "cvs.h"
@@ -18,7 +16,7 @@
Watch out if the enum is changed in cvs.h! */
char *method_names[] = {
- "local", "server (rsh)", "pserver", "kserver", "gserver", "ext"
+ "local", "server (rsh)", "pserver", "kserver", "gserver", "ext", "fork"
};
#ifndef DEBUG
@@ -268,6 +266,11 @@ error 0 Server configuration missing --allow-root in inetd.conf\n");
return 0;
}
+/* This global variable holds the global -d option. It is NULL if -d
+ was not used, which means that we must get the CVSroot information
+ from the CVSROOT environment variable or from a CVS/Root file. */
+
+char *CVSroot_cmdline;
/* Parse a CVSROOT variable into its constituent parts -- method,
* username, hostname, directory. The prototypical CVSROOT variable
@@ -287,30 +290,6 @@ char *CVSroot_username; /* the username or NULL if method == local */
char *CVSroot_hostname; /* the hostname or NULL if method == local */
char *CVSroot_directory; /* the directory name */
-#ifdef AUTH_SERVER_SUPPORT
-/* Die if CVSroot_directory and Pserver_Repos don't match. */
-static void
-check_root_consistent ()
-{
- /* FIXME: Should be using a deferred error, as the rest of
- serve_root does. As it is now the call to error could conceivably
- cause deadlock, as noted in server_cleanup. Best solution would
- presumably be to write some code so that error() automatically
- defers the error in those cases where that is needed. */
- /* FIXME? Possible that the wording should be more clear (e.g.
- Root says "%s" but pserver protocol says "%s"
- or something which would aid people who are writing implementations
- of the client side of the CVS protocol. I don't see any security
- problem with revealing that information. */
- if ((Pserver_Repos != NULL) && (CVSroot_directory != NULL))
- if (strcmp (Pserver_Repos, CVSroot_directory) != 0)
- error (1, 0, "repository mismatch: \"%s\" vs \"%s\"",
- Pserver_Repos, CVSroot_directory);
-}
-
-#endif /* AUTH_SERVER_SUPPORT */
-
-
int
parse_cvsroot (CVSroot)
char *CVSroot;
@@ -335,8 +314,9 @@ parse_cvsroot (CVSroot)
/* Access method specified, as in
* "cvs -d :pserver:user@host:/path",
- * "cvs -d :local:e:\path", or
- * "cvs -d :kserver:user@host:/path".
+ * "cvs -d :local:e:\path",
+ * "cvs -d :kserver:user@host:/path", or
+ * "cvs -d :fork:/path".
* We need to get past that part of CVSroot before parsing the
* rest of it.
*/
@@ -363,6 +343,8 @@ parse_cvsroot (CVSroot)
CVSroot_method = server_method;
else if (strcmp (method, "ext") == 0)
CVSroot_method = ext_method;
+ else if (strcmp (method, "fork") == 0)
+ CVSroot_method = fork_method;
else
{
error (0, 0, "unknown method in CVSroot: %s", CVSroot);
@@ -391,7 +373,8 @@ parse_cvsroot (CVSroot)
CVSroot_username = NULL;
CVSroot_hostname = NULL;
- if (CVSroot_method != local_method)
+ if ((CVSroot_method != local_method)
+ && (CVSroot_method != fork_method))
{
/* Check to see if there is a username in the string. */
@@ -416,9 +399,6 @@ parse_cvsroot (CVSroot)
}
CVSroot_directory = cvsroot_copy;
-#ifdef AUTH_SERVER_SUPPORT
- check_root_consistent ();
-#endif /* AUTH_SERVER_SUPPORT */
#if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG)
if (CVSroot_method != local_method)
@@ -442,10 +422,12 @@ parse_cvsroot (CVSroot)
switch (CVSroot_method)
{
case local_method:
+ case fork_method:
if (CVSroot_username || CVSroot_hostname)
{
error (0, 0, "can't specify hostname and username in CVSROOT");
- error (0, 0, "when using local access method");
+ error (0, 0, "when using %s access method",
+ CVSroot_method == local_method ? "local" : "fork");
error (0, 0, "(%s)", CVSroot);
return 1;
}
@@ -464,18 +446,20 @@ parse_cvsroot (CVSroot)
error (0, 0, "but your CVS executable doesn't support it");
error (0, 0, "(%s)", CVSroot);
return 1;
-#endif
+#else
check_hostname = 1;
break;
+#endif
case gserver_method:
#ifndef HAVE_GSSAPI
error (0, 0, "Your CVSROOT is set for a GSSAPI access method");
error (0, 0, "but your CVS executable doesn't support it");
error (0, 0, "(%s)", CVSroot);
return 1;
-#endif
+#else
check_hostname = 1;
break;
+#endif
case server_method:
case ext_method:
case pserver_method:
@@ -504,18 +488,17 @@ parse_cvsroot (CVSroot)
/* Set up the global CVSroot* variables as if we're using the local
- repository DIR. */
+ repository DIR. DIR must point to storage which will last for the
+ rest of the CVS invocation (for example, the caller might malloc it
+ and never free it, or free it just before exiting CVS). */
void
set_local_cvsroot (dir)
char *dir;
{
- CVSroot_original = xstrdup (dir);
+ CVSroot_original = dir;
CVSroot_method = local_method;
CVSroot_directory = CVSroot_original;
-#ifdef AUTH_SERVER_SUPPORT
- check_root_consistent ();
-#endif /* AUTH_SERVER_SUPPORT */
CVSroot_username = NULL;
CVSroot_hostname = NULL;
client_active = 0;
@@ -523,7 +506,11 @@ set_local_cvsroot (dir)
#ifdef DEBUG
-/* This is for testing the parsing function. */
+/* This is for testing the parsing function. Use
+
+ gcc -I. -I.. -I../lib -DDEBUG root.c -o root
+
+ to compile. */
#include <stdio.h>
@@ -531,6 +518,30 @@ char *CVSroot;
char *program_name = "testing";
char *command_name = "parse_cvsroot"; /* XXX is this used??? */
+/* Toy versions of various functions when debugging under unix. Yes,
+ these make various bad assumptions, but they're pretty easy to
+ debug when something goes wrong. */
+
+void
+error_exit PROTO ((void))
+{
+ exit (1);
+}
+
+char *
+xstrdup (str)
+ const char *str;
+{
+ return strdup (str);
+}
+
+int
+isabsolute (dir)
+ const char *dir;
+{
+ return (dir && (*dir == '/'));
+}
+
void
main (argc, argv)
int argc;
@@ -546,7 +557,7 @@ main (argc, argv)
if (parse_cvsroot (argv[1]))
{
- fprintf (stderr, "%s: Parsing failed.", program_name);
+ fprintf (stderr, "%s: Parsing failed.\n", program_name);
exit (1);
}
printf ("CVSroot: %s\n", argv[1]);
diff --git a/contrib/cvs/src/rtag.c b/contrib/cvs/src/rtag.c
index 3207c1b..5fd825f 100644
--- a/contrib/cvs/src/rtag.c
+++ b/contrib/cvs/src/rtag.c
@@ -64,7 +64,7 @@ static int force_tag_move; /* don't move existing tags by default *
static const char *const rtag_usage[] =
{
- "Usage: %s %s [-aflRnF] [-b] [-d] [-r tag|-D date] tag modules...\n",
+ "Usage: %s %s [-aflRnF] [-b] [-d] [-r rev|-D date] tag modules...\n",
"\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
@@ -388,9 +388,16 @@ check_fileproc (callerdat, finfo)
{
if (delete_flag)
{
+ /* Deleting a tag which did not exist is a noop and
+ should not be logged. */
addit = 0;
}
}
+ else if (delete_flag)
+ {
+ free (p->data);
+ p->data = xstrdup (oversion);
+ }
else if (strcmp(oversion, p->data) == 0)
{
addit = 0;
@@ -458,7 +465,7 @@ pretag_proc(repository, filter)
s = xstrdup(filter);
for (cp=s; *cp; cp++)
{
- if (isspace(*cp))
+ if (isspace ((unsigned char) *cp))
{
*cp = '\0';
break;
@@ -583,7 +590,9 @@ rtag_fileproc (callerdat, finfo)
}
return (0);
}
- if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0)
+ if (numtag
+ && isdigit ((unsigned char) *numtag)
+ && strcmp (numtag, version) != 0)
{
/*
diff --git a/contrib/cvs/src/run.c b/contrib/cvs/src/run.c
index dc35a78..41f4457 100644
--- a/contrib/cvs/src/run.c
+++ b/contrib/cvs/src/run.c
@@ -175,10 +175,11 @@ run_exec (stin, stout, sterr, flags)
/* The output files, if any, are now created. Do the fork and dups.
- We use vfork not so much for the sake of unices without
- copy-on-write (such systems are rare these days), but for the
- sake of systems without an MMU, which therefore can't do
- copy-on-write (e.g. Amiga). The other solution is spawn (see
+ We use vfork not so much for a performance boost (the
+ performance boost, if any, is modest on most modern unices),
+ but for the sake of systems without a memory management unit,
+ which find it difficult or impossible to implement fork at all
+ (e.g. Amiga). The other solution is spawn (see
windows-NT/run.c). */
#ifdef HAVE_VFORK
@@ -365,12 +366,8 @@ run_popen (cmd, mode)
const char *mode;
{
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> run_popen(%s,%s)\n",
- (server_active) ? 'S' : ' ', cmd, mode);
-#else
- (void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode);
-#endif
+ (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n",
+ CLIENT_SERVER_STR, cmd, mode);
if (noexec)
return (NULL);
@@ -409,21 +406,21 @@ piped_child (command, tofdp, fromfdp)
if (pid == 0)
{
if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0)
- error (1, errno, "cannot dup2");
+ error (1, errno, "cannot dup2 pipe");
if (close (to_child_pipe[1]) < 0)
- error (1, errno, "cannot close");
+ error (1, errno, "cannot close pipe");
if (close (from_child_pipe[0]) < 0)
- error (1, errno, "cannot close");
+ error (1, errno, "cannot close pipe");
if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0)
- error (1, errno, "cannot dup2");
+ error (1, errno, "cannot dup2 pipe");
execvp (command[0], command);
- error (1, errno, "cannot exec");
+ error (1, errno, "cannot exec %s", command[0]);
}
if (close (to_child_pipe[0]) < 0)
- error (1, errno, "cannot close");
+ error (1, errno, "cannot close pipe");
if (close (from_child_pipe[1]) < 0)
- error (1, errno, "cannot close");
+ error (1, errno, "cannot close pipe");
*tofdp = to_child_pipe[1];
*fromfdp = from_child_pipe[0];
@@ -436,81 +433,7 @@ close_on_exec (fd)
int fd;
{
#if defined (FD_CLOEXEC) && defined (F_SETFD)
- if (fcntl (fd, F_SETFD, 1))
- error (1, errno, "can't set close-on-exec flag on %d", fd);
+ if (fcntl (fd, F_SETFD, 1))
+ error (1, errno, "can't set close-on-exec flag on %d", fd);
#endif
}
-
-/*
- * dir = 0 : main proc writes to new proc, which writes to oldfd
- * dir = 1 : main proc reads from new proc, which reads from oldfd
- *
- * Returns: a file descriptor. On failure (i.e., the exec fails),
- * then filter_stream_through_program() complains and dies.
- */
-
-int
-filter_stream_through_program (oldfd, dir, prog, pidp)
- int oldfd, dir;
- char **prog;
- pid_t *pidp;
-{
- int p[2], newfd;
- pid_t newpid;
-
- if (pipe (p))
- error (1, errno, "cannot create pipe");
-#ifdef USE_SETMODE_BINARY
- setmode (p[0], O_BINARY);
- setmode (p[1], O_BINARY);
-#endif
-
-#ifdef HAVE_VFORK
- newpid = vfork ();
-#else
- newpid = fork ();
-#endif
- if (pidp)
- *pidp = newpid;
- switch (newpid)
- {
- case -1:
- error (1, errno, "cannot fork");
- case 0:
- /* child */
- if (dir)
- {
- /* write to new pipe */
- close (p[0]);
- dup2 (oldfd, 0);
- dup2 (p[1], 1);
- }
- else
- {
- /* read from new pipe */
- close (p[1]);
- dup2 (p[0], 0);
- dup2 (oldfd, 1);
- }
- /* Should I be blocking some signals here? */
- execvp (prog[0], prog);
- error (1, errno, "couldn't exec %s", prog[0]);
- default:
- /* parent */
- close (oldfd);
- if (dir)
- {
- /* read from new pipe */
- close (p[1]);
- newfd = p[0];
- }
- else
- {
- /* write to new pipe */
- close (p[0]);
- newfd = p[1];
- }
- close_on_exec (newfd);
- return newfd;
- }
-}
diff --git a/contrib/cvs/src/sanity.sh b/contrib/cvs/src/sanity.sh
index f97e036..6130289 100755
--- a/contrib/cvs/src/sanity.sh
+++ b/contrib/cvs/src/sanity.sh
@@ -43,6 +43,15 @@
# required to make this script work properly.
unset CVSREAD
+# We want to invoke a predictable set of i18n behaviors, not whatever
+# the user running this script might have set.
+# In particular:
+# 'sort' and tabs and spaces (LC_COLLATE).
+# Messages from getopt (LC_MESSAGES) (in the future, CVS itself might
+# also alter its messages based on LC_MESSAGES).
+LC_ALL=C
+export LC_ALL
+
# The default value of /tmp/cvs-sanity for TESTDIR is dubious,
# because it loses if two people/scripts try to run the tests
# at the same time. Some possible solutions:
@@ -69,12 +78,6 @@ echo 'This test should produce no other output than this line, and a final "OK".
if test x"$1" = x"-r"; then
shift
remote=yes
- # If we're going to do remote testing, make sure 'rsh' works first.
- host="`hostname`"
- if test "x`${CVS_RSH-rsh} $host -n 'echo hi'`" != "xhi"; then
- echo "ERROR: cannot test remote CVS, because \`rsh $host' fails." >&2
- exit 1
- fi
else
remote=no
fi
@@ -94,12 +97,16 @@ fi
# Use full path for CVS executable, so that CVS_SERVER gets set properly
# for remote.
case $1 in
+"")
+ echo "Usage: `basename $0` [-r] [--keep] CVS-TO-TEST [TESTS-TO-RUN...]" 1>&2
+ exit 1
+ ;;
/*)
- testcvs=$1
- ;;
+ testcvs=$1
+ ;;
*)
- testcvs=`pwd`/$1
- ;;
+ testcvs=`pwd`/$1
+ ;;
esac
shift
@@ -278,13 +285,18 @@ dotest_internal ()
# so special-case it.
if test -z "$3"; then
if test -s ${TESTDIR}/dotest.tmp; then
- echo "** expected: " >>${LOGFILE}
- echo "$3" >>${LOGFILE}
- echo "$3" > ${TESTDIR}/dotest.exp
- rm -f ${TESTDIR}/dotest.ex2
- echo "** got: " >>${LOGFILE}
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- fail "$1"
+ if test x"$4" != x; then
+ # We want to match either the empty string or $4.
+ dotest_internal "$1" "$2" "$4"
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "$3" >>${LOGFILE}
+ echo "$3" > ${TESTDIR}/dotest.exp
+ rm -f ${TESTDIR}/dotest.ex2
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ fail "$1"
+ fi
else
pass "$1"
fi
@@ -477,7 +489,8 @@ dotest_fail ()
fail "$1"
else
: so far so good
- fi
+ fi 2>${TESTDIR}/dotest.tmp1
+ cat ${TESTDIR}/dotest.tmp1 >>${TESTDIR}/dotest.tmp
dotest_internal "$@"
}
@@ -553,34 +566,48 @@ RCSINIT=; export RCSINIT
if test x"$*" = x; then
# Basic/miscellaneous functionality
- tests="basica basicb basicc basic1 deep basic2 commit-readonly"
+ tests="basica basicb basicc basic1 deep basic2"
+ tests="${tests} files spacefiles commit-readonly"
# Branching, tagging, removing, adding, multiple directories
- tests="${tests} rdiff death death2 branches branches2"
+ tests="${tests} rdiff diff death death2 rmadd rmadd2 dirs dirs2"
+ tests="${tests} branches branches2 tagc tagf"
tests="${tests} rcslib multibranch import importb importc"
- tests="${tests} join join2 join3"
+ tests="${tests} import-after-initial"
+ tests="${tests} join join2 join3 join-readonly-conflict"
tests="${tests} new newb conflicts conflicts2 conflicts3"
# Checking out various places (modules, checkout -d, &c)
tests="${tests} modules modules2 modules3 modules4"
+ tests="${tests} mkmodules-temp-file-removal"
tests="${tests} cvsadm emptydir abspath toplevel toplevel2"
# Log messages, error messages.
tests="${tests} mflag editor errmsg1 errmsg2"
# Watches, binary files, history browsing, &c.
- tests="${tests} devcom devcom2 devcom3 watch4"
+ tests="${tests} devcom devcom2 devcom3 watch4 watch5"
tests="${tests} unedit-without-baserev"
- tests="${tests} ignore binfiles binfiles2 mcopy binwrap binwrap2"
+ tests="${tests} ignore binfiles binfiles2 binfiles3"
+ tests="${tests} mcopy binwrap binwrap2"
tests="${tests} binwrap3 mwrap info taginfo config"
- tests="${tests} serverpatch log log2 ann ann-id crerepos rcs rcs2"
+ tests="${tests} serverpatch log log2 ann ann-id"
+ # Repository Storage (RCS file format, CVS lock files, creating
+ # a repository without "cvs init", &c).
+ tests="${tests} crerepos rcs rcs2 rcs3 lockfiles backuprecover"
+ # More history browsing, &c.
tests="${tests} history"
- tests="${tests} big modes modes2 stamps"
+ tests="${tests} big modes modes2 modes3 stamps"
# PreservePermissions stuff: permissions, symlinks et al.
- tests="${tests} perms symlinks hardlinks"
+ tests="${tests} perms symlinks symlinks2 hardlinks"
# More tag and branch tests, keywords.
- tests="${tests} sticky keyword keywordlog"
+ tests="${tests} sticky keyword keyword2 keywordlog"
tests="${tests} head tagdate multibranch2 tag8k"
# "cvs admin", reserved checkouts.
tests="${tests} admin reserved"
# Nuts and bolts of diffing/merging (diff library, &c)
tests="${tests} diffmerge1 diffmerge2"
+ # Release of multiple directories
+ tests="${tests} release"
+ # Multiple root directories and low-level protocol tests.
+ tests="${tests} multiroot multiroot2 multiroot3 multiroot4"
+ tests="${tests} rmroot reposmv pserver server server2 client"
else
tests="$*"
fi
@@ -629,10 +656,13 @@ directory_cmp ()
CVSROOT_DIRNAME=${TESTDIR}/cvsroot
CVSROOT=${CVSROOT_DIRNAME} ; export CVSROOT
if test "x$remote" = xyes; then
- # Use rsh so we can test it without having to muck with inetd
- # or anything like that. Also needed to get CVS_SERVER to
- # work.
- CVSROOT=:ext:`hostname`:${CVSROOT_DIRNAME} ; export CVSROOT
+ # Currently we test :fork: and :ext: (see crerepos test).
+ # Testing :pserver: would be hard (inetd issues).
+ # Also :ext: and :fork support CVS_SERVER in a convenient way.
+ # If you want to edit this script to change the next line to
+ # :ext:, you can run the tests that way. There is a known
+ # difference in modes-15 (see comments there).
+ CVSROOT=:fork:${CVSROOT_DIRNAME} ; export CVSROOT
CVS_SERVER=${testcvs}; export CVS_SERVER
fi
@@ -725,8 +755,8 @@ ${PROG} \[[a-z]* aborted\]: failed to set tag BASE to revision 1\.1 in ${TESTDIR
RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v
retrieving revision 1\.1
diff -c -r1\.1 ssfile
-\*\*\* ssfile [0-9/]* [0-9:]* 1\.1
---- ssfile [0-9/]* [0-9:]*
+\*\*\* sdir/ssdir/ssfile [0-9/]* [0-9:]* 1\.1
+--- sdir/ssdir/ssfile [0-9/]* [0-9:]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
@@ -738,8 +768,8 @@ ${PLUS} ssfile line 2"
RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v
retrieving revision 1\.1
diff -c -r1\.1 ssfile
-\*\*\* ssfile [0-9/]* [0-9:]* 1\.1
---- ssfile [0-9/]* [0-9:]*
+\*\*\* sdir/ssdir/ssfile [0-9/]* [0-9:]* 1\.1
+--- sdir/ssdir/ssfile [0-9/]* [0-9:]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
@@ -1140,6 +1170,8 @@ Directory ${TESTDIR}/cvsroot/second-dir added to the repository"
# and then blow it away (don't complain if it does not
# exist). But that is perfectly legal; people who are used
# to the old behavior especially may be interested.
+ # FIXME: this test is intended for the TopLevelAdmin=yes case;
+ # should adjust/move it accordingly.
rm -rf CVS
dotest basicc-4 "echo *" "first-dir second-dir"
dotest basicc-5 "${testcvs} update" \
@@ -1149,8 +1181,39 @@ ${PROG} [a-z]*: Updating second-dir" \
${PROG} [a-z]*: Updating first-dir
${PROG} [a-z]*: Updating second-dir"
+ cd first-dir
+ dotest basicc-6 "${testcvs} release -d" ""
+ dotest basicc-7 "test -d ../first-dir" ""
+ # The Linux 2.2 kernel lets you delete ".". That's OK either way,
+ # the point is that CVS must not mess with anything *outside* "."
+ # the way that CVS 1.10 and older tried to.
+ dotest basicc-8 "${testcvs} -Q release -d ." \
+"" "${PROG} release: deletion of directory \. failed: .*"
+ dotest basicc-9 "test -d ../second-dir" ""
+ # For CVS to make a syntactic check for "." wouldn't suffice.
+ # On Linux 2.2 systems, the cwd may be gone, so we recreate it
+ # to allow basicc-11 to actually happen
+ if ! test -d ../first-dir; then
+ cd ..
+ mkdir ./first-dir
+ cd ./first-dir
+ fi
+ dotest basicc-11 "${testcvs} -Q release -d ./." \
+"" "${PROG} release: deletion of directory \./\. failed: .*"
+ dotest basicc-11a "test -d ../second-dir" ""
+
cd ..
- rm -r 1
+ cd ..
+
+ mkdir 2; cd 2
+ dotest basicc-12 "${testcvs} -Q co ." ""
+ dotest basicc-13 "echo *" "CVS CVSROOT first-dir second-dir"
+ dotest basicc-14 "${testcvs} -Q release first-dir second-dir" ""
+ dotest basicc-15 "${testcvs} -Q release -d first-dir second-dir" ""
+ dotest basicc-16 "echo *" "CVS CVSROOT"
+
+ cd ..
+ rm -r 1 2
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
@@ -2047,6 +2110,242 @@ O [0-9/]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-di
rm -rf ${CVSROOT_DIRNAME}/second-dir
;;
+ files)
+ # Test of how we specify files on the command line
+ # (recurse.c and that sort of thing). Vaguely similar to
+ # tests like basic* and deep. See modules and such tests
+ # for what happens when we throw in modules and co -d, &c.
+
+ # This particular test is fairly carefully crafted, to spot
+ # one particular issue with remote.
+ mkdir 1; cd 1
+ dotest files-1 "${testcvs} -q co -l ." ""
+ mkdir first-dir
+ dotest files-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ touch tfile
+ dotest files-3 "${testcvs} add tfile" \
+"${PROG} [a-z]*: scheduling file .tfile. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest files-4 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/tfile,v
+done
+Checking in tfile;
+${TESTDIR}/cvsroot/first-dir/tfile,v <-- tfile
+initial revision: 1\.1
+done"
+ dotest files-5 "${testcvs} -q tag -b C" "T tfile"
+ dotest files-6 "${testcvs} -q update -r C" ""
+ mkdir dir
+ dotest files-7 "${testcvs} add dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd dir
+ touch .file
+ dotest files-6 "${testcvs} add .file" \
+"${PROG} [a-z]*: scheduling file .\.file' for addition on branch .C.
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ mkdir sdir
+ dotest files-7 "${testcvs} add sdir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir/sdir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd sdir
+ mkdir ssdir
+ dotest files-8 "${testcvs} add ssdir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir added to the repository
+--> Using per-directory sticky tag .C'"
+ cd ssdir
+ touch .file
+ dotest files-9 "${testcvs} add .file" \
+"${PROG} [a-z]*: scheduling file .\.file' for addition on branch .C.
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ../..
+ dotest files-10 "${testcvs} -q ci -m test" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v
+done
+Checking in \.file;
+${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v
+done
+Checking in sdir/ssdir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done"
+ dotest files-11 \
+"${testcvs} commit -m test -f ./.file ./sdir/ssdir/.file" \
+"Checking in \.file;
+${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
+done
+Checking in \./sdir/ssdir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
+done"
+ if test "$remote" = yes; then
+ # This is a bug, looks like that toplevel_repos cruft in
+ # client.c is coming back to haunt us.
+ # May want to think about the whole issue, toplevel_repos
+ # has always been crufty and trying to patch it up again
+ # might be a mistake.
+ dotest_fail files-12 \
+"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \
+"${PROG} server: Up-to-date check failed for .\.file'
+${PROG} \[server aborted\]: correct above errors first!"
+
+ # Sync up the version numbers so that the rest of the
+ # tests don't need to expect different numbers based
+ # local or remote.
+ dotest files-12-workaround \
+"${testcvs} commit -f -m test sdir/ssdir/.file .file" \
+"Checking in sdir/ssdir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
+done
+Checking in \.file;
+${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
+done"
+ else
+ dotest files-12 \
+"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \
+"Checking in \./sdir/ssdir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
+done
+Checking in \.file;
+${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
+done"
+ fi
+ dotest files-13 \
+"${testcvs} commit -fmtest ./sdir/../sdir/ssdir/..///ssdir/.file" \
+"Checking in \./sdir/\.\./sdir/ssdir/\.\.///ssdir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3
+done"
+ if test "$remote" = yes; then
+ dotest_fail files-14 \
+"${testcvs} commit -fmtest ../../first-dir/dir/.file" \
+"protocol error: .\.\./\.\./first-dir/dir' has too many \.\."
+ else
+ dotest files-14 \
+"${testcvs} commit -fmtest ../../first-dir/dir/.file" \
+"Checking in \.\./\.\./first-dir/dir/\.file;
+${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file
+new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3
+done"
+ fi
+ cd ../../..
+
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ spacefiles)
+ # More filename tests, in particular spaces in file names.
+ # If we start using eval in dotest, this test should become
+ # easier to write (in fact, it may be possible to just
+ # change a few of the names in basica or some other test,
+ # always good to keep the testsuite concise).
+
+ # I wrote this test to worry about problems in do_module;
+ # but then I found that the CVS server has its own problems
+ # with filenames starting with "-". Work around it for now.
+ if test "$remote" = yes; then
+ dashb=dashb
+ dashc=dashc
+ else
+ dashb=-b
+ dashc=-c
+ fi
+
+ mkdir 1; cd 1
+ dotest spacefiles-1 "${testcvs} -q co -l ." ""
+ touch ./${dashc} top
+ dotest spacefiles-2 "${testcvs} add -- ${dashc} top" \
+"${PROG} [a-z]*: scheduling file .${dashc}. for addition
+${PROG} [a-z]*: scheduling file .top. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ dotest spacefiles-3 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/${dashc},v
+done
+Checking in ${dashc};
+${TESTDIR}/cvsroot/${dashc},v <-- ${dashc}
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/top,v
+done
+Checking in top;
+${TESTDIR}/cvsroot/top,v <-- top
+initial revision: 1\.1
+done"
+ mkdir 'first dir'
+ if ${testcvs} add 'first dir' >${TESTDIR}/output.tmp 2>&1; then
+ dotest spacefiles-4 "cat ${TESTDIR}/output.tmp" \
+"Directory ${TESTDIR}/cvsroot/first dir added to the repository"
+ else
+ fail spacefiles-4
+ fi
+ mkdir ./${dashb}
+ dotest spacefiles-5 "${testcvs} add -- ${dashb}" \
+"Directory ${TESTDIR}/cvsroot/${dashb} added to the repository"
+ cd 'first dir'
+ touch 'a file'
+ if ${testcvs} add 'a file' >${TESTDIR}/output.tmp 2>&1; then
+ dotest spacefiles-6 "cat ${TESTDIR}/output.tmp" \
+"${PROG} [a-z]*: scheduling file .a file. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ else
+ fail spacefiles-6
+ fi
+ dotest spacefiles-7 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first dir/a file,v
+done
+Checking in a file;
+${TESTDIR}/cvsroot/first dir/a file,v <-- a file
+initial revision: 1\.1
+done"
+ dotest spacefiles-8 "${testcvs} -q tag new-tag" "T a file"
+ cd ../..
+
+ mkdir 2; cd 2
+ # Leading slash strikes me as kind of oddball, but there is
+ # a special case for it in do_module. And (in the case of
+ # "top", rather than "-c") it has worked in CVS 1.10.6 and
+ # presumably back to CVS 1.3 or so.
+ dotest spacefiles-9 "${testcvs} -q co -- /top" "U \./top"
+ dotest spacefiles-10 "${testcvs} co -- ${dashb}" \
+"${PROG} [a-z]*: Updating ${dashb}"
+ dotest spacefiles-11 "${testcvs} -q co -- ${dashc}" "U \./${dashc}"
+ rm ./${dashc}
+ dotest spacefiles-12 "${testcvs} -q co -- /${dashc}" "U \./${dashc}"
+ if ${testcvs} -q co 'first dir' >${TESTDIR}/output.tmp 2>&1; then
+ dotest spacefiles-13 "cat ${TESTDIR}/output.tmp" \
+"U first dir/a file"
+ else
+ fail spacefiles-13
+ fi
+ cd ..
+
+ mkdir 3; cd 3
+ if ${testcvs} -q co 'first dir/a file' >${TESTDIR}/output.tmp 2>&1
+ then
+ dotest spacefiles-14 "cat ${TESTDIR}/output.tmp" \
+"U first dir/a file"
+ else
+ fail spacefiles-14
+ fi
+ cd ..
+
+ rm -r 1 2 3
+ rm -rf "${CVSROOT_DIRNAME}/first dir"
+ rm -r ${CVSROOT_DIRNAME}/${dashb}
+ rm -f ${CVSROOT_DIRNAME}/${dashc},v ${CVSROOT_DIRNAME}/top,v
+ ;;
+
commit-readonly)
mkdir 1; cd 1
module=x
@@ -2194,6 +2493,66 @@ diff -c /dev/null trdiff/new:1\.1
rm -rf ${CVSROOT_DIRNAME}/trdiff
;;
+ diff)
+ # Various tests specific to the "cvs diff" command.
+ # Related tests:
+ # death2: -N
+ # rcslib: cvs diff and $Name.
+ # rdiff: cvs rdiff.
+ # diffmerge*: nuts and bolts (stuff within diff library)
+ mkdir 1; cd 1
+ dotest diff-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest diff-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+
+ # diff is anomalous. Most CVS commands print the "nothing
+ # known" message (or worse yet, no message in some cases) but
+ # diff says "I know nothing". Shrug.
+ dotest_fail diff-3 "${testcvs} diff xyzpdq" \
+"${PROG} [a-z]*: I know nothing about xyzpdq"
+ touch abc
+ dotest diff-4 "${testcvs} add abc" \
+"${PROG} [a-z]*: scheduling file .abc. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest diff-5 "${testcvs} -q ci -mtest" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/abc,v
+done
+Checking in abc;
+${TESTDIR}/cvsroot/first-dir/abc,v <-- abc
+initial revision: 1\.1
+done"
+ echo "extern int gethostname ();" >abc
+ dotest diff-6 "${testcvs} -q ci -mtest" \
+"Checking in abc;
+${TESTDIR}/cvsroot/first-dir/abc,v <-- abc
+new revision: 1\.2; previous revision: 1\.1
+done"
+ echo "#include <winsock.h>" >abc
+ # check the behavior of the --ifdef=MACRO option
+ dotest_fail diff-7 "${testcvs} -q diff --ifdef=HAVE_WINSOCK_H" \
+"Index: abc
+===================================================================
+RCS file: ${TESTDIR}/cvsroot/first-dir/abc,v
+retrieving revision 1\.2
+diff --ifdef=HAVE_WINSOCK_H -r1\.2 abc
+#ifndef HAVE_WINSOCK_H
+extern int gethostname ();
+#else /\* HAVE_WINSOCK_H \*/
+#include <winsock\.h>
+#endif /\* HAVE_WINSOCK_H \*/"
+
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ cd ../..
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ rm -r 1
+ ;;
+
death)
# next dive. test death support.
@@ -2894,6 +3253,496 @@ ${PLUS} first revision"
cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir
;;
+ rmadd)
+ # More tests of adding and removing files.
+ # In particular ci -r.
+ # Other ci -r tests:
+ # * editor-9: checking in a modified file,
+ # where "ci -r" means a branch.
+ # * basica-8a1: checking in a modified file with numeric revision.
+ # * basica-8a2: likewise.
+ # * keywordlog-4: adding a new file with numeric revision.
+ mkdir 1; cd 1
+ dotest rmadd-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmadd-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ echo first file1 >file1
+ dotest rmadd-3 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+
+ dotest_fail rmadd-4 "${testcvs} -q ci -r 1.2.2.4 -m add" \
+"${PROG} [a-z]*: cannot add file .file1' with revision .1\.2\.2\.4'; must be on trunk
+${PROG} \[[a-z]* aborted\]: correct above errors first!"
+ dotest_fail rmadd-5 "${testcvs} -q ci -r 1.2.2 -m add" \
+"${PROG} [a-z]*: cannot add file .file1' with revision .1\.2\.2'; must be on trunk
+${PROG} \[[a-z]* aborted\]: correct above errors first!"
+ dotest_fail rmadd-6 "${testcvs} -q ci -r mybranch -m add" \
+"${PROG} \[[a-z]* aborted\]: no such tag mybranch"
+
+ # The thing with the trailing periods strikes me as a very
+ # bizarre behavior, but it would seem to be intentional
+ # (see commit.c). It probably could go away....
+ dotest rmadd-7 "${testcvs} -q ci -r 7.... -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 7\.1
+done"
+ if test "$remote" = yes; then
+ # I guess remote doesn't set a sticky tag in this case.
+ # Kind of odd, in the sense that rmadd-24a does set one
+ # both local and remote.
+ dotest_fail rmadd-7a "test -f CVS/Tag"
+ echo T7 >CVS/Tag
+ else
+ dotest rmadd-7a "cat CVS/Tag" "T7"
+ fi
+
+ dotest rmadd-8 "${testcvs} -q tag -b mybranch" "T file1"
+ dotest rmadd-9 "${testcvs} -q tag mynonbranch" "T file1"
+
+ touch file2
+ # The previous "cvs ci -r" set a sticky tag of '7'. Seems a
+ # bit odd, and I guess commit.c (findmaxrev) makes '7' sticky
+ # tags unnecessary (?). I kind of suspect that it should be
+ # saying "sticky tag is not a branch" like keywordlog-4b.
+ # Or something.
+ dotest rmadd-10 "${testcvs} add file2" \
+"${PROG} [a-z]*: scheduling file .file2. for addition on branch .7'
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ # As in the previous example, CVS is confused....
+ dotest rmadd-11 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file2,v
+done
+Checking in file2;
+${TESTDIR}/cvsroot/first-dir/file2,v <-- file2
+initial revision: 7\.1
+done"
+
+ dotest rmadd-12 "${testcvs} -q update -A" ""
+ touch file3
+ dotest rmadd-13 "${testcvs} add file3" \
+"${PROG} [a-z]*: scheduling file .file3. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ # Huh? file2 is not up to date? Seems buggy to me....
+ dotest_fail rmadd-14 "${testcvs} -q ci -r mybranch -m add" \
+"${PROG} [a-z]*: Up-to-date check failed for .file2'
+${PROG} \[[a-z]* aborted\]: correct above errors first!"
+ # Whatever, let's not let file2 distract us....
+ dotest rmadd-15 "${testcvs} -q ci -r mybranch -m add file3" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/file3,v
+done
+Checking in file3;
+${TESTDIR}/cvsroot/first-dir/Attic/file3,v <-- file3
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done"
+
+ touch file4
+ dotest rmadd-16 "${testcvs} add file4" \
+"${PROG} [a-z]*: scheduling file .file4. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ # Same "Up-to-date check" issues as in rmadd-14.
+ # The "no such tag" thing is due to the fact that we only
+ # update val-tags when the tag is used (might be more of a
+ # bug than a feature, I dunno).
+ dotest_fail rmadd-17 \
+"${testcvs} -q ci -r mynonbranch -m add file4" \
+"${PROG} \[[a-z]* aborted\]: no such tag mynonbranch"
+ # Try to make CVS write val-tags.
+ dotest rmadd-18 "${testcvs} -q update -p -r mynonbranch file1" \
+"first file1"
+ # Oops, -p suppresses writing val-tags (probably a questionable
+ # behavior).
+ dotest_fail rmadd-19 \
+"${testcvs} -q ci -r mynonbranch -m add file4" \
+"${PROG} \[[a-z]* aborted\]: no such tag mynonbranch"
+ # Now make CVS write val-tags for real.
+ dotest rmadd-20 "${testcvs} -q update -r mynonbranch file1" ""
+ # Oops - CVS isn't distinguishing between a branch tag and
+ # a non-branch tag.
+ dotest rmadd-21 \
+"${testcvs} -q ci -r mynonbranch -m add file4" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/file4,v
+done
+Checking in file4;
+${TESTDIR}/cvsroot/first-dir/Attic/file4,v <-- file4
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done"
+
+ # OK, we add this one in a vanilla way, but then check in
+ # a modification with ci -r and sniff around for sticky tags.
+ echo file5 >file5
+ dotest rmadd-22 "${testcvs} add file5" \
+"${PROG} [a-z]*: scheduling file .file5. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ if test "$remote" = yes; then
+ # Interesting bug (or missing feature) here. findmaxrev
+ # gets the major revision from the Entries. Well, remote
+ # doesn't send the entries for files which are not involved.
+ dotest rmadd-23 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file5,v
+done
+Checking in file5;
+${TESTDIR}/cvsroot/first-dir/file5,v <-- file5
+initial revision: 1\.1
+done"
+ dotest rmadd-23-workaround \
+"${testcvs} -q ci -r 7 -m bump-it file5" \
+"Checking in file5;
+${TESTDIR}/cvsroot/first-dir/file5,v <-- file5
+new revision: 7\.1; previous revision: 1\.1
+done"
+ else
+ dotest rmadd-23 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file5,v
+done
+Checking in file5;
+${TESTDIR}/cvsroot/first-dir/file5,v <-- file5
+initial revision: 7\.1
+done"
+ fi
+ echo change it >file5
+ dotest_fail rmadd-24 "${testcvs} -q ci -r 4.8 -m change file5" \
+"Checking in file5;
+${TESTDIR}/cvsroot/first-dir/file5,v <-- file5
+${PROG} [a-z]*: ${TESTDIR}/cvsroot/first-dir/file5,v: revision 4\.8 too low; must be higher than 7\.1
+${PROG} [a-z]*: could not check in file5
+7\.1 unlocked"
+ dotest rmadd-24a "${testcvs} -q ci -r 8.4 -m change file5" \
+"Checking in file5;
+${TESTDIR}/cvsroot/first-dir/file5,v <-- file5
+new revision: 8\.4; previous revision: 7\.1
+done"
+ # I'm not really sure that a sticky tag make sense here.
+ # It seems to be longstanding behavior for what that is worth.
+ dotest rmadd-25 "${testcvs} status file5" \
+"===================================================================
+File: file5 Status: Up-to-date
+
+ Working revision: 8\.4.*
+ Repository revision: 8\.4 ${TESTDIR}/cvsroot/first-dir/file5,v
+ Sticky Tag: 8\.4
+ Sticky Date: (none)
+ Sticky Options: (none)"
+
+ cd ../..
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ rmadd2)
+ # Tests of undoing commits, including in the presence of
+ # adding and removing files. See join for a list of -j tests.
+ mkdir 1; cd 1
+ dotest rmadd2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmadd2-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ echo 'initial contents' >file1
+ dotest rmadd2-3 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest rmadd2-4 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done"
+ dotest rmadd2-4a "${testcvs} -Q tag tagone" ""
+ dotest rmadd2-5 "${testcvs} rm -f file1" \
+"${PROG} [a-z]*: scheduling .file1. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ dotest rmadd2-6 "${testcvs} -q ci -m remove" \
+"Removing file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1
+done"
+ dotest rmadd2-7 "${testcvs} -q update -j 1.2 -j 1.1 file1" "U file1"
+ dotest rmadd2-8 "${testcvs} -q ci -m readd" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+done"
+ echo 'new contents' >file1
+ dotest rmadd2-9 "${testcvs} -q ci -m modify" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+done"
+ dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.4
+retrieving revision 1\.3
+Merging differences between 1\.4 and 1\.3 into file1"
+ dotest rmadd2-11 "${testcvs} -q ci -m undo" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+done"
+ dotest rmadd2-12 "cat file1" "initial contents"
+ dotest rmadd2-13 "${testcvs} -q update -p -r 1.3" "initial contents"
+
+ # Hmm, might be a bit odd that this works even if 1.3 is not
+ # the head.
+ dotest rmadd2-14 "${testcvs} -q update -j 1.3 -j 1.2 file1" \
+"${PROG} [a-z]*: scheduling file1 for removal"
+ dotest rmadd2-15 "${testcvs} -q ci -m re-remove" \
+"Removing file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.5
+done"
+ dotest rmadd2-16 "${testcvs} log -h file1" "
+RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/file1,v
+Working file: file1
+head: 1\.6
+branch:
+locks: strict
+access list:
+symbolic names:
+ tagone: 1\.1
+keyword substitution: kv
+total revisions: 6
+============================================================================="
+ dotest rmadd2-17 "${testcvs} status -v file1" \
+"===================================================================
+File: no file file1 Status: Up-to-date
+
+ Working revision: No entry for file1
+ Repository revision: 1\.6 ${TESTDIR}/cvsroot/first-dir/Attic/file1,v
+
+ Existing Tags:
+ tagone (revision: 1.1)"
+
+ cd ../..
+
+ rm -r 1
+ rm -rf ${TESTDIR}/cvsroot/first-dir
+ ;;
+
+ dirs)
+ # Tests related to removing and adding directories.
+ # See also:
+ # conflicts (especially dir1 in conflicts-130): What happens if
+ # directory exists in repository and a non-CVS-controlled
+ # directory in the working directory?
+ # conflicts3-15. More cases, especially where CVS directory
+ # exists but without CVS/Repository and friends.
+ # conflicts3-22. Similar to conflicts-130 but there is a file
+ # in the directory.
+ # dirs2. Sort of similar to conflicts3-22 but somewhat different.
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ mkdir sdir
+ echo sfile >sdir/sfile
+ dotest_sort dirs-1 \
+"${testcvs} import -m import-it dir1 vend rel" "
+
+N dir1/file1
+N dir1/sdir/sfile
+No conflicts created by this import
+${PROG} [a-z]*: Importing ${TESTDIR}/cvsroot/dir1/sdir"
+ cd ..
+
+ mkdir 1; cd 1
+ dotest dirs-2 "${testcvs} -Q co dir1" ""
+
+ # Various CVS administrators are in the habit of removing
+ # the repository directory for things they don't want any
+ # more. I've even been known to do it myself (on rare
+ # occasions). Not the usual recommended practice, but we want
+ # to try to come up with some kind of reasonable/documented/sensible
+ # behavior.
+ rm -rf ${CVSROOT_DIRNAME}/dir1/sdir
+
+ dotest dirs-3 "${testcvs} update" \
+"${PROG} [a-z]*: Updating dir1
+${PROG} [a-z]*: Updating dir1/sdir
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory
+${PROG} [a-z]*: skipping directory dir1/sdir"
+ dotest dirs-3a "${testcvs} update -d" \
+"${PROG} [a-z]*: Updating dir1
+${PROG} [a-z]*: Updating dir1/sdir
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory
+${PROG} [a-z]*: skipping directory dir1/sdir"
+
+ # If we say "yes", then CVS gives errors about not being able to
+ # create lock files.
+ if echo no | ${testcvs} release -d dir1/sdir \
+ >${TESTDIR}/output.tmp 2>&1; then
+ pass dirs-4
+ else
+ fail dirs-4
+ fi
+ # The fact that it says "skipping directory " rather than
+ # "skipping directory dir1/sdir" is some kind of bug.
+ dotest dirs-4a "cat ${TESTDIR}/output.tmp" \
+"${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory
+${PROG} [a-z]*: skipping directory
+You have \[0\] altered files in this repository\.
+Are you sure you want to release (and delete) directory .dir1/sdir': .. .release' aborted by user choice."
+
+ # OK, if "cvs release" won't help, we'll try it the other way...
+ rm -r dir1/sdir
+
+ dotest dirs-5 "cat dir1/CVS/Entries" \
+"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
+D/sdir////"
+ dotest dirs-6 "${testcvs} update" "${PROG} [a-z]*: Updating dir1"
+ dotest dirs-7 "cat dir1/CVS/Entries" \
+"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
+D/sdir////"
+ dotest dirs-8 "${testcvs} update -d dir1" \
+"${PROG} [a-z]*: Updating dir1"
+
+ cd ..
+
+ rm -r imp-dir 1
+ rm ${TESTDIR}/output.tmp
+
+ # clean up our repositories
+ rm -rf ${CVSROOT_DIRNAME}/dir1
+ ;;
+
+ dirs2)
+ # See "dirs" for a list of tests involving adding and
+ # removing directories.
+ mkdir 1; cd 1
+ dotest dirs2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest dirs2-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ mkdir sdir
+ dotest dirs2-3 "${testcvs} add sdir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/sdir added to the repository"
+ touch sdir/file1
+ dotest dirs2-4 "${testcvs} add sdir/file1" \
+"${PROG} [a-z]*: scheduling file .sdir/file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest dirs2-5 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/file1,v
+done
+Checking in sdir/file1;
+${TESTDIR}/cvsroot/first-dir/sdir/file1,v <-- file1
+initial revision: 1\.1
+done"
+ rm -r sdir/CVS
+ if test "$remote" = yes; then
+ # This is just like conflicts3-23
+ dotest_fail dirs2-6 "${testcvs} update -d" \
+"${QUESTION} sdir
+${PROG} server: Updating \.
+${PROG} update: in directory sdir:
+${PROG} update: cannot open CVS/Entries for reading: No such file or directory
+${PROG} server: Updating sdir
+${PROG} update: move away sdir/file1; it is in the way
+C sdir/file1"
+ rm sdir/file1
+
+ # This is where things are not just like conflicts3-23
+ # As with conflicts3-23, all these CVS/Entries* warnings
+ # are somewhat doubtful, and we probably should think some
+ # about whether they should be changed/fixed.
+ dotest dirs2-7 "${testcvs} update -d" \
+"${QUESTION} sdir
+${PROG} server: Updating \.
+${PROG} update: in directory sdir:
+${PROG} update: cannot open CVS/Entries for reading: No such file or directory
+${PROG} server: Updating sdir
+U sdir/file1
+${PROG} update: cannot open CVS/Entries.Log: No such file or directory"
+ else
+ dotest dirs2-6 "${testcvs} update -d" \
+"${PROG} update: Updating \.
+${QUESTION} sdir"
+ rm sdir/file1
+ dotest dirs2-7 "${testcvs} update -d" \
+"${PROG} update: Updating \.
+${QUESTION} sdir"
+ fi
+ cd ../..
+
+ # Now, the same thing (more or less) on a branch.
+ mkdir 2; cd 2
+ dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1'
+ cd first-dir
+ dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1"
+ rm -r sdir/CVS
+ if test "$remote" = yes; then
+ # Cute little quirk of val-tags; if we don't recurse into
+ # the directories where the tag is defined, val-tags won't
+ # get updated.
+ dotest_fail dirs2-10 "${testcvs} update -d -r br" \
+"${QUESTION} sdir
+${PROG} \[server aborted\]: no such tag br"
+ dotest dirs2-10-rem \
+"${testcvs} -q rdiff -u -r 1.1 -r br first-dir/sdir/file1" \
+""
+ dotest_fail dirs2-10-again "${testcvs} update -d -r br" \
+"${QUESTION} sdir
+${PROG} server: Updating \.
+${PROG} update: in directory sdir:
+${PROG} update: cannot open CVS/Entries for reading: No such file or directory
+${PROG} update: cannot open CVS/Tag: No such file or directory
+${PROG} update: cannot open CVS/Tag: No such file or directory
+${PROG} server: Updating sdir
+${PROG} update: move away sdir/file1; it is in the way
+C sdir/file1
+${PROG} update: cannot open CVS/Tag: No such file or directory"
+ else
+ dotest_fail dirs2-10 "${testcvs} update -d -r br" \
+"${PROG} update: in directory sdir:
+${PROG} \[update aborted\]: there is no version here; do '${PROG} checkout' first"
+ fi
+ cd ../..
+
+ # OK, the above tests make the situation somewhat harder
+ # than it might be, in the sense that they actually have a
+ # file which is alive on the branch we are updating. Let's
+ # try it where it is just a directory where all the files
+ # have been removed.
+ mkdir 3; cd 3
+ dotest dirs2-11 "${testcvs} -q co -r br first-dir" \
+"U first-dir/sdir/file1"
+ cd first-dir
+ # Hmm, this doesn't mention the branch like add does. That's
+ # an odd non-orthogonality.
+ dotest dirs2-12 "${testcvs} rm -f sdir/file1" \
+"${PROG} [a-z]*: scheduling .sdir/file1. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ dotest dirs2-13 "${testcvs} -q ci -m remove" \
+"Removing sdir/file1;
+${TESTDIR}/cvsroot/first-dir/sdir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1\.2
+done"
+ cd ../../2/first-dir
+ if test "$remote" = yes; then
+ dotest dirs2-14 "${testcvs} update -d -r br" \
+"${QUESTION} sdir
+${PROG} server: Updating \.
+${PROG} update: in directory sdir:
+${PROG} update: cannot open CVS/Entries for reading: No such file or directory
+${PROG} update: cannot open CVS/Tag: No such file or directory
+${PROG} update: cannot open CVS/Tag: No such file or directory
+${PROG} server: Updating sdir
+${PROG} update: cannot open CVS/Tag: No such file or directory"
+ else
+ dotest dirs2-14 "${testcvs} update -d -r br" \
+"${PROG} update: Updating \.
+${QUESTION} sdir"
+ fi
+ cd ../..
+
+ rm -r 1 2 3
+ rm -rf ${TESTDIR}/cvsroot/first-dir
+ ;;
+
branches)
# More branch tests, including branches off of branches
mkdir ${CVSROOT_DIRNAME}/first-dir
@@ -2949,14 +3798,18 @@ done"
T file2
T file3
T file4"
+ # Modify this file before branching, to deal with the case where
+ # someone is hacking along, says "oops, I should be doing this on
+ # a branch", and only then creates the branch.
+ echo 1:br1 >file1
dotest branches-4 "${testcvs} tag -b br1" "${PROG}"' [a-z]*: Tagging \.
T file1
T file2
T file3
T file4'
dotest branches-5 "${testcvs} update -r br1" \
-"${PROG}"' [a-z]*: Updating \.'
- echo 1:br1 >file1
+"${PROG} [a-z]*: Updating \.
+M file1"
echo 2:br1 >file2
echo 4:br1 >file4
dotest branches-6 "${testcvs} -q ci -m modify" \
@@ -3389,6 +4242,172 @@ File: file5 Status: Up-to-date
rm -r trunk b1a b1b
;;
+ tagc)
+ # Test the tag -c option.
+ mkdir 1; cd 1
+ dotest tagc-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest tagc-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ touch file1
+ dotest tagc-3 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest tagc-4 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done"
+ dotest tagc-5 "${testcvs} -q tag -c tag1" "T file1"
+ touch file1
+ dotest tagc-6 "${testcvs} -q tag -c tag2" "T file1"
+ # Avoid timestamp granularity bugs (FIXME: CVS should be
+ # doing the sleep, right?).
+ sleep 1
+ echo myedit >>file1
+ dotest_fail tagc-7 "${testcvs} -q tag -c tag3" \
+"${PROG} [a-z]*: file1 is locally modified
+${PROG} \[[a-z]* aborted\]: correct the above errors first!"
+ cd ../..
+ mkdir 2
+ cd 2
+ dotest tagc-8 "${testcvs} -q co first-dir" "U first-dir/file1"
+ cd ../1/first-dir
+ dotest tagc-9 "${testcvs} -q ci -m modify" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+done"
+ cd ../../2/first-dir
+ # That this is an error is a bug. Although the bug has existed
+ # since tag -c was created, I don't think there would be a
+ # compatibility problem with just fixing it.
+ dotest_fail tagc-10 "${testcvs} -q tag -c tag4" \
+"${PROG} [a-z]*: file1 is locally modified
+${PROG} \[[a-z]* aborted\]: correct the above errors first!"
+ cd ../..
+
+ rm -r 1 2
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ tagf)
+ # More tagging tests, including using tag -F to convert a
+ # branch tag to a regular tag and recovering thereof.
+
+ # Setup; check in first-dir/file1
+ mkdir 1; cd 1
+ dotest tagf-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest tagf-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest tagf-3 "${testcvs} add file1 file2" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: scheduling file .file2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ dotest tagf-4 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/first-dir/file2,v
+done
+Checking in file2;
+${TESTDIR}/cvsroot/first-dir/file2,v <-- file2
+initial revision: 1\.1
+done"
+
+ # Now create a branch and commit a revision there.
+ dotest tagf-5 "${testcvs} -q tag -b br" "T file1
+T file2"
+ dotest tagf-6 "${testcvs} -q update -r br" ""
+ echo brmod >> file1
+ echo brmod >> file2
+ dotest tagf-7 "${testcvs} -q ci -m modify" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done
+Checking in file2;
+${TESTDIR}/cvsroot/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done"
+ # Here we make it a non-branch tag. Some think this should
+ # be an error. But if -F means "I want to put this tag here,
+ # never mind whether there was a tag of that name before", then
+ # an error wouldn't fit.
+ dotest tagf-8 "${testcvs} -q tag -F br" "T file1
+T file2"
+ echo moremod >> file1
+ echo moremod >> file2
+ dotest tagf-9 "${testcvs} -q status -v file1" \
+"===================================================================
+File: file1 Status: Locally Modified
+
+ Working revision: 1\.1\.2\.1.*
+ Repository revision: 1\.1\.2\.1 ${TESTDIR}/cvsroot/first-dir/file1,v
+ Sticky Tag: br (revision: 1\.1\.2\.1)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ br (revision: 1\.1\.2\.1)"
+
+ # Now, how do we recover?
+ dotest tagf-10 "${testcvs} -q tag -d br" "D file1
+D file2"
+ # This creates a new branch, 1.1.4. See the code in RCS_magicrev
+ # which will notice that there is a (non-magic) 1.1.2 and thus
+ # skip that number.
+ dotest tagf-11 "${testcvs} -q tag -r 1.1 -b br file1" "T file1"
+ # Fix it with admin -n (cf admin-18, admin-26-4).
+ dotest tagf-12 "${testcvs} -q admin -nbr:1.1.2 file2" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file2,v
+done"
+ # Another variation on the file2 test would be to use two working
+ # directories so that the update -r br would need to
+ # a merge to get from 1.1.2.1 to the head of the 1.1.2 branch.
+ dotest tagf-13 "${testcvs} -q update -r br" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.1\.2\.1
+retrieving revision 1\.1
+Merging differences between 1\.1\.2\.1 and 1\.1 into file1
+rcsmerge: warning: conflicts during merge
+${PROG} [a-z]*: conflicts found in file1
+C file1
+M file2"
+ # CVS is giving a conflict because we are trying to get back to
+ # 1.1.4. I'm not sure why it is a conflict rather than just
+ # "M file1".
+ dotest tagf-14 "cat file1" \
+"<<<<<<< file1
+brmod
+moremod
+[=]======
+[>]>>>>>> 1\.1"
+ echo resolve >file1
+ dotest tagf-15 "${testcvs} -q ci -m recovered" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.1; previous revision: 1\.1
+done
+Checking in file2;
+${TESTDIR}/cvsroot/first-dir/file2,v <-- file2
+new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
+done"
+ cd ../..
+
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
rcslib)
# Test librarification of RCS.
# First: test whether `cvs diff' handles $Name expansion
@@ -3603,7 +4622,46 @@ two
${TESTDIR}/cvsroot/first-dir/file1,v <-- file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
done"
- dotest rcslib-symlink-4 "test -L ${CVSROOT_DIRNAME}/first-dir/file2,v"
+ dotest rcslib-symlink-4 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+ # Test 5 reveals a problem with having symlinks in the
+ # repository. CVS will try to tag both of the files
+ # separately. After processing one, it will do the same
+ # operation to the other, which is actually the same file,
+ # so the tag will already be there. FIXME: do we bother
+ # changing operations to notice cases like this? This
+ # strikes me as a difficult problem. -Noel
+ dotest rcslib-symlink-5 "${testcvs} tag the_tag" \
+"${PROG} [a-z]*: Tagging .
+T file1
+W file2 : the_tag already exists on version 1.1.2.1 : NOT MOVING tag to version 1.1.2.2"
+ dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
+".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+
+ # Symlinks tend to interact poorly with the Attic.
+ cd ..
+ mkdir 2; cd 2
+ dotest rcslib-symlink-7 "${testcvs} -q co first-dir" \
+"U first-dir/file1
+U first-dir/file2"
+ cd first-dir
+ dotest rcslib-symlink-8 "${testcvs} rm -f file2" \
+"${PROG} [a-z]*: scheduling .file2. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ dotest rcslib-symlink-9 "${testcvs} -q ci -m rm-it" \
+"Removing file2;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file2
+new revision: delete; previous revision: 1\.2
+done"
+ # OK, why this message happens twice is relatively clear
+ # (the check_* and rtag_* calls to start_recursion).
+ # Why it happens a third time I didn't try to find out.
+ dotest rcslib-symlink-10 \
+"${testcvs} -q rtag -b -r the_tag brtag first-dir" \
+"${PROG} [a-z]*: could not read RCS file for file2
+${PROG} [a-z]*: could not read RCS file for first-dir/file2
+${PROG} [a-z]*: could not read RCS file for first-dir/file2"
+ cd ..
cd ..
@@ -3613,7 +4671,7 @@ done"
fi
rm -rf ${CVSROOT_DIRNAME}/first-dir
- rm -r first-dir
+ rm -r first-dir 2
;;
multibranch)
@@ -3718,7 +4776,7 @@ modify-on-br1
mkdir import-dir ; cd import-dir
for i in 1 2 3 4 ; do
- echo imported file"$i" > imported-f"$i"
+ echo imported file"$i" > imported-f"$i"
done
# This directory should be on the default ignore list,
@@ -3729,157 +4787,164 @@ modify-on-br1
echo 'import should not expand $''Id$' >>imported-f2
cp imported-f2 ../imported-f2-orig.tmp
- if ${CVS} import -m first-import first-dir vendor-branch junk-1_0 ; then
- pass 96
- else
- fail 96
- fi
+ dotest_sort import-96 \
+"${testcvs} import -m first-import first-dir vendor-branch junk-1_0" \
+"
+
+I first-dir/RCS
+N first-dir/imported-f1
+N first-dir/imported-f2
+N first-dir/imported-f3
+N first-dir/imported-f4
+No conflicts created by this import"
+
+ dotest import-96.5 "cmp ../imported-f2-orig.tmp imported-f2" ''
- if cmp ../imported-f2-orig.tmp imported-f2; then
- pass 96.5
- else
- fail 96.5
- fi
cd ..
# co
- if ${CVS} co first-dir ; then
- pass 97
- else
- fail 97
- fi
+ dotest import-97 "${testcvs} -q co first-dir" \
+"U first-dir/imported-f1
+U first-dir/imported-f2
+U first-dir/imported-f3
+U first-dir/imported-f4"
cd first-dir
+
for i in 1 2 3 4 ; do
- if test -f imported-f"$i" ; then
- pass 98-$i
- else
- fail 98-$i
- fi
+ dotest import-98-$i "test -f imported-f$i" ''
done
- if test -d RCS; then
- fail 98.5
- else
- pass 98.5
- fi
+ dotest_fail import-98.5 "test -d RCS" ''
# remove
rm imported-f1
- if ${CVS} rm imported-f1 2>> ${LOGFILE}; then
- pass 99
- else
- fail 99
- fi
+ dotest import-99 "${testcvs} rm imported-f1" \
+"${PROG}"' [a-z]*: scheduling `imported-f1'\'' for removal
+'"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to remove this file permanently'
# change
echo local-change >> imported-f2
# commit
- if ${CVS} ci -m local-changes >> ${LOGFILE} 2>&1; then
- pass 100
- else
- fail 100
- fi
+ dotest import-100 "${testcvs} ci -m local-changes" \
+"${PROG} [a-z]*: Examining .
+Removing imported-f1;
+${TESTDIR}/cvsroot/first-dir/imported-f1,v <-- imported-f1
+new revision: delete; previous revision: 1\.1\.1\.1
+done
+Checking in imported-f2;
+${TESTDIR}/cvsroot/first-dir/imported-f2,v <-- imported-f2
+new revision: 1\.2; previous revision: 1\.1
+done"
# log
- if ${CVS} log imported-f1 | grep '1.1.1.2 (dead)' ; then
- fail 101
- else
- pass 101
- fi
+ dotest import-101 "${testcvs} log imported-f1" \
+"
+RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/imported-f1,v
+Working file: imported-f1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ junk-1_0: 1\.1\.1\.1
+ vendor-branch: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: dead; lines: ${PLUS}0 -0
+local-changes
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}0 -0
+first-import
+============================================================================="
# update into the vendor branch.
- if ${CVS} update -rvendor-branch ; then
- pass 102
- else
- fail 102
- fi
+ dotest import-102 "${testcvs} update -rvendor-branch" \
+"${PROG} [a-z]*: Updating .
+[UP] imported-f1
+[UP] imported-f2"
# remove file4 on the vendor branch
rm imported-f4
-
- if ${CVS} rm imported-f4 2>> ${LOGFILE}; then
- pass 103
- else
- fail 103
- fi
+ dotest import-103 "${testcvs} rm imported-f4" \
+"${PROG}"' [a-z]*: scheduling `imported-f4'\'' for removal
+'"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to remove this file permanently'
# commit
- if ${CVS} ci -m vendor-removed imported-f4 >>${LOGFILE}; then
- pass 104
- else
- fail 104
- fi
+ dotest import-104 \
+"${testcvs} ci -m vendor-removed imported-f4" \
+"Removing imported-f4;
+${TESTDIR}/cvsroot/first-dir/imported-f4,v <-- imported-f4
+new revision: delete; previous revision: 1\.1\.1\.1
+done"
# update to main line
- if ${CVS} update -A 2>> ${LOGFILE}; then
- pass 105
- else
- fail 105
- fi
+ dotest import-105 "${testcvs} -q update -A" \
+"${PROG} [a-z]*: warning: imported-f1 is not (any longer) pertinent
+[UP] imported-f2"
# second import - file4 deliberately unchanged
cd ../import-dir
for i in 1 2 3 ; do
- echo rev 2 of file $i >> imported-f"$i"
+ echo rev 2 of file $i >> imported-f"$i"
done
cp imported-f2 ../imported-f2-orig.tmp
- if ${CVS} import -m second-import first-dir vendor-branch junk-2_0 ; then
- pass 106
- else
- fail 106
- fi
- if cmp ../imported-f2-orig.tmp imported-f2; then
- pass 106.5
- else
- fail 106.5
- fi
+ dotest_sort import-106 \
+"${testcvs} import -m second-import first-dir vendor-branch junk-2_0" \
+"
+
+
+ ${PROG} checkout -jvendor-branch:yesterday -jvendor-branch first-dir
+2 conflicts created by this import.
+C first-dir/imported-f1
+C first-dir/imported-f2
+I first-dir/RCS
+U first-dir/imported-f3
+U first-dir/imported-f4
+Use the following command to help the merge:"
+
+ dotest import-106.5 "cmp ../imported-f2-orig.tmp imported-f2" \
+''
+
cd ..
+
rm imported-f2-orig.tmp
# co
- if ${CVS} co first-dir ; then
- pass 107
- else
- fail 107
- fi
+ dotest import-107 "${testcvs} co first-dir" \
+"${PROG} [a-z]*: Updating first-dir
+[UP] first-dir/imported-f3
+[UP] first-dir/imported-f4"
cd first-dir
- if test -f imported-f1 ; then
- fail 108
- else
- pass 108
- fi
+ dotest_fail import-108 "test -f imported-f1" ''
for i in 2 3 ; do
- if test -f imported-f"$i" ; then
- pass 109-$i
- else
- fail 109-$i
- fi
+ dotest import-109-$i "test -f imported-f$i" ''
done
# check vendor branch for file4
- if ${CVS} update -rvendor-branch ; then
- pass 110
- else
- fail 110
- fi
+ dotest import-110 "${testcvs} -q update -rvendor-branch" \
+"[UP] imported-f1
+[UP] imported-f2"
- if test -f imported-f4 ; then
- pass 111
- else
- fail 111
- fi
+ dotest import-111 "test -f imported-f4" ''
# update to main line
- if ${CVS} update -A 2>> ${LOGFILE}; then
- pass 112
- else
- fail 112
- fi
+ dotest import-112 "${testcvs} -q update -A" \
+"${PROG} [a-z]*: warning: imported-f1 is not (any longer) pertinent
+[UP] imported-f2"
cd ..
@@ -3894,18 +4959,10 @@ rcsmerge: warning: conflicts during merge"
cd first-dir
- if test -f imported-f1 ; then
- fail 114
- else
- pass 114
- fi
+ dotest_fail import-114 "test -f imported-f1" ''
for i in 2 3 ; do
- if test -f imported-f"$i" ; then
- pass 115-$i
- else
- fail 115-$i
- fi
+ dotest import-115-$i "test -f imported-f$i" ''
done
dotest import-116 'cat imported-f2' \
@@ -3950,12 +5007,14 @@ No conflicts created by this import"
echo 'FreeMunger sources' >file2
# Not completely sure how the conflict detection is supposed to
# be working here (haven't really thought about it).
+ # We use an explicit -d option to test that it is reflected
+ # in the suggested checkout.
dotest_sort importb-2 \
-"${testcvs} import -m add -b 1.1.3 first-dir freemunger freemunger-1_0" \
+"${testcvs} -d ${CVSROOT} import -m add -b 1.1.3 first-dir freemunger freemunger-1_0" \
"
- ${PROG} checkout -jfreemunger:yesterday -jfreemunger first-dir
+ ${PROG} -d ${CVSROOT} checkout -jfreemunger:yesterday -jfreemunger first-dir
2 conflicts created by this import.
C first-dir/file1
C first-dir/file2
@@ -4024,16 +5083,25 @@ add
importc)
# Test importing a bunch o' files in a bunch o' directories.
+ # Also the -d option.
mkdir 1; cd 1
mkdir adir bdir cdir
mkdir adir/sub1 adir/sub2
mkdir adir/sub1/ssdir
mkdir bdir/subdir
touch adir/sub1/file1 adir/sub2/file2 adir/sub1/ssdir/ssfile
- touch bdir/subdir/file1
- touch cdir/cfile
+ # If I'm correctly reading the Single Unix Specification,
+ # version 2, then "touch -t 197107040343" or "touch -t 203412251801"
+ # should work. But GNU touch seems to have other ideas.
+ # I sort of wonder if this is lossage by the standards bodies,
+ # I'm not sure.
+ # Note that some versions of touch when used without -t don't handle
+ # y2k and/or set the seconds reliably.
+ # We should probably find a different way of doing this.
+ touch 0704034371 bdir/subdir/file1
+ touch 1225180134 cdir/cfile
dotest_sort importc-1 \
-"${testcvs} import -m import-it first-dir vendor release" \
+"${testcvs} import -d -m import-it first-dir vendor release" \
"
N first-dir/adir/sub1/file1
@@ -4077,7 +5145,7 @@ ${PROG} [a-z]*: Updating bdir/subdir"
# 1.9 did not).
dotest_fail importc-7 "${testcvs} -q ci -m modify -r wip_test" \
"${PROG} [a-z]*: in directory adir/sub1/ssdir:
-${PROG} \[[a-z]* aborted\]: there is no version here; do .cvs checkout. first"
+${PROG} \[[a-z]* aborted\]: there is no version here; do .${PROG} checkout. first"
# The workaround is to leave off the "-r wip_test".
dotest importc-8 "${testcvs} -q ci -m modify" \
"Checking in cdir/cfile;
@@ -4092,13 +5160,136 @@ ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v <-- cfile
new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1
done"
fi
+
+ # TODO: should also be testing "import -d" when we update
+ # an existing file.
+ dotest importc-8 "${testcvs} -q log cdir/cfile" "
+RCS file: ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v
+Working file: cdir/cfile
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ wip_test: 1\.1\.1\.1\.0\.2
+ release: 1\.1\.1\.1
+ vendor: 1\.1\.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+----------------------------
+revision 1\.1
+date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp;
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0
+branches: 1\.1\.1\.1\.2;
+import-it
+----------------------------
+revision 1\.1\.1\.1\.2\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+modify
+============================================================================="
+
+ dotest importc-9 "${testcvs} -q log bdir/subdir/file1" "
+RCS file: ${TESTDIR}/cvsroot/first-dir/bdir/subdir/file1,v
+Working file: bdir/subdir/file1
+head: 1\.1
+branch: 1\.1\.1
+locks: strict
+access list:
+symbolic names:
+ wip_test: 1\.1\.1\.1\.0\.2
+ release: 1\.1\.1\.1
+ vendor: 1\.1\.1
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.1
+date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp;
+branches: 1\.1\.1;
+Initial revision
+----------------------------
+revision 1\.1\.1\.1
+date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0
+import-it
+============================================================================="
cd ..
+ # Now tests of absolute pathnames and .. as repository directory.
+ cd ../1
+ dotest_fail importc-10 \
+"${testcvs} import -m imp ../other vendor release2" \
+"${PROG} \[[a-z]* aborted\]: directory \.\./other not relative within the repository"
+ dotest_fail importc-11 \
+"${testcvs} import -m imp ${TESTDIR}/other vendor release3" \
+"${PROG} \[[a-z]* aborted\]: directory ${TESTDIR}/other not relative within the repository"
+ dotest_fail importc-12 "test -d ${TESTDIR}/other" ""
cd ..
+
rm -r 1 2
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ import-after-initial)
+ # Properly handle the case in which the first version of a
+ # file is created by a regular cvs add and commit, and there
+ # is a subsequent cvs import of the same file. cvs update with
+ # a date tag must resort to searching the vendor branch only if
+ # the initial version of the file was created at the same time
+ # as the initial version on the vendor branch.
+
+ mkdir 1; cd 1
+ module=x
+
+ echo > unused-file
+
+ # Create the module.
+ dotest import-after-initial-1 \
+ "$testcvs -Q import -m. $module X Y" ''
+
+ file=m
+ # Check it out and add a file.
+ dotest import-after-initial-2 "$testcvs -Q co $module" ''
+ cd $module
+ echo original > $file
+ dotest import-after-initial-3 "${testcvs} -Q add $file" \
+"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to add this file permanently'
+ dotest import-after-initial-4 "${testcvs} -Q ci -m. $file" \
+"RCS file: ${TESTDIR}/cvsroot/$module/$file,v
+done
+Checking in $file;
+${TESTDIR}/cvsroot/$module/$file,v <-- $file
+initial revision: 1\.1
+done"
+
+ # Delay a little so the following import isn't done in the same
+ # second as the preceding commit.
+ sleep 2
+
+ # Do the first import of $file *after* $file already has an
+ # initial version.
+ mkdir sub
+ cd sub
+ echo newer-via-import > $file
+ dotest import-after-initial-5 \
+ "$testcvs -Q import -m. $module X Y2" ''
+ cd ..
+
+ # Sleep a second so we're sure to be after the second of the import.
+ sleep 1
+
+ dotest import-after-initial-6 \
+ "$testcvs -Q update -p -D now $file" 'original'
+
+ cd ../..
+ rm -rf 1
+ rm -rf ${CVSROOT_DIRNAME}/$module
+ ;;
+
join)
# Test doing joins which involve adding and removing files.
# Variety of scenarios (see list below), in the context of:
@@ -4108,6 +5299,8 @@ done"
# See also binfile2, which does similar things with binary files.
# See also join2, which tests joining (and update -A) on only
# a single file, rather than a directory.
+ # See also rmadd2, which tests -j cases not involving branches
+ # (e.g. undoing a commit)
# See also join3, which tests some cases involving the greatest
# common ancestor. Here is a list of tests according to branch
# topology:
@@ -4728,6 +5921,60 @@ br2:line1
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ join-readonly-conflict)
+ # Demonstrate that cvs-1.9.29 can fail on 2nd and subsequent
+ # conflict-evoking join attempts.
+ # Even with that version of CVS, This test failed only in
+ # client-server mode, and would have been noticed in normal
+ # operation only for files that were read-only (either due to
+ # use of cvs' global -r option, setting the CVSREAD envvar,
+ # or use of watch lists).
+ mkdir 1; cd 1
+ dotest join-readonly-conflict-1 "$testcvs -q co -l ." ''
+ module=x
+ mkdir $module
+ $testcvs -q add $module >>$LOGFILE 2>&1
+ cd $module
+
+ file=m
+ echo trunk > $file
+ $testcvs -q add $file >>$LOGFILE 2>&1
+ $testcvs -q ci -m . $file >>$LOGFILE 2>&1
+
+ $testcvs tag -b B $file >>$LOGFILE 2>&1
+ $testcvs -q update -rB $file >>$LOGFILE 2>&1
+ echo branch B > $file
+ $testcvs ci -m . $file >>$LOGFILE 2>&1
+
+ rm $file
+ $testcvs update -A $file >>$LOGFILE 2>&1
+ # Make sure $file is read-only. This can happen more realistically
+ # via patch -- which could be used to apply a delta, yet would
+ # preserve a file's read-only permissions.
+ echo conflict > $file; chmod u-w $file
+ $testcvs update -r B $file >>$LOGFILE 2>&1
+
+ rm -f $file
+ $testcvs update -A $file >>$LOGFILE 2>&1
+ # This one would fail because cvs couldn't open the existing
+ # (and read-only) .# file for writing.
+ echo conflict > $file
+
+ test -w ".#$file.1.1" && fail "$file is writable"
+ dotest join-readonly-conflict-2 "$testcvs update -r B $file" \
+"RCS file: ${TESTDIR}/cvsroot/$module/$file,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into $file
+rcsmerge: warning: conflicts during merge
+${PROG} [a-z]*: conflicts found in $file
+C m"
+
+ cd ../..
+ rm -rf 1
+ rm -rf ${CVSROOT_DIRNAME}/$module
+ ;;
+
new) # look for stray "no longer pertinent" messages.
mkdir ${CVSROOT_DIRNAME}/first-dir
@@ -4973,6 +6220,14 @@ File: a Status: Needs Merge
Sticky Tag: (none)
Sticky Date: (none)
Sticky Options: (none)"
+ dotest conflicts-129a "${testcvs} -nq update a" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/a,v
+retrieving revision 1\.1
+retrieving revision 1\.2
+Merging differences between 1\.1 and 1\.2 into a
+rcsmerge: warning: conflicts during merge
+${PROG} [a-z]*: conflicts found in a
+C a"
dotest conflicts-130 "${testcvs} -q update" \
"RCS file: ${TESTDIR}/cvsroot/first-dir/a,v
retrieving revision 1\.1
@@ -5163,6 +6418,9 @@ done"
U first-dir/abc'
cd ..
+ # BEGIN TESTS USING THE FILE A
+ # FIXME: would be cleaner to separate them out into their own
+ # tests; conflicts2 is getting long.
# Now test that if one person modifies and commits a
# file and a second person removes it, it is a
# conflict
@@ -5186,7 +6444,46 @@ C a"
dotest conflicts2-142b5 "${testcvs} add a" "U a
${PROG} [a-z]*: a, version 1\.1, resurrected"
dotest conflicts2-142b6 "${testcvs} -q update" ''
+
+ # Now one level up.
+ cd ..
+ dotest conflicts2-142b7 "${testcvs} rm -f first-dir/a" \
+"${PROG} [a-z]*: scheduling .first-dir/a. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+
+ if test "$remote" = no; then
+ # The "nothing known" is a bug. Correct behavior is for a to get
+ # created, as above. Cause is pretty obvious - add.c
+ # calls update() without dealing with the fact we are chdir'd.
+ # Also note that resurrecting 1.2 instead of 1.1 is also a
+ # bug, I think (the same part of add.c has a comment which says
+ # "XXX - bugs here; this really resurrect the head" which
+ # presumably refers to this).
+ # The fix for both is presumably to call RCS_checkout() or
+ # something other than update().
+ dotest conflicts2-142b8 "${testcvs} add first-dir/a" \
+"${PROG} [a-z]*: nothing known about first-dir
+${PROG} [a-z]*: first-dir/a, version 1\.2, resurrected"
+ cd first-dir
+ # Now recover from the damage that the 142b8 test did.
+ dotest conflicts2-142b9 "${testcvs} rm -f a" \
+"${PROG} [a-z]*: scheduling .a. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ else
+ # Haven't investigated this one.
+ dotest_fail conflicts2-142b8 "${testcvs} add first-dir/a" \
+"${PROG} add: in directory \.:
+${PROG} \[add aborted\]: there is no version here; do '${PROG} checkout' first"
+ cd first-dir
+ fi
+
+ # As before, 1.2 instead of 1.1 is a bug.
+ dotest conflicts2-142b10 "${testcvs} add a" "U a
+${PROG} [a-z]*: a, version 1\.2, resurrected"
+ # As with conflicts2-142b6, check that things are normal again.
+ dotest conflicts2-142b11 "${testcvs} -q update" ''
cd ../..
+ # END TESTS USING THE FILE A
# Now test that if one person removes a file and
# commits it, and a second person removes it, is it
@@ -5438,7 +6735,7 @@ ${PROG} [a-z]*: ignoring first-dir/sdir (CVS/Entries missing)"
dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile"
rm -r sdir/CVS
- dotest conflicts3-22 "${testcvs} -q update" "? sdir"
+ dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir"
if test "x$remote" = xyes; then
# It isn't particularly swift that CVS prints this
# "cannot open CVS/Entries" where it has already printed
@@ -5456,6 +6753,37 @@ C sdir/sfile"
"${QUESTION} sdir"
fi
+ # Not that it should really affect much, but let's do the case
+ # where sfile has been removed. For example, suppose that sdir
+ # had been a CVS-controlled directory which was then removed
+ # by removing each file (and using update -P or some such). Then
+ # suppose that the build process creates an sdir directory which
+ # is not supposed to be under CVS.
+ rm -r sdir
+ dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile"
+ rm sdir/sfile
+ dotest conflicts3-25 "${testcvs} rm sdir/sfile" \
+"${PROG} [a-z]*: scheduling .sdir/sfile. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ dotest conflicts3-26 "${testcvs} ci -m remove sdir/sfile" \
+"Removing sdir/sfile;
+${TESTDIR}/cvsroot/first-dir/sdir/sfile,v <-- sfile
+new revision: delete; previous revision: 1\.1
+done"
+ rm -r sdir/CVS
+ dotest conflicts3-27 "${testcvs} -q update" "${QUESTION} sdir"
+ if test "x$remote" = xyes; then
+ # Regarding "cannot open CVS/Entries", see comments at
+ # conflicts3-23.
+ dotest conflicts3-28 "${testcvs} -q update -PdA" \
+"${QUESTION} sdir
+${PROG} update: in directory sdir:
+${PROG} update: cannot open CVS/Entries for reading: No such file or directory"
+ else
+ dotest conflicts3-28 "${testcvs} -q update -PdA" \
+"${QUESTION} sdir"
+ fi
+
cd ../..
rm -r 1 2
@@ -5906,10 +7234,7 @@ ${PROG} [a-z]*: Rebuilding administrative file database"
dotest modules2-5 "test -d ampermodule/second-dir" ''
# Test ability of cvs release to handle multiple arguments
- # Other CVS release tests:
- # info-cleanup-0 for "cvs -n release".
- # ignore-193 for the text of the question that cvs release asks.
- # Also for interactions with cvsignore.
+ # See comment at "release" for list of other cvs release tests.
cd ampermodule
if ${testcvs} release -d first-dir second-dir <<EOF >>${LOGFILE}
yes
@@ -5983,26 +7308,15 @@ U first-dir/amper1"
dotest modules2-16 "test -f combmodule/first-dir/amper1" ""
cd combmodule
rm -r first-dir
- # Might be possible to have a more graceful error message,
- # but at least for now there is no way to tell CVS that
+ # At least for now there is no way to tell CVS that
# some files/subdirectories come from one repository directory,
# and others from another.
- if test "$remote" = no; then
- dotest_fail modules2-17 "${testcvs} update -d" \
-"${PROG} [a-z]*: Updating \.
-${PROG} [a-z]*: Updating first-dir
-${PROG} \[[a-z]* aborted\]: cannot open directory ${TESTDIR}/cvsroot/third-dir/first-dir: No such file or directory"
- # Clean up the droppings left by the previous command.
- # This should definitely not be necessary (I think).
- rm -r first-dir
- else
- # This seems like a pretty sensible behavior to me, in the
- # sense that first-dir doesn't "really" exist within
- # third-dir, so CVS just acts as if there is nothing there
- # to do.
- dotest modules2-17 "${testcvs} update -d" \
-"${PROG} server: Updating \."
- fi
+ # This seems like a pretty sensible behavior to me, in the
+ # sense that first-dir doesn't "really" exist within
+ # third-dir, so CVS just acts as if there is nothing there
+ # to do.
+ dotest modules2-17 "${testcvs} update -d" \
+"${PROG} [a-z]*: Updating \."
cd ..
dotest modules2-18 "${testcvs} -q co combmodule" \
@@ -6164,7 +7478,7 @@ done"
if test "x$remote" = xyes; then
dotest_fail modules3-11b \
"${testcvs} -q update ${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1" \
-"${PROG} .server aborted.: absolute pathname .${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1. illegal for server"
+"absolute pathname .${TESTDIR}/1/src/sub1/sub2/sub3/dir. illegal for server"
fi # end of remote-only tests
cd ..
@@ -6332,6 +7646,30 @@ add-it
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ mkmodules-temp-file-removal)
+ # When a file listed in checkoutlist doesn't exist, cvs-1.10.4
+ # would fail to remove the CVSROOT/.#[0-9]* temporary file it
+ # creates while mkmodules is in the process of trying to check
+ # out the missing file.
+
+ mkdir 1; cd 1
+ dotest mtfr-1 "${testcvs} -Q co CVSROOT" ''
+ cd CVSROOT
+ echo no-such-file >> checkoutlist
+ dotest mtfr-2 "${testcvs} -Q ci -m. checkoutlist" \
+"Checking in checkoutlist;
+$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist
+new revision: 1\.2; previous revision: 1\.1
+done
+$PROG [a-z]*: Rebuilding administrative file database"
+
+ dotest mtfr-3 "echo $CVSROOT_DIRNAME/CVSROOT/.#[0-9]*" \
+ "$CVSROOT_DIRNAME/CVSROOT/\.#\[0-9\]\*"
+
+ cd ../..
+ rm -rf 1
+ ;;
+
cvsadm)
# These test check the content of CVS' administrative
# files as they are checked out in various configurations.
@@ -7812,22 +9150,15 @@ done"
U dir2d1/sub2d1/file1"
cd dir2d1
touch emptyfile
- # The fact that CVS lets us add a file here is a CVS bug, right?
- # I can just make this an error message (on the add and/or the
- # commit) without getting flamed, right?
- # Right?
- # Right?
+ # It doesn't make any sense to add a file (or do much of anything
+ # else) in Emptydir; Emptydir is a placeholder indicating that
+ # the working directory doesn't correspond to anything in
+ # the repository.
dotest emptydir-7 "${testcvs} add emptyfile" \
"${PROG} [a-z]*: scheduling file .emptyfile. for addition
${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
- dotest emptydir-8 "${testcvs} -q ci -m add" \
-"RCS file: ${TESTDIR}/cvsroot/CVSROOT/Emptydir/emptyfile,v
-done
-Checking in emptyfile;
-${TESTDIR}/cvsroot/CVSROOT/Emptydir/emptyfile,v <-- emptyfile
-initial revision: 1\.1
-done
-${PROG} [a-z]*: Rebuilding administrative file database"
+ dotest_fail emptydir-8 "${testcvs} -q ci -m add" \
+"${PROG} \[[a-z]* aborted\]: cannot check in to ${TESTDIR}/cvsroot/CVSROOT/Emptydir"
cd ..
rm -rf CVS dir2d1
@@ -8739,6 +10070,10 @@ Checking in first-dir/sdir10/ssdir/ssfile;
${TESTDIR}/cvsroot/first-dir/sdir10/ssdir/ssfile,v <-- ssfile
initial revision: 1\.1
done"
+ dotest errmsg2-18 "${testcvs} -Q tag test" ''
+
+ dotest_fail errmsg2-19 "${testcvs} annotate -rtest -Dyesterday" \
+"${PROG} \[[a-z]* aborted\]: rcsbuf_open: internal error"
cd ..
rm -r 1
@@ -8806,17 +10141,7 @@ done"
pass 177
fi
- if ${testcvs} editors >../ans178.tmp; then
- pass 178
- else
- fail 178
- fi
- cat ../ans178.tmp >>${LOGFILE}
- if test -s ../ans178.tmp; then
- fail 178a
- else
- pass 178a
- fi
+ dotest devcom-178 "${testcvs} editors" ""
if ${testcvs} edit abb; then
pass 179
@@ -8824,17 +10149,13 @@ done"
fail 179
fi
- if ${testcvs} editors >../ans180.tmp; then
- pass 180
- else
- fail 180
- fi
- cat ../ans180.tmp >>${LOGFILE}
- if test -s ../ans180.tmp; then
- pass 181
- else
- fail 181
- fi
+ # Here we test for the traditional ISO C ctime() date format.
+ # We assume the C locale; I guess that works provided we set
+ # LC_ALL at the start of this script but whether these
+ # strings should vary based on locale does not strike me as
+ # self-evident.
+ dotest devcom-180 "${testcvs} editors" \
+"abb ${username} [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] GMT [-a-zA-Z_.0-9]* ${TESTDIR}/2/first-dir"
echo aaaa >>abb
if ${testcvs} ci -m modify abb >>${LOGFILE} 2>&1; then
@@ -8845,17 +10166,7 @@ done"
# Unedit of a file not being edited should be a noop.
dotest 182.5 "${testcvs} unedit abb" ''
- if ${testcvs} editors >../ans183.tmp; then
- pass 183
- else
- fail 183
- fi
- cat ../ans183.tmp >>${LOGFILE}
- if test -s ../ans183.tmp; then
- fail 184
- else
- pass 184
- fi
+ dotest devcom-183 "${testcvs} editors" ""
if test -w abb; then
fail 185
@@ -9083,7 +10394,7 @@ D _watched="
Fw2 _watched="
# Now write a few more lines, just as if we were a newer version
# of CVS implementing some new feature.
- cat <<EOF >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
+ cat <<'EOF' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
Enew line here
G@#$^!@#=&
EOF
@@ -9112,6 +10423,31 @@ Fw1 _watched=
Enew line here
G@#..!@#=&"
+ # Now test disconnected "cvs edit" and the format of the
+ # CVS/Notify file.
+ if test "$remote" = yes; then
+ CVS_SERVER_SAVED=${CVS_SERVER}
+ CVS_SERVER=${TESTDIR}/cvs-none; export CVS_SERVER
+
+ # The ${DOTSTAR} matches the exact exec error message
+ # (which varies) and either "end of file from server"
+ # (if the process doing the exec exits before the parent
+ # gets around to sending data to it) or "broken pipe" (if it
+ # is the other way around).
+ dotest_fail devcom3-9a "${testcvs} edit w1" \
+"${PROG} \[edit aborted\]: cannot exec ${TESTDIR}/cvs-none: ${DOTSTAR}"
+ dotest devcom3-9b "test -w w1" ""
+ dotest devcom3-9c "cat CVS/Notify" \
+"Ew1 [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] GMT [-a-zA-Z_.0-9]* ${TESTDIR}/1/first-dir EUC"
+ CVS_SERVER=${CVS_SERVER_SAVED}; export CVS_SERVER
+ dotest devcom3-9d "${testcvs} -q update" ""
+ dotest_fail devcom3-9e "test -f CVS/Notify" ""
+ dotest devcom3-9f "${testcvs} watchers w1" \
+"w1 ${username} tedit tunedit tcommit"
+ dotest devcom3-9g "${testcvs} unedit w1" ""
+ dotest devcom3-9h "${testcvs} watchers w1" ""
+ fi
+
cd ../..
# OK, now change the tab to a space, and see that CVS gives
# a reasonable error (this is database corruption but CVS should
@@ -9221,6 +10557,71 @@ C file1"
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ watch5)
+ # This test was designed to catch a problem in server
+ # mode where an 'cvs edit'd file disappeared from the
+ # CVS/Base directory when 'cvs status' or 'cvs update'
+ # was called on the file after the file was touched.
+ #
+ # This test is still here to prevent the bug from
+ # being reintroduced.
+ #
+ # The rationale for having CVS/Base stay around is that
+ # CVS/Base should be there if "cvs edit" has been run (this
+ # may be helpful as a "cvs editors" analogue, it is
+ # client-side and based on working directory not username;
+ # but more importantly, it isn't clear why a "cvs status"
+ # would act like an unedit, and even if it does, it would
+ # need to make the file read-only again).
+
+ mkdir watch5; cd watch5
+ dotest watch5-0a "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest watch5-0b "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+
+ cd first-dir
+ dotest watch5-1 "${testcvs} watch on" ''
+ # This is just like the 173 test
+ touch file1
+ dotest watch5-2 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest watch5-3 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done"
+ dotest watch5-4 "${testcvs} edit file1" ''
+ dotest watch5-5 "test -f CVS/Base/file1" ''
+ if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
+ pass watch5-6
+ else
+ fail watch5-6
+ fi
+ dotest watch5-7 "test -f CVS/Base/file1" ''
+
+ # Here's where the file used to dissappear
+ touch file1
+ if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
+ pass watch5-8
+ else
+ fail watch5-8
+ fi
+ dotest watch5-10 "test -f CVS/Base/file1" ''
+
+ # Make sure update won't remove the file either
+ touch file1
+ dotest watch5-11 "${testcvs} -q up" ''
+ dotest watch5-12 "test -f CVS/Base/file1" ''
+
+ cd ../..
+ rm -r watch5
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
unedit-without-baserev)
mkdir 1; cd 1
module=x
@@ -9250,7 +10651,7 @@ ${PROG} unedit: run update to complete the unedit"
# SunOS4.1.4 systems make it this far, but with a corrupted
# CVS/Entries file. Demonstrate the corruption!
dotest unedit-without-baserev-5 "cat CVS/Entries" \
- "/$file/1\.1\.1\.1/.*"
+ "/$file/1\.1\.1\.1/${DOTSTAR}"
if test "$remote" = yes; then
dotest unedit-without-baserev-6 "${testcvs} -q update" "U m"
@@ -9476,11 +10877,18 @@ Are you sure you want to release (and delete) directory .second-dir': "
binfiles)
# Test cvs's ability to handle binary files.
+ # List of binary file tests:
+ # * conflicts, "cvs admin": binfiles
+ # * branching and joining: binfiles2
+ # * adding and removing files: binfiles3
+ # * -k wrappers: binwrap, binwrap2, binwrap3
+ # * "cvs import" and wrappers: binwrap, binwrap2, binwrap3
+ # * -k option to "cvs import": none yet, as far as I know.
mkdir ${CVSROOT_DIRNAME}/first-dir
mkdir 1; cd 1
dotest binfiles-1 "${testcvs} -q co first-dir" ''
- awk 'BEGIN { printf "%c%c%c%c%c%c", 2, 10, 137, 0, 13, 10 }' \
- </dev/null >binfile.dat
+ awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | tr '@' '\000' >binfile.dat
cat binfile.dat binfile.dat >binfile2.dat
cd first-dir
cp ../binfile.dat binfile
@@ -9577,7 +10985,6 @@ done"
dotest binfiles-13 "${testcvs} -q update -A" ''
cd ../..
- rm -r 1
mkdir 3
cd 3
@@ -9713,8 +11120,14 @@ keyword substitution: v
total revisions: 1
============================================================================="
+ # Check that the contents were right. This isn't the hard case
+ # (in which RCS_delete_revs does a diff), but might as well.
+ dotest binfiles-o4 "${testcvs} -q update binfile" "U binfile"
+ dotest binfiles-o5 "cmp binfile ../../1/binfile.dat" ""
+
cd ../..
rm -rf ${CVSROOT_DIRNAME}/first-dir
+ rm -r 1
rm -r 2
;;
@@ -9746,8 +11159,8 @@ total revisions: 1
# each be distinct from each other. We also make sure to include
# a few likely end-of-line patterns to make sure nothing is
# being munged as if in text mode.
- awk 'BEGIN { printf "%c%c%c%c%c%c", 2, 10, 137, 0, 13, 10 }' \
- </dev/null >../binfile
+ awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | tr '@' '\000' >../binfile
cat ../binfile ../binfile >../binfile2
cat ../binfile2 ../binfile >../binfile3
@@ -9902,6 +11315,96 @@ checkin
rm -r 1
;;
+ binfiles3)
+ # More binary file tests, especially removing, adding, &c.
+ # See "binfiles" for a list of binary file tests.
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ mkdir 1; cd 1
+ dotest binfiles3-1 "${testcvs} -q co first-dir" ''
+ awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | tr '@' '\000' >binfile.dat
+ cd first-dir
+ echo hello >file1
+ dotest binfiles3-2 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest binfiles3-3 "${testcvs} -q ci -m add-it" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done"
+ rm file1
+ dotest binfiles3-4 "${testcvs} rm file1" \
+"${PROG} [a-z]*: scheduling .file1. for removal
+${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently"
+ dotest binfiles3-5 "${testcvs} -q ci -m remove-it" \
+"Removing file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: delete; previous revision: 1\.1
+done"
+ cp ../binfile.dat file1
+ dotest binfiles3-6 "${testcvs} add -kb file1" \
+"${PROG} [a-z]*: re-adding file file1 (in place of dead revision 1\.2)
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ # The idea behind this test is to make sure that the file
+ # gets opened in binary mode to send to "cvs ci".
+ dotest binfiles3-6a "cat CVS/Entries" \
+"/file1/0/[A-Za-z0-9 :]*/-kb/
+D"
+ # TODO: This just tests the case where the old keyword
+ # expansion mode is the default (RCS_getexpand == NULL
+ # in checkaddfile()); should also test the case in which
+ # we are changing it from one non-default value to another.
+ dotest binfiles3-7 "${testcvs} -q ci -m readd-it" \
+"${PROG} [a-z]*: changing keyword expansion mode to -kb
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+done"
+ dotest binfiles3-8 "${testcvs} -q log -h -N file1" "
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+Working file: file1
+head: 1\.3
+branch:
+locks: strict
+access list:
+keyword substitution: b
+total revisions: 3
+============================================================================="
+
+ # OK, now test admin -o on a binary file. See "admin"
+ # test for a more complete list of admin -o tests.
+ cp ${TESTDIR}/1/binfile.dat ${TESTDIR}/1/binfile4.dat
+ echo '%%$$##@@!!jjiiuull' | tr j '\000' >>${TESTDIR}/1/binfile4.dat
+ cp ${TESTDIR}/1/binfile4.dat ${TESTDIR}/1/binfile5.dat
+ echo 'aawwee%$$##@@!!jjil' | tr w '\000' >>${TESTDIR}/1/binfile5.dat
+
+ cp ../binfile4.dat file1
+ dotest binfiles3-9 "${testcvs} -q ci -m change" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+done"
+ cp ../binfile5.dat file1
+ dotest binfiles3-10 "${testcvs} -q ci -m change" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+done"
+ dotest binfiles3-11 "${testcvs} admin -o 1.3::1.5 file1" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+deleting revision 1\.4
+done"
+ dotest binfiles3-12 "${testcvs} -q update -r 1.3 file1" "U file1"
+ dotest binfiles3-13 "cmp file1 ${TESTDIR}/1/binfile.dat" ""
+
+ cd ../..
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
mcopy)
# See comment at "mwrap" test for list of other wrappers tests.
# Test cvs's ability to handle nonmergeable files specified with
@@ -10447,7 +11950,24 @@ done"
cd ../..
cd m1/first-dir
echo "changed in m1" >aa
- dotest_fail mwrap-7 "${testcvs} -nq update" "C aa"
+ if test "$remote" = no; then
+ dotest mwrap-7 "${testcvs} -nq update" \
+"U aa
+${PROG} [a-z]*: nonmergeable file needs merge
+${PROG} [a-z]*: revision 1\.2 from repository is now in aa
+${PROG} [a-z]*: file from working directory is now in \.#aa\.1\.1
+C aa"
+ else
+ # The tagged text code swallows up "U aa" but isn't yet up to
+ # trying to figure out how it interacts with the "C aa" and
+ # other stuff. The whole deal of having both is pretty iffy.
+ dotest mwrap-7 "${testcvs} -nq update" \
+"${PROG} [a-z]*: nonmergeable file needs merge
+${PROG} [a-z]*: revision 1\.2 from repository is now in aa
+${PROG} [a-z]*: file from working directory is now in \.#aa\.1\.1
+C aa
+U aa"
+ fi
dotest mwrap-8 "${testcvs} -q update" \
"U aa
${PROG} [a-z]*: nonmergeable file needs merge
@@ -10630,6 +12150,7 @@ ${PROG} [a-z]*: Rebuilding administrative file database"
fi
cd ..
rm -r wnt
+ rm $HOME/.cvsrc
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
@@ -10639,8 +12160,6 @@ ${PROG} [a-z]*: Rebuilding administrative file database"
# Tests to add:
# -F to move
- # -d
- # rtag
mkdir 1; cd 1
dotest taginfo-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}"
@@ -10708,6 +12227,16 @@ ${PROG} \[[a-z]* aborted\]: correct the above errors first!"
# specified or not.
dotest taginfo-13 "${testcvs} -nq tag would-be-tag" "T file1"
+ # Deleting: the cases are basically either the tag existed,
+ # or it didn't exist.
+ dotest taginfo-14 "${testcvs} -q tag -d tag1" "D file1"
+ dotest taginfo-15 "${testcvs} -q tag -d tag1" ""
+
+ # Likewise with rtag.
+ dotest taginfo-16 "${testcvs} -q rtag tag1 first-dir" ""
+ dotest taginfo-17 "${testcvs} -q rtag -d tag1 first-dir" ""
+ dotest taginfo-18 "${testcvs} -q rtag -d tag1 first-dir" ""
+
# The "br" example should be passing 1.1.2 or 1.1.0.2.
# But it turns out that is very hard to implement, since
# check_fileproc doesn't know what branch number it will
@@ -10722,7 +12251,12 @@ ${PROG} \[[a-z]* aborted\]: correct the above errors first!"
dotest taginfo-examine "cat ${TESTDIR}/1/taglog" \
"tag1 add ${TESTDIR}/cvsroot/first-dir file1 1.1
br add ${TESTDIR}/cvsroot/first-dir file1 1.1
-brtag mov ${TESTDIR}/cvsroot/first-dir file1 1.1.2.1"
+brtag mov ${TESTDIR}/cvsroot/first-dir file1 1.1.2.1
+tag1 del ${TESTDIR}/cvsroot/first-dir file1 1.1
+tag1 del ${TESTDIR}/cvsroot/first-dir
+tag1 add ${TESTDIR}/cvsroot/first-dir file1 1.1
+tag1 del ${TESTDIR}/cvsroot/first-dir file1 1.1
+tag1 del ${TESTDIR}/cvsroot/first-dir"
cd ..
cd CVSROOT
@@ -10859,6 +12393,7 @@ U file1'
# -N: log, log2, admin-19a-log
# -b, -r: log
# -d: rcs
+ # -s, -R: rcs3
# Check in a file with a few revisions and branches.
mkdir ${CVSROOT_DIRNAME}/first-dir
@@ -11003,6 +12538,28 @@ description:
${log_rev3}
${log_trailer}"
+ dotest log-14a "${testcvs} log -rHEAD file1" \
+"${log_header}
+${log_tags}
+${log_header2}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
+ # The user might not realize that "-r" must not take a space.
+ # In the error message, HEAD is a file name, not a tag name (which
+ # might be confusing itself).
+ dotest_fail log-14b "${testcvs} log -r HEAD file1" \
+"${PROG} [a-z]*: nothing known about HEAD
+${log_header}
+${log_tags}
+${log_header2}
+total revisions: 5; selected revisions: 1
+description:
+${log_rev3}
+${log_trailer}"
+
dotest log-15 "${testcvs} log -r1.2 file1" \
"${log_header}
${log_tags}
@@ -11182,6 +12739,9 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
dotest log2-7 "${testcvs} admin -t${TESTDIR}/descrip file1" \
"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
done"
+ dotest_fail log2-7a "${testcvs} admin -t${TESTDIR}/nonexist file1" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+${PROG} \[[a-z]* aborted\]: can't stat ${TESTDIR}/nonexist: No such file or directory"
dotest log2-8 "${testcvs} log -N file1" "
RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
Working file: file1
@@ -11204,6 +12764,11 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
# See comments in cvs.texinfo for a few more notes on this.
if test "x$remote" = xno; then
+ # TODO: `cvs admin -t "my message" file1' is a request to
+ # read the message from stdin and to operate on two files.
+ # Should test that there is an error because "my message"
+ # doesn't exist.
+
if echo change from stdin | ${testcvs} admin -t -q file1
then
pass log2-9
@@ -11240,6 +12805,7 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
# Tests of "cvs annotate". See also:
# basica-10 A simple annotate test
# rcs Annotate and the year 2000
+ # keywordlog Annotate and $Log.
mkdir 1; cd 1
dotest ann-1 "${testcvs} -q co -l ." ''
mkdir first-dir
@@ -11471,8 +13037,26 @@ ${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then
mkdir crerepos
mkdir crerepos/CVSROOT
+ # Use :ext: rather than :fork:. Most of the tests use :fork:,
+ # so we want to make sure that we test :ext: _somewhere_.
+
+ # Maybe a bit dubious in the sense that people need to
+ # have rsh working to run the tests, but at least it
+ # isn't inetd :-). Might want to think harder about this -
+ # maybe try :ext:, and if it fails, print a (single, nice)
+ # message and fall back to :fork:. Maybe testing :ext:
+ # with our own CVS_RSH rather than worrying about a system one
+ # would do the trick.
+
+ # Note that we set CVS_SERVER at the beginning.
CREREPOS_ROOT=:ext:`hostname`:${TESTDIR}/crerepos
+ # If we're going to do remote testing, make sure 'rsh' works first.
+ host="`hostname`"
+ if test "x`${CVS_RSH-rsh} $host -n 'echo hi'`" != "xhi"; then
+ echo "ERROR: cannot test remote CVS, because \`rsh $host' fails." >&2
+ exit 1
+ fi
fi
if test "x$remote" = "xno"; then
@@ -11491,6 +13075,10 @@ ${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then
else # remote
# Test that CVS rejects a relative path in CVSROOT.
mkdir 1; cd 1
+ # Note that having the client reject the pathname (as :fork:
+ # does), does _not_ test for the bugs we are trying to catch
+ # here. The point is that malicious clients might send all
+ # manner of things and the server better protect itself.
dotest_fail crerepos-6a \
"${testcvs} -q -d :ext:`hostname`:../crerepos get ." \
"Root ../crerepos must be an absolute pathname"
@@ -11560,31 +13148,17 @@ U first-dir/file1"
dotest crerepos-17 "${testcvs} -d ${CREREPOS_ROOT} co crerepos-dir" \
"${PROG} [a-z]*: Updating crerepos-dir
U crerepos-dir/cfile"
-
- if test x`cat crerepos-dir/CVS/Repository` = xcrerepos-dir; then
- # RELATIVE_REPOS
- # Fatal error so that we don't go traipsing through the
- # directories which happen to have the same names from the
- # wrong repository.
- dotest_fail crerepos-18 "${testcvs} -q update" \
-"${PROG} \[[a-z]* aborted\]: cannot open directory ${TESTDIR}/cvsroot/crerepos-dir: .*" ''
- else
- if test "$remote" = no; then
- # The lack of an error doesn't mean CVS is really
- # working (things are getting logged to the wrong
- # history file and such).
- dotest crerepos-18 "${testcvs} -q update" ''
- else
- # Fatal error so that we don't go traipsing through the
- # directories which happen to have the same names from the
- # wrong repository.
- dotest_fail crerepos-18 "${testcvs} -q update" \
-"protocol error: directory .${TESTDIR}/crerepos/crerepos-dir. not within root .${TESTDIR}/cvsroot."
- fi
- fi
+ dotest crerepos-18 "${testcvs} update" \
+"${PROG} [a-z]*: Updating first-dir
+${PROG} [a-z]*: Updating crerepos-dir"
cd ..
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
rm -r 1
rm -rf ${CVSROOT_DIRNAME}/first-dir ${TESTDIR}/crerepos
;;
@@ -12145,6 +13719,38 @@ EOF
dotest rcs2-5 "cat ${TESTDIR}/rcs4.tmp" \
"${PROG} \[[a-z]* aborted\]: Can't parse date/time: 2003-02-29 11:30 UT"
fi
+
+ dotest rcs2-6 "${testcvs} -q update -p -D 2007-01-07 file1" \
+"head revision"
+ # This assumes that the clock of the machine running the tests
+ # is set to at least the year 1998 or so. There don't seem
+ # to be a lot of ways to test the relative date code (short
+ # of something like LD_LIBRARY_PRELOAD'ing in our own
+ # getttimeofday, or hacking the CVS source with testing
+ # features, which always seems to be problematic since then
+ # someone feels like documenting them and things go downhill
+ # from there).
+ #
+ # Hmm, if this test is run on the 31st of the month, and 100
+ # months from now is a month with only 30 days (e.g. run on
+ # 31 May 1999), it seems to fail.
+ #
+ # Sigh.
+ if ${testcvs} -q update -p -D '100 months' file1 \
+ >${TESTDIR}/rcs4.tmp 2>&1
+ then
+ dotest rcs2-7 "cat ${TESTDIR}/rcs4.tmp" "head revision"
+ else
+ fail rcs2-7
+ fi
+ if ${testcvs} -q update -p -D '8 years' file1 \
+ >${TESTDIR}/rcs4.tmp 2>&1
+ then
+ dotest rcs2-8 "cat ${TESTDIR}/rcs4.tmp" "head revision"
+ else
+ fail rcs2-8
+ fi
+
rm ${TESTDIR}/rcs4.tmp
cd ..
@@ -12152,6 +13758,440 @@ EOF
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ rcs3)
+ # More RCS file tests, in particular at least some of the
+ # error handling issues.
+ mkdir ${CVSROOT_DIRNAME}/first-dir
+ cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc@@1.1log@@text@head@
+EOF
+ mkdir 1; cd 1
+ # CVS requires whitespace between "desc" and its value.
+ # The rcsfile(5) manpage doesn't really seem to answer the
+ # question one way or the other (it has a grammar but almost
+ # nothing about lexical analysis).
+ dotest_fail rcs3-1 "${testcvs} -q co first-dir" \
+"${PROG} \[[a-z]* aborted\]: unexpected end of file reading ${TESTDIR}/cvsroot/first-dir/file1,v"
+ cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1log@@text@head@
+EOF
+ # Whitespace issues, likewise.
+ dotest_fail rcs3-2 "${testcvs} -q co first-dir" \
+"${PROG} \[[a-z]* aborted\]: unexpected '.x6c' reading revision number in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v"
+ cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1 log@@text@head@
+EOF
+ # Charming array of different messages for similar
+ # whitespace issues (depending on where the whitespace is).
+ dotest_fail rcs3-3 "${testcvs} -q co first-dir" \
+"${PROG} \[[a-z]* aborted\]: EOF while looking for value in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v"
+ cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v
+head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
+; author jeremiah ;state ; branches; next;desc @@1.1 log @@text @head@
+EOF
+ dotest rcs3-4 "${testcvs} -q co first-dir" 'U first-dir/file1'
+ if test "$remote" = no; then
+ # Ouch, didn't expect this one. FIXCVS. Or maybe just remove
+ # the feature, if this is a -s problem?
+ dotest_fail rcs3-5 "${testcvs} log -s nostate first-dir/file1" \
+".*[Aa]ssertion.*failed${DOTSTAR}" ".*failed assertion${DOTSTAR}"
+ else # remote
+ # Is this a reaction to the lack of TopLevelAdmin or something?
+ # Seems pretty strange to me. Seems vaguely similar to the
+ # "no repository" message in errmsg2-16 although I'm leaving
+ # it here in case there is a difference between "cvs add" and a
+ # normal start_recursion command like "cvs log".
+ dotest_fail rcs3-5 "${testcvs} log -s nostate first-dir/file1" \
+"${PROG} log: cannot open CVS/Entries for reading: No such file or directory
+${PROG} \[log aborted\]: no repository"
+ cd first-dir
+ dotest_fail rcs3-5a "${testcvs} log -s nostate file1" \
+"${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}"
+ cd ..
+ fi # remote
+
+ # See remote code above for rationale for cd.
+ cd first-dir
+ dotest rcs3-6 "${testcvs} log -R file1" \
+"${TESTDIR}/cvsroot/first-dir/file1,v"
+
+ # OK, now put an extraneous '\0' at the end.
+ awk </dev/null 'BEGIN { printf "@%c", 10 }' | tr '@' '\000' \
+ >>${CVSROOT_DIRNAME}/first-dir/file1,v
+ dotest_fail rcs3-7 "${testcvs} log -s nostate file1" \
+"${PROG} \[[a-z]* aborted\]: unexpected '.x0' reading revision number in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v"
+
+ cd ../..
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ lockfiles)
+ # Tests of CVS lock files.
+ # TODO-maybe: Add a test where we arrange for a loginfo
+ # script (or some such) to ensure that locks are in place
+ # so then we can see how they are behaving.
+
+ mkdir 1; cd 1
+ mkdir sdir
+ mkdir sdir/ssdir
+ echo file >sdir/ssdir/file1
+ dotest lockfiles-1 \
+"${testcvs} -Q import -m import-it first-dir bar baz" ""
+ cd ..
+
+ mkdir 2; cd 2
+ dotest lockfiles-2 "${testcvs} -q co first-dir" \
+"U first-dir/sdir/ssdir/file1"
+ dotest lockfiles-3 "${testcvs} -Q co CVSROOT" ""
+ cd CVSROOT
+ echo "LockDir=${TESTDIR}/locks" >config
+ dotest lockfiles-4 "${testcvs} -q ci -m config-it" \
+"Checking in config;
+${TESTDIR}/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+done
+${PROG} [a-z]*: Rebuilding administrative file database"
+ cd ../first-dir/sdir/ssdir
+ # The error message appears twice because Lock_Cleanup only
+ # stops recursing after the first attempt.
+ dotest_fail lockfiles-5 "${testcvs} -q update" \
+"${PROG} \[[a-z]* aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory
+${PROG} \[[a-z]* aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory"
+ mkdir ${TESTDIR}/locks
+ chmod u=rwx,g=r,o= ${TESTDIR}/locks
+ umask 0077
+ CVSUMASK=0077; export CVSUMASK
+ dotest lockfiles-6 "${testcvs} -q update" ""
+ # TODO: should also be testing that CVS continues to honor the
+ # umask and CVSUMASK normally. In the case of the umask, CVS
+ # doesn't seem to use it for much (although it perhaps should).
+ dotest lockfiles-7 "ls ${TESTDIR}/locks/first-dir/sdir/ssdir" ""
+
+ # The policy is that when CVS creates new lock directories, they
+ # inherit the permissions from the parent directory. CVSUMASK
+ # isn't right, because typically the reason for LockDir is to
+ # use a different set of permissions.
+ dotest lockfiles-7a "ls -ld ${TESTDIR}/locks/first-dir" \
+"drwxr----- .*first-dir"
+ dotest lockfiles-7b "ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir" \
+"drwxr----- .*first-dir/sdir/ssdir"
+
+ cd ../../..
+ dotest lockfiles-8 "${testcvs} -q update" ""
+
+ cd CVSROOT
+ echo "# nobody here but us comments" >config
+ dotest lockfiles-cleanup-1 "${testcvs} -q ci -m config-it" \
+"Checking in config;
+${TESTDIR}/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+done
+${PROG} [a-z]*: Rebuilding administrative file database"
+ cd ../..
+ # Perhaps should restore the umask and CVSUMASK to what they
+ # were before. But the other tests "should" not care about them...
+ umask 0077
+ unset CVSUMASK
+ rm -r ${TESTDIR}/locks
+ rm -r 1 2
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
+ backuprecover)
+ # Tests to make sure we get the expected behavior
+ # when we recover a repository from an old backup
+ #
+ # Details:
+ # Backup will be older than some developer's workspaces
+ # This means the first attempt at an update will fail
+ # The workaround for this is to replace the CVS
+ # directories with those from a "new" checkout from
+ # the recovered repository. Due to this, multiple
+ # merges should cause conflicts (the same data
+ # will be merged more than once).
+ # A workspace updated before the date of the recovered
+ # copy will not need any extra attention
+ #
+ # Note that backuprecover-15 is probably a failure case
+ # If nobody else had a more recent update, the data would be lost
+ # permanently
+ # Granted, the developer should have been notified not to do this
+ # by now, but still...
+ #
+ mkdir backuprecover; cd backuprecover
+ mkdir 1; cd 1
+ dotest backuprecover-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest backuprecover-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ mkdir dir
+ dotest backuprecover-3 "${testcvs} add dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir added to the repository"
+ touch file1 dir/file2
+ dotest backuprecover-4 "${testcvs} -q add file1 dir/file2" \
+"${PROG} [a-z]*: use '${PROG} commit' to add these files permanently"
+ dotest backuprecover-5 "${testcvs} -q ci -mtest" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/first-dir/dir/file2,v
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+initial revision: 1\.1
+done"
+ echo "Line one" >>file1
+ echo " is the place" >>file1
+ echo " we like to begin" >>file1
+ echo "Anything else" >>file1
+ echo " looks like" >>file1
+ echo " a sin" >>file1
+ echo "File 2" >>dir/file2
+ echo " is the place" >>dir/file2
+ echo " the rest of it goes" >>dir/file2
+ echo "Why I don't use" >>dir/file2
+ echo " something like 'foo'" >>dir/file2
+ echo " God only knows" >>dir/file2
+ dotest backuprecover-6 "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.2; previous revision: 1\.1
+done"
+
+ # Simulate the lazy developer
+ # (he did some work but didn't check it in...)
+ cd ../..
+ mkdir 2; cd 2
+ dotest backuprecover-7 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ sed -e"s/looks like/just looks like/" file1 >tmp; mv tmp file1
+ sed -e"s/don't use/don't just use/" dir/file2 >tmp; mv tmp dir/file2
+
+ # developer 1 is on a roll
+ cd ../../1/first-dir
+ echo "I need some more words" >>file1
+ echo " to fill up this space" >>file1
+ echo " anything else would be a disgrace" >>file1
+ echo "My rhymes cross many boundries" >>dir/file2
+ echo " this time it's files" >>dir/file2
+ echo " a word that fits here would be something like dials" >>dir/file2
+ dotest backuprecover-8 "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.3; previous revision: 1\.2
+done"
+
+ # Save a backup copy
+ cp -r ${TESTDIR}/cvsroot/first-dir ${TESTDIR}/cvsroot/backup
+
+ # Simulate developer 3
+ cd ../..
+ mkdir 3; cd 3
+ dotest backuprecover-9a "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ echo >>file1
+ echo >>dir/file2
+ echo "Developer 1 makes very lame rhymes" >>file1
+ echo " I think he should quit and become a mime" >>file1
+ echo "What the %*^# kind of rhyme crosses a boundry?" >>dir/file2
+ echo " I think you should quit and get a job in the foundry" >>dir/file2
+ dotest backuprecover-9b "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.4; previous revision: 1\.3
+done"
+
+ # Developer 4 so we can simulate a conflict later...
+ cd ../..
+ mkdir 4; cd 4
+ dotest backuprecover-10 "${testcvs} -Q co first-dir" ''
+ cd first-dir
+ sed -e"s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2
+
+ # And back to developer 1
+ cd ../../1/first-dir
+ dotest backuprecover-11 "${testcvs} -Q update" ''
+ echo >>file1
+ echo >>dir/file2
+ echo "Oh yeah, well rhyme this" >>file1
+ echo " developer three" >>file1
+ echo " you want opposition" >>file1
+ echo " you found some in me!" >>file1
+ echo "I'll give you mimes" >>dir/file2
+ echo " and foundries galore!" >>dir/file2
+ echo " your head will spin" >>dir/file2
+ echo " once you find what's in store!" >>dir/file2
+ dotest backuprecover-12 "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.5; previous revision: 1\.4
+done"
+
+ # developer 3'll do a bit of work that never gets checked in
+ cd ../../3/first-dir
+ dotest backuprecover-13 "${testcvs} -Q update" ''
+ sed -e"s/very/some extremely/" file1 >tmp; mv tmp file1
+ dotest backuprecover-14 "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.6; previous revision: 1\.5
+done"
+ echo >>file1
+ echo "Tee hee hee hee" >>file1
+ echo >>dir/file2
+ echo "Find what's in store?" >>dir/file2
+ echo " Oh, I'm so sure!" >>dir/file2
+ echo " You've got an ill, and I have the cure!" >>dir/file2
+
+ # Slag the original and restore it a few revisions back
+ rm -rf ${TESTDIR}/cvsroot/first-dir
+ mv ${TESTDIR}/cvsroot/backup ${TESTDIR}/cvsroot/first-dir
+
+ # Have developer 1 try an update and lose some data
+ #
+ # Feel free to imagine the horrific scream of despair
+ cd ../../1/first-dir
+ dotest backuprecover-15 "${testcvs} update" \
+"${PROG} [a-z]*: Updating .
+U file1
+${PROG} [a-z]*: Updating dir
+U dir/file2"
+
+ # Developer 3 tries the same thing (he has an office)
+ # but fails without losing data since all of his files have
+ # uncommitted changes
+ cd ../../3/first-dir
+ dotest_fail backuprecover-16 "${testcvs} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} \[[a-z]* aborted\]: could not find desired version 1\.6 in ${TESTDIR}/cvsroot/first-dir/file1,v"
+
+ # create our workspace fixin' script
+ cd ../..
+ echo \
+"#!/bin/sh
+
+# This script will copy the CVS database dirs from the checked out
+# version of a newly recovered repository and replace the CVS
+# database dirs in a workspace with later revisions than those in the
+# recovered repository
+cd repos-first-dir
+DATADIRS=\`find . -name CVS\`
+cd ../first-dir
+find . -name CVS |xargs rm -rf
+for file in \${DATADIRS}; do
+ cp -r ../repos-first-dir/\${file} \${file}
+done" >fixit
+
+ # We only need to fix the workspaces of developers 3 and 4
+ # (1 lost all her data and 2 has an update date from
+ # before the date the backup was made)
+ cd 3
+ dotest backuprecover-17 \
+ "${testcvs} -Q co -d repos-first-dir first-dir" ''
+ cd ../4
+ dotest backuprecover-18 \
+ "${testcvs} -Q co -d repos-first-dir first-dir" ''
+ sh ../fixit
+ cd ../3; sh ../fixit
+
+ # (re)commit developer 3's stuff
+ cd first-dir
+ dotest backuprecover-19 "${testcvs} -q ci -mrecover/merge" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.4; previous revision: 1\.3
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.4; previous revision: 1\.3
+done"
+
+ # and we should get a conflict on developer 4's stuff
+ cd ../../4/first-dir
+ dotest backuprecover-20 "${testcvs} update" \
+"${PROG} [a-z]*: Updating \.
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.3
+retrieving revision 1\.4
+Merging differences between 1\.3 and 1\.4 into file1
+rcsmerge: warning: conflicts during merge
+${PROG} [a-z]*: conflicts found in file1
+C file1
+${PROG} [a-z]*: Updating dir
+RCS file: ${TESTDIR}/cvsroot/first-dir/dir/file2,v
+retrieving revision 1\.3
+retrieving revision 1\.4
+Merging differences between 1\.3 and 1\.4 into file2
+rcsmerge: warning: conflicts during merge
+${PROG} [a-z]*: conflicts found in dir/file2
+C dir/file2"
+ sed -e \
+"/^<<<<<<</,/^=======/d
+/^>>>>>>>/d" file1 >tmp; mv tmp file1
+ sed -e \
+"/^<<<<<<</,/^=======/d
+/^>>>>>>>/d
+s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2
+ dotest backuprecover-21 "${testcvs} -q ci -mrecover/merge" \
+"Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.5; previous revision: 1\.4
+done"
+
+ # go back and commit developer 2's stuff to prove it can still be done
+ cd ../../2/first-dir
+ dotest backuprecover-22 "${testcvs} -Q update" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.2
+retrieving revision 1\.4
+Merging differences between 1\.2 and 1\.4 into file1
+RCS file: ${TESTDIR}/cvsroot/first-dir/dir/file2,v
+retrieving revision 1\.2
+retrieving revision 1\.5
+Merging differences between 1\.2 and 1\.5 into file2"
+ dotest backuprecover-23 "${testcvs} -q ci -mtest" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.5; previous revision: 1\.4
+done
+Checking in dir/file2;
+${TESTDIR}/cvsroot/first-dir/dir/file2,v <-- file2
+new revision: 1\.6; previous revision: 1\.5
+done"
+
+ # and restore the data to developer 1
+ cd ../../1/first-dir
+ dotest backuprecover-24 "${testcvs} -Q update" ''
+
+ cd ../../..
+ rm -r backuprecover
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
history)
# CVSROOT/history tests:
# history: various "cvs history" invocations
@@ -12368,10 +14408,13 @@ done"
if test "x$remote" = xyes; then
# The problem here is that the CVSUMASK environment variable
# needs to be set on the server (e.g. .bashrc). This is, of
- # course, bogus, but that is the way it is currently.
+ # course, bogus, but that is the way it is currently. The
+ # first match is for the :ext: method (where the CVSUMASK
+ # won't be set), while the second is for the :fork: method
+ # (where it will be).
dotest modes-15 \
"ls -l ${TESTDIR}/cvsroot/first-dir/Attic/ac,v" \
-"-r--r--r--.*"
+"-r--r--r--.*" "-r--r-----.*"
else
dotest modes-15 \
"ls -l ${TESTDIR}/cvsroot/first-dir/Attic/ac,v" \
@@ -12431,6 +14474,64 @@ done"
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ modes3)
+ # Repository permissions. Particularly, what happens if we
+ # can't read/write in the repository.
+ # TODO: the case where we can access the repository, just not
+ # the attic (may that one can remain a fatal error, seems less
+ # useful for access control).
+ mkdir 1; cd 1
+ dotest modes-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir second-dir
+ dotest modes-2 "${testcvs} add first-dir second-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository
+Directory ${TESTDIR}/cvsroot/second-dir added to the repository"
+ touch first-dir/aa second-dir/ab
+ dotest modes-3 "${testcvs} add first-dir/aa second-dir/ab" \
+"${PROG} [a-z]*: scheduling file .first-dir/aa. for addition
+${PROG} [a-z]*: scheduling file .second-dir/ab. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ dotest modes-4 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/aa,v
+done
+Checking in first-dir/aa;
+${TESTDIR}/cvsroot/first-dir/aa,v <-- aa
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/second-dir/ab,v
+done
+Checking in second-dir/ab;
+${TESTDIR}/cvsroot/second-dir/ab,v <-- ab
+initial revision: 1\.1
+done"
+ chmod a= ${TESTDIR}/cvsroot/first-dir
+ dotest modes-5 "${testcvs} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} [a-z]*: Updating first-dir
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/first-dir: Permission denied
+${PROG} [a-z]*: skipping directory first-dir
+${PROG} [a-z]*: Updating second-dir"
+
+ # OK, I can see why one might say the above case could be a
+ # fatal error, because normally users without access to first-dir
+ # won't have it in their working directory. But the next
+ # one is more of a problem if it is fatal.
+ rm -r first-dir
+ dotest modes-6 "${testcvs} update -dP" \
+"${PROG} [a-z]*: Updating .
+${PROG} [a-z]*: Updating CVSROOT
+U ${DOTSTAR}
+${PROG} [a-z]*: Updating first-dir
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/first-dir: Permission denied
+${PROG} [a-z]*: skipping directory first-dir
+${PROG} [a-z]*: Updating second-dir"
+
+ cd ..
+ rm -r 1
+ chmod u+rwx ${TESTDIR}/cvsroot/first-dir
+ rm -rf ${TESTDIR}/cvsroot/first-dir ${TESTDIR}/cvsroot/second-dir
+ ;;
+
stamps)
# Test timestamps.
mkdir 1; cd 1
@@ -12665,6 +14766,45 @@ done"
chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config
;;
+ symlinks2)
+ # Symlinks in working directory without PreservePermissions.
+ # Also see: symlinks: with PreservePermissions
+ # rcslib-symlink-*: symlinks in repository.
+ mkdir 1; cd 1
+ dotest symlinks2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest symlinks2-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ echo nonsymlink > slink
+ dotest symlinks2-3 "${testcvs} add slink" \
+"${PROG} [a-z]*: scheduling file .slink. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest symlinks2-4 "${testcvs} -q ci -m ''" \
+"RCS file: ${CVSROOT_DIRNAME}/first-dir/slink,v
+done
+Checking in slink;
+${TESTDIR}/cvsroot/first-dir/slink,v <-- slink
+initial revision: 1\.1
+done"
+ rm slink
+ # Choose name cvslog.* so it is in default ignore list.
+ echo second file >cvslog.file2
+ dotest symlinks2-5 "ln -s cvslog.file2 slink" ""
+ dotest symlinks2-6 "${testcvs} -q ci -m linkify" \
+"Checking in slink;
+${TESTDIR}/cvsroot/first-dir/slink,v <-- slink
+new revision: 1\.2; previous revision: 1\.1
+done"
+ dotest symlinks2-7 "${testcvs} -q update -r 1.1 slink" "[UP] slink"
+ dotest symlinks2-8 "cat slink" "nonsymlink"
+ dotest symlinks2-9 "ls -l slink" "-[-rwx]* .* slink"
+ cd ../..
+
+ rm -rf 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
hardlinks)
# short cut around checking out and committing CVSROOT
rm -f ${CVSROOT_DIRNAME}/CVSROOT/config
@@ -12872,7 +15012,10 @@ U file1" "U file1"
# "rdiff" tests "cvs co -k".
# "binfiles" (and this test) test "cvs update -k".
# "binwrap" tests setting the mode from wrappers.
+ # "keyword2" tests "cvs update -kk -j" with text and binary files
# I don't think any test is testing "cvs import -k".
+ # Other keyword expansion tests:
+ # keywordlog - $Log.
mkdir 1; cd 1
dotest keyword-1 "${testcvs} -q co -l ." ''
mkdir first-dir
@@ -13051,12 +15194,20 @@ new revision: 1\.3; previous revision: 1\.2
done"
dotest keyword-21 "${testcvs} -q update -r tag1" "[UP] file1"
- # FIXME: This test fails when remote. The second expect
- # string below should be removed when this is fixed.
- dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$' \
-'\$'"Name: "'\$'
+ dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$'
- dotest keyword-23 "${testcvs} update -A file1" "[UP] file1"
+ if test "$remote" = yes; then
+ # Like serverpatch-8. Not sure there is anything much we
+ # can or should do about this.
+ dotest keyword-23 "${testcvs} update -A file1" "P file1
+${PROG} update: checksum failure after patch to \./file1; will refetch
+${PROG} client: refetching unpatchable files
+U file1"
+ else
+ dotest keyword-23 "${testcvs} update -A file1" "[UP] file1"
+ fi
+ dotest keyword-24 "cat file1" '\$'"Name: "'\$'"
+change"
cd ../..
rm -r 1
@@ -13071,22 +15222,18 @@ done"
dotest keywordlog-2 "${testcvs} add first-dir" \
"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
cd first-dir
- echo change >file1
+ echo initial >file1
dotest keywordlog-3 "${testcvs} add file1" \
"${PROG} [a-z]*: scheduling file .file1. for addition
${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
- # Note that we wanted to try "ci -r 1.3 -m add file1" and CVS
- # seemed to get all confused, thinking it was adding on a branch
- # or something. FIXME? Do something about this? Document it
- # in BUGS or someplace?
-
- dotest keywordlog-4 "${testcvs} -q ci -m add file1" \
+ # See "rmadd" for a list of other tests of cvs ci -r.
+ dotest keywordlog-4 "${testcvs} -q ci -r 1.3 -m add file1" \
"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
done
Checking in file1;
${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
-initial revision: 1\.1
+initial revision: 1\.3
done"
cd ../..
@@ -13094,21 +15241,29 @@ done"
dotest keywordlog-4a "${testcvs} -q co first-dir" "U first-dir/file1"
cd ../1/first-dir
- echo 'xx $''Log$' > file1
+ echo 'xx $''Log$' >> file1
cat >${TESTDIR}/comment.tmp <<EOF
First log line
Second log line
EOF
+ # As with rmadd-25, "cvs ci -r" sets a sticky tag.
+ dotest_fail keywordlog-4b \
+"${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
+"${PROG} [a-z]*: sticky tag .1\.3. for file .file1. is not a branch
+${PROG} \[[a-z]* aborted\]: correct above errors first!"
+ dotest keywordlog-4c "${testcvs} -q update -A" "M file1"
+
dotest keywordlog-5 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
"Checking in file1;
${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
-new revision: 1\.2; previous revision: 1\.1
+new revision: 1\.4; previous revision: 1\.3
done"
rm -f ${TESTDIR}/comment.tmp
dotest keywordlog-6 "${testcvs} -q tag -b br" "T file1"
dotest keywordlog-7 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx"
@@ -13116,8 +15271,9 @@ xx"
cd ../../2/first-dir
dotest keywordlog-8 "${testcvs} -q update" "[UP] file1"
dotest keywordlog-9 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx"
@@ -13127,14 +15283,15 @@ xx"
dotest keywordlog-10 "${testcvs} ci -m modify file1" \
"Checking in file1;
${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
-new revision: 1\.3; previous revision: 1\.2
+new revision: 1\.5; previous revision: 1\.4
done"
dotest keywordlog-11 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.3 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 [0-9/]* [0-9:]* ${username}
xx modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
@@ -13143,11 +15300,12 @@ change"
cd ../../2/first-dir
dotest keywordlog-12 "${testcvs} -q update" "[UP] file1"
dotest keywordlog-13 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.3 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 [0-9/]* [0-9:]* ${username}
xx modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
@@ -13159,14 +15317,15 @@ change"
dotest keywordlog-15 "${testcvs} -q ci -m br-modify" \
"Checking in file1;
${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
-new revision: 1\.2\.2\.1; previous revision: 1\.2
+new revision: 1\.4\.2\.1; previous revision: 1\.4
done"
dotest keywordlog-16 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username}
xx br-modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
@@ -13174,47 +15333,272 @@ br-change"
cd ../../2/first-dir
dotest keywordlog-17 "${testcvs} -q update -r br" "[UP] file1"
dotest keywordlog-18 "cat file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username}
xx br-modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
br-change"
cd ../..
dotest keywordlog-19 "${testcvs} -q co -p -r br first-dir/file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username}
xx br-modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
br-change"
dotest keywordlog-20 "${testcvs} -q co -p first-dir/file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.3 [0-9/]* [0-9:]* ${username}
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.5 [0-9/]* [0-9:]* ${username}
xx modify
xx
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx
change"
- dotest keywordlog-21 "${testcvs} -q co -p -r 1.2 first-dir/file1" \
-"xx "'\$'"Log: file1,v "'\$'"
-xx Revision 1\.2 [0-9/]* [0-9:]* ${username}
+ dotest keywordlog-21 "${testcvs} -q co -p -r 1.4 first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
xx First log line
xx Second log line
xx"
+ cd 2/first-dir
+ # OK, the basic rule for keyword expansion is that it
+ # happens on checkout. And the rule for annotate is that
+ # it annotates a checked-in revision, rather than a checked-out
+ # file. So, although it is kind of confusing that the latest
+ # revision does not appear in the annotated output, and the
+ # annotated output does not quite match what you'd get with
+ # update or checkout, the behavior is more or less logical.
+ # The same issue occurs with annotate and other keywords,
+ # I think, although it is particularly noticeable for $Log.
+ dotest keywordlog-22 "${testcvs} ann -r br file1" \
+"Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.3 (${username} *[0-9a-zA-Z-]*): initial
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'"
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx First log line
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx Second log line
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx
+1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): br-change"
+ dotest keywordlog-23 "${testcvs} ann -r HEAD file1" \
+"Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.3 (${username} *[0-9a-zA-Z-]*): initial
+1\.5 (${username} *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'"
+1\.5 (${username} *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
+1\.5 (${username} *[0-9a-zA-Z-]*): xx First log line
+1\.5 (${username} *[0-9a-zA-Z-]*): xx Second log line
+1\.5 (${username} *[0-9a-zA-Z-]*): xx
+1\.5 (${username} *[0-9a-zA-Z-]*): change"
+ cd ../..
+
+ #
+ # test the operation of 'admin -o' in conjunction with keywords
+ # (especially Log - this used to munge the RCS file for all time)
+ #
+
+ dotest keywordlog-24 \
+"${testcvs} admin -oHEAD 1/first-dir/file1" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+deleting revision 1\.5
+done"
+
+ dotest keywordlog-25 \
+"${testcvs} -q co -p first-dir/file1" \
+"initial
+xx "'\$'"Log: file1,v "'\$'"
+xx Revision 1\.4 [0-9/]* [0-9:]* ${username}
+xx First log line
+xx Second log line
+xx"
+
+ if test $keep = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
rm -r 1 2
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
+ keyword2)
+ # Test merging on files with keywords:
+ # without -kk
+ # with -kk
+ # on text files
+ # on binary files
+ # Note: This test assumes that CVS has already passed the binfiles
+ # test sequence
+ # Note2: We are testing positive on binary corruption here
+ # we probably really DON'T want to 'cvs update -kk' a binary file...
+ mkdir 1; cd 1
+ dotest keyword2-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest keyword2-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+
+ echo '$''Revision$' >> file1
+ echo "I" >>file1
+ echo "like" >>file1
+ echo "long" >>file1
+ echo "files!" >>file1
+ echo "" >>file1
+ echo "a test line for our times" >>file1
+ echo "" >>file1
+ echo "They" >>file1
+ echo "make" >>file1
+ echo "diff" >>file1
+ echo "look like it" >>file1
+ echo "did a much better" >>file1
+ echo "job." >>file1
+ dotest keyword2-3 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+
+ awk 'BEGIN { printf "%c%c%c%sRevision: 1.1 $@%c%c", \
+ 2, 10, 137, "$", 13, 10 }' \
+ </dev/null | tr '@' '\000' >../binfile.dat
+ cp ../binfile.dat .
+ dotest keyword2-5 "${testcvs} add -kb binfile.dat" \
+"${PROG} [a-z]*: scheduling file .binfile\.dat. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+
+ dotest keyword2-6 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/binfile\.dat,v
+done
+Checking in binfile\.dat;
+${TESTDIR}/cvsroot/first-dir/binfile\.dat,v <-- binfile\.dat
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done"
+
+ dotest keyword2-7 "${testcvs} -q tag -b branch" \
+"T binfile\.dat
+T file1"
+
+ sed -e 's/our/the best of and the worst of/' file1 >f; mv f file1
+ dotest keyword2-8 "${testcvs} -q ci -m change" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+done"
+
+ dotest keyword2-9 "${testcvs} -q update -r branch" '[UP] file1'
+
+ echo "what else do we have?" >>file1
+ dotest keyword2-10 "${testcvs} -q ci -m change" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.1\.2\.1; previous revision: 1\.1
+done"
+
+ # Okay, first a conflict in file1 - should be okay with binfile.dat
+ dotest keyword2-11 "${testcvs} -q update -A -j branch" \
+"U file1
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1
+rcsmerge: warning: conflicts during merge"
+
+ dotest_fail keyword2-12 "${testcvs} diff file1" \
+"Index: file1
+===================================================================
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.2
+diff -r1\.2 file1
+0a1
+> <<<<<<< file1
+1a3,5
+> =======
+> \\\$""Revision: 1\.1\.2\.1 \\\$
+> >>>>>>> 1\.1\.2\.1
+14a19
+> what else do we have${QUESTION}"
+
+ # Here's the problem... shouldn't -kk a binary file...
+ rm file1
+ if test "$remote" = yes; then
+ dotest keyword2-13 "${testcvs} -q update -A -kk -j branch" \
+"U binfile.dat
+U file1
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+ else
+ dotest keyword2-13 "${testcvs} -q update -A -kk -j branch" \
+"U binfile.dat
+${PROG} [a-z]*: warning: file1 was lost
+U file1
+RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.2\.1
+Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+ fi
+
+ # binfile won't get checked in, but it is now corrupt and could
+ # have been checked in if it had changed on the branch...
+ dotest keyword2-14 "${testcvs} -q ci -m change" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.3; previous revision: 1\.2
+done"
+
+ dotest_fail keyword2-15 "cmp binfile.dat ../binfile.dat" \
+"binfile\.dat \.\./binfile\.dat differ: char 13, line 2"
+
+ # Okay, restore everything and make CVS try and merge a binary file...
+ dotest keyword2-16 "${testcvs} -q update -A" \
+"[UP] binfile.dat
+[UP] file1"
+ dotest keyword2-17 "${testcvs} -q tag -b branch2" \
+"T binfile\.dat
+T file1"
+ dotest keyword2-18 "${testcvs} -q update -r branch2" ''
+
+ awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
+ </dev/null | tr '@' '\000' >>binfile.dat
+ dotest keyword2-19 "${testcvs} -q ci -m badbadbad" \
+"Checking in binfile\.dat;
+${TESTDIR}/cvsroot/first-dir/binfile\.dat,v <-- binfile\.dat
+new revision: 1\.1\.4\.1; previous revision: 1\.1
+done"
+ dotest keyword2-20 "${testcvs} -q update -A -kk -j branch2" \
+"U binfile\.dat
+RCS file: ${TESTDIR}/cvsroot/first-dir/binfile\.dat,v
+retrieving revision 1\.1
+retrieving revision 1\.1\.4\.1
+Merging differences between 1\.1 and 1\.1\.4\.1 into binfile\.dat
+U file1"
+
+ # Yep, it's broke, 'cept for that gal in Hodunk who uses -kk
+ # so that some files only merge when she says so. Time to clean up...
+ cd ../..
+ rm -r 1
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
+ ;;
+
head)
# Testing handling of the HEAD special tag.
# There are many cases involving added and removed files
@@ -13385,6 +15769,21 @@ done"
tagdate)
# Test combining -r and -D.
+ #
+ # Note that this is not a complete test. It relies on the fact
+ # that update, checkout and export have a LOT of shared code.
+ # Notice:
+ # 1) checkout is never tested at all with -r -D
+ # 2) update never uses an argument to '-D' besides 'now'
+ # (this test does not provide enough data to prove
+ # that 'cvs update' with both a '-r' and a '-D'
+ # specified does not ignore '-D': a 'cvs up
+ # -r<branch> -Dnow' and a 'cvs up -r<branch>'
+ # should specify the same file revision).
+ # 3) export uses '-r<branch> -D<when there was a different
+ # revision>', hopefully completing this behavior test
+ # for checkout and update as well.
+ #
mkdir 1; cd 1
dotest tagdate-1 "${testcvs} -q co -l ." ''
mkdir first-dir
@@ -13422,11 +15821,95 @@ done"
${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
new revision: 1\.1\.4\.1; previous revision: 1\.1
done"
+
# Then the case where br2 does have revisions:
dotest tagdate-11 "${testcvs} -q update -p -r br1 -D now" "trunk-1"
+ # For some reason, doing this on a branch seems to be relevant.
+ dotest_fail tagdate-12 "${testcvs} -q update -j:yesterday" \
+"${PROG} \[[a-z]* aborted\]: argument to join may not contain a date specifier without a tag"
+ # And check export
+
+ # Wish some shorter sleep interval would suffice, but I need to
+ # guarantee that the point in time specified by the argument to -D
+ # in tagdate-14 and tagdate-16
+ # falls in the space of time between commits to br2 and I
+ # figure 60 seconds is probably a large enough range to
+ # account for most network file system delays and such...
+ # as it stands, it takes between 1 and 2 seconds between
+ # calling CVS on my machine and the -D argument being used to
+ # recall the file revision and this timing will certainly vary
+ # by several seconds between machines - dependant on CPUspeeds,
+ # I/O speeds, load, etc.
+ sleep 60
+
+ echo br2-2 >file1
+ dotest tagdate-13 "${testcvs} -q ci -m modify-2-on-br2" \
+"Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+new revision: 1\.1\.4\.2; previous revision: 1\.1\.4\.1
+done"
cd ../..
- rm -r 1
+ mkdir 2; cd
+ if ${testcvs} -q export -r br2 -D'1 minute ago' first-dir \
+ >${TESTDIR}/tagdate.tmp 2>&1; then
+ if ${EXPR} "`cat ${TESTDIR}/tagdate.tmp`" : \
+"[UP] first-dir/file1" >/dev/null; then
+ pass tagdate-14
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "[UP] first-dir/file1" >>${LOGFILE}
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/tagdate.tmp >>${LOGFILE}
+ fail tagdate-14
+ fi
+ else
+ echo "Bad exit status" >>${LOGFILE}
+ fail tagdate-14
+ fi
+
+ if ${EXPR} "`cat first-dir/file1`" : "br2-1" >/dev/null; then
+ pass tagdate-15
+ else
+ fail tagdate-15
+ fi
+
+ # Now for annotate
+ cd ../1/first-dir
+ if ${testcvs} annotate -rbr2 -D'1 minute ago' \
+ >${TESTDIR}/tagdate.tmp 2>&1; then
+ if ${EXPR} "`cat ${TESTDIR}/tagdate.tmp`" : \
+"Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1\.4\.1 (${username} *[0-9a-zA-Z-]*): br2-1" >/dev/null; then
+ pass tagdate-16
+ else
+ echo "** expected: " >>${LOGFILE}
+ echo "Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1\.4\.1 (${username} *[0-9a-zA-Z-]*): br2-1" >>${LOGFILE}
+ echo "** got: " >>${LOGFILE}
+ cat ${TESTDIR}/tagdate.tmp >>${LOGFILE}
+ fail tagdate-16
+ fi
+ else
+ echo "Bad exit status" >>${LOGFILE}
+ fail tagdate-16
+ fi
+
+ dotest tagdate-17 "${testcvs} annotate -rbr2 -Dnow" \
+"Annotations for file1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1\.1\.4\.2 (${username} *[0-9a-zA-Z-]*): br2-2"
+
+ if test $keep = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ cd ../..
+ rm ${TESTDIR}/tagdate.tmp
+ rm -r 1 2
rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
@@ -13621,14 +16104,13 @@ done"
dotest tag8k-15 "$testcvs -Q tag $t-9 $file" ''
dotest tag8k-16 "$testcvs -Q tag $t-a $file" ''
- # Determine the length of the author value.
+ # Extract the author value.
name=`sed -n 's/.*; author \([^;]*\);.*/\1/p' ${TESTDIR}/cvsroot/$module/$file,v|head -1`
- name_len=`expr length $name`
+ # Form a suffix string of length (16 - length($name)).
# CAREFUL: this will lose if $name is longer than 16.
- # Then, form a string of length 16 - $name_len.
- add_len=`expr 16 - $name_len`
- suffix=`expr substr 1234567890123456 1 $add_len`
+ sed_pattern=`echo $name|sed s/././g`
+ suffix=`echo 1234567890123456|sed s/$sed_pattern//`
# Add a final tag with length chosen so that it will push the
# offset of the `;' in the 2nd occurrence of `;\tauthor' in the
@@ -13663,12 +16145,14 @@ done"
# head-o1 (::branch, where this deletes a revision or is noop)
# branches-o1 (::branch, similar, with different branch topology)
# log-o1 (1.3.2.1::)
- # binfiles-o1 (1.3:: and ::1.3)
+ # binfiles-o1 (1.3:: and ::1.3; binary files)
+ # binfiles3-9 (binary files)
# Also could be testing:
# 1.3.2.6::1.3.2.8
# 1.3.2.6::1.3.2
# 1.3.2.1::1.3.2.6
# 1.3::1.3.2.6 (error? or synonym for ::1.3.2.6?)
+ # -n: admin, tagf tests.
mkdir 1; cd 1
dotest admin-1 "${testcvs} -q co -l ." ''
@@ -13803,6 +16287,7 @@ modify-on-branch
# test for what CVS actually exports, and figure we can revise
# the check as needed (within the confines of the RCS5 format as
# documented in RCSFILES).
+ # Note that we must accept either 2 or 4 digit year.
dotest admin-13 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \
"head 1\.1;
branch 1\.1\.2;
@@ -13817,13 +16302,13 @@ comment @xx@;
1\.1
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
branches
1\.1\.2\.1;
next ;
1\.1\.2\.1
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo;
branches;
next ;
@@ -13973,6 +16458,11 @@ total revisions: 2
done"
fi # end of tests skipped for remote
+ # Now test that plain -e is at least parsed right. CVS 1.10
+ # would wrongly treat "-e file1" as "-efile1".
+ dotest_fail admin-19a-2 "${testcvs} -q admin -e file1" \
+"${PROG} \[[a-z]* aborted\]: removing entire access list not yet implemented"
+
# Add another revision to file2, so we can delete one.
echo 'add a line' >> file2
dotest admin-21 "${testcvs} -q ci -m modify file2" \
@@ -14222,13 +16712,13 @@ comment @xx@;
1\.1
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
branches
1\.1\.2\.1;
next ;
1\.1\.2\.1
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo;
branches;
next ;
@@ -14393,17 +16883,17 @@ comment @# @;
1\.4
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
branches;
next 1\.3;
1\.3
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
branches;
next 1\.2;
1\.2
-date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
+date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp;
branches;
next ;
@@ -15496,6 +17986,2277 @@ d472 12
rm -rf ${CVSROOT_DIRNAME}/diffmerge2
;;
+ release)
+ # Tests of "cvs release", particularly multiple arguments.
+ # Other CVS release tests:
+ # info-cleanup-0 for "cvs -n release".
+ # ignore-193 for the text of the question that cvs release asks.
+ # Also for interactions with cvsignore.
+ # basicc: "-d .", global -Q, no arguments (is a noop),
+ # "cvs release" without -d, multiple arguments.
+ # dirs-4: repository directory has been deleted.
+ # modules2-6: multiple arguments.
+
+ # First the usual setup; create a directory first-dir.
+ mkdir 1; cd 1
+ dotest release-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest release-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ mkdir dir1
+ dotest release-3 "${testcvs} add dir1" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir1 added to the repository"
+ mkdir dir2
+ dotest release-4 "${testcvs} add dir2" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir2 added to the repository"
+ cd dir2
+ mkdir dir3
+ dotest release-5 "${testcvs} add dir3" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir2/dir3 added to the repository"
+
+ cd ../..
+ dotest release-6 "${testcvs} release -d first-dir/dir2/dir3 first-dir/dir1" \
+"You have .0. altered files in this repository.
+Are you sure you want to release (and delete) directory .first-dir/dir2/dir3.: \
+You have .0. altered files in this repository.
+Are you sure you want to release (and delete) directory .first-dir/dir1.: " <<EOF
+yes
+yes
+EOF
+ dotest_fail release-7 "test -d first-dir/dir1" ''
+ dotest_fail release-8 "test -d first-dir/dir2/dir3" ''
+ dotest release-9 "${testcvs} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} [a-z]*: Updating first-dir
+${PROG} [a-z]*: Updating first-dir/dir2"
+
+ cd first-dir
+ mkdir dir1
+ dotest release-10 "${testcvs} add dir1" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir1 added to the repository"
+ cd dir2
+ mkdir dir3
+ dotest release-11 "${testcvs} add dir3" \
+"Directory ${TESTDIR}/cvsroot/first-dir/dir2/dir3 added to the repository"
+
+ cd ../..
+ dotest release-12 "${testcvs} release first-dir/dir2/dir3 first-dir/dir1" \
+"You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2/dir3.: .. .release. aborted by user choice.
+You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir1.: " <<EOF
+no
+yes
+EOF
+ dotest release-13 "${testcvs} release first-dir/dir2/dir3 first-dir/dir2" \
+"You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2/dir3.: \
+You have .0. altered files in this repository.
+Are you sure you want to release directory .first-dir/dir2.: " <<EOF
+yes
+yes
+EOF
+ dotest release-14 "test -d first-dir/dir1" ''
+ dotest release-15 "test -d first-dir/dir2/dir3" ''
+ rm -rf first-dir/dir1 first-dir/dir2
+
+ dotest release-16 "${testcvs} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} [a-z]*: Updating first-dir"
+ cd ..
+ rm -rf 1
+ ;;
+
+ multiroot)
+
+ #
+ # set up two repositories
+ #
+
+ CVSROOT1_DIRNAME=${TESTDIR}/root1
+ CVSROOT2_DIRNAME=${TESTDIR}/root2
+ CVSROOT1=${CVSROOT1_DIRNAME} ; export CVSROOT1
+ CVSROOT2=${CVSROOT2_DIRNAME} ; export CVSROOT2
+ if test "x$remote" = xyes; then
+ CVSROOT1=:fork:${CVSROOT1_DIRNAME} ; export CVSROOT1
+ CVSROOT2=:fork:${CVSROOT2_DIRNAME} ; export CVSROOT2
+ fi
+ testcvs1="${testcvs} -d ${CVSROOT1}"
+ testcvs2="${testcvs} -d ${CVSROOT2}"
+
+ dotest multiroot-setup-1 "mkdir ${CVSROOT1_DIRNAME} ${CVSROOT2_DIRNAME}" ""
+ dotest multiroot-setup-2 "${testcvs1} init" ""
+ dotest multiroot-setup-3 "${testcvs2} init" ""
+
+ #
+ # create some directories in root1
+ #
+ mkdir 1; cd 1
+ dotest multiroot-setup-4 "${testcvs1} co -l ." "${PROG} [a-z]*: Updating ."
+ mkdir mod1-1 mod1-2
+ dotest multiroot-setup-5 "${testcvs1} add mod1-1 mod1-2" \
+"Directory ${CVSROOT1_DIRNAME}/mod1-1 added to the repository
+Directory ${CVSROOT1_DIRNAME}/mod1-2 added to the repository"
+ echo file1-1 > mod1-1/file1-1
+ echo file1-2 > mod1-2/file1-2
+ dotest multiroot-setup-6 "${testcvs1} add mod1-1/file1-1 mod1-2/file1-2" \
+"${PROG} [a-z]*: scheduling file .mod1-1/file1-1. for addition
+${PROG} [a-z]*: scheduling file .mod1-2/file1-2. for addition
+${PROG} [a-z]*: use '${PROG} commit' to add these files permanently"
+ dotest multiroot-setup-7 "${testcvs1} commit -m is" \
+"${PROG} [a-z]*: Examining \.
+${PROG} [a-z]*: Examining mod1-1
+${PROG} [a-z]*: Examining mod1-2
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+done
+Checking in mod1-1/file1-1;
+${CVSROOT1_DIRNAME}/mod1-1/file1-1,v <-- file1-1
+initial revision: 1.1
+done
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+done
+Checking in mod1-2/file1-2;
+${CVSROOT1_DIRNAME}/mod1-2/file1-2,v <-- file1-2
+initial revision: 1.1
+done"
+ cd ..
+ rm -rf 1
+
+ #
+ # create some directories in root2
+ #
+ mkdir 1; cd 1
+ dotest multiroot-setup-8 "${testcvs2} co -l ." "${PROG} [a-z]*: Updating ."
+ mkdir mod2-1 mod2-2
+ dotest multiroot-setup-9 "${testcvs2} add mod2-1 mod2-2" \
+"Directory ${CVSROOT2_DIRNAME}/mod2-1 added to the repository
+Directory ${CVSROOT2_DIRNAME}/mod2-2 added to the repository"
+ echo file2-1 > mod2-1/file2-1
+ echo file2-2 > mod2-2/file2-2
+ dotest multiroot-setup-6 "${testcvs2} add mod2-1/file2-1 mod2-2/file2-2" \
+"${PROG} [a-z]*: scheduling file .mod2-1/file2-1. for addition
+${PROG} [a-z]*: scheduling file .mod2-2/file2-2. for addition
+${PROG} [a-z]*: use '${PROG} commit' to add these files permanently"
+ dotest multiroot-setup-10 "${testcvs2} commit -m anyone" \
+"${PROG} [a-z]*: Examining \.
+${PROG} [a-z]*: Examining mod2-1
+${PROG} [a-z]*: Examining mod2-2
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+done
+Checking in mod2-1/file2-1;
+${CVSROOT2_DIRNAME}/mod2-1/file2-1,v <-- file2-1
+initial revision: 1.1
+done
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+done
+Checking in mod2-2/file2-2;
+${CVSROOT2_DIRNAME}/mod2-2/file2-2,v <-- file2-2
+initial revision: 1.1
+done"
+ cd ..
+ rm -rf 1
+
+ # check out a few directories, from simple/shallow to
+ # complex/deep
+ mkdir 1; cd 1
+
+ # OK, this case is kind of weird. If we just run things from
+ # here, without CVS/Root, then CVS will contact the server
+ # mentioned in CVSROOT (which is irrelevant) which will print
+ # some messages. Our workaround is to make sure we have a
+ # CVS/Root file at top level. In the future, it is possible
+ # the best behavior will be to extend the existing behavior
+ # ("being called from a directory without CVS administration
+ # has always meant to process each of the sub-dirs") to also
+ # do that if there is no CVSROOT, CVS/Root, or -d at top level.
+ #
+ # The local case could stumble through the tests without creating
+ # the top-level CVS/Root, but we create it for local and for
+ # remote to reduce special cases later in the test.
+ dotest multiroot-workaround "${testcvs1} -q co -l ." ""
+
+ dotest multiroot-setup-11 "${testcvs1} co mod1-1 mod1-2" \
+"${PROG} [a-z]*: Updating mod1-1
+U mod1-1/file1-1
+${PROG} [a-z]*: Updating mod1-2
+U mod1-2/file1-2"
+ dotest multiroot-setup-12 "${testcvs2} co mod2-1 mod2-2" \
+"${PROG} [a-z]*: Updating mod2-1
+U mod2-1/file2-1
+${PROG} [a-z]*: Updating mod2-2
+U mod2-2/file2-2"
+ cd mod1-2
+ dotest multiroot-setup-13 "${testcvs2} co mod2-2" \
+"${PROG} [a-z]*: Updating mod2-2
+U mod2-2/file2-2"
+ cd ..
+ cd mod2-2
+ dotest multiroot-setup-14 "${testcvs1} co mod1-2" \
+"${PROG} [a-z]*: Updating mod1-2
+U mod1-2/file1-2"
+ cd ..
+
+ # Try to determine whether RELATIVE_REPOS is defined
+ # so that we can make the following a lot less
+ # verbose.
+
+ echo "${CVSROOT1_DIRNAME}/mod1-1" > dotest.abs
+ echo "mod1-1" > dotest.rel
+ if cmp dotest.abs mod1-1/CVS/Repository >/dev/null 2>&1; then
+ AREP1="${CVSROOT1_DIRNAME}/"
+ AREP2="${CVSROOT2_DIRNAME}/"
+ elif cmp dotest.rel mod1-1/CVS/Repository >/dev/null 2>&1; then
+ AREP1=""
+ AREP2=""
+ else
+ fail "Cannot figure out if RELATIVE_REPOS is defined."
+ fi
+ rm -f dotest.abs dotest.rel
+
+ #
+ # Make sure that the Root and Repository files contain the
+ # correct information.
+ #
+ dotest multiroot-cvsadm-1a "cat mod1-1/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-1b "cat mod1-1/CVS/Repository" "${AREP1}mod1-1"
+ dotest multiroot-cvsadm-2a "cat mod2-1/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-2b "cat mod2-1/CVS/Repository" "${AREP2}mod2-1"
+ dotest multiroot-cvsadm-3a "cat mod1-2/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-3b "cat mod1-2/CVS/Repository" "${AREP1}mod1-2"
+ dotest multiroot-cvsadm-3c "cat mod1-2/mod2-2/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-3d "cat mod1-2/mod2-2/CVS/Repository" "${AREP2}mod2-2"
+ dotest multiroot-cvsadm-4a "cat mod2-2/CVS/Root" "${CVSROOT2}"
+ dotest multiroot-cvsadm-4b "cat mod2-2/CVS/Repository" "${AREP2}mod2-2"
+ dotest multiroot-cvsadm-4c "cat mod2-2/mod1-2/CVS/Root" "${CVSROOT1}"
+ dotest multiroot-cvsadm-4d "cat mod2-2/mod1-2/CVS/Repository" "${AREP1}mod1-2"
+
+ #
+ # Start testing various cvs commands. Begin with commands
+ # without extra arguments (e.g. "cvs update", "cvs diff",
+ # etc.
+ #
+
+ # Do at least one command with both CVSROOTs to make sure
+ # that there's not some kind of unexpected dependency on the
+ # choice of which CVSROOT is specified on the command line.
+
+ if test "${AREP1}" = ""; then
+ # RELATIVE_REPOS.
+ dotest multiroot-update-1a "${testcvs1} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-2: No such file or directory
+${PROG} [a-z]*: skipping directory mod1-2/mod2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-1: No such file or directory
+${PROG} [a-z]*: skipping directory mod2-1
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-2: No such file or directory
+${PROG} [a-z]*: skipping directory mod2-2"
+
+ # Same deal but with -d ${CVSROOT2}.
+ dotest multiroot-update-1b "${testcvs2} update" \
+"${PROG} [a-z]*: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-1: No such file or directory
+${PROG} [a-z]*: skipping directory mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-2: No such file or directory
+${PROG} [a-z]*: skipping directory mod1-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2
+${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-2: No such file or directory
+${PROG} [a-z]*: skipping directory mod2-2/mod1-2"
+ else
+ # non-RELATIVE_REPOS.
+ if test "$remote" = no; then
+ # The basic idea is that -d overrides CVS/Root.
+ # With RELATIVE_REPOS, CVS could print an error when it
+ # tries to recurse to mod2-2, which doesn't exist in
+ # this repository (?) With absolute, CVS will just look at the
+ # CVS/Repository for the other root (and log to the wrong
+ # history file and that sort of thing).
+ dotest multiroot-update-1a "${testcvs1} update" \
+"${PROG} update: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2"
+ else
+ # Hmm, this one is specific to non-RELATIVE_REPOS too I think.
+ dotest_fail multiroot-update-1a "${testcvs1} update" \
+"protocol error: directory '${TESTDIR}/root2/mod2-2' not within root '${TESTDIR}/root1'"
+ fi # non-remote
+
+ # Same deal but with -d ${CVSROOT2}.
+ if test "$remote" = no; then
+ dotest multiroot-update-1b "${testcvs2} update" \
+"${PROG} update: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2"
+ else
+ dotest_fail multiroot-update-1b "${testcvs2} update" \
+"protocol error: directory '${TESTDIR}/root1' not within root '${TESTDIR}/root2'"
+ fi # non-remote
+ fi # non-RELATIVE_REPOS
+
+ # modify all files and do a diff
+
+ echo bobby >> mod1-1/file1-1
+ echo brown >> mod1-2/file1-2
+ echo goes >> mod2-1/file2-1
+ echo down >> mod2-2/file2-2
+
+ dotest_status multiroot-diff-1 1 "${testcvs} diff" \
+"${PROG} diff: Diffing \.
+${PROG} [a-z]*: Diffing mod1-1
+Index: mod1-1/file1-1
+===================================================================
+RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v
+retrieving revision 1\.1
+diff -r1\.1 file1-1
+1a2
+> bobby
+${PROG} [a-z]*: Diffing mod1-2
+Index: mod1-2/file1-2
+===================================================================
+RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v
+retrieving revision 1\.1
+diff -r1\.1 file1-2
+1a2
+> brown
+${PROG} [a-z]*: Diffing mod2-2/mod1-2
+${PROG} [a-z]*: Diffing mod1-2/mod2-2
+${PROG} [a-z]*: Diffing mod2-1
+Index: mod2-1/file2-1
+===================================================================
+RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v
+retrieving revision 1\.1
+diff -r1\.1 file2-1
+1a2
+> goes
+${PROG} [a-z]*: Diffing mod2-2
+Index: mod2-2/file2-2
+===================================================================
+RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v
+retrieving revision 1\.1
+diff -r1\.1 file2-2
+1a2
+> down" \
+"${PROG} server: Diffing \.
+${PROG} [a-z]*: Diffing mod1-1
+Index: mod1-1/file1-1
+===================================================================
+RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v
+retrieving revision 1\.1
+diff -r1\.1 file1-1
+1a2
+> bobby
+${PROG} [a-z]*: Diffing mod1-2
+Index: mod1-2/file1-2
+===================================================================
+RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v
+retrieving revision 1\.1
+diff -r1\.1 file1-2
+1a2
+> brown
+${PROG} [a-z]*: Diffing mod2-2
+${PROG} [a-z]*: Diffing mod2-2/mod1-2
+${PROG} [a-z]*: Diffing mod1-2
+${PROG} [a-z]*: Diffing mod1-2/mod2-2
+${PROG} [a-z]*: Diffing mod2-1
+Index: mod2-1/file2-1
+===================================================================
+RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v
+retrieving revision 1\.1
+diff -r1\.1 file2-1
+1a2
+> goes
+${PROG} [a-z]*: Diffing mod2-2
+Index: mod2-2/file2-2
+===================================================================
+RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v
+retrieving revision 1\.1
+diff -r1\.1 file2-2
+1a2
+> down"
+
+
+ dotest multiroot-commit-1 "${testcvs} commit -m actually" \
+"${PROG} [a-z]*: Examining \.
+${PROG} [a-z]*: Examining mod1-1
+${PROG} [a-z]*: Examining mod1-2
+${PROG} [a-z]*: Examining mod2-2/mod1-2
+Checking in mod1-1/file1-1;
+${TESTDIR}/root1/mod1-1/file1-1,v <-- file1-1
+new revision: 1.2; previous revision: 1.1
+done
+Checking in mod1-2/file1-2;
+${TESTDIR}/root1/mod1-2/file1-2,v <-- file1-2
+new revision: 1.2; previous revision: 1.1
+done
+${PROG} [a-z]*: Examining mod1-2/mod2-2
+${PROG} [a-z]*: Examining mod2-1
+${PROG} [a-z]*: Examining mod2-2
+Checking in mod2-1/file2-1;
+${TESTDIR}/root2/mod2-1/file2-1,v <-- file2-1
+new revision: 1.2; previous revision: 1.1
+done
+Checking in mod2-2/file2-2;
+${TESTDIR}/root2/mod2-2/file2-2,v <-- file2-2
+new revision: 1.2; previous revision: 1.1
+done"
+
+ dotest multiroot-update-2 "${testcvs} update" \
+"${PROG} update: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2
+U mod2-2/mod1-2/file1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+U mod1-2/mod2-2/file2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2" \
+"${PROG} server: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2
+P mod2-2/mod1-2/file1-2
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+P mod1-2/mod2-2/file2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2"
+
+ dotest multiroot-tag-1 "${testcvs} tag cattle" \
+"${PROG} tag: Tagging \.
+${PROG} [a-z]*: Tagging mod1-1
+T mod1-1/file1-1
+${PROG} [a-z]*: Tagging mod1-2
+T mod1-2/file1-2
+${PROG} [a-z]*: Tagging mod2-2/mod1-2
+${PROG} [a-z]*: Tagging mod1-2/mod2-2
+T mod1-2/mod2-2/file2-2
+${PROG} [a-z]*: Tagging mod2-1
+T mod2-1/file2-1
+${PROG} [a-z]*: Tagging mod2-2" \
+"${PROG} server: Tagging \.
+${PROG} [a-z]*: Tagging mod1-1
+T mod1-1/file1-1
+${PROG} [a-z]*: Tagging mod1-2
+T mod1-2/file1-2
+${PROG} [a-z]*: Tagging mod2-2
+${PROG} [a-z]*: Tagging mod2-2/mod1-2
+${PROG} [a-z]*: Tagging mod1-2
+${PROG} [a-z]*: Tagging mod1-2/mod2-2
+T mod1-2/mod2-2/file2-2
+${PROG} [a-z]*: Tagging mod2-1
+T mod2-1/file2-1
+${PROG} [a-z]*: Tagging mod2-2"
+
+ echo anotherfile1-1 > mod1-1/anotherfile1-1
+ echo anotherfile2-1 > mod2-1/anotherfile2-1
+ echo anotherfile1-2 > mod2-2/mod1-2/anotherfile1-2
+ echo anotherfile2-2 > mod1-2/mod2-2/anotherfile2-2
+
+ if test "x$remote" = xno; then
+ dotest multiroot-add-1 "${testcvs} add mod1-1/anotherfile1-1 mod2-1/anotherfile2-1 mod2-2/mod1-2/anotherfile1-2 mod1-2/mod2-2/anotherfile2-2" \
+"${PROG} [a-z]*: scheduling file .mod1-1/anotherfile1-1. for addition
+${PROG} [a-z]*: scheduling file .mod2-1/anotherfile2-1. for addition
+${PROG} [a-z]*: scheduling file .mod2-2/mod1-2/anotherfile1-2. for addition
+${PROG} [a-z]*: scheduling file .mod1-2/mod2-2/anotherfile2-2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ else
+ cd mod1-1
+ dotest multiroot-add-1a "${testcvs} add anotherfile1-1" \
+"${PROG} [a-z]*: scheduling file .anotherfile1-1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ../mod2-1
+ dotest multiroot-add-1b "${testcvs} add anotherfile2-1" \
+"${PROG} [a-z]*: scheduling file .anotherfile2-1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ../mod2-2/mod1-2
+ dotest multiroot-add-1c "${testcvs} add anotherfile1-2" \
+"${PROG} [a-z]*: scheduling file .anotherfile1-2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ../../mod1-2/mod2-2
+ dotest multiroot-add-1d "${testcvs} add anotherfile2-2" \
+"${PROG} [a-z]*: scheduling file .anotherfile2-2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ../..
+ fi
+
+ dotest multiroot-status-1 "${testcvs} status -v" \
+"${PROG} status: Examining \.
+${PROG} [a-z]*: Examining mod1-1
+===================================================================
+File: anotherfile1-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod1-2
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-2/mod1-2
+===================================================================
+File: anotherfile1-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod1-2/mod2-2
+===================================================================
+File: anotherfile2-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-1
+===================================================================
+File: anotherfile2-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-2
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)" \
+"${PROG} server: Examining \.
+${PROG} [a-z]*: Examining mod1-1
+===================================================================
+File: anotherfile1-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod1-2
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-2
+${PROG} [a-z]*: Examining mod2-2/mod1-2
+===================================================================
+File: anotherfile1-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file1-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod1-2
+${PROG} [a-z]*: Examining mod1-2/mod2-2
+===================================================================
+File: anotherfile2-2 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-1
+===================================================================
+File: anotherfile2-1 Status: Locally Added
+
+ Working revision: New file!
+ Repository revision: No revision control file
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: file2-1 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)
+
+${PROG} [a-z]*: Examining mod2-2
+===================================================================
+File: file2-2 Status: Up-to-date
+
+ Working revision: 1\.2.*
+ Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+ Existing Tags:
+ cattle (revision: 1\.2)"
+
+ dotest multiroot-commit-2 "${testcvs} commit -m reading" \
+"${PROG} [a-z]*: Examining \.
+${PROG} [a-z]*: Examining mod1-1
+${PROG} [a-z]*: Examining mod1-2
+${PROG} [a-z]*: Examining mod2-2/mod1-2
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v
+done
+Checking in mod1-1/anotherfile1-1;
+${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v <-- anotherfile1-1
+initial revision: 1\.1
+done
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+done
+Checking in mod2-2/mod1-2/anotherfile1-2;
+${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v <-- anotherfile1-2
+initial revision: 1\.1
+done
+${PROG} [a-z]*: Examining mod1-2/mod2-2
+${PROG} [a-z]*: Examining mod2-1
+${PROG} [a-z]*: Examining mod2-2
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+done
+Checking in mod1-2/mod2-2/anotherfile2-2;
+${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v <-- anotherfile2-2
+initial revision: 1\.1
+done
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v
+done
+Checking in mod2-1/anotherfile2-1;
+${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v <-- anotherfile2-1
+initial revision: 1\.1
+done"
+
+ dotest multiroot-update-3 "${testcvs} update" \
+"${PROG} update: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+U mod1-2/anotherfile1-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2
+U mod2-2/anotherfile2-2" \
+"${PROG} server: Updating \.
+${PROG} [a-z]*: Updating mod1-1
+${PROG} [a-z]*: Updating mod1-2
+U mod1-2/anotherfile1-2
+${PROG} [a-z]*: Updating mod2-2
+${PROG} [a-z]*: Updating mod2-2/mod1-2
+${PROG} [a-z]*: Updating mod1-2
+${PROG} [a-z]*: Updating mod1-2/mod2-2
+${PROG} [a-z]*: Updating mod2-1
+${PROG} [a-z]*: Updating mod2-2
+U mod2-2/anotherfile2-2"
+
+ dotest multiroot-log-1 "${testcvs} log" \
+"${PROG} log: Logging \.
+${PROG} [a-z]*: Logging mod1-1
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v
+Working file: mod1-1/anotherfile1-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+Working file: mod1-1/file1-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod2-2/mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod2-2/mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod2-2/mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod1-2/mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod1-2/mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod1-2/mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+=============================================================================
+${PROG} [a-z]*: Logging mod2-1
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v
+Working file: mod2-1/anotherfile2-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+Working file: mod2-1/file2-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+=============================================================================
+${PROG} [a-z]*: Logging mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+=============================================================================" \
+"${PROG} server: Logging \.
+${PROG} [a-z]*: Logging mod1-1
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v
+Working file: mod1-1/anotherfile1-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
+Working file: mod1-1/file1-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod2-2
+${PROG} [a-z]*: Logging mod2-2/mod1-2
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v
+Working file: mod2-2/mod1-2/anotherfile1-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
+Working file: mod2-2/mod1-2/file1-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+is
+=============================================================================
+${PROG} [a-z]*: Logging mod1-2
+${PROG} [a-z]*: Logging mod1-2/mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod1-2/mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod1-2/mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+=============================================================================
+${PROG} [a-z]*: Logging mod2-1
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v
+Working file: mod2-1/anotherfile2-1
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
+Working file: mod2-1/file2-1
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+=============================================================================
+${PROG} [a-z]*: Logging mod2-2
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v
+Working file: mod2-2/anotherfile2-2
+head: 1\.1
+branch:
+locks: strict
+access list:
+symbolic names:
+keyword substitution: kv
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+reading
+=============================================================================
+
+RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
+Working file: mod2-2/file2-2
+head: 1\.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ cattle: 1\.2
+keyword substitution: kv
+total revisions: 2; selected revisions: 2
+description:
+----------------------------
+revision 1\.2
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0
+actually
+----------------------------
+revision 1\.1
+date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;
+anyone
+============================================================================="
+
+
+ # After the simple cases, let's execute some commands which
+ # refer to parts of our checked-out tree (e.g. "cvs update
+ # mod1-1 mod2-2")
+
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ # clean up after ourselves
+ cd ..
+ rm -r 1
+
+ # clean up our repositories
+ rm -rf root1 root2
+ ;;
+
+ multiroot2)
+ # More multiroot tests. In particular, nested directories.
+
+ CVSROOT1_DIRNAME=${TESTDIR}/root1
+ CVSROOT2_DIRNAME=${TESTDIR}/root2
+ CVSROOT1=${CVSROOT1_DIRNAME} ; export CVSROOT1
+ CVSROOT2=${CVSROOT2_DIRNAME} ; export CVSROOT2
+ if test "x$remote" = xyes; then
+ CVSROOT1=:fork:${CVSROOT1_DIRNAME} ; export CVSROOT1
+ CVSROOT2=:fork:${CVSROOT2_DIRNAME} ; export CVSROOT2
+ fi
+
+ dotest multiroot2-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot2-2 "${testcvs} -d ${CVSROOT2} init" ""
+
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ mkdir sdir
+ echo sfile >sdir/sfile
+ mkdir sdir/ssdir
+ echo ssfile >sdir/ssdir/ssfile
+ dotest_sort multiroot2-3 \
+"${testcvs} -d ${CVSROOT1} import -m import-to-root1 dir1 vend rel" "
+
+N dir1/file1
+N dir1/sdir/sfile
+N dir1/sdir/ssdir/ssfile
+No conflicts created by this import
+${PROG} [a-z]*: Importing ${TESTDIR}/root1/dir1/sdir
+${PROG} [a-z]*: Importing ${TESTDIR}/root1/dir1/sdir/ssdir"
+ cd sdir
+ dotest_sort multiroot2-4 \
+"${testcvs} -d ${CVSROOT2} import -m import-to-root2 sdir vend2 rel2" "
+
+N sdir/sfile
+N sdir/ssdir/ssfile
+No conflicts created by this import
+${PROG} [a-z]*: Importing ${TESTDIR}/root2/sdir/ssdir"
+ cd ../..
+
+ mkdir 1; cd 1
+ # Get TopLevelAdmin-like behavior.
+ dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co -l ."
+ dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co dir1" \
+"U dir1/file1
+U dir1/sdir/sfile
+U dir1/sdir/ssdir/ssfile"
+ cd dir1
+ dotest multiroot2-6 "${testcvs} -Q release -d sdir" ""
+ dotest multiroot2-7 "${testcvs} -d ${CVSROOT2} -q co sdir" \
+"U sdir/sfile
+U sdir/ssdir/ssfile"
+ cd ..
+ # This has one subtle effect - it deals with Entries.Log
+ # so that the next test doesn't get trace messages for
+ # Entries.Log
+ dotest multiroot2-8 "${testcvs} update" \
+"${PROG} update: Updating \.
+${PROG} update: Updating dir1
+${PROG} update: Updating dir1/sdir
+${PROG} update: Updating dir1/sdir/ssdir" \
+"${PROG} server: Updating \.
+${PROG} server: Updating dir1
+${PROG} server: Updating dir1
+${PROG} server: Updating dir1/sdir
+${PROG} server: Updating dir1/sdir/ssdir"
+ # Two reasons we don't run this on the server: (1) the server
+ # also prints some trace messages, and (2) the server trace
+ # messages are subject to out-of-order bugs (this one is hard
+ # to work around).
+ if test "$remote" = no; then
+ dotest multiroot2-9 "${testcvs} -t update" \
+"${PROG} update: notice: main loop with CVSROOT=${TESTDIR}/root1
+${PROG} update: Updating \.
+${PROG} update: Updating dir1
+${PROG} update: notice: main loop with CVSROOT=${TESTDIR}/root2
+${PROG} update: Updating dir1/sdir
+${PROG} update: Updating dir1/sdir/ssdir"
+ fi
+
+ dotest multiroot2-9 "${testcvs} -q tag tag1" \
+"T dir1/file1
+T dir1/sdir/sfile
+T dir1/sdir/ssdir/ssfile"
+ echo "change it" >>dir1/file1
+ echo "change him too" >>dir1/sdir/sfile
+ dotest multiroot2-10 "${testcvs} -q ci -m modify" \
+"Checking in dir1/file1;
+${TESTDIR}/root1/dir1/file1,v <-- file1
+new revision: 1\.2; previous revision: 1\.1
+done
+Checking in dir1/sdir/sfile;
+${TESTDIR}/root2/sdir/sfile,v <-- sfile
+new revision: 1\.2; previous revision: 1\.1
+done"
+ dotest multiroot2-11 "${testcvs} -q tag tag2" \
+"T dir1/file1
+T dir1/sdir/sfile
+T dir1/sdir/ssdir/ssfile"
+ dotest_status multiroot2-12 1 \
+"${testcvs} -q diff -u -r tag1 -r tag2" \
+"Index: dir1/file1
+===================================================================
+RCS file: ${TESTDIR}/root1/dir1/file1,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.2
+diff -u -r1\.1\.1\.1 -r1\.2
+--- dir1/file1 [0-9/]* [0-9:]* 1\.1\.1\.1
+${PLUS}${PLUS}${PLUS} dir1/file1 [0-9/]* [0-9:]* 1\.2
+@@ -1 ${PLUS}1,2 @@
+ file1
+${PLUS}change it
+Index: dir1/sdir/sfile
+===================================================================
+RCS file: ${TESTDIR}/root2/sdir/sfile,v
+retrieving revision 1\.1\.1\.1
+retrieving revision 1\.2
+diff -u -r1\.1\.1\.1 -r1\.2
+--- dir1/sdir/sfile [0-9/]* [0-9:]* 1\.1\.1\.1
+${PLUS}${PLUS}${PLUS} dir1/sdir/sfile [0-9/]* [0-9:]* 1\.2
+@@ -1 ${PLUS}1,2 @@
+ sfile
+${PLUS}change him too"
+
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ # clean up after ourselves
+ cd ..
+ rm -r imp-dir 1
+
+ # clean up our repositories
+ rm -rf root1 root2
+ ;;
+
+ multiroot3)
+ # More multiroot tests. Directories are side-by-side, not nested.
+ # Not drastically different from multiroot but it covers somewhat
+ # different stuff.
+
+ if test "x$remote" = xyes; then
+ CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT2=:fork:${TESTDIR}/root2 ; export CVSROOT2
+ else
+ CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT2=${TESTDIR}/root2 ; export CVSROOT2
+ fi
+
+ mkdir 1; cd 1
+ dotest multiroot3-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot3-2 "${testcvs} -d ${CVSROOT1} -q co -l ." ""
+ mkdir dir1
+ dotest multiroot3-3 "${testcvs} add dir1" \
+"Directory ${TESTDIR}/root1/dir1 added to the repository"
+ dotest multiroot3-4 "${testcvs} -d ${CVSROOT2} init" ""
+ rm -r CVS
+ dotest multiroot3-5 "${testcvs} -d ${CVSROOT2} -q co -l ." ""
+ mkdir dir2
+
+ # OK, the problem is that CVS/Entries doesn't look quite right,
+ # I suppose because of the "rm -r".
+ # For local this fixes it up.
+ dotest multiroot3-6 "${testcvs} -d ${CVSROOT1} -q co dir1" ""
+ if test "$remote" = yes; then
+ # For remote that doesn't do it. Use the quick and dirty fix.
+ echo "D/dir1////" >CVS/Entries
+ echo "D/dir2////" >>CVS/Entries
+ fi
+
+ dotest multiroot3-7 "${testcvs} add dir2" \
+"Directory ${TESTDIR}/root2/dir2 added to the repository"
+
+ touch dir1/file1 dir2/file2
+ if test "$remote" = yes; then
+ # Trying to add them both in one command doesn't work,
+ # because add.c doesn't do multiroot (it doesn't use recurse.c).
+ # Furthermore, it can't deal with the parent directory
+ # having a different root from the child, hence the cd.
+ cd dir1
+ dotest multiroot3-8 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ cd ..
+ dotest multiroot3-8a "${testcvs} add dir2/file2" \
+"${PROG} [a-z]*: scheduling file .dir2/file2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ else
+ dotest multiroot3-8 "${testcvs} add dir1/file1 dir2/file2" \
+"${PROG} [a-z]*: scheduling file .dir1/file1. for addition
+${PROG} [a-z]*: scheduling file .dir2/file2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ fi
+
+ dotest multiroot3-9 "${testcvs} -q ci -m add-them" \
+"RCS file: ${TESTDIR}/root2/dir2/file2,v
+done
+Checking in dir2/file2;
+${TESTDIR}/root2/dir2/file2,v <-- file2
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/root1/dir1/file1,v
+done
+Checking in dir1/file1;
+${TESTDIR}/root1/dir1/file1,v <-- file1
+initial revision: 1\.1
+done"
+
+ if test "`cat dir1/CVS/Repository`" = "dir1"; then
+ # RELATIVE_REPOS
+ # That this is an error is good - we are asking CVS to do
+ # something which doesn't make sense.
+ dotest_fail multiroot3-10 \
+"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \
+"${PROG} [a-z]*: failed to create lock directory in repository .${TESTDIR}/root1/dir2': No such file or directory
+${PROG} [a-z]*: failed to obtain dir lock in repository .${TESTDIR}/root1/dir2'
+${PROG} \[[a-z]* aborted\]: read lock failed - giving up"
+ else
+ # Not RELATIVE_REPOS.
+ if test "$remote" = yes; then
+ # This is good behavior - we are asking CVS to do something
+ # which doesn't make sense.
+ dotest_fail multiroot3-10 \
+"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \
+"protocol error: directory '${TESTDIR}/root2/dir2' not within root '${TESTDIR}/root1'"
+ else
+ # Local isn't as picky as we'd want in terms of getting
+ # the wrong root.
+ dotest multiroot3-10 \
+"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" ""
+ fi
+ fi
+ # This one is supposed to work.
+ dotest multiroot3-11 "${testcvs} -q diff dir1/file1 dir2/file2" ""
+
+ cd ..
+
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ rm -r 1
+ rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2
+ unset CVSROOT1
+ unset CVSROOT2
+ ;;
+
+ multiroot4)
+ # More multiroot tests, in particular we have two roots with
+ # similarly-named directories and we try to see that CVS can
+ # keep them separate.
+ if test "x$remote" = xyes; then
+ CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT2=:fork:${TESTDIR}/root2 ; export CVSROOT2
+ else
+ CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT2=${TESTDIR}/root2 ; export CVSROOT2
+ fi
+
+ mkdir 1; cd 1
+ dotest multiroot4-1 "${testcvs} -d ${CVSROOT1} init" ""
+ dotest multiroot4-2 "${testcvs} -d ${CVSROOT1} -q co -l ." ""
+ mkdir dircom
+ dotest multiroot4-3 "${testcvs} add dircom" \
+"Directory ${TESTDIR}/root1/dircom added to the repository"
+ cd dircom
+ touch file1
+ dotest multiroot4-4 "${testcvs} add file1" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest multiroot4-5 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/root1/dircom/file1,v
+done
+Checking in file1;
+${TESTDIR}/root1/dircom/file1,v <-- file1
+initial revision: 1\.1
+done"
+ cd ../..
+ mkdir 2; cd 2
+ dotest multiroot4-6 "${testcvs} -d ${CVSROOT2} init" ""
+ dotest multiroot4-7 "${testcvs} -d ${CVSROOT2} -q co -l ." ""
+ mkdir dircom
+ dotest multiroot4-8 "${testcvs} add dircom" \
+"Directory ${TESTDIR}/root2/dircom added to the repository"
+ cd dircom
+ touch file2
+ dotest multiroot4-9 "${testcvs} add file2" \
+"${PROG} [a-z]*: scheduling file .file2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add this file permanently"
+ dotest multiroot4-10 "${testcvs} -q ci -m add" \
+"RCS file: ${TESTDIR}/root2/dircom/file2,v
+done
+Checking in file2;
+${TESTDIR}/root2/dircom/file2,v <-- file2
+initial revision: 1\.1
+done"
+
+ cd ../..
+ cd 1/dircom
+ # This may look contrived; the real world example which inspired
+ # it was that a user was changing from local to remote. Cases
+ # like switching servers (among those mounting the same
+ # repository) and so on would also look the same.
+ mkdir sdir2
+ dotest multiroot4-11 "${testcvs} -d ${CVSROOT2} add sdir2" \
+"Directory ${TESTDIR}/root2/dircom/sdir2 added to the repository"
+
+ dotest multiroot4-12 "${testcvs} -q update" ""
+ cd ..
+ dotest multiroot4-13 "${testcvs} -q update dircom" ""
+ cd ..
+
+ rm -r 1 2
+ rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2
+ unset CVSROOT1
+ unset CVSROOT2
+ ;;
+
+ rmroot)
+ # When the Entries/Root file is removed from an existing
+ # workspace, CVS should assume $CVSROOT instead
+ #
+ # Right now only checking that CVS exits normally on an
+ # update once CVS/Root is deleted
+ #
+ # There was a time when this would core dump when run in
+ # client/server mode
+
+ mkdir 1; cd 1
+ dotest rmroot-setup-1 "${testcvs} -q co -l ." ''
+ mkdir first-dir
+ dotest rmroot-setup-2 "${testcvs} add first-dir" \
+"Directory ${TESTDIR}/cvsroot/first-dir added to the repository"
+ cd first-dir
+ touch file1 file2
+ dotest rmroot-setup-3 "${testcvs} add file1 file2" \
+"${PROG} [a-z]*: scheduling file .file1. for addition
+${PROG} [a-z]*: scheduling file .file2. for addition
+${PROG} [a-z]*: use .${PROG} commit. to add these files permanently"
+ dotest rmroot-setup-4 "${testcvs} -q commit -minit" \
+"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v
+done
+Checking in file1;
+${TESTDIR}/cvsroot/first-dir/file1,v <-- file1
+initial revision: 1\.1
+done
+RCS file: ${TESTDIR}/cvsroot/first-dir/file2,v
+done
+Checking in file2;
+${TESTDIR}/cvsroot/first-dir/file2,v <-- file2
+initial revision: 1\.1
+done"
+ rm CVS/Root
+ dotest rmroot-1 "${testcvs} -q update" ''
+
+ cd ../..
+ rm -rf 1
+ ;;
+
+ reposmv)
+ # More tests of repositories and specifying them.
+ # Similar to crerepos but that test is probably getting big
+ # enough.
+
+ if test "x$remote" = xyes; then
+ CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT_MOVED=:fork:${TESTDIR}/root-moved ; export CVSROOT1
+ else
+ CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1
+ CVSROOT_MOVED=${TESTDIR}/root-moved ; export CVSROOT1
+ fi
+
+ dotest reposmv-setup-1 "${testcvs} -d ${CVSROOT1} init" ""
+ mkdir imp-dir; cd imp-dir
+ echo file1 >file1
+ dotest reposmv-setup-2 \
+"${testcvs} -d ${CVSROOT1} import -m add dir1 vendor release" \
+"N dir1/file1
+
+No conflicts created by this import"
+ cd ..
+
+ mkdir 1; cd 1
+ dotest reposmv-1 "${testcvs} -d ${CVSROOT1} -Q co dir1" ""
+ mv ${TESTDIR}/root1 ${TESTDIR}/root-moved
+ cd dir1
+
+ # If we didn't have a relative repository, get one now.
+ dotest reposmv-1a "cat CVS/Repository" \
+"${TESTDIR}/root1/dir1" "dir1"
+ echo dir1 >CVS/Repository
+
+ # There were some duplicated warnings and such; only test
+ # for the part of the error message which makes sense.
+ # Bug: "skipping directory " without filename.
+ if test "$remote" = no; then
+ dotest reposmv-2 "${testcvs} update" "${DOTSTAR}
+${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1
+${PROG} update: cannot open directory ${TESTDIR}/cvsroot/dir1: No such file or directory
+${PROG} update: skipping directory "
+ else
+ dotest_fail reposmv-2 "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ fi
+
+ # CVS/Root overrides $CVSROOT
+ if test "$remote" = no; then
+ CVSROOT_SAVED=${CVSROOT}
+ CVSROOT=${TESTDIR}/root-moved; export CVSROOT
+ dotest reposmv-3 "${testcvs} update" \
+"${DOTSTAR}
+${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1
+${PROG} update: Updating \.
+${DOTSTAR}"
+ CVSROOT=${CVSROOT_SAVED}; export CVSROOT
+ else
+ CVSROOT_SAVED=${CVSROOT}
+ CVSROOT=:fork:${TESTDIR}/root-moved; export CVSROOT
+ dotest_fail reposmv-3 "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ CVSROOT=${CVSROOT_SAVED}; export CVSROOT
+ fi
+
+ if test "$remote" = no; then
+ # CVS/Root doesn't seem to quite completely override $CVSROOT
+ # Bug? Not necessarily a big deal if it only affects error
+ # messages.
+ CVSROOT_SAVED=${CVSROOT}
+ CVSROOT=${TESTDIR}/root-none; export CVSROOT
+ dotest_fail reposmv-4 "${testcvs} update" \
+"${PROG} update: in directory \.:
+${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1
+${PROG} \[update aborted\]: ${TESTDIR}/root-none/CVSROOT: No such file or directory"
+ CVSROOT=${CVSROOT_SAVED}; export CVSROOT
+ else
+ CVSROOT_SAVED=${CVSROOT}
+ CVSROOT=:fork:${TESTDIR}/root-none; export CVSROOT
+ dotest_fail reposmv-4 "${testcvs} update" \
+"Cannot access ${TESTDIR}/root1/CVSROOT
+No such file or directory"
+ CVSROOT=${CVSROOT_SAVED}; export CVSROOT
+ fi
+
+ # -d overrides CVS/Root
+ #
+ # Oddly enough, with CVS 1.10 I think this didn't work for
+ # local (that is, it would appear that CVS/Root would not
+ # get used, but would produce an error if it didn't exist).
+ dotest reposmv-5 "${testcvs} -d ${CVSROOT_MOVED} update" \
+"${PROG} [a-z]*: Updating \."
+
+ # TODO: could also test various other things, like what if the
+ # user removes CVS/Root (which is legit). Or another set of
+ # tests would be if both repositories exist but we want to make
+ # sure that CVS is using the correct one.
+
+ cd ../..
+ rm -r imp-dir 1
+ rm -rf root1 root2
+ unset CVSROOT1
+ ;;
+
+ pserver)
+ # Test basic pserver functionality.
+ if test "$remote" = yes; then
+ # First set SystemAuth=no. Not really necessary, I don't
+ # think, but somehow it seems like the clean thing for
+ # the testsuite.
+ mkdir 1; cd 1
+ dotest pserver-1 "${testcvs} -Q co CVSROOT" ""
+ cd CVSROOT
+ echo "SystemAuth=no" >config
+ dotest pserver-2 "${testcvs} -q ci -m config-it" \
+"Checking in config;
+${TESTDIR}/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+done
+${PROG} [a-z]*: Rebuilding administrative file database"
+ echo "testme:q6WV9d2t848B2:`id -un`" \
+ >${CVSROOT_DIRNAME}/CVSROOT/passwd
+ ${testcvs} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+EOF
+ dotest pserver-3 "cat ${TESTDIR}/pserver.tmp" \
+"error 0 Server configuration missing --allow-root in inetd.conf"
+
+ # Sending the Root and noop before waiting for the
+ # "I LOVE YOU" is bogus, but hopefully we can get
+ # away with it.
+ ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+Root ${CVSROOT_DIRNAME}
+noop
+EOF
+ dotest pserver-4 "cat ${TESTDIR}/pserver.tmp" \
+"${DOTSTAR} LOVE YOU
+ok"
+
+ ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+Root ${TESTDIR}/1
+noop
+EOF
+ dotest pserver-5 "cat ${TESTDIR}/pserver.tmp" \
+"${DOTSTAR} LOVE YOU
+E Protocol error: Root says \"${TESTDIR}/1\" but pserver says \"${CVSROOT_DIRNAME}\"
+error "
+
+ ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d^b?hd
+END AUTH REQUEST
+EOF
+ dotest pserver-6 "cat ${TESTDIR}/pserver.tmp" \
+"I HATE YOU"
+
+ ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN VERIFICATION REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d^b?hd
+END VERIFICATION REQUEST
+EOF
+ dotest pserver-7 "cat ${TESTDIR}/pserver.tmp" \
+"I HATE YOU"
+
+ ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF
+BEGIN VERIFICATION REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END VERIFICATION REQUEST
+EOF
+ dotest pserver-8 "cat ${TESTDIR}/pserver.tmp" \
+"${DOTSTAR} LOVE YOU"
+
+ # Clean up.
+ echo "# comments only" >config
+ dotest pserver-cleanup-1 "${testcvs} -q ci -m config-it" \
+"Checking in config;
+${TESTDIR}/cvsroot/CVSROOT/config,v <-- config
+new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
+done
+${PROG} [a-z]*: Rebuilding administrative file database"
+ cd ../..
+ rm -r 1
+ rm ${CVSROOT_DIRNAME}/CVSROOT/passwd
+ fi # skip the whole thing for local
+ ;;
+
+ server)
+ # Some tests of the server (independent of the client).
+ if test "$remote" = yes; then
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Directory bogus
+mumble/bar
+update
+EOF
+ dotest server-1 "cat ${TESTDIR}/server.tmp" \
+"E Protocol error: Root request missing
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-1
+ fi
+
+ # Could also test for relative pathnames here (so that crerepos-6a
+ # and crerepos-6b can use :fork:).
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Set OTHER=variable
+Set MYENV=env-value
+init ${TESTDIR}/crerepos
+EOF
+ dotest server-2 "cat ${TESTDIR}/server.tmp" "ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-2
+ fi
+ dotest server-3 "test -d ${TESTDIR}/crerepos/CVSROOT" ""
+
+ # Now some tests of gzip-file-contents (used by jCVS).
+ awk 'BEGIN { \
+printf "%c%c%c%c%c%c.6%c%c+I-.%c%c%c%c5%c;%c%c%c%c", \
+31, 139, 8, 64, 5, 7, 64, 3, 225, 2, 64, 198, 185, 5, 64, 64, 64}' \
+ </dev/null | tr '\100' '\000' >gzipped.dat
+ # Note that the CVS client sends "-b 1.1.1", and this
+ # test doesn't. But the server also defaults to that.
+ cat <<EOF >session.dat
+Root ${TESTDIR}/crerepos
+UseUnchanged
+gzip-file-contents 3
+Argument -m
+Argument msg
+Argumentx
+Argument dir1
+Argument tag1
+Argument tag2
+Directory .
+${TESTDIR}/crerepos
+Modified file1
+u=rw,g=r,o=r
+z25
+EOF
+ cat gzipped.dat >>session.dat
+ echo import >>session.dat
+ if ${testcvs} server >${TESTDIR}/server.tmp <session.dat; then
+ dotest server-4 "cat ${TESTDIR}/server.tmp" "M N dir1/file1
+M
+M No conflicts created by this import
+M
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-4
+ fi
+ dotest server-5 \
+"${testcvs} -q -d ${TESTDIR}/crerepos co -p dir1/file1" "test"
+
+ # OK, here are some notify tests.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Fri May 7 13:21:09 1999 GMT myhost some-work-dir EUC
+noop
+EOF
+ dotest server-6 "cat ${TESTDIR}/server.tmp" \
+"Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-6
+ fi
+ # Sending the second "noop" before waiting for the output
+ # from the first is bogus but hopefully we can get away
+ # with it.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Fri May 7 13:21:09 1999 GMT myhost some-work-dir EUC
+noop
+Notify file1
+E The 57th day of Discord in the YOLD 3165 myhost some-work-dir EUC
+noop
+EOF
+ dotest server-7 "cat ${TESTDIR}/server.tmp" \
+"Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok
+Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-7
+ fi
+
+ # OK, now test a few error conditions.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Setting Orange, the 52th day of Discord in the YOLD 3165 myhost some-work-dir EUC
+noop
+EOF
+ # FIXCVS: should give "error" and no "Notified", like server-9
+ dotest server-8 "cat ${TESTDIR}/server.tmp" \
+"E ${PROG} server: invalid character in editor value
+Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-8
+ fi
+
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+E Setting Orange+57th day of Discord myhost some-work-dir EUC
+noop
+EOF
+ dotest server-9 "cat ${TESTDIR}/server.tmp" \
+"E Protocol error; misformed Notify request
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-9
+ fi
+
+ # First demonstrate an interesting quirk in the protocol.
+ # The "watchers" request selects the files to operate based
+ # on files which exist in the working directory. So if we
+ # don't send "Entry" or the like, it won't do anything.
+ # Wants to be documented in cvsclient.texi...
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+watchers
+EOF
+ dotest server-10 "cat ${TESTDIR}/server.tmp" \
+"ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-10
+ fi
+
+ # See if "watchers" and "editors" display the right thing.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Entry /file1/1.1////
+watchers
+EOF
+ dotest server-11 "cat ${TESTDIR}/server.tmp" \
+"M file1 ${username} tedit tunedit tcommit
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-11
+ fi
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Entry /file1/1.1////
+editors
+EOF
+ dotest server-12 "cat ${TESTDIR}/server.tmp" \
+"M file1 ${username} The 57th day of Discord in the YOLD 3165 myhost some-work-dir
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-12
+ fi
+
+ # Now do an unedit.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+Notify file1
+U 7 May 1999 15:00 GMT myhost some-work-dir EUC
+noop
+EOF
+ dotest server-13 "cat ${TESTDIR}/server.tmp" \
+"Notified \./
+${TESTDIR}/crerepos/dir1/file1
+ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-13
+ fi
+
+ # Now try "watchers" and "editors" again.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+watchers
+EOF
+ dotest server-14 "cat ${TESTDIR}/server.tmp" \
+"ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-14
+ fi
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/crerepos
+Directory .
+${TESTDIR}/crerepos/dir1
+editors
+EOF
+ dotest server-15 "cat ${TESTDIR}/server.tmp" \
+"ok"
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server-15
+ fi
+
+ if test "$keep" = yes; then
+ echo Keeping ${TESTDIR} and exiting due to --keep
+ exit 0
+ fi
+
+ rm -rf ${TESTDIR}/crerepos
+ rm gzipped.dat session.dat
+ rm ${TESTDIR}/server.tmp
+ fi # skip the whole thing for local
+ ;;
+
+ server2)
+ # More server tests, in particular testing that various
+ # possible security holes are plugged.
+ if test "$remote" = yes; then
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/cvsroot
+Directory .
+${TESTDIR}/cvsroot/../dir1
+noop
+EOF
+ dotest server2-1 "cat ${TESTDIR}/server.tmp" \
+"E protocol error: directory '${TESTDIR}/cvsroot/\.\./dir1' not within root '${TESTDIR}/cvsroot'
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server2-1
+ fi
+
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/cvsroot
+Directory .
+${TESTDIR}/cvsrootdir1
+noop
+EOF
+ dotest server2-2 "cat ${TESTDIR}/server.tmp" \
+"E protocol error: directory '${TESTDIR}/cvsrootdir1' not within root '${TESTDIR}/cvsroot'
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server2-2
+ fi
+
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/cvsroot
+Directory .
+${TESTDIR}
+noop
+EOF
+ dotest server2-3 "cat ${TESTDIR}/server.tmp" \
+"E protocol error: directory '${TESTDIR}' not within root '${TESTDIR}/cvsroot'
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server2-3
+ fi
+
+ # OK, now a few tests for the rule that one cannot pass a
+ # filename containing a slash to Modified, Is-modified,
+ # Notify, Questionable, or Unchanged. For completeness
+ # we'd try them all. For lazyness/conciseness we don't.
+ if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then
+Root ${TESTDIR}/cvsroot
+Directory .
+${TESTDIR}/cvsroot
+Unchanged foo/bar
+noop
+EOF
+ dotest server2-4 "cat ${TESTDIR}/server.tmp" \
+"E protocol error: directory 'foo/bar' not within current directory
+error "
+ else
+ echo "exit status was $?" >>${LOGFILE}
+ fail server2-4
+ fi
+ fi
+ ;;
+
+ client)
+ # Some tests of the client (independent of the server).
+ if test "$remote" = yes; then
+ cat >${TESTDIR}/serveme <<EOF
+#!${TESTSHELL}
+# This is admittedly a bit cheezy, in the sense that we make lots
+# of assumptions about what the client is going to send us.
+# We don't mention Repository, because current clients don't require it.
+# Sending these at our own pace, rather than waiting for the client to
+# make the requests, is bogus, but hopefully we can get away with it.
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M special message"
+echo "Created first-dir/"
+echo "${TESTDIR}/cvsroot/first-dir/file1"
+echo "/file1/1.1///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "xyz"
+echo "ok"
+cat >/dev/null
+EOF
+ chmod +x ${TESTDIR}/serveme
+ CVS_SERVER=${TESTDIR}/serveme; export CVS_SERVER
+ mkdir 1; cd 1
+ dotest_fail client-1 "${testcvs} -q co first-dir" \
+"${PROG} \[checkout aborted\]: This server does not support the global -q option\."
+ dotest client-2 "${testcvs} co first-dir" "special message"
+
+ cat >${TESTDIR}/serveme <<EOF
+#!${TESTSHELL}
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M merge-it"
+echo "Copy-file ./"
+echo "${TESTDIR}/cvsroot/first-dir/file1"
+echo "${TESTDIR}/bogus/.#file1.1.1"
+echo "Merged ./"
+echo "${TESTDIR}/cvsroot/first-dir/file1"
+echo "/file1/1.2///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "abd"
+echo "ok"
+cat >/dev/null
+EOF
+ cd first-dir
+ mkdir ${TESTDIR}/bogus
+ dotest_fail client-3 "${testcvs} update" "merge-it
+${PROG} \[update aborted\]: protocol error: Copy-file tried to specify directory"
+ cat >${TESTDIR}/serveme <<EOF
+#!${TESTSHELL}
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M merge-it"
+echo "Copy-file ./"
+echo "${TESTDIR}/cvsroot/first-dir/file1"
+echo ".#file1.1.1"
+echo "Merged ./"
+echo "${TESTDIR}/cvsroot/first-dir/file1"
+echo "/file1/1.2///"
+echo "u=rw,g=rw,o=rw"
+echo "4"
+echo "abc"
+echo "ok"
+cat >/dev/null
+EOF
+ dotest client-4 "${testcvs} update" "merge-it"
+ dotest client-5 "cat .#file1.1.1" "xyz"
+ dotest client-6 "cat CVS/Entries" "/file1/1.2/[A-Za-z0-9 :]*//
+D"
+ dotest client-7 "cat file1" "abc"
+
+ cat >${TESTDIR}/serveme <<EOF
+#!${TESTSHELL}
+echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update"
+echo "ok"
+echo "M OK, whatever"
+echo "ok"
+cat >${TESTDIR}/client.tmp
+EOF
+ chmod u=rw,go= file1
+ # By specifying the time zone in local time, we don't
+ # know exactly how that will translate to GMT.
+ dotest client-8 "${testcvs} update -D 99-10-04" "OK, whatever"
+ dotest client-9 "cat ${TESTDIR}/client.tmp" \
+"Root ${TESTDIR}/cvsroot
+Valid-responses [-a-zA-Z ]*
+valid-requests
+Argument -D
+Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000
+Directory \.
+${TESTDIR}/cvsroot/first-dir
+Entry /file1/1\.2///
+Modified file1
+u=rw,g=,o=
+4
+abc
+update"
+
+ cd ../..
+ rm -r 1
+ rmdir ${TESTDIR}/bogus
+ rm ${TESTDIR}/serveme
+ CVS_SERVER=${testcvs}; export CVS_SERVER
+ fi # skip the whole thing for local
+ ;;
+
*)
echo $what is not the name of a test -- ignored
;;
@@ -15531,10 +20292,15 @@ echo "OK, all tests completed."
# * Test ability to send notifications in response to watches. (currently
# hard to test because CVS doesn't send notifications if username is the
# same).
-# * Test that remote edit and/or unedit works when disconnected from
-# server (e.g. set CVS_SERVER to "foobar").
# * Test the contents of adm files other than Root and Repository.
# Entries seems the next most important thing.
+# * Test the following compatibility issues:
+# - The filler fields in "D" entries in CVS/Entries get preserved
+# (per cvs.texinfo).
+# - Unrecognized entry types in CVS/Entries get ignored (looks like
+# this needs to be documented in cvs.texinfo, but is not)
+# - Test that unrecognized files in CVS directories (e.g. CVS/Foobar)
+# are ignored (per cvs.texinfo).
# End of TODO list.
# Remove the test directory, but first change out of it.
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index f6e64a5..669cad7 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -133,7 +133,7 @@ char *CVS_Username = NULL;
/* Used to check that same repos is transmitted in pserver auth and in
later CVS protocol. Exported because root.c also uses. */
-char *Pserver_Repos = NULL;
+static char *Pserver_Repos = NULL;
/* Should we check for system usernames/passwords? Can be changed by
CVSROOT/config. */
@@ -341,6 +341,182 @@ fd_buffer_block (closure, block)
return 0;
}
+/* Populate all of the directories between BASE_DIR and its relative
+ subdirectory DIR with CVSADM directories. Return 0 for success or
+ errno value. */
+static int create_adm_p PROTO((char *, char *));
+
+static int
+create_adm_p (base_dir, dir)
+ char *base_dir;
+ char *dir;
+{
+ char *dir_where_cvsadm_lives, *dir_to_register, *p, *tmp;
+ int retval, done;
+ FILE *f;
+
+ if (strcmp (dir, ".") == 0)
+ return 0; /* nothing to do */
+
+ /* Allocate some space for our directory-munging string. */
+ p = malloc (strlen (dir) + 1);
+ if (p == NULL)
+ return ENOMEM;
+
+ dir_where_cvsadm_lives = malloc (strlen (base_dir) + strlen (dir) + 100);
+ if (dir_where_cvsadm_lives == NULL)
+ return ENOMEM;
+
+ /* Allocate some space for the temporary string in which we will
+ construct filenames. */
+ tmp = malloc (strlen (base_dir) + strlen (dir) + 100);
+ if (tmp == NULL)
+ return ENOMEM;
+
+
+ /* We make several passes through this loop. On the first pass,
+ we simply create the CVSADM directory in the deepest directory.
+ For each subsequent pass, we try to remove the last path
+ element from DIR, create the CVSADM directory in the remaining
+ pathname, and register the subdirectory in the newly created
+ CVSADM directory. */
+
+ retval = done = 0;
+
+ strcpy (p, dir);
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ strcat (dir_where_cvsadm_lives, "/");
+ strcat (dir_where_cvsadm_lives, p);
+ dir_to_register = NULL;
+
+ while (1)
+ {
+ /* Create CVSADM. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM);
+ if ((CVS_MKDIR (tmp, 0777) < 0) && (errno != EEXIST))
+ {
+ retval = errno;
+ goto finish;
+ }
+
+ /* Create CVSADM_REP. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_REP);
+ if (! isfile (tmp))
+ {
+ /* Use Emptydir as the placeholder until the client sends
+ us the real value. This code is similar to checkout.c
+ (emptydir_name), but the code below returns errors
+ differently. */
+
+ char *empty;
+ empty = malloc (strlen (CVSroot_directory)
+ + sizeof (CVSROOTADM)
+ + sizeof (CVSNULLREPOS)
+ + 10);
+ if (! empty)
+ {
+ retval = ENOMEM;
+ goto finish;
+ }
+
+ /* Create the directory name. */
+ (void) sprintf (empty, "%s/%s/%s", CVSroot_directory,
+ CVSROOTADM, CVSNULLREPOS);
+
+ /* Create the directory if it doesn't exist. */
+ if (! isfile (empty))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ if (CVS_MKDIR (empty, 0777) < 0)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+ (void) umask (omask);
+ }
+
+
+ f = CVS_FOPEN (tmp, "w");
+ if (f == NULL)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+ /* Write the directory name to CVSADM_REP. */
+ if (fprintf (f, "%s\n", empty) < 0)
+ {
+ retval = errno;
+ fclose (f);
+ free (empty);
+ goto finish;
+ }
+ if (fclose (f) == EOF)
+ {
+ retval = errno;
+ free (empty);
+ goto finish;
+ }
+
+ /* Clean up after ourselves. */
+ free (empty);
+ }
+
+ /* Create CVSADM_ENT. We open in append mode because we
+ don't want to clobber an existing Entries file. */
+ (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_ENT);
+ f = CVS_FOPEN (tmp, "a");
+ if (f == NULL)
+ {
+ retval = errno;
+ goto finish;
+ }
+ if (fclose (f) == EOF)
+ {
+ retval = errno;
+ goto finish;
+ }
+
+ if (dir_to_register != NULL)
+ {
+ /* FIXME: Yes, this results in duplicate entries in the
+ Entries.Log file, but it doesn't currently matter. We
+ might need to change this later on to make sure that we
+ only write one entry. */
+
+ Subdir_Register ((List *) NULL, dir_where_cvsadm_lives,
+ dir_to_register);
+ }
+
+ if (done)
+ break;
+
+ dir_to_register = strrchr (p, '/');
+ if (dir_to_register == NULL)
+ {
+ dir_to_register = p;
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ done = 1;
+ }
+ else
+ {
+ *dir_to_register = '\0';
+ dir_to_register++;
+ strcpy (dir_where_cvsadm_lives, base_dir);
+ strcat (dir_where_cvsadm_lives, "/");
+ strcat (dir_where_cvsadm_lives, p);
+ }
+ }
+
+ finish:
+ free (tmp);
+ free (dir_where_cvsadm_lives);
+ free (p);
+ return retval;
+}
+
/*
* Make directory DIR, including all intermediate directories if necessary.
* Returns 0 for success or errno code.
@@ -563,6 +739,7 @@ serve_root (arg)
char *env;
char *path;
int save_errno;
+ char *arg_dup;
if (error_pending()) return;
@@ -574,9 +751,7 @@ serve_root (arg)
return;
}
- /* Sending "Root" twice is illegal. It would also be nice to
- check for the other case, in which there is no Root request
- prior to a request which requires one.
+ /* Sending "Root" twice is illegal.
The other way to handle a duplicate Root requests would be as a
request to clear out all state and start over as if it was a
@@ -591,16 +766,43 @@ serve_root (arg)
return;
}
- set_local_cvsroot (arg);
+#ifdef AUTH_SERVER_SUPPORT
+ if (Pserver_Repos != NULL)
+ {
+ if (strcmp (Pserver_Repos, arg) != 0)
+ {
+ if (alloc_pending (80 + strlen (Pserver_Repos) + strlen (arg)))
+ /* The explicitness is to aid people who are writing clients.
+ I don't see how this information could help an
+ attacker. */
+ sprintf (pending_error_text, "\
+E Protocol error: Root says \"%s\" but pserver says \"%s\"",
+ arg, Pserver_Repos);
+ }
+ }
+#endif
+ arg_dup = malloc (strlen (arg) + 1);
+ if (arg_dup == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
+ strcpy (arg_dup, arg);
+ set_local_cvsroot (arg_dup);
/* For pserver, this will already have happened, and the call will do
nothing. But for rsh, we need to do it now. */
parse_config (CVSroot_directory);
- path = xmalloc (strlen (CVSroot_directory)
- + sizeof (CVSROOTADM)
- + sizeof (CVSROOTADM_HISTORY)
- + 10);
+ path = malloc (strlen (CVSroot_directory)
+ + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_HISTORY)
+ + 10);
+ if (path == NULL)
+ {
+ pending_error = ENOMEM;
+ return;
+ }
(void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
@@ -670,6 +872,73 @@ server_pathname_check (path)
}
}
+static int outside_root PROTO ((char *));
+
+/* Is file or directory REPOS an absolute pathname within the
+ CVSroot_directory? If yes, return 0. If no, set pending_error
+ and return 1. */
+static int
+outside_root (repos)
+ char *repos;
+{
+ size_t repos_len = strlen (repos);
+ size_t root_len = strlen (CVSroot_directory);
+
+ /* I think isabsolute (repos) should always be true, and that
+ any RELATIVE_REPOS stuff should only be in CVS/Repository
+ files, not the protocol (for compatibility), but I'm putting
+ in the isabsolute check just in case. */
+ if (!isabsolute (repos))
+ {
+ if (alloc_pending (repos_len + 80))
+ sprintf (pending_error_text, "\
+E protocol error: %s is not absolute", repos);
+ return 1;
+ }
+
+ if (repos_len < root_len
+ || strncmp (CVSroot_directory, repos, root_len) != 0)
+ {
+ not_within:
+ if (alloc_pending (strlen (CVSroot_directory)
+ + strlen (repos)
+ + 80))
+ sprintf (pending_error_text, "\
+E protocol error: directory '%s' not within root '%s'",
+ repos, CVSroot_directory);
+ return 1;
+ }
+ if (repos_len > root_len)
+ {
+ if (repos[root_len] != '/')
+ goto not_within;
+ if (pathname_levels (repos + root_len + 1) > 0)
+ goto not_within;
+ }
+ return 0;
+}
+
+static int outside_dir PROTO ((char *));
+
+/* Is file or directory FILE outside the current directory (that is, does
+ it contain '/')? If no, return 0. If yes, set pending_error
+ and return 1. */
+static int
+outside_dir (file)
+ char *file;
+{
+ if (strchr (file, '/') != NULL)
+ {
+ if (alloc_pending (strlen (file)
+ + 80))
+ sprintf (pending_error_text, "\
+E protocol error: directory '%s' not within current directory",
+ file);
+ return 1;
+ }
+ return 0;
+}
+
/*
* Add as many directories to the temp directory as the client tells us it
* will use "..", so we never try to access something outside the temp
@@ -709,13 +978,31 @@ dirswitch (dir, repos)
{
int status;
FILE *f;
- char *b;
size_t dir_len;
server_write_entries ();
if (error_pending()) return;
+ /* Check for bad directory name.
+
+ FIXME: could/should unify these checks with server_pathname_check
+ except they need to report errors differently. */
+ if (isabsolute (dir))
+ {
+ if (alloc_pending (80 + strlen (dir)))
+ sprintf (pending_error_text,
+ "E absolute pathname `%s' illegal for server", dir);
+ return;
+ }
+ if (pathname_levels (dir) > max_dotdot_limit)
+ {
+ if (alloc_pending (80 + strlen (dir)))
+ sprintf (pending_error_text,
+ "E protocol error: `%s' has too many ..", dir);
+ return;
+ }
+
if (dir_name != NULL)
free (dir_name);
@@ -745,7 +1032,7 @@ dirswitch (dir, repos)
strcat (dir_name, "/");
strcat (dir_name, dir);
- status = mkdir_p (dir_name);
+ status = mkdir_p (dir_name);
if (status != 0
&& status != EEXIST)
{
@@ -755,16 +1042,20 @@ dirswitch (dir, repos)
return;
}
- /* Note that this call to Subdir_Register will be a noop if the parent
- directory does not yet exist (for example, if the client sends
- "Directory foo" followed by "Directory .", then the subdirectory does
- not get registered, but if the client sends "Directory ." followed
- by "Directory foo", then the subdirectory does get registered.
- This seems pretty fishy, but maybe it is the way it needs to work. */
- b = strrchr (dir_name, '/');
- *b = '\0';
- Subdir_Register ((List *) NULL, dir_name, b + 1);
- *b = '/';
+ /* We need to create adm directories in all path elements because
+ we want the server to descend them, even if the client hasn't
+ sent the appropriate "Argument xxx" command to match the
+ already-sent "Directory xxx" command. See recurse.c
+ (start_recursion) for a big discussion of this. */
+
+ status = create_adm_p (server_temp_dir, dir);
+ if (status != 0)
+ {
+ pending_error = status;
+ if (alloc_pending (80 + strlen (dir_name)))
+ sprintf (pending_error_text, "E cannot create_adm_p %s", dir_name);
+ return;
+ }
if ( CVS_CHDIR (dir_name) < 0)
{
@@ -777,14 +1068,17 @@ dirswitch (dir, repos)
* This is pretty much like calling Create_Admin, but Create_Admin doesn't
* report errors in the right way for us.
*/
- if (CVS_MKDIR (CVSADM, 0777) < 0)
+ if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
{
- if (errno == EEXIST)
- /* Don't create the files again. */
- return;
pending_error = errno;
return;
}
+
+ /* The following will overwrite the contents of CVSADM_REP. This
+ is the correct behavior -- mkdir_p may have written a
+ placeholder value to this file and we need to insert the
+ correct value. */
+
f = CVS_FOPEN (CVSADM_REP, "w");
if (f == NULL)
{
@@ -864,24 +1158,8 @@ serve_directory (arg)
status = buf_read_line (buf_from_net, &repos, (int *) NULL);
if (status == 0)
{
- /* I think isabsolute (repos) should always be true, and that
- any RELATIVE_REPOS stuff should only be in CVS/Repository
- files, not the protocol (for compatibility), but I'm putting
- in the in isabsolute check just in case. */
- if (isabsolute (repos)
- && strncmp (CVSroot_directory,
- repos,
- strlen (CVSroot_directory)) != 0)
- {
- if (alloc_pending (strlen (CVSroot_directory)
- + strlen (repos)
- + 80))
- sprintf (pending_error_text, "\
-E protocol error: directory '%s' not within root '%s'",
- repos, CVSroot_directory);
+ if (outside_root (repos))
return;
- }
-
dirswitch (arg, repos);
free (repos);
}
@@ -1055,8 +1333,6 @@ receive_file (size, file, gzipped)
{
int fd;
char *arg = file;
- pid_t gzip_pid = 0;
- int gzip_status;
/* Write the file. */
fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
@@ -1069,15 +1345,78 @@ receive_file (size, file, gzipped)
return;
}
- /*
- * FIXME: This doesn't do anything reasonable with gunzip's stderr, which
- * means that if gunzip writes to stderr, it will cause all manner of
- * protocol violations.
- */
if (gzipped)
- fd = filter_through_gunzip (fd, 0, &gzip_pid);
+ {
+ /* Using gunzip_and_write isn't really a high-performance
+ approach, because it keeps the whole thing in memory
+ (contiguous memory, worse yet). But it seems easier to
+ code than the alternative (and less vulnerable to subtle
+ bugs). Given that this feature is mainly for
+ compatibility, that is the better tradeoff. */
+
+ int toread = size;
+ char *filebuf;
+ char *p;
+
+ filebuf = malloc (size);
+ p = filebuf;
+ /* If NULL, we still want to read the data and discard it. */
- receive_partial_file (size, fd);
+ while (toread > 0)
+ {
+ int status, nread;
+ char *data;
+
+ status = buf_read_data (buf_from_net, toread, &data, &nread);
+ if (status != 0)
+ {
+ if (status == -2)
+ pending_error = ENOMEM;
+ else
+ {
+ pending_error_text = malloc (80);
+ if (pending_error_text == NULL)
+ pending_error = ENOMEM;
+ else if (status == -1)
+ {
+ sprintf (pending_error_text,
+ "E premature end of file from client");
+ pending_error = 0;
+ }
+ else
+ {
+ sprintf (pending_error_text,
+ "E error reading from client");
+ pending_error = status;
+ }
+ }
+ return;
+ }
+
+ toread -= nread;
+
+ if (filebuf != NULL)
+ {
+ memcpy (p, data, nread);
+ p += nread;
+ }
+ }
+ if (filebuf == NULL)
+ {
+ pending_error = ENOMEM;
+ goto out;
+ }
+
+ if (gunzip_and_write (fd, file, filebuf, size))
+ {
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E aborting due to compression error");
+ }
+ free (filebuf);
+ }
+ else
+ receive_partial_file (size, fd);
if (pending_error_text)
{
@@ -1091,30 +1430,25 @@ receive_file (size, file, gzipped)
/* else original string is supposed to be unchanged */
}
+ out:
if (close (fd) < 0 && !error_pending ())
{
pending_error_text = malloc (40 + strlen (arg));
if (pending_error_text)
sprintf (pending_error_text, "E cannot close %s", arg);
pending_error = errno;
- if (gzip_pid)
- waitpid (gzip_pid, (int *) 0, 0);
return;
}
-
- if (gzip_pid)
- {
- if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid)
- error (1, errno, "waiting for gunzip process %ld",
- (long) gzip_pid);
- else if (gzip_status != 0)
- error (1, 0, "gunzip exited %d", gzip_status);
- }
}
/* Kopt for the next file sent in Modified or Is-modified. */
static char *kopt;
+/* Timestamp (Checkin-time) for next file sent in Modified or
+ Is-modified. */
+static int checkin_time_valid;
+static time_t checkin_time;
+
static void serve_modified PROTO ((char *));
static void
@@ -1212,12 +1546,31 @@ serve_modified (arg)
return;
}
+ if (outside_dir (arg))
+ return;
+
if (size >= 0)
{
receive_file (size, arg, gzipped);
if (error_pending ()) return;
}
+ if (checkin_time_valid)
+ {
+ struct utimbuf t;
+
+ memset (&t, 0, sizeof (t));
+ t.modtime = t.actime = checkin_time;
+ if (utime (arg, &t) < 0)
+ {
+ pending_error = errno;
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot utime %s", arg);
+ return;
+ }
+ checkin_time_valid = 0;
+ }
+
{
int status = change_mode (arg, mode_text, 0);
free (mode_text);
@@ -1268,6 +1621,9 @@ serve_unchanged (arg)
if (error_pending ())
return;
+ if (outside_dir (arg))
+ return;
+
/* Rewrite entries file to have `=' in timestamp field. */
for (p = entries; p != NULL; p = p->next)
{
@@ -1308,6 +1664,9 @@ serve_is_modified (arg)
if (error_pending ())
return;
+ if (outside_dir (arg))
+ return;
+
/* Rewrite entries file to have `M' in timestamp field. */
found = 0;
for (p = entries; p != NULL; p = p->next)
@@ -1443,6 +1802,34 @@ serve_kopt (arg)
strcpy (kopt, arg);
}
+static void serve_checkin_time PROTO ((char *));
+
+static void
+serve_checkin_time (arg)
+ char *arg;
+{
+ if (error_pending ())
+ return;
+
+ if (checkin_time_valid)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text,
+ "E protocol error: duplicate Checkin-time request: %s",
+ arg);
+ return;
+ }
+
+ checkin_time = get_date (arg, NULL);
+ if (checkin_time == (time_t)-1)
+ {
+ if (alloc_pending (80 + strlen (arg)))
+ sprintf (pending_error_text, "E cannot parse date %s", arg);
+ return;
+ }
+ checkin_time_valid = 1;
+}
+
static void
server_write_entries ()
{
@@ -1530,6 +1917,9 @@ serve_notify (arg)
if (error_pending ()) return;
+ if (outside_dir (arg))
+ return;
+
new = (struct notify_note *) malloc (sizeof (struct notify_note));
if (new == NULL)
{
@@ -1581,6 +1971,9 @@ serve_notify (arg)
{
char *cp;
+ if (strchr (data, '+'))
+ goto error;
+
new->type = data;
if (data[1] != '\t')
goto error;
@@ -1620,7 +2013,7 @@ serve_notify (arg)
}
return;
error:
- pending_error_text = malloc (40);
+ pending_error_text = malloc (80);
if (pending_error_text)
strcpy (pending_error_text,
"E Protocol error; misformed Notify request");
@@ -1681,6 +2074,8 @@ server_notify ()
Lock_Cleanup ();
}
+ last_node = NULL;
+
/* The code used to call fflush (stdout) here, but that is no
longer necessary. The data is now buffered in buf_to_net,
which will be flushed by the caller, do_cvs_command. */
@@ -1926,6 +2321,9 @@ serve_questionable (arg)
return;
}
+ if (outside_dir (arg))
+ return;
+
if (!ign_name (arg))
{
char *update_dir;
@@ -2879,8 +3277,8 @@ server_register (name, version, timestamp, options, tag, date, conflict)
if (trace)
{
(void) fprintf (stderr,
- "%c-> server_register(%s, %s, %s, %s, %s, %s, %s)\n",
- (server_active) ? 'S' : ' ', /* silly */
+ "%s-> server_register(%s, %s, %s, %s, %s, %s, %s)\n",
+ CLIENT_SERVER_STR,
name, version, timestamp ? timestamp : "", options,
tag ? tag : "", date ? date : "",
conflict ? conflict : "");
@@ -3346,6 +3744,12 @@ server_copy_file (file, update_dir, repository, newfile)
char *repository;
char *newfile;
{
+ /* At least for now, our practice is to have the server enforce
+ noexec for the repository and the client enforce it for the
+ working directory. This might want more thought, and/or
+ documentation in cvsclient.texi (other responses do it
+ differently). */
+
if (!supported_response ("Copy-file"))
return;
buf_output0 (protocol, "Copy-file ");
@@ -3364,33 +3768,21 @@ server_modtime (finfo, vers_ts)
Vers_TS *vers_ts;
{
char date[MAXDATELEN];
- int year, month, day, hour, minute, second;
- /* Note that these strings are specified in RFC822 and do not vary
- according to locale. */
- static const char *const month_names[] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ char outdate[MAXDATELEN];
assert (vers_ts->vn_rcs != NULL);
if (!supported_response ("Mod-time"))
return;
- /* The only hard part about this routine is converting the date
- formats. In terms of functionality it all boils down to the
- call to RCS_getrevtime. */
if (RCS_getrevtime (finfo->rcs, vers_ts->vn_rcs, date, 0) == (time_t) -1)
/* FIXME? should we be printing some kind of warning? For one
thing I'm not 100% sure whether this happens in non-error
circumstances. */
return;
-
- sscanf (date, SDATEFORM, &year, &month, &day, &hour, &minute, &second);
- sprintf (date, "%d %s %d %d:%d:%d -0000", day,
- month < 1 || month > 12 ? "???" : month_names[month - 1],
- year, hour, minute, second);
+ date_to_internet (outdate, date);
buf_output0 (protocol, "Mod-time ");
- buf_output0 (protocol, date);
+ buf_output0 (protocol, outdate);
buf_output0 (protocol, "\n");
}
@@ -3438,6 +3830,12 @@ server_updated (finfo, vers, updated, mode, checksum, filebuf)
unsigned long size;
char size_text[80];
+ /* The contents of the file will be in one of filebuf,
+ list/last, or here. */
+ unsigned char *file;
+ size_t file_allocated;
+ size_t file_used;
+
if (filebuf != NULL)
{
size = buf_length (filebuf);
@@ -3546,6 +3944,11 @@ CVS server internal error: no mode in server_updated");
}
list = last = NULL;
+
+ file = NULL;
+ file_allocated = 0;
+ file_used = 0;
+
if (size > 0)
{
/* Throughout this section we use binary mode to read the
@@ -3561,8 +3964,14 @@ CVS server internal error: no mode in server_updated");
*/
&& size > 100)
{
- int status, fd, gzip_status;
- pid_t gzip_pid;
+ /* Basing this routine on read_and_gzip is not a
+ high-performance approach. But it seems easier
+ to code than the alternative (and less
+ vulnerable to subtle bugs). Given that this feature
+ is mainly for compatibility, that is the better
+ tradeoff. */
+
+ int fd;
/* Callers must avoid passing us a buffer if
file_gzip_level is set. We could handle this case,
@@ -3575,22 +3984,13 @@ CVS server internal error: unhandled case in server_updated");
fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0);
if (fd < 0)
error (1, errno, "reading %s", finfo->fullname);
- fd = filter_through_gzip (fd, 1, file_gzip_level, &gzip_pid);
- f = fdopen (fd, "rb");
- status = buf_read_file_to_eof (f, &list, &last);
- size = buf_chain_length (list);
- if (status == -2)
- (*protocol->memory_error) (protocol);
- else if (status != 0)
- error (1, ferror (f) ? errno : 0, "reading %s",
- finfo->fullname);
- if (fclose (f) == EOF)
+ if (read_and_gzip (fd, finfo->fullname, &file,
+ &file_allocated, &file_used,
+ file_gzip_level))
+ error (1, 0, "aborting due to compression error");
+ size = file_used;
+ if (close (fd) < 0)
error (1, errno, "reading %s", finfo->fullname);
- if (waitpid (gzip_pid, &gzip_status, 0) == -1)
- error (1, errno, "waiting for gzip process %ld",
- (long) gzip_pid);
- else if (gzip_status != 0)
- error (1, 0, "gzip exited %d", gzip_status);
/* Prepending length with "z" is flag for using gzip here. */
buf_output0 (protocol, "z");
}
@@ -3615,7 +4015,13 @@ CVS server internal error: unhandled case in server_updated");
sprintf (size_text, "%lu\n", size);
buf_output0 (protocol, size_text);
- if (filebuf == NULL)
+ if (file != NULL)
+ {
+ buf_output (protocol, file, file_used);
+ free (file);
+ file = NULL;
+ }
+ else if (filebuf == NULL)
buf_append_data (protocol, list, last);
else
{
@@ -3638,7 +4044,11 @@ CVS server internal error: unhandled case in server_updated");
/* But if we are joining, we'll need the file when we call
join_file. */
&& !joining ())
- CVS_UNLINK (finfo->file);
+ {
+ if (CVS_UNLINK (finfo->file) < 0)
+ error (0, errno, "cannot remove temp file for %s",
+ finfo->fullname);
+ }
}
else if (scratched_file != NULL && entries_line == NULL)
{
@@ -4133,78 +4543,81 @@ struct request requests[] =
#define REQ_LINE(n, f, s) {n, s}
#endif
- REQ_LINE("Root", serve_root, rq_essential),
- REQ_LINE("Valid-responses", serve_valid_responses, rq_essential),
- REQ_LINE("valid-requests", serve_valid_requests, rq_essential),
- REQ_LINE("Repository", serve_repository, rq_optional),
- REQ_LINE("Directory", serve_directory, rq_essential),
- REQ_LINE("Max-dotdot", serve_max_dotdot, rq_optional),
- REQ_LINE("Static-directory", serve_static_directory, rq_optional),
- REQ_LINE("Sticky", serve_sticky, rq_optional),
- REQ_LINE("Checkin-prog", serve_checkin_prog, rq_optional),
- REQ_LINE("Update-prog", serve_update_prog, rq_optional),
- REQ_LINE("Entry", serve_entry, rq_essential),
- REQ_LINE("Kopt", serve_kopt, rq_optional),
- REQ_LINE("Modified", serve_modified, rq_essential),
- REQ_LINE("Is-modified", serve_is_modified, rq_optional),
+ REQ_LINE("Root", serve_root, RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("Valid-responses", serve_valid_responses,
+ RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("valid-requests", serve_valid_requests,
+ RQ_ESSENTIAL | RQ_ROOTLESS),
+ REQ_LINE("Repository", serve_repository, 0),
+ REQ_LINE("Directory", serve_directory, RQ_ESSENTIAL),
+ REQ_LINE("Max-dotdot", serve_max_dotdot, 0),
+ REQ_LINE("Static-directory", serve_static_directory, 0),
+ REQ_LINE("Sticky", serve_sticky, 0),
+ REQ_LINE("Checkin-prog", serve_checkin_prog, 0),
+ REQ_LINE("Update-prog", serve_update_prog, 0),
+ REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL),
+ REQ_LINE("Kopt", serve_kopt, 0),
+ REQ_LINE("Checkin-time", serve_checkin_time, 0),
+ REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL),
+ REQ_LINE("Is-modified", serve_is_modified, 0),
/* The client must send this request to interoperate with CVS 1.5
through 1.9 servers. The server must support it (although it can
be and is a noop) to interoperate with CVS 1.5 to 1.9 clients. */
- REQ_LINE("UseUnchanged", serve_enable_unchanged, rq_enableme),
-
- REQ_LINE("Unchanged", serve_unchanged, rq_essential),
- REQ_LINE("Notify", serve_notify, rq_optional),
- REQ_LINE("Questionable", serve_questionable, rq_optional),
- REQ_LINE("Case", serve_case, rq_optional),
- REQ_LINE("Argument", serve_argument, rq_essential),
- REQ_LINE("Argumentx", serve_argumentx, rq_essential),
- REQ_LINE("Global_option", serve_global_option, rq_optional),
- REQ_LINE("Gzip-stream", serve_gzip_stream, rq_optional),
+ REQ_LINE("UseUnchanged", serve_enable_unchanged, RQ_ENABLEME | RQ_ROOTLESS),
+
+ REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL),
+ REQ_LINE("Notify", serve_notify, 0),
+ REQ_LINE("Questionable", serve_questionable, 0),
+ REQ_LINE("Case", serve_case, 0),
+ REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL),
+ REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL),
+ REQ_LINE("Global_option", serve_global_option, 0),
+ REQ_LINE("Gzip-stream", serve_gzip_stream, 0),
REQ_LINE("wrapper-sendme-rcsOptions",
serve_wrapper_sendme_rcs_options,
- rq_optional),
- REQ_LINE("Set", serve_set, rq_optional),
+ 0),
+ REQ_LINE("Set", serve_set, RQ_ROOTLESS),
#ifdef ENCRYPTION
# ifdef HAVE_KERBEROS
- REQ_LINE("Kerberos-encrypt", serve_kerberos_encrypt, rq_optional),
+ REQ_LINE("Kerberos-encrypt", serve_kerberos_encrypt, 0),
# endif
# ifdef HAVE_GSSAPI
- REQ_LINE("Gssapi-encrypt", serve_gssapi_encrypt, rq_optional),
+ REQ_LINE("Gssapi-encrypt", serve_gssapi_encrypt, 0),
# endif
#endif
#ifdef HAVE_GSSAPI
- REQ_LINE("Gssapi-authenticate", serve_gssapi_authenticate, rq_optional),
+ REQ_LINE("Gssapi-authenticate", serve_gssapi_authenticate, 0),
#endif
- REQ_LINE("expand-modules", serve_expand_modules, rq_optional),
- REQ_LINE("ci", serve_ci, rq_essential),
- REQ_LINE("co", serve_co, rq_essential),
- REQ_LINE("update", serve_update, rq_essential),
- REQ_LINE("diff", serve_diff, rq_optional),
- REQ_LINE("log", serve_log, rq_optional),
- REQ_LINE("add", serve_add, rq_optional),
- REQ_LINE("remove", serve_remove, rq_optional),
- REQ_LINE("update-patches", serve_ignore, rq_optional),
- REQ_LINE("gzip-file-contents", serve_gzip_contents, rq_optional),
- REQ_LINE("status", serve_status, rq_optional),
- REQ_LINE("rdiff", serve_rdiff, rq_optional),
- REQ_LINE("tag", serve_tag, rq_optional),
- REQ_LINE("rtag", serve_rtag, rq_optional),
- REQ_LINE("import", serve_import, rq_optional),
- REQ_LINE("admin", serve_admin, rq_optional),
- REQ_LINE("export", serve_export, rq_optional),
- REQ_LINE("history", serve_history, rq_optional),
- REQ_LINE("release", serve_release, rq_optional),
- REQ_LINE("watch-on", serve_watch_on, rq_optional),
- REQ_LINE("watch-off", serve_watch_off, rq_optional),
- REQ_LINE("watch-add", serve_watch_add, rq_optional),
- REQ_LINE("watch-remove", serve_watch_remove, rq_optional),
- REQ_LINE("watchers", serve_watchers, rq_optional),
- REQ_LINE("editors", serve_editors, rq_optional),
- REQ_LINE("init", serve_init, rq_optional),
- REQ_LINE("annotate", serve_annotate, rq_optional),
- REQ_LINE("noop", serve_noop, rq_optional),
- REQ_LINE(NULL, NULL, rq_optional)
+ REQ_LINE("expand-modules", serve_expand_modules, 0),
+ REQ_LINE("ci", serve_ci, RQ_ESSENTIAL),
+ REQ_LINE("co", serve_co, RQ_ESSENTIAL),
+ REQ_LINE("update", serve_update, RQ_ESSENTIAL),
+ REQ_LINE("diff", serve_diff, 0),
+ REQ_LINE("log", serve_log, 0),
+ REQ_LINE("add", serve_add, 0),
+ REQ_LINE("remove", serve_remove, 0),
+ REQ_LINE("update-patches", serve_ignore, 0),
+ REQ_LINE("gzip-file-contents", serve_gzip_contents, 0),
+ REQ_LINE("status", serve_status, 0),
+ REQ_LINE("rdiff", serve_rdiff, 0),
+ REQ_LINE("tag", serve_tag, 0),
+ REQ_LINE("rtag", serve_rtag, 0),
+ REQ_LINE("import", serve_import, 0),
+ REQ_LINE("admin", serve_admin, 0),
+ REQ_LINE("export", serve_export, 0),
+ REQ_LINE("history", serve_history, 0),
+ REQ_LINE("release", serve_release, 0),
+ REQ_LINE("watch-on", serve_watch_on, 0),
+ REQ_LINE("watch-off", serve_watch_off, 0),
+ REQ_LINE("watch-add", serve_watch_add, 0),
+ REQ_LINE("watch-remove", serve_watch_remove, 0),
+ REQ_LINE("watchers", serve_watchers, 0),
+ REQ_LINE("editors", serve_editors, 0),
+ REQ_LINE("init", serve_init, RQ_ROOTLESS),
+ REQ_LINE("annotate", serve_annotate, 0),
+ REQ_LINE("noop", serve_noop, 0),
+ REQ_LINE(NULL, NULL, 0)
#undef REQ_LINE
};
@@ -4602,7 +5015,31 @@ error ENOMEM Virtual memory exhausted.\n");
* "co".
*/
continue;
- (*rq->func) (cmd);
+
+ if (!(rq->flags & RQ_ROOTLESS)
+ && CVSroot_directory == NULL)
+ {
+ /* For commands which change the way in which data
+ is sent and received, for example Gzip-stream,
+ this does the wrong thing. Since the client
+ assumes that everything is being compressed,
+ unconditionally, there is no way to give this
+ error to the client without turning on
+ compression. The obvious fix would be to make
+ Gzip-stream RQ_ROOTLESS (with the corresponding
+ change to the spec), and that might be a good
+ idea but then again I can see some settings in
+ CVSROOT about what compression level to allow.
+ I suppose a more baroque answer would be to
+ turn on compression (say, at level 1), just
+ enough to give the "Root request missing"
+ error. For now we just lose. */
+ if (alloc_pending (80))
+ sprintf (pending_error_text,
+ "E Protocol error: Root request missing");
+ }
+ else
+ (*rq->func) (cmd);
break;
}
if (rq->name == NULL)
@@ -4634,48 +5071,74 @@ switch_to_user (username)
pw = getpwnam (username);
if (pw == NULL)
{
+ /* Normally this won't be reached; check_password contains
+ a similar check. */
+
printf ("E Fatal error, aborting.\n\
error 0 %s: no such user\n", username);
- /* I'm doing this manually rather than via error_exit ()
- because I'm not sure whether we want to call server_cleanup.
- Needs more investigation.... */
-
-#ifdef SYSTEM_CLEANUP
- /* Hook for OS-specific behavior, for example socket subsystems on
- NT and OS2 or dealing with windows and arguments on Mac. */
- SYSTEM_CLEANUP ();
-#endif
-
- exit (EXIT_FAILURE);
+ /* Don't worry about server_cleanup; server_active isn't set yet. */
+ error_exit ();
}
- /* FIXME? We don't check for errors from initgroups, setuid, &c.
- I think this mainly would come up if someone is trying to run
- the server as a non-root user. I think we should be checking for
- errors and aborting (as with the error above from getpwnam) if
- there is an error (presumably EPERM). That means that pserver
- should continue to work right if all of the "system usernames"
- in CVSROOT/passwd match the user which the server is being run
- as (in inetd.conf), but fail otherwise. */
-
#if HAVE_INITGROUPS
- initgroups (pw->pw_name, pw->pw_gid);
+ if (initgroups (pw->pw_name, pw->pw_gid) < 0
+# ifdef EPERM
+ /* At least on the system I tried, initgroups() only works as root.
+ But we do still want to report ENOMEM and whatever other
+ errors initgroups() might dish up. */
+ && errno != EPERM
+# endif
+ )
+ {
+ /* This could be a warning, but I'm not sure I see the point
+ in doing that instead of an error given that it would happen
+ on every connection. We could log it somewhere and not tell
+ the user. But at least for now make it an error. */
+ printf ("error 0 initgroups failed: %s\n", strerror (errno));
+ /* Don't worry about server_cleanup; server_active isn't set yet. */
+ error_exit ();
+ }
#endif /* HAVE_INITGROUPS */
#ifdef SETXID_SUPPORT
/* honor the setgid bit iff set*/
if (getgid() != getegid())
{
- setgid (getegid ());
+ if (setgid (getegid ()) < 0)
+ {
+ /* See comments at setuid call below for more discussion. */
+ printf ("error 0 setuid failed: %s\n", strerror (errno));
+ /* Don't worry about server_cleanup;
+ server_active isn't set yet. */
+ error_exit ();
+ }
}
else
-#else
+#endif
{
- setgid (pw->pw_gid);
+ if (setgid (pw->pw_gid) < 0)
+ {
+ /* See comments at setuid call below for more discussion. */
+ printf ("error 0 setuid failed: %s\n", strerror (errno));
+ /* Don't worry about server_cleanup;
+ server_active isn't set yet. */
+ error_exit ();
+ }
}
-#endif
- setuid (pw->pw_uid);
+ if (setuid (pw->pw_uid) < 0)
+ {
+ /* Note that this means that if run as a non-root user,
+ CVSROOT/passwd must contain the user we are running as
+ (e.g. "joe:FsEfVcu:cvs" if run as "cvs" user). This seems
+ cleaner than ignoring the error like CVS 1.10 and older but
+ it does mean that some people might need to update their
+ CVSROOT/passwd file. */
+ printf ("error 0 setuid failed: %s\n", strerror (errno));
+ /* Don't worry about server_cleanup; server_active isn't set yet. */
+ error_exit ();
+ }
+
/* We don't want our umask to change file modes. The modes should
be set by the modes used in the repository, and by the umask of
the client. */
@@ -5080,32 +5543,23 @@ pserver_authenticate_connection ()
host_user = check_password (username, descrambled_password, repository);
memset (descrambled_password, 0, strlen (descrambled_password));
free (descrambled_password);
- if (host_user)
- {
- printf ("I LOVE YOU\n");
- fflush (stdout);
- }
- else
+ if (host_user == NULL)
{
i_hate_you:
printf ("I HATE YOU\n");
fflush (stdout);
- /* I'm doing this manually rather than via error_exit ()
- because I'm not sure whether we want to call server_cleanup.
- Needs more investigation.... */
-
-#ifdef SYSTEM_CLEANUP
- /* Hook for OS-specific behavior, for example socket subsystems on
- NT and OS2 or dealing with windows and arguments on Mac. */
- SYSTEM_CLEANUP ();
-#endif
- exit (EXIT_FAILURE);
+ /* Don't worry about server_cleanup, server_active isn't set
+ yet. */
+ error_exit ();
}
/* Don't go any farther if we're just responding to "cvs login". */
if (verify_and_exit)
{
+ printf ("I LOVE YOU\n");
+ fflush (stdout);
+
#ifdef SYSTEM_CLEANUP
/* Hook for OS-specific behavior, for example socket subsystems on
NT and OS2 or dealing with windows and arguments on Mac. */
@@ -5127,6 +5581,8 @@ pserver_authenticate_connection ()
free (username);
free (password);
+ printf ("I LOVE YOU\n");
+ fflush (stdout);
#endif /* AUTH_SERVER_SUPPORT */
}
diff --git a/contrib/cvs/src/server.h b/contrib/cvs/src/server.h
index f94b7aa..caeff8a 100644
--- a/contrib/cvs/src/server.h
+++ b/contrib/cvs/src/server.h
@@ -7,6 +7,16 @@
#define STDERR_FILENO 2
#endif
+
+/*
+ * Expand to `S', ` ', or the empty string. Used in `%s-> ...' trace printfs.
+ */
+#ifdef SERVER_SUPPORT
+# define CLIENT_SERVER_STR ((server_active) ? "S" : " ")
+#else
+# define CLIENT_SERVER_STR ""
+#endif
+
#ifdef SERVER_SUPPORT
/*
@@ -139,38 +149,30 @@ struct request
void (*func) PROTO((char *args));
#endif
- /* Stuff for use by the client. */
- enum {
- /*
- * Failure to implement this request can imply a fatal
- * error. This should be set only for commands which were in the
- * original version of the protocol; it should not be set for new
- * commands.
- */
- rq_essential,
-
- /* Some servers might lack this request. */
- rq_optional,
-
- /*
- * Set by the client to one of the following based on what this
- * server actually supports.
- */
- rq_supported,
- rq_not_supported,
-
- /*
- * If the server supports this request, and we do too, tell the
- * server by making the request.
- */
- rq_enableme
- } status;
+ /* One or more of the RQ_* flags described below. */
+ int flags;
+
+ /* If set, failure to implement this request can imply a fatal
+ error. This should be set only for commands which were in the
+ original version of the protocol; it should not be set for new
+ commands. */
+#define RQ_ESSENTIAL 1
+
+ /* Set by the client if the server we are talking to supports it. */
+#define RQ_SUPPORTED 2
+
+ /* If set, and client and server both support the request, the
+ client should tell the server by making the request. */
+#define RQ_ENABLEME 4
+
+ /* The server may accept this request before "Root". */
+#define RQ_ROOTLESS 8
};
/* Table of requests ending with an entry with a NULL name. */
extern struct request requests[];
/* Gzip library, see zlib.c. */
-extern void gunzip_and_write PROTO ((int, char *, unsigned char *, size_t));
-extern void read_and_gzip PROTO ((int, char *, unsigned char **, size_t *,
- size_t *, int));
+extern int gunzip_and_write PROTO ((int, char *, unsigned char *, size_t));
+extern int read_and_gzip PROTO ((int, char *, unsigned char **, size_t *,
+ size_t *, int));
diff --git a/contrib/cvs/src/status.c b/contrib/cvs/src/status.c
index 541a969..4e5ddcb 100644
--- a/contrib/cvs/src/status.c
+++ b/contrib/cvs/src/status.c
@@ -67,37 +67,38 @@ cvsstatus (argc, argv)
wrap_setup ();
#ifdef CLIENT_SUPPORT
- if (client_active) {
- start_server ();
+ if (client_active)
+ {
+ start_server ();
- ign_setup ();
+ ign_setup ();
- if (long_format)
- send_arg("-v");
- if (local)
- send_arg("-l");
+ if (long_format)
+ send_arg("-v");
+ if (local)
+ send_arg("-l");
- send_file_names (argc, argv, SEND_EXPAND_WILD);
+ /* For a while, we tried setting SEND_NO_CONTENTS here so this
+ could be a fast operation. That prevents the
+ server from updating our timestamp if the timestamp is
+ changed but the file is unmodified. Worse, it is user-visible
+ (shows "locally modified" instead of "up to date" if
+ timestamp is changed but file is not). And there is no good
+ workaround (you might not want to run "cvs update"; "cvs -n
+ update" doesn't update CVS/Entries; "cvs diff --brief" or
+ something perhaps could be made to work but somehow that
+ seems nonintuitive to me even if so). Given that timestamps
+ seem to have the potential to get munged for any number of
+ reasons, it seems better to not rely too much on them. */
- /* For a while, we tried setting SEND_NO_CONTENTS here so this
- could be a fast operation. That prevents the
- server from updating our timestamp if the timestamp is
- changed but the file is unmodified. Worse, it is user-visible
- (shows "locally modified" instead of "up to date" if
- timestamp is changed but file is not). And there is no good
- workaround (you might not want to run "cvs update"; "cvs -n
- update" doesn't update CVS/Entries; "cvs diff --brief" or
- something perhaps could be made to work but somehow that
- seems nonintuitive to me even if so). Given that timestamps
- seem to have the potential to get munged for any number of
- reasons, it seems better to not rely too much on them. */
+ send_files (argc, argv, local, 0, 0);
- send_files (argc, argv, local, 0, 0);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
- send_to_server ("status\012", 0);
- err = get_responses_and_close ();
+ send_to_server ("status\012", 0);
+ err = get_responses_and_close ();
- return err;
+ return err;
}
#endif
@@ -242,7 +243,7 @@ status_fileproc (callerdat, finfo)
}
else
{
- if (isdigit (edata->tag[0]))
+ if (isdigit ((unsigned char) edata->tag[0]))
{
cvs_output (" Sticky Tag:\t\t", 0);
cvs_output (edata->tag, 0);
@@ -288,20 +289,20 @@ status_fileproc (callerdat, finfo)
}
else if (!really_quiet)
cvs_output (" Sticky Options:\t(none)\n", 0);
+ }
- if (long_format && vers->srcfile)
- {
- List *symbols = RCS_symbols(vers->srcfile);
+ if (long_format && vers->srcfile)
+ {
+ List *symbols = RCS_symbols(vers->srcfile);
- cvs_output ("\n Existing Tags:\n", 0);
- if (symbols)
- {
- xrcsnode = finfo->rcs;
- (void) walklist (symbols, tag_list_proc, NULL);
- }
- else
- cvs_output ("\tNo Tags Exist\n", 0);
+ cvs_output ("\n Existing Tags:\n", 0);
+ if (symbols)
+ {
+ xrcsnode = finfo->rcs;
+ (void) walklist (symbols, tag_list_proc, NULL);
}
+ else
+ cvs_output ("\tNo Tags Exist\n", 0);
}
cvs_output ("\n", 0);
diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c
index 07d516f..6a97f28 100644
--- a/contrib/cvs/src/subr.c
+++ b/contrib/cvs/src/subr.c
@@ -16,7 +16,7 @@ extern char *getlogin ();
/*
* malloc some data and die if it fails
*/
-char *
+void *
xmalloc (bytes)
size_t bytes;
{
@@ -30,8 +30,12 @@ xmalloc (bytes)
cp = malloc (bytes);
if (cp == NULL)
- error (1, 0, "out of memory; can not allocate %lu bytes",
- (unsigned long) bytes);
+ {
+ char buf[80];
+ sprintf (buf, "out of memory; can not allocate %lu bytes",
+ (unsigned long) bytes);
+ error (1, 0, buf);
+ }
return (cp);
}
@@ -53,7 +57,12 @@ xrealloc (ptr, bytes)
cp = realloc (ptr, bytes);
if (cp == NULL)
- error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes);
+ {
+ char buf[80];
+ sprintf (buf, "out of memory; can not reallocate %lu bytes",
+ (unsigned long) bytes);
+ error (1, 0, buf);
+ }
return (cp);
}
@@ -64,7 +73,11 @@ xrealloc (ptr, bytes)
memory which is likely to get as big as MAX_INCR shouldn't be doing
it in one block which must be contiguous, but since getrcskey does
so, we might as well limit the wasted memory to MAX_INCR or so
- bytes. */
+ bytes.
+
+ MIN_INCR and MAX_INCR should both be powers of two and we generally
+ try to keep our allocations to powers of two for the most part.
+ Most malloc implementations these days tend to like that. */
#define MIN_INCR 1024
#define MAX_INCR (2*1024*1024)
@@ -84,11 +97,15 @@ expand_string (strptr, n, newsize)
while (*n < newsize)
{
if (*n < MIN_INCR)
- *n += MIN_INCR;
- else if (*n > MAX_INCR)
+ *n = MIN_INCR;
+ else if (*n >= MAX_INCR)
*n += MAX_INCR;
else
+ {
*n *= 2;
+ if (*n > MAX_INCR)
+ *n = MAX_INCR;
+ }
}
*strptr = xrealloc (*strptr, *n);
}
@@ -487,7 +504,7 @@ check_numeric (rev, argc, argv)
int argc;
char **argv;
{
- if (rev == NULL || !isdigit (*rev))
+ if (rev == NULL || !isdigit ((unsigned char) *rev))
return;
/* Note that the check for whether we are processing more than one
@@ -534,7 +551,7 @@ make_message_rcslegal (message)
}
/* Backtrack to last non-space at end of string, and truncate. */
- while (dp > dst && isspace (dp[-1]))
+ while (dp > dst && isspace ((unsigned char) dp[-1]))
--dp;
*dp = '\0';
@@ -615,15 +632,14 @@ get_file (name, fullname, mode, buf, bufsize, len)
}
else
{
- if (CVS_LSTAT (name, &s) < 0)
- error (1, errno, "can't stat %s", fullname);
+ /* Although it would be cleaner in some ways to just read
+ until end of file, reallocating the buffer, this function
+ does get called on files in the working directory which can
+ be of arbitrary size, so I think we better do all that
+ extra allocation. */
- /* Don't attempt to read special files or symlinks. */
- if (!S_ISREG (s.st_mode))
- {
- *len = 0;
- return;
- }
+ if (CVS_STAT (name, &s) < 0)
+ error (1, errno, "can't stat %s", fullname);
/* Convert from signed to unsigned. */
filesize = s.st_size;
@@ -652,9 +668,7 @@ get_file (name, fullname, mode, buf, bufsize, len)
if (feof (e))
break;
- /* It's probably paranoid to think S.ST_SIZE might be
- too small to hold the entire file contents, but we
- handle it just in case. */
+ /* Allocate more space if needed. */
if (tobuf == *buf + *bufsize)
{
int c;
@@ -684,3 +698,49 @@ get_file (name, fullname, mode, buf, bufsize, len)
(*buf)[nread] = '\0';
}
}
+
+
+/* Follow a chain of symbolic links to its destination. FILENAME
+ should be a handle to a malloc'd block of memory which contains the
+ beginning of the chain. This routine will replace the contents of
+ FILENAME with the destination (a real file). */
+
+void
+resolve_symlink (filename)
+ char **filename;
+{
+ if ((! filename) || (! *filename))
+ return;
+
+ while (islink (*filename))
+ {
+ 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 (*filename);
+#else
+ error (1, 0, "internal error: islink doesn't like readlink");
+#endif
+
+ if (isabsolute (newname))
+ {
+ free (*filename);
+ *filename = newname;
+ }
+ else
+ {
+ char *oldname = last_component (*filename);
+ int dirlen = oldname - *filename;
+ char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
+ strncpy (fullnewname, *filename, dirlen);
+ strcpy (fullnewname + dirlen, newname);
+ free (newname);
+ free (*filename);
+ *filename = fullnewname;
+ }
+ }
+}
diff --git a/contrib/cvs/src/tag.c b/contrib/cvs/src/tag.c
index a5b8794..fb19cba 100644
--- a/contrib/cvs/src/tag.c
+++ b/contrib/cvs/src/tag.c
@@ -59,7 +59,7 @@ static List *tlist;
static const char *const tag_usage[] =
{
- "Usage: %s %s [-lRF] [-b] [-d] [-c] [-r tag|-D date] tag [files...]\n",
+ "Usage: %s %s [-lRF] [-b] [-d] [-c] [-r rev|-D date] tag [files...]\n",
"\t-l\tLocal directory only, not recursive.\n",
"\t-R\tProcess directories recursively.\n",
"\t-d\tDelete the given tag.\n",
@@ -178,15 +178,13 @@ cvstag (argc, argv)
send_arg (symtag);
- send_file_names (argc, argv, SEND_EXPAND_WILD);
-
- /* SEND_NO_CONTENTS has a mildly bizarre interaction with
- check_uptodate; if the timestamp is modified but the file
- is unmodified, the check will fail, only to have "cvs diff"
- show no differences (and one must do "update" or something to
- reset the client's notion of the timestamp). */
+ send_files (argc, argv, local, 0,
- send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ /* I think the -c case is like "cvs status", in
+ which we really better be correct rather than
+ being fast; it is just too confusing otherwise. */
+ check_uptodate ? 0 : SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("tag\012", 0);
return get_responses_and_close ();
}
@@ -297,9 +295,16 @@ check_fileproc (callerdat, finfo)
{
if (delete_flag)
{
+ /* Deleting a tag which did not exist is a noop and
+ should not be logged. */
addit = 0;
}
}
+ else if (delete_flag)
+ {
+ free (p->data);
+ p->data = xstrdup (oversion);
+ }
else if (strcmp(oversion, p->data) == 0)
{
addit = 0;
@@ -367,7 +372,7 @@ pretag_proc(repository, filter)
s = xstrdup(filter);
for (cp=s; *cp; cp++)
{
- if (isspace(*cp))
+ if (isspace ((unsigned char) *cp))
{
*cp = '\0';
break;
@@ -747,12 +752,12 @@ tag_check_valid (name, argc, argv, local, aflag, repository)
int which;
/* Numeric tags require only a syntactic check. */
- if (isdigit (name[0]))
+ if (isdigit ((unsigned char) name[0]))
{
char *p;
for (p = name; *p != '\0'; ++p)
{
- if (!(isdigit (*p) || *p == '.'))
+ if (!(isdigit ((unsigned char) *p) || *p == '.'))
error (1, 0, "\
Numeric tag %s contains characters other than digits and '.'", name);
}
@@ -903,12 +908,19 @@ tag_check_valid_join (join_tag, argc, argv, local, aflag, repository)
s = strchr (c, ':');
if (s != NULL)
{
- if (isdigit (join_tag[0]))
+ if (isdigit ((unsigned char) join_tag[0]))
error (1, 0,
"Numeric join tag %s may not contain a date specifier",
join_tag);
*s = '\0';
+ /* hmmm... I think it makes sense to allow -j:<date>, but
+ * for now this fixes a bug where CVS just spins and spins (I
+ * think in the RCS code) looking for a zero length tag.
+ */
+ if (!*c)
+ error (1, 0,
+ "argument to join may not contain a date specifier without a tag");
}
tag_check_valid (c, argc, argv, local, aflag, repository);
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index d25eeb2..4a24d15 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -1,32 +1,32 @@
/*
* 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.
- *
+ *
* "update" updates the version in the present directory with respect to the RCS
* repository. The present version must have been created by "checkout". The
* user can keep up-to-date by calling "update" whenever he feels like it.
- *
+ *
* The present version can be committed by "commit", but this keeps the version
* in tact.
- *
+ *
* Arguments following the options are taken to be file names to be updated,
* rather than updating the entire directory.
- *
+ *
* Modified or non-existent RCS files are checked out and reported as U
* <user_file>
- *
+ *
* Modified user files are reported as M <user_file>. If both the RCS file and
* the user file have been modified, the user file is replaced by the result
* of rcsmerge, and a backup file is written for the user in .#file.version.
* If this throws up irreconcilable differences, the file is reported as C
* <user_file>, and as M <user_file> otherwise.
- *
+ *
* Files added but not yet committed are reported as A <user_file>. Files
* removed but not yet committed are reported as R <user_file>.
- *
+ *
* If the current directory contains subdirectories that hold concurrent
* versions, these are updated too. If the -d option was specified, new
* directories added to the repository are automatically created and updated
@@ -284,11 +284,11 @@ update (argc, argv)
if (failed_patches == NULL)
{
- send_file_names (argc, argv, SEND_EXPAND_WILD);
/* If noexec, probably could be setting SEND_NO_CONTENTS.
Same caveats as for "cvs status" apply. */
send_files (argc, argv, local, aflag,
update_build_dirs ? SEND_BUILD_DIRS : 0);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
}
else
{
@@ -304,10 +304,13 @@ update (argc, argv)
}
for (i = 0; i < failed_patches_count; i++)
- (void) unlink_file (failed_patches[i]);
- send_file_names (failed_patches_count, failed_patches, 0);
+ if (unlink_file (failed_patches[i]) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s",
+ failed_patches[i]);
send_files (failed_patches_count, failed_patches, local,
aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
+ send_file_names (failed_patches_count, failed_patches, 0);
}
failed_patches = NULL;
@@ -486,9 +489,12 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
{
time_t now;
- (void) time (&now);
- if (now == last_register_time)
+ for (;;)
+ {
+ (void) time (&now);
+ if (now != last_register_time) break;
sleep (1); /* to avoid time-stamp races */
+ }
}
return (err);
@@ -631,15 +637,7 @@ update_fileproc (callerdat, finfo)
write_letter (finfo, 'C');
break;
case T_NEEDS_MERGE: /* needs merging */
- if (noexec)
- {
- retval = 1;
- write_letter (finfo, 'C');
- }
- else
- {
- retval = merge_file (finfo, vers);
- }
+ retval = merge_file (finfo, vers);
break;
case T_MODIFIED: /* locally modified */
retval = 0;
@@ -874,6 +872,28 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
if (!update_build_dirs)
return (R_SKIP_ALL);
+ /* Various CVS administrators are in the habit of removing
+ the repository directory for things they don't want any
+ more. I've even been known to do it myself (on rare
+ occasions). Not the usual recommended practice, but we
+ want to try to come up with some kind of
+ reasonable/documented/sensible behavior. Generally
+ the behavior is to just skip over that directory (see
+ dirs test in sanity.sh; the case which reaches here
+ is when update -d is specified, and the working directory
+ is gone but the subdirectory is still mentioned in
+ CVS/Entries). */
+ if (1
+#ifdef SERVER_SUPPORT
+ /* In the remote case, the client should refrain from
+ sending us the directory in the first place. So we
+ want to continue to give an error, so clients make
+ sure to do this. */
+ && !server_active
+#endif
+ && !isdir (repository))
+ return R_SKIP_ALL;
+
if (noexec)
{
/* ignore the missing dir if -n is specified */
@@ -1285,11 +1305,14 @@ VERS: ", 0);
{
Vers_TS *xvers_ts;
- if (revbuf != NULL)
+ if (revbuf != NULL && !noexec)
{
struct stat sb;
- /* FIXME: We should have RCS_checkout return the mode. */
+ /* FIXME: We should have RCS_checkout return the mode.
+ That would also fix the kludge with noexec, above, which
+ is here only because noexec doesn't write srcfile->path
+ for us to stat. */
if (stat (vers_ts->srcfile->path, &sb) < 0)
error (1, errno, "cannot stat %s",
vers_ts->srcfile->path);
@@ -1489,7 +1512,7 @@ struct patch_file_data
/* Whether to compute the MD5 checksum. */
int compute_checksum;
/* Data structure for computing the MD5 checksum. */
- struct MD5Context context;
+ struct cvs_MD5Context context;
/* Set if the file has a final newline. */
int final_nl;
};
@@ -1568,7 +1591,11 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
if (isfile (finfo->file))
rename_file (finfo->file, backup);
else
- (void) unlink_file (backup);
+ {
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
+ }
file1 = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
@@ -1617,10 +1644,10 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
data.fp = e;
data.final_nl = 0;
data.compute_checksum = 1;
- MD5Init (&data.context);
+ cvs_MD5Init (&data.context);
retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL,
- vers_ts->vn_rcs, (char *) NULL,
+ vers_ts->vn_rcs, vers_ts->vn_tag,
vers_ts->options, RUN_TTY,
patch_file_write, (void *) &data);
@@ -1630,7 +1657,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
if (retcode != 0 || ! data.final_nl)
fail = 1;
else
- MD5Final (checksum, &data.context);
+ cvs_MD5Final (checksum, &data.context);
}
retcode = 0;
@@ -1755,9 +1782,15 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
retval = retcode;
}
- (void) unlink_file (backup);
- (void) unlink_file (file1);
- (void) unlink_file (file2);
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
+ if (unlink_file (file1) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", file1);
+ if (unlink_file (file2) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", file2);
free (backup);
free (file1);
@@ -1783,7 +1816,7 @@ patch_file_write (callerdat, buffer, len)
data->final_nl = (buffer[len - 1] == '\n');
if (data->compute_checksum)
- MD5Update (&data->context, (unsigned char *) buffer, len);
+ cvs_MD5Update (&data->context, (unsigned char *) buffer, len);
}
#endif /* SERVER_SUPPORT */
@@ -1859,7 +1892,8 @@ merge_file (finfo, vers)
+ 10);
(void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
- (void) unlink_file (backup);
+ if (unlink_file (backup) && !existence_error (errno))
+ error (0, errno, "unable to remove %s", backup);
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);
@@ -1962,10 +1996,17 @@ merge_file (finfo, vers)
}
#endif
+ /* FIXME: the noexec case is broken. RCS_merge could be doing the
+ xcmp on the temporary files without much hassle, I think. */
if (!noexec && !xcmp (backup, finfo->file))
{
- printf ("%s already contains the differences between %s and %s\n",
- finfo->fullname, vers->vn_user, vers->vn_rcs);
+ cvs_output (finfo->fullname, 0);
+ cvs_output (" already contains the differences between ", 0);
+ cvs_output (vers->vn_user, 0);
+ cvs_output (" and ", 0);
+ cvs_output (vers->vn_rcs, 0);
+ cvs_output ("\n", 1);
+
history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
finfo->repository);
retval = 0;
@@ -1974,8 +2015,7 @@ merge_file (finfo, vers)
if (status == 1)
{
- if (!noexec)
- error (0, 0, "conflicts found in %s", finfo->fullname);
+ error (0, 0, "conflicts found in %s", finfo->fullname);
write_letter (finfo, 'C');
@@ -2326,7 +2366,9 @@ join_file (finfo, vers)
+ 10);
(void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
- (void) unlink_file (backup);
+ if (unlink_file (backup) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", backup);
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);
diff --git a/contrib/cvs/src/vers_ts.c b/contrib/cvs/src/vers_ts.c
index be0f588..e1ba32d 100644
--- a/contrib/cvs/src/vers_ts.c
+++ b/contrib/cvs/src/vers_ts.c
@@ -34,6 +34,10 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time)
struct stickydirtag *sdtp;
Entnode *entdata;
+#ifdef UTIME_EXPECTS_WRITABLE
+ int change_it_back = 0;
+#endif
+
/* get a new Vers_TS struct */
vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
memset ((char *) vers_ts, 0, sizeof (*vers_ts));
@@ -209,12 +213,28 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time)
{
t.actime = t.modtime;
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (!iswritable (finfo->file))
+ {
+ xchmod (finfo->file, 1);
+ change_it_back = 1;
+ }
+#endif /* UTIME_EXPECTS_WRITABLE */
+
/* This used to need to ignore existence_errors
(for cases like where update.c now clears
set_time if noexec, but didn't used to). I
think maybe now it doesn't (server_modtime does
not like those kinds of cases). */
(void) utime (finfo->file, &t);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+ if (change_it_back == 1)
+ {
+ xchmod (finfo->file, 0);
+ change_it_back = 0;
+ }
+#endif /* UTIME_EXPECTS_WRITABLE */
}
}
}
diff --git a/contrib/cvs/src/version.c b/contrib/cvs/src/version.c
index 479e5e6..97622ff 100644
--- a/contrib/cvs/src/version.c
+++ b/contrib/cvs/src/version.c
@@ -12,8 +12,7 @@
#include "cvs.h"
-/* NOTE: remember to remove `Halibut' when patching this code. */
-char *version_string = "\nConcurrent Versions System (CVS) 1.10 `Halibut'";
+char *version_string = "\nConcurrent Versions System (CVS) 1.10.7";
#ifdef CLIENT_SUPPORT
#ifdef SERVER_SUPPORT
diff --git a/contrib/cvs/src/watch.c b/contrib/cvs/src/watch.c
index d9ba1d7..b2935ac 100644
--- a/contrib/cvs/src/watch.c
+++ b/contrib/cvs/src/watch.c
@@ -337,8 +337,8 @@ watch_addremove (argc, argv)
send_arg ("-a");
send_arg ("none");
}
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server (the_args.adding ?
"watch-add\012" : "watch-remove\012",
0);
@@ -437,29 +437,29 @@ watchers_fileproc (callerdat, finfo)
if (them == NULL)
return 0;
- fputs (finfo->fullname, stdout);
+ cvs_output (finfo->fullname, 0);
p = them;
while (1)
{
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (*p != '>' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
/* Only happens if attribute is misformed. */
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (1)
{
while (*p != '+' && *p != ',' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
goto out;
}
if (*p == ',')
@@ -468,9 +468,9 @@ watchers_fileproc (callerdat, finfo)
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
}
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
}
out:;
return 0;
@@ -515,8 +515,8 @@ watchers (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("watchers\012", 0);
return get_responses_and_close ();
}
diff --git a/contrib/cvs/src/wrapper.c b/contrib/cvs/src/wrapper.c
index e7c540d..2d53c7a 100644
--- a/contrib/cvs/src/wrapper.c
+++ b/contrib/cvs/src/wrapper.c
@@ -118,6 +118,11 @@ void wrap_setup()
/* Then add entries found in home dir, (if user has one) and file
exists. */
homedir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvswrappers. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvswrappers (and many users won't even know what
+ .cvswrappers is). */
if (homedir != NULL)
{
char *file;
@@ -348,9 +353,11 @@ wrap_add (line, isTemp)
memset (&e, 0, sizeof(e));
/* Search for the wild card */
- while(*line && isspace(*line))
+ while (*line && isspace ((unsigned char) *line))
++line;
- for(temp=line;*line && !isspace(*line);++line)
+ for (temp = line;
+ *line && !isspace ((unsigned char) *line);
+ ++line)
;
if(temp==line)
return;
@@ -423,8 +430,6 @@ wrap_add (line, isTemp)
error (1, 0, "Correct above errors first");
break;
case 'm':
- /* FIXME: look into whether this option is still relevant given
- the 24 Jun 96 change to merge_file. */
if(*temp=='C' || *temp=='c')
e.mergeMethod=WRAP_COPY;
else
diff --git a/contrib/cvs/src/zlib.c b/contrib/cvs/src/zlib.c
index ca50130..fa0c2ad 100644
--- a/contrib/cvs/src/zlib.c
+++ b/contrib/cvs/src/zlib.c
@@ -430,18 +430,14 @@ compress_buffer_shutdown_output (closure)
/* Here is our librarified gzip implementation. It is very minimal
but attempts to be RFC1952 compliant. */
-/* Note that currently only the client uses the gzip library. If we
- make the server use it too (which should be straightforward), then
- filter_stream_through_program, filter_through_gzip, and
- filter_through_gunzip can go away. */
/* BUF should contain SIZE bytes of gzipped data (RFC1952/RFC1951).
We are to uncompress the data and write the result to the file
- descriptor FD. If something goes wrong, give an error message
- mentioning FULLNAME as the name of the file for FD (and make it a
- fatal error if we can't recover from it). */
+ descriptor FD. If something goes wrong, give a nonfatal error message
+ mentioning FULLNAME as the name of the file for FD. Return 1 if
+ it is an error we can't recover from. */
-void
+int
gunzip_and_write (fd, fullname, buf, size)
int fd;
char *fullname;
@@ -455,9 +451,15 @@ gunzip_and_write (fd, fullname, buf, size)
unsigned long crc;
if (buf[0] != 31 || buf[1] != 139)
- error (1, 0, "gzipped data does not start with gzip identification");
+ {
+ error (0, 0, "gzipped data does not start with gzip identification");
+ return 1;
+ }
if (buf[2] != 8)
- error (1, 0, "only the deflate compression method is supported");
+ {
+ error (0, 0, "only the deflate compression method is supported");
+ return 1;
+ }
/* Skip over the fixed header, and then skip any of the variable-length
fields. */
@@ -496,9 +498,15 @@ gunzip_and_write (fd, fullname, buf, size)
zstr.next_out = outbuf;
zstatus = inflate (&zstr, Z_NO_FLUSH);
if (zstatus != Z_STREAM_END && zstatus != Z_OK)
- compress_error (1, zstatus, &zstr, fullname);
+ {
+ compress_error (0, zstatus, &zstr, fullname);
+ return 1;
+ }
if (write (fd, outbuf, sizeof (outbuf) - zstr.avail_out) < 0)
- error (1, errno, "writing decompressed file %s", fullname);
+ {
+ error (0, errno, "writing decompressed file %s", fullname);
+ return 1;
+ }
crc = crc32 (crc, outbuf, sizeof (outbuf) - zstr.avail_out);
} while (zstatus != Z_STREAM_END);
zstatus = inflateEnd (&zstr);
@@ -509,23 +517,31 @@ gunzip_and_write (fd, fullname, buf, size)
+ (buf[zstr.total_in + 11] << 8)
+ (buf[zstr.total_in + 12] << 16)
+ (buf[zstr.total_in + 13] << 24)))
- error (1, 0, "CRC error uncompressing %s", fullname);
+ {
+ error (0, 0, "CRC error uncompressing %s", fullname);
+ return 1;
+ }
if (zstr.total_out != (buf[zstr.total_in + 14]
+ (buf[zstr.total_in + 15] << 8)
+ (buf[zstr.total_in + 16] << 16)
+ (buf[zstr.total_in + 17] << 24)))
- error (1, 0, "invalid length uncompressing %s", fullname);
+ {
+ error (0, 0, "invalid length uncompressing %s", fullname);
+ return 1;
+ }
+
+ return 0;
}
/* Read all of FD and put the gzipped data (RFC1952/RFC1951) into *BUF,
replacing previous contents of *BUF. *BUF is malloc'd and *SIZE is
its allocated size. Put the actual number of bytes of data in
- *LEN. If something goes wrong, give an error message mentioning
- FULLNAME as the name of the file for FD (and make it a fatal error
- if we can't recover from it). LEVEL is the compression level (1-9). */
+ *LEN. If something goes wrong, give a nonfatal error mentioning
+ FULLNAME as the name of the file for FD, and return 1 if we can't
+ recover from it). LEVEL is the compression level (1-9). */
-void
+int
read_and_gzip (fd, fullname, buf, size, len, level)
int fd;
char *fullname;
@@ -542,8 +558,16 @@ read_and_gzip (fd, fullname, buf, size, len, level)
if (*size < 1024)
{
+ unsigned char *newbuf;
+
*size = 1024;
- *buf = (unsigned char *) xrealloc (*buf, *size);
+ newbuf = realloc (*buf, *size);
+ if (newbuf == NULL)
+ {
+ error (0, 0, "out of memory");
+ return 1;
+ }
+ *buf = newbuf;
}
(*buf)[0] = 31;
(*buf)[1] = 139;
@@ -559,7 +583,10 @@ read_and_gzip (fd, fullname, buf, size, len, level)
Z_DEFAULT_STRATEGY);
crc = crc32 (0, NULL, 0);
if (zstatus != Z_OK)
- compress_error (1, zstatus, &zstr, fullname);
+ {
+ compress_error (0, zstatus, &zstr, fullname);
+ return 1;
+ }
zstr.avail_out = *size;
zstr.next_out = *buf + 10;
@@ -569,7 +596,10 @@ read_and_gzip (fd, fullname, buf, size, len, level)
nread = read (fd, inbuf, sizeof inbuf);
if (nread < 0)
- error (1, errno, "cannot read %s", fullname);
+ {
+ error (0, errno, "cannot read %s", fullname);
+ return 1;
+ }
else if (nread == 0)
/* End of file. */
finish = 1;
@@ -588,9 +618,17 @@ read_and_gzip (fd, fullname, buf, size, len, level)
if (zstr.avail_out < 4096)
{
+ unsigned char *newbuf;
+
offset = zstr.next_out - *buf;
*size *= 2;
- *buf = xrealloc (*buf, *size);
+ newbuf = realloc (*buf, *size);
+ if (newbuf == NULL)
+ {
+ error (0, 0, "out of memory");
+ return 1;
+ }
+ *buf = newbuf;
zstr.next_out = *buf + offset;
zstr.avail_out = *size - offset;
}
@@ -618,5 +656,7 @@ read_and_gzip (fd, fullname, buf, size, len, level)
zstatus = deflateEnd (&zstr);
if (zstatus != Z_OK)
compress_error (0, zstatus, &zstr, fullname);
+
+ return 0;
}
#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
diff --git a/contrib/cvs/tools/ChangeLog b/contrib/cvs/tools/ChangeLog
index 8cd177e..99c3af7 100644
--- a/contrib/cvs/tools/ChangeLog
+++ b/contrib/cvs/tools/ChangeLog
@@ -1,3 +1,9 @@
+1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * README: Update now that pcl-cvs is no longer here.
+ * pcl-cvs: Remove this subdirectory and all its contents.
+ * Makefile.in: Remove references to pcl-cvs directory.
+
Sat Feb 21 22:02:12 1998 Ian Lance Taylor <ian@cygnus.com>
* Makefile.in (clean): Change "/bin/rm" to "rm".
diff --git a/contrib/cvs/tools/Makefile.in b/contrib/cvs/tools/Makefile.in
index 578b210..752224d 100644
--- a/contrib/cvs/tools/Makefile.in
+++ b/contrib/cvs/tools/Makefile.in
@@ -54,7 +54,7 @@ clean:
.PHONY: clean
distclean: clean
- rm -f Makefile pcl-cvs/Makefile
+ rm -f Makefile
.PHONY: distclean
realclean: distclean
@@ -65,7 +65,6 @@ dist-dir:
for i in ${DISTFILES}; do \
ln $(srcdir)/$${i} ${DISTDIR}; \
done
- cd pcl-cvs; ${MAKE} dist-dir DISTDIR="../${DISTDIR}/pcl-cvs"
.PHONY: dist-dir
subdir = tools
diff --git a/contrib/cvs/tools/README b/contrib/cvs/tools/README
index af7bd7e..e8e73b3 100644
--- a/contrib/cvs/tools/README
+++ b/contrib/cvs/tools/README
@@ -1,5 +1,11 @@
- This subdirectory contains tools that can be used with CVS.
-Note that they will not necessarily be installed when you "make
-install" from the top-level of the CVS source tree.
+This subdirectory formerly contained tools that can be used with CVS.
+In particular, it used to contain a copy of pcl-cvs version 1.x.
+Pcl-cvs is an Emacs interface to CVS.
-pcl-cvs ............................. an Emacs interface to CVS.
+If you are looking for pcl-cvs, we'd suggest pcl-cvs version 2.x, at:
+ ftp://ftp.weird.com/pub/local/
+
+Both of the following CVS sites have a page about pcl-cvs:
+ http://www.loria.fr/~molli/cvs-index.html
+ http://www.cyclic.com/
+They also have much information about CVS tools more generally.
OpenPOWER on IntegriCloud