summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r--contrib/cvs/src/NOTES60
-rw-r--r--contrib/cvs/src/README-rm-add31
-rw-r--r--contrib/cvs/src/commit.c132
-rw-r--r--contrib/cvs/src/cvs.h16
-rw-r--r--contrib/cvs/src/diff.c25
-rw-r--r--contrib/cvs/src/import.c213
-rw-r--r--contrib/cvs/src/lock.c19
-rw-r--r--contrib/cvs/src/logmsg.c67
-rw-r--r--contrib/cvs/src/main.c83
-rw-r--r--contrib/cvs/src/mkmodules.c6
-rw-r--r--contrib/cvs/src/rcs.c2617
-rw-r--r--contrib/cvs/src/rcs.h11
-rw-r--r--contrib/cvs/src/rcscmds.c179
-rw-r--r--contrib/cvs/src/recurse.c11
-rw-r--r--contrib/cvs/src/server.c93
-rw-r--r--contrib/cvs/src/update.c652
16 files changed, 1274 insertions, 2941 deletions
diff --git a/contrib/cvs/src/NOTES b/contrib/cvs/src/NOTES
deleted file mode 100644
index 646ebdf..0000000
--- a/contrib/cvs/src/NOTES
+++ /dev/null
@@ -1,60 +0,0 @@
-wishlist - Tue Nov 2 15:22:58 PST 1993
-
-* bcopy -> memcpy & friends.
- ** done 12/18/93
-
-* remove static buffers.
-* replace list & node cache with recursive obstacks, (xmalloc,
- getnode, getlist)
-* check all io functions for error return codes. also check all
- system calls.
-* error check mkdir.
-
----
-Old notes...
-
-* All sizing limits are gone. The rest of these items were incidental
- in that effort.
-
-* login name from history was duplicated. taught existing routine to
- cache and use that instead. Also add routines to cache uid, pid,
- etc.
-
-* ign strings were never freed. Now they are.
-
-* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now
- fixed.
-
-* The environment variables TMPDIR, HOME, and LOGNAME were not
- honored. Now they are.
-
-* extra line inserted by do_editor() is gone. Then obviated. Editor
- is now called exactly once per checkin.
-
-* revised editor behaviour. Never use /dev/tty. If the editor
- session fails, we haven't yet done anything. Therefor the user can
- safely rerun cvs and we should just fail. Also use the editor for
- initial log messages on added files. Also omit the confirmation
- when adding directories. Adding directories will require an
- explicit "commit" step soon. Make it possible to prevent null login
- messages using #define REQUIRE_LOG_MESSAGES
-
-* prototypes for all callbacks.
-
-* all callbacks get ref pointers.
-
-* do_recursion/start_recursion now use recusion_frame's rather than a
- list of a lot of pointers and global variables.
-
-* corrected types on status_dirproc().
-
-* CONFIRM_DIRECTORY_ADDS
-
-* re_comp was innappropriate in a few places. I've eliminated it.
-
-* FORCE_MESSAGE_ON_ADD
-
-* So I built a regression test. Let's call it a sanity check to be
- less ambitious. It exposed that cvs is difficult to call from
- scripts.
-
diff --git a/contrib/cvs/src/README-rm-add b/contrib/cvs/src/README-rm-add
deleted file mode 100644
index 87fd7c6..0000000
--- a/contrib/cvs/src/README-rm-add
+++ /dev/null
@@ -1,31 +0,0 @@
-WHAT THE "DEATH SUPPORT" FEATURES DO:
-
-(Some of the death support stuff is documented in the main manual, but
-this file is for stuff which noone has gotten around to adding to the
-main manual yet).
-
-CVS with death support can record when a file is active, or alive, and
-when it is removed, or dead. With this facility you can record the
-history of a file, including the fact that at some point in its life
-the file was removed and then later added.
-
-Files can now be added or removed in a branch and later merged
-into the trunk.
-
- cvs update -A
- touch a b c
- cvs add a b c ; cvs ci -m "added" a b c
- cvs tag -b branchtag
- cvs update -r branchtag
- touch d ; cvs add d
- rm a ; cvs rm a
- cvs ci -m "added d, removed a"
- cvs update -A
- cvs update -jbranchtag
-
-Added and removed files may also be merged between branches.
-
-Files removed in the trunk may be merged into branches.
-
-Files added on the trunk are a special case. They cannot be merged
-into a branch. Instead, simply branch the file by hand.
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c
index 4aa2438..71b491f 100644
--- a/contrib/cvs/src/commit.c
+++ b/contrib/cvs/src/commit.c
@@ -19,7 +19,6 @@
#include "getline.h"
#include "edit.h"
#include "fileattr.h"
-#include "hardlink.h"
static Dtype check_direntproc PROTO ((void *callerdat, char *dir,
char *repos, char *update_dir,
@@ -82,6 +81,7 @@ static List *mulist;
static char *message;
static time_t last_register_time;
+
static const char *const commit_usage[] =
{
"Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n",
@@ -505,7 +505,7 @@ commit (argc, argv)
/* Run the user-defined script to verify/check information in
*the log message
*/
- do_verify (message, (char *)NULL);
+ do_verify (&message, (char *)NULL);
/* We always send some sort of message, even if empty. */
/* FIXME: is that true? There seems to be some code in do_editor
@@ -622,23 +622,10 @@ commit (argc, argv)
lock_tree_for_write (argc, argv, local, aflag);
/*
- * Set up the master update list and hard link list
+ * Set up the master update list
*/
mulist = getlist ();
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (preserve_perms)
- {
- hardlist = getlist ();
-
- /*
- * We need to save the working directory so that
- * check_fileproc can construct a full pathname for each file.
- */
- working_dir = xgetwd();
- }
-#endif
-
/*
* Run the recursion processor to verify the files are all up-to-date
*/
@@ -651,17 +638,6 @@ commit (argc, argv)
error (1, 0, "correct above errors first!");
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (preserve_perms)
- {
- /* hardlist now includes a complete index of the files
- to be committed, indexed by inode. For each inode,
- compile a list of the files that are linked to it,
- and save this list in each file's hardlink_info node. */
- (void) walklist (hardlist, cache_hardlinks_proc, NULL);
- }
-#endif
-
/*
* Run the recursion processor to commit the files
*/
@@ -1016,43 +992,6 @@ warning: file `%s' seems to still contain conflict indicators",
ci->options = xstrdup(vers->options);
p->data = (char *) ci;
(void) addnode (cilist, p);
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (preserve_perms)
- {
- /* Add this file to hardlist, indexed on its inode. When
- we are done, we can find out what files are hardlinked
- to a given file by looking up its inode in hardlist. */
- char *fullpath;
- Node *linkp;
- struct hardlink_info *hlinfo;
-
- /* Get the full pathname of the current file. */
- fullpath = xmalloc (strlen(working_dir) +
- strlen(finfo->fullname) + 2);
- sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
-
- /* To permit following links in subdirectories, files
- are keyed on finfo->fullname, not on finfo->name. */
- linkp = lookup_file_by_inode (fullpath);
-
- /* If linkp is NULL, the file doesn't exist... maybe
- we're doing a remove operation? */
- if (linkp != NULL)
- {
- /* Create a new hardlink_info node, which will record
- the current file's status and the links listed in its
- `hardlinks' delta field. We will append this
- hardlink_info node to the appropriate hardlist entry. */
- hlinfo = (struct hardlink_info *)
- xmalloc (sizeof (struct hardlink_info));
- hlinfo->status = status;
- hlinfo->links = NULL;
- linkp->data = (char *) hlinfo;
- }
- }
-#endif
-
break;
case T_UNKNOWN:
error (0, 0, "nothing known about `%s'", finfo->fullname);
@@ -1239,7 +1178,7 @@ commit_fileproc (callerdat, finfo)
got_message = 1;
if (use_editor)
do_editor (finfo->update_dir, &message, finfo->repository, ulist);
- do_verify (message, finfo->repository);
+ do_verify (&message, finfo->repository);
}
p = findnode (cilist, finfo->file);
@@ -1341,9 +1280,8 @@ commit_fileproc (callerdat, finfo)
/* Doesn't matter, it won't get checked. */
SERVER_UPDATED,
- (mode_t) -1,
- (unsigned char *) NULL,
- (struct buffer *) NULL);
+ (struct stat *) NULL,
+ (unsigned char *) NULL);
}
#endif
}
@@ -1530,7 +1468,7 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries)
got_message = 1;
if (use_editor)
do_editor (update_dir, &message, real_repos, ulist);
- do_verify (message, real_repos);
+ do_verify (&message, real_repos);
free (real_repos);
return (R_PROCESS);
}
@@ -1707,8 +1645,9 @@ remove_file (finfo, tag, message)
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
{
- error (0, 0,
- "failed to check out `%s'", finfo->fullname);
+ if (!quiet)
+ error (0, retcode == -1 ? errno : 0,
+ "failed to check out `%s'", finfo->fullname);
return (1);
}
@@ -2042,21 +1981,13 @@ internal error: `%s' didn't move out of the attic",
if (tag && newfile)
{
char *tmp;
- FILE *fp;
/* move the new file out of the way. */
fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ sizeof (CVSPREFIX) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
rename_file (file, fname);
-
- /* Create empty FILE. Can't use copy_file with a DEVNULL
- argument -- copy_file now ignores device files. */
- fp = fopen (file, "w");
- if (fp == NULL)
- error (1, errno, "cannot open %s for writing", file);
- if (fclose (fp) < 0)
- error (0, errno, "cannot close %s", file);
+ copy_file (DEVNULL, file);
tmp = xmalloc (strlen (file) + strlen (tag) + 80);
/* commit a dead revision. */
@@ -2128,6 +2059,8 @@ internal error: `%s' didn't move out of the attic",
char *head;
char *magicrev;
+ fixbranch(rcsfile, sbranch);
+
head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
magicrev = RCS_magicrev (rcsfile, head);
@@ -2225,31 +2158,18 @@ lock_RCS (user, rcs, rev, repository)
{
(void) RCS_lock(rcs, rev, 1);
}
-
- /* We used to call RCS_rewrite here, and that might seem
- appropriate in order to write out the locked revision
- information. However, such a call would actually serve no
- purpose. CVS locks will prevent any interference from other
- CVS processes. The comment above rcs_internal_lockfile
- explains that it is already unsafe to use RCS and CVS
- simultaneously. It follows that writing out the locked
- revision information here would add no additional security.
-
- If we ever do care about it, the proper fix is to create the
- RCS lock file before calling this function, and maintain it
- until the checkin is complete.
-
- The call to RCS_lock is still required at present, since in
- some cases RCS_checkin will determine which revision to check
- in by looking for a lock. FIXME: This is rather roundabout,
- and a more straightforward approach would probably be easier to
- understand. */
+ RCS_rewrite (rcs, NULL, NULL);
if (err == 0)
{
if (sbranch != NULL)
free (sbranch);
- sbranch = branch;
+ if (branch)
+ {
+ sbranch = branch;
+ }
+ else
+ sbranch = NULL;
return (0);
}
@@ -2264,8 +2184,7 @@ lock_RCS (user, rcs, rev, repository)
/* 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. */
+ the fact. */
static void
fix_rcs_modes (rcs, user)
@@ -2275,12 +2194,6 @@ fix_rcs_modes (rcs, 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. */
@@ -2290,9 +2203,6 @@ fix_rcs_modes (rcs, user)
/* 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
diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h
index 3a7e9e4..7e68639 100644
--- a/contrib/cvs/src/cvs.h
+++ b/contrib/cvs/src/cvs.h
@@ -187,6 +187,7 @@ extern int errno;
#define CVSROOTADM_WRITERS "writers"
#define CVSROOTADM_PASSWD "passwd"
#define CVSROOTADM_CONFIG "config"
+#define CVSROOTADM_OPTIONS "options"
#define CVSNULLREPOS "Emptydir" /* an empty directory */
@@ -256,6 +257,8 @@ extern int errno;
#define CVSREAD_ENV "CVSREAD" /* make files read-only */
#define CVSREAD_DFLT 0 /* writable files by default */
+#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */
+
#define TMPDIR_ENV "TMPDIR" /* Temporary directory */
/* #define TMPDIR_DFLT Set by options.h */
@@ -363,6 +366,7 @@ extern int really_quiet, quiet;
extern int use_editor;
extern int cvswrite;
extern mode_t cvsumask;
+extern char *RCS_citag;
/* Access method specified in CVSroot. */
typedef enum {
@@ -383,6 +387,7 @@ extern char *emptydir_name PROTO ((void));
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
+extern int readonlyfs; /* fail on all write locks; succeed all read locks */
extern int logoff; /* Don't write history entry */
#ifdef AUTH_SERVER_SUPPORT
@@ -402,7 +407,6 @@ int RCS_merge PROTO((RCSNode *, char *, char *, char *, char *, char *));
#define RCS_FLAGS_DEAD 2
#define RCS_FLAGS_QUIET 4
#define RCS_FLAGS_MODTIME 8
-#define RCS_FLAGS_KEEPFILE 16
extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile,
char *opts, char *options,
@@ -423,7 +427,7 @@ DBM *open_module PROTO((void));
FILE *open_file PROTO((const char *, const char *));
List *Find_Directories PROTO((char *repository, int which, List *entries));
void Entries_Close PROTO((List *entries));
-List *Entries_Open PROTO ((int aflag, char *update_dir));
+List *Entries_Open PROTO((int aflag));
void Subdirs_Known PROTO((List *entries));
void Subdir_Register PROTO((List *, const char *, const char *));
void Subdir_Deregister PROTO((List *, const char *, const char *));
@@ -462,15 +466,14 @@ int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup));
int isdir PROTO((const char *file));
int isfile PROTO((const char *file));
int islink PROTO((const char *file));
-int isdevice PROTO ((const char *));
int isreadable PROTO((const char *file));
int iswritable PROTO((const char *file));
int isaccessible PROTO((const char *file, const int mode));
int isabsolute PROTO((const char *filename));
-char *xreadlink PROTO((const char *link));
char *last_component PROTO((char *path));
char *get_homedir PROTO ((void));
char *cvs_temp_name PROTO ((void));
+void parseopts PROTO ((const char *root));
int numdots PROTO((const char *s));
char *increment_revnum PROTO ((const char *));
@@ -558,7 +561,7 @@ void Update_Logfile PROTO((char *repository, char *xmessage, FILE * xlogfp,
void do_editor PROTO((char *dir, char **messagep,
char *repository, List * changes));
-void do_verify PROTO((char *message, char *repository));
+void do_verify PROTO((char **messagep, char *repository));
typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where,
char *mwhere, char *mfile, int shorten, int local_specified,
@@ -730,9 +733,6 @@ void freevers_ts PROTO ((Vers_TS ** versp));
int Checkin PROTO ((int type, struct file_info *finfo, char *rcs, char *rev,
char *tag, char *options, char *message));
int No_Difference PROTO ((struct file_info *finfo, Vers_TS *vers));
-/* TODO: can the finfo argument to special_file_mismatch be changed? -twp */
-int special_file_mismatch PROTO ((struct file_info *finfo,
- char *rev1, char *rev2));
/* CVSADM_BASEREV stuff, from entries.c. */
extern char *base_get PROTO ((struct file_info *));
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c
index 7a4c105..4690ed8 100644
--- a/contrib/cvs/src/diff.c
+++ b/contrib/cvs/src/diff.c
@@ -434,14 +434,16 @@ diff_fileproc (callerdat, finfo)
exists = 0;
/* special handling for TAG_HEAD */
if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
- exists = vers->vn_rcs != NULL;
+ exists = (vers->vn_rcs != NULL && /* XXX ? */
+ !RCS_isdead (vers->srcfile, vers->vn_rcs)); /*XXX*/
else
{
Vers_TS *xvers;
xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1,
1, 0);
- exists = xvers->vn_rcs != NULL;
+ exists = (vers->vn_rcs != NULL &&
+ !RCS_isdead (vers->srcfile, vers->vn_rcs)); /*XXX*/
freevers_ts (&xvers);
}
if (exists)
@@ -636,11 +638,13 @@ RCS file: ", 0);
: vers->options),
tmp, (RCSCHECKOUTPROC) NULL,
(void *) NULL);
- if (retcode != 0)
+ if (retcode == -1)
{
- diff_mark_errors (err);
- return err;
+ (void) CVS_UNLINK (tmp);
+ error (1, errno, "fork failed during checkout of %s",
+ vers->srcfile->path);
}
+ /* FIXME: what if retcode > 0? */
status = diff_exec (DEVNULL, tmp, opts, RUN_TTY);
}
@@ -655,11 +659,13 @@ RCS file: ", 0);
*options ? options : vers->options,
tmp, (RCSCHECKOUTPROC) NULL,
(void *) NULL);
- if (retcode != 0)
+ if (retcode == -1)
{
- diff_mark_errors (err);
- return err;
+ (void) CVS_UNLINK (tmp);
+ error (1, errno, "fork failed during checkout of %s",
+ vers->srcfile->path);
}
+ /* FIXME: what if retcode > 0? */
status = diff_exec (tmp, DEVNULL, opts, RUN_TTY);
}
@@ -715,8 +721,7 @@ RCS file: ", 0);
if (empty_file == DIFF_REMOVED
|| (empty_file == DIFF_ADDED && use_rev2 != NULL))
{
- if (CVS_UNLINK (tmp) < 0)
- error (0, errno, "cannot remove %s", tmp);
+ (void) CVS_UNLINK (tmp);
free (tmp);
}
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index d79a10e..11fc99d 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -194,7 +194,7 @@ import (argc, argv)
do_editor ((char *) NULL, &message, repository,
(List *) NULL);
}
- do_verify (message, repository);
+ do_verify (&message, repository);
msglen = message == NULL ? 0 : strlen (message);
if (msglen == 0 || message[msglen - 1] != '\n')
{
@@ -260,11 +260,7 @@ import (argc, argv)
tmpfile = cvs_temp_name ();
if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL)
error (1, errno, "cannot create temporary file `%s'", tmpfile);
- /* On systems where we can unlink an open file, do so, so it will go
- away no matter how we exit. FIXME-maybe: Should be checking for
- errors but I'm not sure which error(s) we get if we are on a system
- where one can't unlink open files. */
- (void) CVS_UNLINK (tmpfile);
+ (void) CVS_UNLINK (tmpfile); /* to be sure it goes away */
(void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
(void) fprintf (logfp, "Release Tags:\t");
for (i = 2; i < argc; i++)
@@ -324,13 +320,11 @@ import (argc, argv)
(void) addnode (ulist, p);
Update_Logfile (repository, message, logfp, ulist);
dellist (&ulist);
- if (fclose (logfp) < 0)
- error (0, errno, "error closing %s", tmpfile);
+ (void) fclose (logfp);
/* Make sure the temporary file goes away, even on systems that don't let
you delete a file that's in use. */
- if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
- error (0, errno, "cannot remove %s", tmpfile);
+ CVS_UNLINK (tmpfile);
free (tmpfile);
if (message)
@@ -497,7 +491,7 @@ process_import_file (message, vfile, vtag, targc, targv)
/* Reading all the entries for each file is fairly silly, and
probably slow. But I am too lazy at the moment to do
anything else. */
- entries = Entries_Open (0, NULL);
+ entries = Entries_Open (0);
node = findnode_fn (entries, vfile);
if (node != NULL)
{
@@ -983,7 +977,6 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
char *userfile;
char *local_opt = key_opt;
char *free_opt = NULL;
- mode_t file_type;
if (noexec)
return (0);
@@ -1011,39 +1004,18 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
which does not depend on what the client or server OS is, as
documented in cvsclient.texi), but as long as the server just
runs on unix it is a moot point. */
-
- /* If PreservePermissions is set, then make sure that the file
- is a plain file before trying to open it. Longstanding (although
- often unpopular) CVS behavior has been to follow symlinks, so we
- maintain that behavior if PreservePermissions is not on.
-
- NOTE: this error message used to be `cannot fstat', but is now
- `cannot lstat'. I don't see a way around this, since we must
- stat the file before opening it. -twp */
-
- if (CVS_LSTAT (userfile, &sb) < 0)
- error (1, errno, "cannot lstat %s", user);
- file_type = sb.st_mode & S_IFMT;
-
- fpuser = NULL;
- if (!preserve_perms || file_type == S_IFREG)
+ fpuser = CVS_FOPEN (userfile,
+ ((local_opt != NULL && strcmp (local_opt, "b") == 0)
+ ? "rb"
+ : "r")
+ );
+ if (fpuser == NULL)
{
- fpuser = CVS_FOPEN (userfile,
- ((local_opt != NULL && strcmp (local_opt, "b") == 0)
- ? "rb"
- : "r")
- );
- if (fpuser == NULL)
- {
- /* not fatal, continue import */
- if (add_logfp != NULL)
- fperror (add_logfp, 0, errno,
- "ERROR: cannot read file %s", userfile);
- error (0, errno, "ERROR: cannot read file %s", userfile);
- goto read_error;
- }
+ /* not fatal, continue import */
+ fperror (add_logfp, 0, errno, "ERROR: cannot read file %s", userfile);
+ error (0, errno, "ERROR: cannot read file %s", userfile);
+ goto read_error;
}
-
fprcs = CVS_FOPEN (rcs, "w+b");
if (fprcs == NULL)
{
@@ -1110,6 +1082,10 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (fprintf (fprcs, "\012") < 0)
goto write_error;
+ /* Get information on modtime and mode. */
+ if (fstat (fileno (fpuser), &sb) < 0)
+ error (1, errno, "cannot fstat %s", user);
+
/* Write the revision(s), with the date and author and so on
(that is "delta" rather than "deltatext" from rcsfile(5)). */
if (add_vhead != NULL)
@@ -1142,102 +1118,13 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (fprintf (fprcs, "next ;\012") < 0)
goto write_error;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Store initial permissions if necessary. */
- if (preserve_perms)
- {
- if (file_type == S_IFLNK)
- {
- char *link = xreadlink (userfile);
- if (fprintf (fprcs, "symlink\t@") < 0 ||
- expand_at_signs (link, strlen (link), fprcs) < 0 ||
- fprintf (fprcs, "@;\012") < 0)
- goto write_error;
- free (link);
- }
- else
- {
- if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
- goto write_error;
- if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
- goto write_error;
- if (fprintf (fprcs, "permissions\t%o;\012",
- sb.st_mode & 07777) < 0)
- goto write_error;
- switch (file_type)
- {
- case S_IFREG: break;
- case S_IFCHR:
- case S_IFBLK:
- if (fprintf (fprcs, "special\t%s %lu;\012",
- (file_type == S_IFCHR
- ? "character"
- : "block"),
- (unsigned long) sb.st_rdev) < 0)
- goto write_error;
- break;
- default:
- error (0, 0,
- "can't import %s: unknown kind of special file",
- userfile);
- }
- }
- }
-#endif
-
if (add_vbranch != NULL)
{
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
fprintf (fprcs, "date %s; author %s; state Exp;\012",
altdate1, author) < 0 ||
fprintf (fprcs, "branches ;\012") < 0 ||
- fprintf (fprcs, "next ;\012") < 0)
- goto write_error;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Store initial permissions if necessary. */
- if (preserve_perms)
- {
- if (file_type == S_IFLNK)
- {
- char *link = xreadlink (userfile);
- if (fprintf (fprcs, "symlink\t@") < 0 ||
- expand_at_signs (link, strlen (link), fprcs) < 0 ||
- fprintf (fprcs, "@;\012") < 0)
- goto write_error;
- free (link);
- }
- else
- {
- if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
- fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
- fprintf (fprcs, "permissions\t%o;\012",
- sb.st_mode & 07777) < 0)
- goto write_error;
-
- switch (file_type)
- {
- case S_IFREG: break;
- case S_IFCHR:
- case S_IFBLK:
- if (fprintf (fprcs, "special\t%s %lu;\012",
- (file_type == S_IFCHR
- ? "character"
- : "block"),
- (unsigned long) sb.st_rdev) < 0)
- goto write_error;
- break;
- default:
- error (0, 0,
- "cannot import %s: special file of unknown type",
- userfile);
- }
- }
- }
-#endif
-
- if (fprintf (fprcs, "\012") < 0)
+ fprintf (fprcs, "next ;\012\012") < 0)
goto write_error;
}
}
@@ -1283,9 +1170,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
goto write_error;
}
- /* Now copy over the contents of the file, expanding at signs.
- If preserve_perms is set, do this only for regular files. */
- if (!preserve_perms || file_type == S_IFREG)
+ /* Now copy over the contents of the file, expanding at signs. */
{
char buf[8192];
unsigned int len;
@@ -1323,12 +1208,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
ierrno = errno;
goto write_error_noclose;
}
- /* Close fpuser only if we opened it to begin with. */
- if (fpuser != NULL)
- {
- if (fclose (fpuser) < 0)
- error (0, errno, "cannot close %s", user);
- }
+ (void) fclose (fpuser);
/*
* Fix the modes on the RCS files. The user modes of the original
@@ -1344,9 +1224,8 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (chmod (rcs, mode) < 0)
{
ierrno = errno;
- if (add_logfp != NULL)
- fperror (add_logfp, 0, ierrno,
- "WARNING: cannot change mode of file %s", rcs);
+ fperror (add_logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
err++;
}
@@ -1359,20 +1238,15 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
write_error:
ierrno = errno;
- if (fclose (fprcs) < 0)
- error (0, errno, "cannot close %s", rcs);
+ (void) fclose (fprcs);
write_error_noclose:
- if (fclose (fpuser) < 0)
- error (0, errno, "cannot close %s", user);
- if (add_logfp != NULL)
- fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
+ (void) fclose (fpuser);
+ fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
error (0, ierrno, "ERROR: cannot write file %s", rcs);
if (ierrno == ENOSPC)
{
- if (CVS_UNLINK (rcs) < 0)
- error (0, errno, "cannot remove %s", rcs);
- if (add_logfp != NULL)
- fperror (add_logfp, 0, 0, "ERROR: out of space - aborting");
+ (void) CVS_UNLINK (rcs);
+ fperror (add_logfp, 0, 0, "ERROR: out of space - aborting");
error (1, 0, "ERROR: out of space - aborting");
}
read_error:
@@ -1397,27 +1271,20 @@ expand_at_signs (buf, size, fp)
off_t size;
FILE *fp;
{
- register char *cp, *next;
+ char *cp, *end;
- cp = buf;
- while ((next = memchr (cp, '@', size)) != NULL)
+ errno = 0;
+ for (cp = buf, end = buf + size; cp < end; cp++)
{
- int len;
-
- ++next;
- len = next - cp;
- if (fwrite (cp, 1, len, fp) != len)
- return EOF;
- if (putc ('@', fp) == EOF)
- return EOF;
- cp = next;
- size -= len;
+ if (*cp == '@')
+ {
+ if (putc ('@', fp) == EOF && errno != 0)
+ return EOF;
+ }
+ if (putc (*cp, fp) == EOF && errno != 0)
+ return (EOF);
}
-
- if (fwrite (cp, 1, size, fp) != size)
- return EOF;
-
- return 1;
+ return (1);
}
/*
diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c
index 72818f3..0d5cef6 100644
--- a/contrib/cvs/src/lock.c
+++ b/contrib/cvs/src/lock.c
@@ -243,7 +243,7 @@ Reader_Lock (xrepository)
FILE *fp;
char *tmp;
- if (noexec)
+ if (noexec || readonlyfs)
return (0);
/* we only do one directory at a time for read locks! */
@@ -319,6 +319,11 @@ Writer_Lock (list)
if (noexec)
return (0);
+ if (readonlyfs) {
+ error (0, 0, "write lock failed - read-only repository");
+ return (1);
+ }
+
/* We only know how to do one list at a time */
if (locklist != (List *) NULL)
{
@@ -704,6 +709,7 @@ lock_obtained (repos)
static int lock_filesdoneproc PROTO ((void *callerdat, int err,
char *repository, char *update_dir,
List *entries));
+static int fsortcmp PROTO((const Node * p, const Node * q));
/*
* Create a list of repositories to lock
@@ -732,6 +738,17 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
return (err);
}
+/*
+ * compare two lock list nodes (for sort)
+ */
+static int
+fsortcmp (p, q)
+ const Node *p;
+ const Node *q;
+{
+ return (strcmp (p->key, q->key));
+}
+
void
lock_tree_for_write (argc, argv, local, aflag)
int argc;
diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c
index 67194be..e471341 100644
--- a/contrib/cvs/src/logmsg.c
+++ b/contrib/cvs/src/logmsg.c
@@ -385,14 +385,20 @@ do_editor (dir, messagep, repository, changes)
independant of the running of an editor for getting a message.
*/
void
-do_verify (message, repository)
- char *message;
+do_verify (messagep, repository)
+ char **messagep;
char *repository;
{
FILE *fp;
char *fname;
int retcode = 0;
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+ char *p;
+ struct stat stbuf;
+
#ifdef CLIENT_SUPPORT
if (client_active)
/* The verification will happen on the server. */
@@ -406,7 +412,7 @@ do_verify (message, repository)
/* If there's no message, then we have nothing to verify. Can this
case happen? And if so why would we print a message? */
- if (message == NULL)
+ if (*messagep == NULL)
{
cvs_output ("No message to verify\n", 0);
return;
@@ -422,9 +428,9 @@ do_verify (message, repository)
error (1, errno, "cannot create temporary file %s", fname);
else
{
- fprintf (fp, "%s", message);
- if ((message)[0] == '\0' ||
- (message)[strlen (message) - 1] != '\n')
+ fprintf (fp, "%s", *messagep);
+ if ((*messagep)[0] == '\0' ||
+ (*messagep)[strlen (*messagep) - 1] != '\n')
(void) fprintf (fp, "%s", "\n");
if (fclose (fp) == EOF)
error (1, errno, "%s", fname);
@@ -450,13 +456,62 @@ do_verify (message, repository)
error (1, retcode == -1 ? errno : 0,
"Message verification failed");
+ }
+
+ /* put the entire message back into the *messagep variable */
+
+ fp = open_file (fname, "r");
+ if (fp == NULL)
+ {
+ error (1, errno, "cannot open temporary file %s", fname);
+ return;
+ }
+
+ if (*messagep)
+ free (*messagep);
+
+ if ( CVS_STAT (fname, &stbuf) != 0)
+ error (1, errno, "cannot find size of temp file %s", fname);
+
+ if (stbuf.st_size == 0)
+ *messagep = NULL;
+ else
+ {
+ /* On NT, we might read less than st_size bytes, but we won't
+ read more. So this works. */
+ *messagep = (char *) xmalloc (stbuf.st_size + 1);
+ *messagep[0] = '\0';
+ }
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if (*messagep)
+ {
+ p = *messagep;
+ while (1)
+ {
+ line_length = getline (&line, &line_chars_allocated, fp);
+ if (line_length == -1)
+ {
+ if (ferror (fp))
+ error (0, errno, "warning: cannot read %s", fname);
+ break;
+ }
+ if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
+ continue;
+ (void) strcpy (p, line);
+ p += line_length;
}
}
+ if (fclose (fp) < 0)
+ error (0, errno, "warning: cannot close %s", fname);
/* Delete the temp file */
unlink_file (fname);
free (fname);
+ }
}
}
diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c
index 9465be6..89a10cd 100644
--- a/contrib/cvs/src/main.c
+++ b/contrib/cvs/src/main.c
@@ -40,6 +40,7 @@ int really_quiet = 0;
int quiet = 0;
int trace = 0;
int noexec = 0;
+int readonlyfs = 0;
int logoff = 0;
mode_t cvsumask = UMASK_DFLT;
@@ -212,6 +213,7 @@ static const char *const opt_usage[] =
" -l Turn history logging off.\n",
" -n Do not execute anything that will change the disk.\n",
" -t Show trace of program execution -- try with -n.\n",
+ " -R Assume repository is read-only, such as CDROM\n",
" -v CVS version and copyright.\n",
" -b bindir Find RCS programs in 'bindir'.\n",
" -T tmpdir Use 'tmpdir' for temporary files.\n",
@@ -444,6 +446,10 @@ main (argc, argv)
}
if (getenv (CVSREAD_ENV) != NULL)
cvswrite = 0;
+ if (getenv (CVSREADONLYFS_ENV) != NULL) {
+ readonlyfs = 1;
+ logoff = 1;
+ }
/* Set this to 0 to force getopt initialization. getopt() sets
this to 1 internally. */
@@ -473,7 +479,7 @@ main (argc, argv)
opterr = 1;
while ((c = getopt_long
- (argc, argv, "+Qqrwtnlvb:T:e:d:Hfz:s:xa", long_options, &option_index))
+ (argc, argv, "+QqrwtnRlvb:T:e:d:Hfz:s:xa", long_options, &option_index))
!= EOF)
{
switch (c)
@@ -509,6 +515,10 @@ main (argc, argv)
case 't':
trace = 1;
break;
+ case 'R':
+ readonlyfs = 1;
+ logoff = 1;
+ break;
case 'n':
noexec = 1;
case 'l': /* Fall through */
@@ -522,7 +532,7 @@ main (argc, argv)
(void) fputs (config_string, stdout);
(void) fputs ("\n", stdout);
(void) fputs ("\
-Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
+Copyright (c) 1989-1997 Brian Berliner, david d `zoo' zuhn, \n\
Jeff Polk, and other authors\n", stdout);
(void) fputs ("\n", stdout);
(void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout);
@@ -811,7 +821,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
- if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
{
save_errno = errno;
error (0, 0, "Sorry, you don't have read/write access to the history file");
@@ -863,6 +873,12 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
(void) putenv (env);
/* do not free env, as putenv has control of it */
}
+ {
+ char *env;
+ env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */
+ (void) sprintf (env, "CVS_PID=%ld", (long) getpid ());
+ (void) putenv (env);
+ }
#endif
#ifndef DONT_USE_SIGNALS
@@ -923,6 +939,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\
if we didn't, then there would be no way to check in a new
CVSROOT/config file to fix the broken one! */
parse_config (CVSroot_directory);
+
+ /* Now is a convenient time to read CVSROOT/options */
+ parseopts(CVSroot_directory);
}
} /* end of stuff that gets done if the user DOESN'T ask for help */
@@ -1000,3 +1019,61 @@ usage (cpp)
(void) fprintf (stderr, *cpp);
error_exit ();
}
+
+void
+parseopts(root)
+ const char *root;
+{
+ char path[PATH_MAX];
+ int save_errno;
+ char buf[1024];
+ const char *p;
+ char *q;
+ FILE *fp;
+
+ if (root == NULL) {
+ printf("no CVSROOT in parseopts\n");
+ return;
+ }
+ p = strchr (root, ':');
+ if (p)
+ p++;
+ else
+ p = root;
+ if (p == NULL) {
+ printf("mangled CVSROOT in parseopts\n");
+ return;
+ }
+ (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS);
+ if ((fp = fopen(path, "r")) != NULL) {
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ if (buf[0] == '#')
+ continue;
+ q = strrchr(buf, '\n');
+ if (q)
+ *q = '\0';
+
+ if (!strncmp(buf, "tag=", 4)) {
+ char *what;
+ char *rcs_localid;
+
+ rcs_localid = buf + 4;
+ RCS_setlocalid(rcs_localid);
+ }
+ if (!strncmp(buf, "tagexpand=", 10)) {
+ char *what;
+ char *rcs_incexc;
+
+ rcs_incexc = buf + 10;
+ RCS_setincexc(rcs_incexc);
+ }
+ /*
+ * OpenBSD has a "umask=" and "dlimit=" command, we silently
+ * ignore them here since they are not much use to us. cvsumask
+ * defaults to 002 already, and the dlimit (data size limit)
+ * should really be handled elsewhere (eg: login.conf).
+ */
+ }
+ fclose(fp);
+ }
+}
diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c
index c3c530d..dab5b3f 100644
--- a/contrib/cvs/src/mkmodules.c
+++ b/contrib/cvs/src/mkmodules.c
@@ -279,10 +279,6 @@ static const char *const modules_contents[] = {
static const char *const config_contents[] = {
"# Set this to \"no\" if pserver shouldn't check system users/passwords\n",
"#SystemAuth=no\n",
- "\n",
- "# Set `PreservePermissions' to `yes' to save file status information\n",
- "# in the repository.\n",
- "#PreservePermissions=no\n",
NULL
};
@@ -542,7 +538,7 @@ checkout_file (file, temp)
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
{
- error (0, 0, "failed to check out %s file",
+ error (0, retcode == -1 ? errno : 0, "failed to check out %s file",
file);
}
freercsnode (&rcsnode);
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 89af760..3400027 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -11,9 +11,6 @@
#include <assert.h>
#include "cvs.h"
#include "edit.h"
-#include "hardlink.h"
-
-int preserve_perms = 0;
/* The RCS -k options, and a set of enums that must match the array.
These come first so that we can use enum kflag in function
@@ -22,57 +19,11 @@ static const char *const kflags[] =
{"kv", "kvl", "k", "v", "o", "b", (char *) NULL};
enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B };
-/* A structure we use to buffer the contents of an RCS file. The
- various fields are only referenced directly by the rcsbuf_*
- functions. We declare the struct here so that we can allocate it
- on the stack, rather than in memory. */
-
-struct rcsbuffer
-{
- /* Points to the current position in the buffer. */
- char *ptr;
- /* Points just after the last valid character in the buffer. */
- char *ptrend;
- /* The file. */
- FILE *fp;
- /* The name of the file, used for error messages. */
- const char *filename;
- /* The starting file position of the data in the buffer. */
- unsigned long pos;
- /* The length of the value. */
- size_t vlen;
- /* Whether the value contains an '@' string. If so, we can not
- compress whitespace characters. */
- int at_string;
- /* The number of embedded '@' characters in an '@' string. If
- this is non-zero, we must search the string for pairs of '@'
- and convert them to a single '@'. */
- int embedded_at;
-};
-
static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
-static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp,
- const char *filename, unsigned long pos));
-static void rcsbuf_close PROTO ((struct rcsbuffer *));
-static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
- char **valp));
-static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
-static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
- char **valp));
-static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
- size_t *lenp));
-static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
- size_t *lenp));
-static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to,
- const char *from, size_t *lenp));
-static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *));
-static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap,
- size_t *lenp));
-static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *));
-static void rcsbuf_cache_close PROTO ((void));
-static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
- struct rcsbuffer *));
+static int getrcskey PROTO((FILE * fp, char **keyp, char **valp,
+ size_t *lenp));
+static void getrcsrev PROTO ((FILE *fp, char **revp));
static int checkmagic_proc PROTO((Node *p, void *closure));
static void do_branches PROTO((List * list, char *val));
static void do_symbols PROTO((List * list, char *val));
@@ -89,15 +40,12 @@ static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *,
static void cmp_file_buffer PROTO((void *, const char *, size_t));
enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH};
-static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *,
- enum rcs_delta_op, char **, size_t *,
- char **, size_t *));
+static void RCS_deltas PROTO ((RCSNode *, FILE *, char *, enum rcs_delta_op,
+ char **, size_t *, char **, size_t *));
/* Routines for reading, parsing and writing RCS files. */
-static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **,
- char **));
-static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *,
- struct rcsbuffer *));
+static RCSVers *getdelta PROTO ((FILE *, char *));
+static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *));
static void freedeltatext PROTO ((Deltatext *));
static void RCS_putadmin PROTO ((RCSNode *, FILE *));
@@ -106,20 +54,14 @@ static void RCS_putdesc PROTO ((RCSNode *, FILE *));
static void putdelta PROTO ((RCSVers *, FILE *));
static int putrcsfield_proc PROTO ((Node *, void *));
static int putsymbol_proc PROTO ((Node *, void *));
-static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *,
- FILE *, Deltatext *, char *));
-static int count_delta_actions PROTO ((Node *, void *));
+static void RCS_copydeltas PROTO ((RCSNode *, FILE *, FILE *, Deltatext *, char *));
static void putdeltatext PROTO ((FILE *, Deltatext *));
static FILE *rcs_internal_lockfile PROTO ((char *));
static void rcs_internal_unlockfile PROTO ((FILE *, char *));
static char *rcs_lockfilename PROTO ((char *));
-/* The RCS file reading functions are called a lot, and they do some
- string comparisons. This macro speeds things up a bit by skipping
- the function call when the first characters are different. It
- evaluates its arguments multiple times. */
-#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
+static char * getfullCVSname PROTO ((char *, char **));
/*
* We don't want to use isspace() from the C library because:
@@ -150,6 +92,7 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
+
/* 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
@@ -165,10 +108,6 @@ RCS_parse (file, repos)
RCSNode *retval;
char *rcsfile;
- /* We're creating a new RCSNode, so there is no hope of finding it
- in the cache. */
- rcsbuf_cache_close ();
-
rcsfile = xmalloc (strlen (repos) + strlen (file)
+ sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
(void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
@@ -178,6 +117,7 @@ RCS_parse (file, repos)
if (rcs != NULL)
rcs->flags |= VALID;
+ fclose (fp);
retval = rcs;
goto out;
}
@@ -198,6 +138,7 @@ RCS_parse (file, repos)
rcs->flags |= VALID;
}
+ fclose (fp);
retval = rcs;
goto out;
}
@@ -226,6 +167,7 @@ RCS_parse (file, repos)
if (rcs != NULL)
rcs->flags |= VALID;
+ fclose (fp);
free (rcs->path);
rcs->path = found_path;
retval = rcs;
@@ -249,6 +191,7 @@ RCS_parse (file, repos)
rcs->flags |= VALID;
}
+ fclose (fp);
free (rcs->path);
rcs->path = found_path;
retval = rcs;
@@ -280,10 +223,6 @@ RCS_parsercsfile (rcsfile)
FILE *fp;
RCSNode *rcs;
- /* We're creating a new RCSNode, so there is no hope of finding it
- in the cache. */
- rcsbuf_cache_close ();
-
/* open the rcsfile */
if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL)
{
@@ -293,6 +232,7 @@ RCS_parsercsfile (rcsfile)
rcs = RCS_parsercsfile_i (fp, rcsfile);
+ fclose (fp);
return (rcs);
}
@@ -305,7 +245,6 @@ RCS_parsercsfile_i (fp, rcsfile)
const char *rcsfile;
{
RCSNode *rdata;
- struct rcsbuffer rcsbuf;
char *key, *value;
/* make a node */
@@ -314,32 +253,40 @@ RCS_parsercsfile_i (fp, rcsfile)
rdata->refcount = 1;
rdata->path = xstrdup (rcsfile);
- /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header.
+ /* Process HEAD and BRANCH keywords from the RCS header.
Most cvs operations on the main branch don't need any more
information. Those that do call RCS_reparsercsfile to parse
- the rest of the header and the deltas. */
-
- rcsbuf_open (&rcsbuf, fp, rcsfile, 0);
-
- if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ the rest of the header and the deltas.
+
+ People often wonder whether this is inefficient, to open the
+ file once here and once in RCS_reparsercsfile. Well, it might
+ help a little bit if we kept the file open (I haven't tried
+ timing this myself), but basically the common case, which we
+ want to optimize, is the one in which we call
+ RCS_parsercsfile_i and not RCS_reparsercsfile (for example,
+ "cvs update" on a lot of files most of which are unmodified).
+ So making the case in which we call RCS_reparsercsfile fast is
+ not as important. */
+
+ if (getrcskey (fp, &key, &value, NULL) == -1 || key == NULL)
goto l_error;
- if (STREQ (key, RCSDESC))
+ if (strcmp (key, RCSDESC) == 0)
goto l_error;
- if (STREQ (RCSHEAD, key) && value != NULL)
- rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
+ if (strcmp (RCSHEAD, key) == 0 && value != NULL)
+ rdata->head = xstrdup (value);
- if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ if (getrcskey (fp, &key, &value, NULL) == -1 || key == NULL)
goto l_error;
- if (STREQ (key, RCSDESC))
+ if (strcmp (key, RCSDESC) == 0)
goto l_error;
- if (STREQ (RCSBRANCH, key) && value != NULL)
+ if (strcmp (RCSBRANCH, key) == 0 && value != NULL)
{
char *cp;
- rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
+ rdata->branch = xstrdup (value);
if ((numdots (rdata->branch) & 1) != 0)
{
/* turn it into a branch if it's a revision */
@@ -348,43 +295,23 @@ RCS_parsercsfile_i (fp, rcsfile)
}
}
- /* Look ahead for expand, stopping when we see desc or a revision
- number. */
- while (1)
- {
- char *cp;
-
- if (STREQ (RCSEXPAND, key))
- {
- rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0,
- (size_t *) NULL);
- break;
- }
-
- for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++)
- /* do nothing */ ;
- if (*cp == '\0')
- break;
-
- if (STREQ (RCSDESC, key))
- break;
-
- if (! rcsbuf_getkey (&rcsbuf, &key, &value))
- break;
- }
-
rdata->flags |= PARTIAL;
-
- rcsbuf_cache (rdata, &rcsbuf);
-
return rdata;
l_error:
- error (0, 0, "`%s' does not appear to be a valid rcs file",
- rcsfile);
- rcsbuf_close (&rcsbuf);
+ if (!really_quiet)
+ {
+ if (ferror(fp))
+ {
+ error (1, 0, "error reading `%s'", rcsfile);
+ }
+ else
+ {
+ error (0, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ }
+ }
freercsnode (&rdata);
- fclose (fp);
return (NULL);
}
@@ -396,24 +323,25 @@ l_error:
If PFP is NULL, close the file when done. Otherwise, leave it open
and store the FILE * in *PFP. */
void
-RCS_reparsercsfile (rdata, pfp, rcsbufp)
+RCS_reparsercsfile (rdata, pfp)
RCSNode *rdata;
FILE **pfp;
- struct rcsbuffer *rcsbufp;
{
FILE *fp;
char *rcsfile;
- struct rcsbuffer rcsbuf;
+
Node *q, *kv;
RCSVers *vnode;
- int gotkey;
+ long fpos;
char *cp;
char *key, *value;
assert (rdata != NULL);
rcsfile = rdata->path;
- rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf);
+ fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ);
+ if (fp == NULL)
+ error (1, 0, "unable to reopen `%s'", rcsfile);
/* make a node */
/* This probably shouldn't be done until later: if a file has an
@@ -425,68 +353,66 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
* process all the special header information, break out when we get to
* the first revision delta
*/
- gotkey = 0;
for (;;)
{
+ fpos = ftell (fp);
+
/* get the next key/value pair */
- if (!gotkey)
+
+ /* if key is NULL here, then the file is missing some headers
+ or we had trouble reading the file. */
+ if (getrcskey (fp, &key, &value, NULL) == -1 || key == NULL)
{
- if (! rcsbuf_getkey (&rcsbuf, &key, &value))
+ if (ferror(fp))
+ {
+ error (1, 0, "error reading `%s'", rcsfile);
+ }
+ else
{
error (1, 0, "`%s' does not appear to be a valid rcs file",
rcsfile);
}
}
- gotkey = 0;
-
- /* Skip head, branch and expand tags; we already have them. */
- if (STREQ (key, RCSHEAD)
- || STREQ (key, RCSBRANCH)
- || STREQ (key, RCSEXPAND))
- {
+ /* Skip head and branch tags; we already have them. */
+ if (strcmp (key, RCSHEAD) == 0 || strcmp (key, RCSBRANCH) == 0)
continue;
- }
- if (STREQ (key, "access"))
+ if (strcmp (key, "access") == 0)
{
if (value != NULL)
- {
- /* We pass the POLISH parameter as 1 because
- RCS_addaccess expects nothing but spaces. FIXME:
- It would be easy and more efficient to change
- RCS_addaccess. */
- rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1,
- (size_t *) NULL);
- }
+ rdata->access = xstrdup (value);
continue;
}
/* We always save lock information, so that we can handle
-kkvl correctly when checking out a file. */
- if (STREQ (key, "locks"))
+ if (strcmp (key, "locks") == 0)
{
if (value != NULL)
- rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0,
- (size_t *) NULL);
- if (! rcsbuf_getkey (&rcsbuf, &key, &value))
- {
- error (1, 0, "premature end of file reading %s", rcsfile);
- }
- if (STREQ (key, "strict") && value == NULL)
+ rdata->locks_data = xstrdup (value);
+ fpos = ftell (fp);
+ if (getrcskey (fp, &key, &value, NULL) >= 0 &&
+ strcmp (key, "strict") == 0 &&
+ value == NULL)
{
rdata->strict_locks = 1;
}
else
- gotkey = 1;
+ (void) fseek (fp, fpos, SEEK_SET);
continue;
}
- if (STREQ (RCSSYMBOLS, key))
+ if (strcmp (RCSSYMBOLS, key) == 0)
{
if (value != NULL)
- rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0,
- (size_t *) NULL);
+ rdata->symbols_data = xstrdup(value);
+ continue;
+ }
+
+ if (strcmp (RCSEXPAND, key) == 0)
+ {
+ rdata->expand = xstrdup (value);
continue;
}
@@ -497,19 +423,15 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
*/
for (cp = key; (isdigit (*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 we know exactly what to expect. */
- if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0)
+ if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
break;
- if (STREQ (key, RCSDESC))
+ if (strcmp (key, RCSDESC) == 0)
break;
- if (STREQ (key, "comment"))
+ if (strcmp (key, "comment") == 0)
{
- rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0,
- (size_t *) NULL);
+ rdata->comment = xstrdup (value);
continue;
}
if (rdata->other == NULL)
@@ -517,7 +439,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
kv = getnode ();
kv->type = RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = xstrdup (value);
if (addnode (rdata->other, kv) != 0)
{
error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
@@ -528,11 +450,15 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
/* if we haven't grabbed it yet, we didn't want it */
}
- /* We got out of the loop, so we have the first part of the first
- revision delta in KEY (the revision) and VALUE (the date key
- and its value). This is what getdelta expects to receive. */
+ /*
+ * we got out of the loop, so we have the first part of the first
+ * revision delta in our hand key=the revision and value=the date key and
+ * its value
+ */
+ /* First, seek back to the start of the delta block. */
+ (void) fseek (fp, fpos, SEEK_SET);
- while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL)
+ while ((vnode = getdelta (fp, rcsfile)) != NULL)
{
/* get the node */
q = getnode ();
@@ -552,9 +478,8 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
}
}
- /* Here KEY and VALUE are whatever caused getdelta to return NULL. */
-
- if (STREQ (key, RCSDESC))
+ (void) getrcskey (fp, &key, &value, NULL);
+ if (key != NULL && strcmp (key, RCSDESC) == 0)
{
if (rdata->desc != NULL)
{
@@ -563,17 +488,19 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
key, rcsfile);
free (rdata->desc);
}
- rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *) NULL);
+ rdata->desc = xstrdup (value);
}
- rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
+ rdata->delta_pos = ftell (fp);
if (pfp == NULL)
- rcsbuf_cache (rdata, &rcsbuf);
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", rcsfile);
+ }
else
{
*pfp = fp;
- *rcsbufp = rcsbuf;
}
rdata->flags &= ~PARTIAL;
}
@@ -595,21 +522,31 @@ RCS_fully_parse (rcs)
RCSNode *rcs;
{
FILE *fp;
- struct rcsbuffer rcsbuf;
- RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+ RCS_reparsercsfile (rcs, &fp);
while (1)
{
+ int c;
char *key, *value;
+ size_t vallen;
Node *vers;
RCSVers *vnode;
/* Rather than try to keep track of how much information we
have read, just read to the end of the file. */
- if (! rcsbuf_getrevnum (&rcsbuf, &key))
+ do
+ {
+ c = getc (fp);
+ if (c == EOF)
+ break;
+ } while (whitespace (c));
+ if (c == EOF)
break;
+ if (ungetc (c, fp) == EOF)
+ error (1, errno, "ungetc failed");
+ getrcsrev (fp, &key);
vers = findnode (rcs->versions, key);
if (vers == NULL)
error (1, 0,
@@ -618,9 +555,9 @@ RCS_fully_parse (rcs)
vnode = (RCSVers *) vers->data;
- while (rcsbuf_getkey (&rcsbuf, &key, &value))
+ while (getrcskey (fp, &key, &value, &vallen) >= 0)
{
- if (! STREQ (key, "text"))
+ if (strcmp (key, "text") != 0)
{
Node *kv;
@@ -629,7 +566,7 @@ RCS_fully_parse (rcs)
kv = getnode ();
kv->type = RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = xstrdup (value);
if (addnode (vnode->other, kv) != 0)
{
error (0, 0,
@@ -642,7 +579,7 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
continue;
}
- if (! STREQ (vnode->version, rcs->head))
+ if (strcmp (vnode->version, rcs->head) != 0)
{
unsigned long add, del;
char buf[50];
@@ -654,10 +591,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
del = 0;
if (value != NULL)
{
- size_t vallen;
const char *cp;
- rcsbuf_valpolish (&rcsbuf, value, 0, &vallen);
cp = value;
while (cp < value + vallen)
{
@@ -737,7 +672,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
}
}
- rcsbuf_cache (rcs, &rcsbuf);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", rcs->path);
}
/*
@@ -832,877 +768,353 @@ rcsvers_delproc (p)
{
free_rcsvers_contents ((RCSVers *) p->data);
}
-
-/* These functions retrieve keys and values from an RCS file using a
- buffer. We use this somewhat complex approach because it turns out
- that for many common operations, CVS spends most of its time
- reading keys, so it's worth doing some fairly hairy optimization. */
-
-/* The number of bytes we try to read each time we need more data. */
-
-#define RCSBUF_BUFSIZE (8192)
-
-/* The buffer we use to store data. This grows as needed. */
-
-static char *rcsbuf_buffer = NULL;
-static size_t rcsbuf_buffer_size = 0;
-
-/* Whether rcsbuf_buffer is in use. This is used as a sanity check. */
-
-static int rcsbuf_inuse;
-
-/* Set up to start gathering keys and values from an RCS file. This
- initializes RCSBUF. */
-
-static void
-rcsbuf_open (rcsbuf, fp, filename, pos)
- struct rcsbuffer *rcsbuf;
- FILE *fp;
- const char *filename;
- unsigned long pos;
-{
- if (rcsbuf_inuse)
- error (1, 0, "rcsbuf_open: internal error");
- rcsbuf_inuse = 1;
-
- if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
- expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
-
- rcsbuf->ptr = rcsbuf_buffer;
- rcsbuf->ptrend = rcsbuf_buffer;
- rcsbuf->fp = fp;
- rcsbuf->filename = filename;
- rcsbuf->pos = pos;
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-}
-
-/* Stop gathering keys from an RCS file. */
-
-static void
-rcsbuf_close (rcsbuf)
- struct rcsbuffer *rcsbuf;
-{
- if (! rcsbuf_inuse)
- error (1, 0, "rcsbuf_close: internal error");
- rcsbuf_inuse = 0;
-}
-/* Read a key/value pair from an RCS file. This sets *KEYP to point
- to the key, and *VALUEP to point to the value. A missing or empty
- value is indicated by setting *VALUEP to NULL.
-
- This function returns 1 on success, or 0 on EOF. If there is an
- error reading the file, or an EOF in an unexpected location, it
- gives a fatal error.
+/*
+ * getrcskey - fill in the key and value from the rcs file the algorithm is
+ * as follows
+ *
+ * o skip whitespace
+ * o fill in key with everything up to next white
+ * space or semicolon
+ * o if key == "desc" then key and data are NULL and return -1
+ * o if key wasn't terminated by a semicolon, skip white space and fill
+ * in value with everything up to a semicolon
+ * o compress all whitespace down to a single space
+ * o if a word starts with @, do funky rcs processing
+ * o strip whitespace off end of value or set value to NULL if it empty
+ * o return 0 since we found something besides "desc"
+ *
+ * Sets *KEYP and *VALUEP to point to storage managed by the getrcskey
+ * function; the contents are only valid until the next call to
+ * getrcskey or getrcsrev. If LENP is not NULL, this sets *LENP to
+ * the length of *VALUEP; this is needed if the string might contain
+ * binary data.
+ */
- This sets *KEYP and *VALUEP to point to storage managed by
- rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the
- RCS format: it may contain embedded whitespace and embedded '@'
- characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
- appropriate massaging. */
+static char *key = NULL;
+static char *value = NULL;
+static size_t keysize = 0;
+static size_t valsize = 0;
static int
-rcsbuf_getkey (rcsbuf, keyp, valp)
- struct rcsbuffer *rcsbuf;
+getrcskey (fp, keyp, valp, lenp)
+ FILE *fp;
char **keyp;
char **valp;
+ size_t *lenp;
{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
+ char *cur, *max;
+ int c;
+ int just_string;
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
+ if (lenp != NULL)
+ *lenp = 0;
- /* If the pointer is more than RCSBUF_BUFSIZE bytes into the
- buffer, move back to the start of the buffer. This keeps the
- buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
+ /* skip leading whitespace */
+ do
{
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ } while (whitespace (c));
- while (1)
+ /* fill in key */
+ cur = key;
+ max = key + keysize;
+ while (!whitespace (c) && c != ';')
{
- if (ptr >= ptrend)
+ if (cur >= max)
{
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- return 0;
- ptrend = rcsbuf->ptrend;
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
}
+ *cur++ = c;
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* We've found the start of the key. */
-
- *keyp = ptr;
-
- if (c != ';')
- {
- while (1)
+ c = getc (fp);
+ if (c == EOF)
{
- ++ptr;
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "EOF in key in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- c = *ptr;
- if (c == ';' || my_whitespace (c))
- break;
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
}
}
-
- /* Here *KEYP points to the key in the buffer, C is the character
- we found at the of the key, and PTR points to the location in
- the buffer where we found C. We must set *PTR to \0 in order
- to terminate the key. If the key ended with ';', then there is
- no value. */
-
- *ptr = '\0';
- ++ptr;
-
- if (c == ';')
+ if (cur >= max)
{
- *valp = NULL;
- rcsbuf->ptr = ptr;
- return 1;
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
}
+ *cur = '\0';
- /* C must be whitespace. Skip whitespace between the key and the
- value. If we find ';' now, there is no value. */
-
- while (1)
+ /* skip whitespace between key and val */
+ while (whitespace (c))
{
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "EOF while looking for value in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- c = *ptr;
- if (c == ';')
+ c = getc (fp);
+ if (c == EOF)
{
- *valp = NULL;
- rcsbuf->ptr = ptr + 1;
- return 1;
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
}
- if (! my_whitespace (c))
- break;
- ++ptr;
- }
+ }
- /* Now PTR points to the start of the value, and C is the first
- character of the value. */
-
- if (c != '@')
- *valp = ptr;
- else
+ /* if we ended key with a semicolon, there is no value */
+ if (c == ';')
{
- char *pat;
- size_t vlen;
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
+ *keyp = key;
+ *valp = (char *) NULL;
+ return (0);
+ }
- ++ptr;
+ /* otherwise, there might be a value, so fill it in */
+ cur = value;
+ max = value + valsize;
- *valp = ptr;
+ just_string = (strcmp (key, RCSDESC) == 0
+ || strcmp (key, "text") == 0
+ || strcmp (key, "log") == 0);
- while (1)
+ /* process the value */
+ for (;;)
+ {
+ /* handle RCS "strings" */
+ if (c == '@')
{
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
+ for (;;)
{
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
- if (pat == NULL)
+ c = getc (fp);
+ if (c == EOF)
{
- /* EOF here is OK; it just means that the last
- character of the file was an '@' terminating a
- value for a key type which does not require a
- trailing ';'. */
- pat = rcsbuf->ptrend - 1;
-
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
}
- ptrend = rcsbuf->ptrend;
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *valp;
- if (vlen == 0)
- *valp = NULL;
- rcsbuf->vlen = vlen;
-
- ptr = pat + 1;
- }
-
- /* Certain keywords only have a '@' string. If there is no '@'
- string, then the old getrcskey function assumed that they had
- no value, and we do the same. */
-
- {
- char *k;
-
- k = *keyp;
- if (STREQ (k, RCSDESC)
- || STREQ (k, "text")
- || STREQ (k, "log"))
- {
- if (c != '@')
- *valp = NULL;
- rcsbuf->ptr = ptr;
- return 1;
- }
- }
-
- /* If we've already gathered a '@' string, try to skip whitespace
- and find a ';'. */
- if (c == '@')
- {
- while (1)
- {
- char n;
+ if (c == '@')
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+
+ if (c != '@')
+ break;
+ }
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
- if (ptr == NULL)
- error (1, 0, "EOF in value in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- n = *ptr;
- if (n == ';')
- {
- /* We're done. We already set everything up for this
- case above. */
- rcsbuf->ptr = ptr + 1;
- return 1;
+ if (cur >= max)
+ {
+ size_t curoff = cur - value;
+ expand_string (&value, &valsize, valsize + 1);
+ cur = value + curoff;
+ max = value + valsize;
+ }
+ *cur++ = c;
}
- if (! my_whitespace (n))
- break;
- ++ptr;
- }
-
- /* The value extends past the '@' string. We need to undo the
- closing of the '@' done in the default case above. This
- case never happens in a plain RCS file, but it can happen
- if user defined phrases are used. */
- if (rcsbuf->vlen != 0)
- (*valp)[rcsbuf->vlen] = ' ';
- else
- *valp = ptr;
- }
-
- /* Here we have a value which is not a simple '@' string. We need
- to gather up everything until the next ';', including any '@'
- strings. *VALP points to the start of the value. If
- RCSBUF->VLEN is not zero, then we have already read an '@'
- string, and PTR points to the data following the '@' string.
- Otherwise, PTR points to the start of the value. */
-
- while (1)
- {
- char *start, *psemi, *pat;
-
- /* Find the ';' which must end the value. */
- start = ptr;
- while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
- {
- int slen;
-
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to the
- location corresponding to the old PTREND, so that we
- don't search the same bytes again. */
- slen = start - *valp;
- ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
- if (ptr == NULL)
- error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
- start = *valp + slen;
- ptrend = rcsbuf->ptrend;
}
- /* See if there are any '@' strings in the value. */
- pat = memchr (start, '@', psemi - start);
-
- if (pat == NULL)
- {
- size_t vlen;
-
- /* We're done with the value. Trim any trailing
- whitespace. */
-
- rcsbuf->ptr = psemi + 1;
-
- start = *valp;
- while (psemi > start && my_whitespace (psemi[-1]))
- --psemi;
- *psemi = '\0';
-
- vlen = psemi - start;
- if (vlen == 0)
- *valp = NULL;
- rcsbuf->vlen = vlen;
-
- return 1;
- }
-
- /* We found an '@' string in the value. We set
- RCSBUF->AT_STRING, which means that we won't be able to
- compress whitespace correctly for this type of value.
- Since this type of value never arises in a normal RCS file,
- this should not be a big deal. It means that if anybody
- adds a phrase which can have both an '@' string and regular
- text, they will have to handle whitespace compression
- themselves. */
-
- rcsbuf->at_string = 1;
-
- *pat = ' ';
-
- ptr = pat + 1;
+ /* The syntax for some key-value pairs is different; they
+ don't end with a semicolon. */
+ if (just_string)
+ break;
- while (1)
+ /* compress whitespace down to a single space */
+ if (whitespace (c))
{
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuff_fill, so that we will wind up setting PTR
- to the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
+ do {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ } while (whitespace (c));
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
+ /* Do not include any trailing whitespace in the value. */
+ if (c != ';')
{
- ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
- if (ptr == NULL)
- error (1, 0, "EOF in value in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
+ if (cur >= max)
+ {
+ size_t curoff = cur - value;
+ expand_string (&value, &valsize, valsize + 1);
+ cur = value + curoff;
+ max = value + valsize;
+ }
+ *cur++ = ' ';
}
-
- if (pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
}
- /* Here PAT points to the final '@' in the string. */
-
- *pat = ' ';
-
- ptr = pat + 1;
- }
-
-#undef my_whitespace
-}
-
-/* Read an RCS revision number from an RCS file. This sets *REVP to
- point to the revision number; it will point to space that is
- managed by the rcsbuf functions, and is only good until the next
- call to rcsbuf_getkey or rcsbuf_getrevnum.
-
- This function returns 1 on success, or 0 on EOF. If there is an
- error reading the file, or an EOF in an unexpected location, it
- gives a fatal error. */
-
-static int
-rcsbuf_getrevnum (rcsbuf, revp)
- struct rcsbuffer *rcsbuf;
- char **revp;
-{
- char *ptr, *ptrend;
- char c;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- *revp = NULL;
-
- /* Skip leading whitespace. */
+ /* if we got a semi-colon we are done with the entire value */
+ if (c == ';')
+ break;
- while (1)
- {
- if (ptr >= ptrend)
+ if (cur >= max)
{
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- return 0;
- ptrend = rcsbuf->ptrend;
+ size_t curoff = cur - value;
+ expand_string (&value, &valsize, valsize + 1);
+ cur = value + curoff;
+ max = value + valsize;
}
+ *cur++ = c;
- c = *ptr;
- if (! whitespace (c))
- break;
-
- ++ptr;
- }
-
- if (! isdigit (c) && c != '.')
- error (1, 0,
- "unexpected `%c' reading revision number in RCS file %s",
- c, rcsbuf->filename);
-
- *revp = ptr;
-
- do
- {
- ++ptr;
- if (ptr >= ptrend)
+ c = getc (fp);
+ if (c == EOF)
{
- ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0,
- "unexpected EOF reading revision number in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
}
-
- c = *ptr;
}
- while (isdigit (c) || c == '.');
-
- if (! whitespace (c))
- error (1, 0, "unexpected `%c' reading revision number in RCS file %s",
- c, rcsbuf->filename);
-
- *ptr = '\0';
-
- rcsbuf->ptr = ptr + 1;
-
- return 1;
-}
-
-/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
- updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
- then *KEYP points into the buffer, and must be adjusted if the
- buffer is changed. Likewise for VALP. Returns the new value of
- PTR, or NULL on error. */
-static char *
-rcsbuf_fill (rcsbuf, ptr, keyp, valp)
- struct rcsbuffer *rcsbuf;
- char *ptr;
- char **keyp;
- char **valp;
-{
- int got;
-
- if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
+ /* terminate the string */
+ if (cur >= max)
{
- int poff, peoff, koff, voff;
-
- poff = ptr - rcsbuf_buffer;
- peoff = rcsbuf->ptrend - rcsbuf_buffer;
- if (keyp != NULL && *keyp != NULL)
- koff = *keyp - rcsbuf_buffer;
- if (valp != NULL && *valp != NULL)
- voff = *valp - rcsbuf_buffer;
-
- expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
- rcsbuf_buffer_size + RCSBUF_BUFSIZE);
-
- ptr = rcsbuf_buffer + poff;
- rcsbuf->ptrend = rcsbuf_buffer + peoff;
- if (keyp != NULL && *keyp != NULL)
- *keyp = rcsbuf_buffer + koff;
- if (valp != NULL && *valp != NULL)
- *valp = rcsbuf_buffer + voff;
+ size_t curoff = cur - value;
+ expand_string (&value, &valsize, valsize + 1);
+ cur = value + curoff;
+ max = value + valsize;
}
+ *cur = '\0';
- got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp);
- if (got == 0)
+ /* if the string is empty, make it null */
+ if (value && cur != value)
{
- if (ferror (rcsbuf->fp))
- error (1, errno, "cannot read %s", rcsbuf->filename);
- return NULL;
- }
-
- rcsbuf->ptrend += got;
-
- return ptr;
-}
-
-/* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
- returning the memory buffer. Polish the value like
- rcsbuf_valpolish, q.v. */
-
-static char *
-rcsbuf_valcopy (rcsbuf, val, polish, lenp)
- struct rcsbuffer *rcsbuf;
- char *val;
- int polish;
- size_t *lenp;
-{
- size_t vlen;
- int embedded_at;
- char *ret;
-
- if (val == NULL)
- {
- if (lenp != NULL)
- *lenp = 0;
- return NULL;
- }
-
- vlen = rcsbuf->vlen;
- embedded_at = rcsbuf->embedded_at;
-
- ret = xmalloc (vlen - embedded_at + 1);
-
- if (rcsbuf->at_string ? embedded_at == 0 : ! polish)
- {
- /* No special action to take. */
- memcpy (ret, val, vlen + 1);
- if (lenp != NULL)
- *lenp = vlen;
- return ret;
- }
-
- rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp);
- return ret;
-}
-
-/* Polish the value VAL returned by rcsbuf_getkey. The POLISH
- parameter is non-zero if multiple embedded whitespace characters
- should be compressed into a single whitespace character. Note that
- leading and trailing whitespace was already removed by
- rcsbuf_getkey. Within an '@' string, pairs of '@' characters are
- compressed into a single '@' character regardless of the value of
- POLISH. If LENP is not NULL, set *LENP to the length of the value. */
-
-static void
-rcsbuf_valpolish (rcsbuf, val, polish, lenp)
- struct rcsbuffer *rcsbuf;
- char *val;
- int polish;
- size_t *lenp;
-{
- if (val == NULL)
- {
- if (lenp != NULL)
- *lenp= 0;
- return;
- }
-
- if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish)
- {
- /* No special action to take. */
+ *valp = value;
if (lenp != NULL)
- *lenp = rcsbuf->vlen;
- return;
+ *lenp = cur - value;
}
-
- rcsbuf_valpolish_internal (rcsbuf, val, val, lenp);
+ else
+ *valp = NULL;
+ *keyp = key;
+ return (0);
}
-/* Internal polishing routine, called from rcsbuf_valcopy and
- rcsbuf_valpolish. */
-
+/* Read an RCS revision number from FP. Put a pointer to it in *REVP;
+ it points to space managed by getrcsrev which is only good until
+ the next call to getrcskey or getrcsrev. */
static void
-rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
- struct rcsbuffer *rcsbuf;
- char *to;
- const char *from;
- size_t *lenp;
+getrcsrev (fp, revp)
+ FILE *fp;
+ char **revp;
{
- size_t len;
-
- len = rcsbuf->vlen;
-
- if (! rcsbuf->at_string)
- {
- char *orig_to;
- size_t clen;
-
- orig_to = to;
+ char *cur;
+ char *max;
+ int c;
- for (clen = len; clen > 0; ++from, --clen)
+ do {
+ c = getc (fp);
+ if (c == EOF)
{
- char c;
-
- c = *from;
- if (whitespace (c))
- {
- /* Note that we know that clen can not drop to zero
- while we have whitespace, because we know there is
- no trailing whitespace. */
- while (whitespace (from[1]))
- {
- ++from;
- --clen;
- }
- c = ' ';
- }
- *to++ = c;
+ /* FIXME: should be including filename in error message. */
+ if (ferror (fp))
+ error (1, errno, "cannot read rcs file");
+ else
+ error (1, 0, "unexpected end of file reading rcs file");
}
+ } while (whitespace (c));
- *to = '\0';
+ if (!(isdigit (c) || c == '.'))
+ /* FIXME: should be including filename in error message. */
+ error (1, 0, "error reading rcs file; revision number expected");
- if (lenp != NULL)
- *lenp = to - orig_to;
- }
- else
+ cur = key;
+ max = key + keysize;
+ while (isdigit (c) || c == '.')
{
- const char *orig_from;
- char *orig_to;
- int embedded_at;
- size_t clen;
-
- orig_from = from;
- orig_to = to;
-
- embedded_at = rcsbuf->embedded_at;
-
- if (lenp != NULL)
- *lenp = len - embedded_at;
-
- for (clen = len; clen > 0; ++from, --clen)
+ if (cur >= max)
{
- char c;
-
- c = *from;
- *to++ = c;
- if (c == '@')
- {
- ++from;
-
- /* Sanity check. */
- if (*from != '@' || clen == 0)
- abort ();
-
- --clen;
-
- --embedded_at;
- if (embedded_at == 0)
- {
- /* We've found all the embedded '@' characters.
- We can just memcpy the rest of the buffer after
- this '@' character. */
- if (orig_to != orig_from)
- memcpy (to, from + 1, clen - 1);
- else
- memmove (to, from + 1, clen - 1);
- from += clen;
- to += clen - 1;
- break;
- }
- }
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
}
+ *cur++ = c;
- /* Sanity check. */
- if (from != orig_from + len
- || to != orig_to + (len - rcsbuf->embedded_at))
+ c = getc (fp);
+ if (c == EOF)
{
- abort ();
+ /* FIXME: should be including filename in error message. */
+ if (ferror (fp))
+ error (1, errno, "cannot read rcs file");
+ else
+ error (1, 0, "unexpected end of file reading rcs file");
}
-
- *to = '\0';
}
-}
-
-/* Return the current position of an rcsbuf. */
-
-static unsigned long
-rcsbuf_ftell (rcsbuf)
- struct rcsbuffer *rcsbuf;
-{
- return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
-}
-/* Return a pointer to any data buffered for RCSBUF, along with the
- length. */
-
-static void
-rcsbuf_get_buffered (rcsbuf, datap, lenp)
- struct rcsbuffer *rcsbuf;
- char **datap;
- size_t *lenp;
-{
- *datap = rcsbuf->ptr;
- *lenp = rcsbuf->ptrend - rcsbuf->ptr;
+ if (cur >= max)
+ {
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
+ }
+ *cur = '\0';
+ *revp = key;
}
-/* CVS optimizes by quickly reading some header information from a
- file. If it decides it needs to do more with the file, it reopens
- it. We speed that up here by maintaining a cache of a single open
- file, to save the time it takes to reopen the file in the common
- case. */
-
-static RCSNode *cached_rcs;
-static struct rcsbuffer cached_rcsbuf;
-
-/* Cache RCS and RCSBUF. This takes responsibility for closing
- RCSBUF->FP. */
-
-static void
-rcsbuf_cache (rcs, rcsbuf)
- RCSNode *rcs;
- struct rcsbuffer *rcsbuf;
+/* Like getrcsrev, but don't die on error. Return the last character
+ read (last call to getc, which may be EOF). TODO: implement getrcsrev
+ in terms of this function. */
+static int
+getrevnum (fp, revp)
+ FILE *fp;
+ char **revp;
{
- if (cached_rcs != NULL)
- rcsbuf_cache_close ();
- cached_rcs = rcs;
- ++rcs->refcount;
- cached_rcsbuf = *rcsbuf;
-}
-
-/* If there is anything in the cache, close it. */
+ char *cur;
+ char *max;
+ int c;
-static void
-rcsbuf_cache_close ()
-{
- if (cached_rcs != NULL)
- {
- if (fclose (cached_rcsbuf.fp) != 0)
- error (0, errno, "cannot close %s", cached_rcsbuf.filename);
- rcsbuf_close (&cached_rcsbuf);
- freercsnode (&cached_rcs);
- cached_rcs = NULL;
- }
-}
+ *revp = NULL;
+ do {
+ c = getc (fp);
+ if (c == EOF)
+ return c;
+ } while (whitespace (c));
-/* Open an rcsbuffer for RCS, getting it from the cache if possible.
- Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should
- be put at position POS. */
+ if (!(isdigit (c) || c == '.'))
+ return c;
-static void
-rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
- RCSNode *rcs;
- long pos;
- FILE **pfp;
- struct rcsbuffer *prcsbuf;
-{
- if (cached_rcs == rcs)
+ cur = key;
+ max = key + keysize;
+ while (isdigit (c) || c == '.')
{
- if (rcsbuf_ftell (&cached_rcsbuf) != pos)
+ if (cur >= max)
{
- if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0)
- error (1, 0, "cannot fseek RCS file %s",
- cached_rcsbuf.filename);
- cached_rcsbuf.ptr = rcsbuf_buffer;
- cached_rcsbuf.ptrend = rcsbuf_buffer;
- cached_rcsbuf.pos = pos;
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
}
- *pfp = cached_rcsbuf.fp;
-
- /* When RCS_parse opens a file using fopen_case, it frees the
- filename which we cached in CACHED_RCSBUF and stores a new
- file name in RCS->PATH. We avoid problems here by always
- copying the filename over. FIXME: This is hackish. */
- cached_rcsbuf.filename = rcs->path;
-
- *prcsbuf = cached_rcsbuf;
+ *cur = c;
- cached_rcs = NULL;
-
- /* Removing RCS from the cache removes a reference to it. */
- --rcs->refcount;
- if (rcs->refcount <= 0)
- error (1, 0, "rcsbuf_cache_open: internal error");
+ c = getc (fp);
+ if (c == EOF)
+ break;
+ cur++;
}
- else
- {
- if (cached_rcs != NULL)
- rcsbuf_cache_close ();
- *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
- if (*pfp == NULL)
- error (1, 0, "unable to reopen `%s'", rcs->path);
- if (pos != 0)
- {
- if (fseek (*pfp, pos, SEEK_SET) != 0)
- error (1, 0, "cannot fseek RCS file %s", rcs->path);
- }
- rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
+ if (cur >= max)
+ {
+ size_t curoff = cur - key;
+ expand_string (&key, &keysize, keysize + 1);
+ cur = key + curoff;
+ max = key + keysize;
}
+ *cur = '\0';
+ *revp = key;
+ return c;
}
-
/*
* process the symbols list of the rcs file
*/
@@ -1902,10 +1314,10 @@ RCS_gettag (rcs, symtag, force_tag_match, simple_tag)
/* XXX this is probably not necessary, --jtc */
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* If tag is "HEAD", special case to get head RCS revision */
- if (tag && (STREQ (tag, TAG_HEAD) || *tag == '\0'))
+ if (tag && (strcmp (tag, TAG_HEAD) == 0 || *tag == '\0'))
#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */
if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
return ((char *) NULL); /* head request for removed file */
@@ -2053,13 +1465,25 @@ RCS_magicrev (rcs, rev)
char *rev;
{
int rev_num;
- char *xrev, *test_branch;
+ char *xrev, *test_branch, *local_branch_num;
xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
check_rev = xrev;
+ local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM");
+ if (local_branch_num)
+ {
+ rev_num = atoi(local_branch_num);
+ if (rev_num < 2)
+ rev_num = 2;
+ else
+ rev_num &= ~1;
+ }
+ else
+ rev_num = 2;
+
/* only look at even numbered branches */
- for (rev_num = 2; ; rev_num += 2)
+ for ( ; ; rev_num += 2)
{
/* see if the physical branch exists */
(void) sprintf (xrev, "%s.%d", rev, rev_num);
@@ -2091,7 +1515,7 @@ checkmagic_proc (p, closure)
Node *p;
void *closure;
{
- if (STREQ (check_rev, p->data))
+ if (strcmp (check_rev, p->data) == 0)
return (1);
else
return (0);
@@ -2245,7 +1669,7 @@ RCS_getbranch (rcs, tag, force_tag_match)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* find out if the tag contains a dot, or is on the trunk */
cp = strrchr (tag, '.');
@@ -2463,7 +1887,7 @@ RCS_getdate (rcs, date, force_tag_match)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* if the head is on a branch, try the branch first */
if (rcs->branch != NULL)
@@ -2501,7 +1925,7 @@ 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"))
+ if (cur_rev != NULL && strcmp (cur_rev, "1.1") != 0)
return (xstrdup (cur_rev));
/* look on the vendor branch */
@@ -2550,7 +1974,7 @@ RCS_getdatebranch (rcs, date, branch)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
p = findnode (rcs->versions, xrev);
free (xrev);
@@ -2647,7 +2071,7 @@ RCS_getrevtime (rcs, rev, date, fudge)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* look up the revision */
p = findnode (rcs->versions, rev);
@@ -2699,7 +2123,7 @@ RCS_getlocks (rcs)
assert(rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->locks_data) {
rcs->locks = getlist ();
@@ -2718,7 +2142,7 @@ RCS_symbols(rcs)
assert(rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->symbols_data) {
rcs->symbols = getlist ();
@@ -2740,7 +2164,7 @@ translate_symtag (rcs, tag)
const char *tag;
{
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->symbols != NULL)
{
@@ -2824,7 +2248,7 @@ RCS_check_kflag (arg)
{
for (cpp = kflags; *cpp != NULL; cpp++)
{
- if (STREQ (arg, *cpp))
+ if (strcmp (arg, *cpp) == 0)
break;
}
}
@@ -2882,7 +2306,7 @@ RCS_isdead (rcs, tag)
RCSVers *version;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
p = findnode (rcs->versions, tag);
if (p == NULL)
@@ -2902,6 +2326,8 @@ RCS_getexpand (rcs)
RCSNode *rcs;
{
assert (rcs != NULL);
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL);
return rcs->expand;
}
@@ -2910,27 +2336,31 @@ struct rcs_keyword
{
const char *string;
size_t len;
+ int expandit;
};
#define KEYWORD_INIT(s) (s), sizeof (s) - 1
-static const struct rcs_keyword keywords[] =
+static struct rcs_keyword keywords[] =
{
- { KEYWORD_INIT ("Author") },
- { KEYWORD_INIT ("Date") },
- { KEYWORD_INIT ("Header") },
- { KEYWORD_INIT ("Id") },
- { KEYWORD_INIT ("Locker") },
- { KEYWORD_INIT ("Log") },
- { KEYWORD_INIT ("Name") },
- { KEYWORD_INIT ("RCSfile") },
- { KEYWORD_INIT ("Revision") },
- { KEYWORD_INIT ("Source") },
- { KEYWORD_INIT ("State") },
- { NULL, 0 }
+ { KEYWORD_INIT ("Author"), 1 },
+ { KEYWORD_INIT ("Date"), 1 },
+ { KEYWORD_INIT ("CVSHeader"), 1 },
+ { KEYWORD_INIT ("Header"), 1 },
+ { KEYWORD_INIT ("Id"), 1 },
+ { KEYWORD_INIT ("Locker"), 1 },
+ { KEYWORD_INIT ("Log"), 1 },
+ { KEYWORD_INIT ("Name"), 1 },
+ { KEYWORD_INIT ("RCSfile"), 1 },
+ { KEYWORD_INIT ("Revision"), 1 },
+ { KEYWORD_INIT ("Source"), 1 },
+ { KEYWORD_INIT ("State"), 1 },
+ { NULL, 0, 0 },
+ { NULL, 0, 0 }
};
enum keyword
{
KEYWORD_AUTHOR = 0,
KEYWORD_DATE,
+ KEYWORD_CVSHEADER,
KEYWORD_HEADER,
KEYWORD_ID,
KEYWORD_LOCKER,
@@ -2939,8 +2369,10 @@ enum keyword
KEYWORD_RCSFILE,
KEYWORD_REVISION,
KEYWORD_SOURCE,
- KEYWORD_STATE
+ KEYWORD_STATE,
+ KEYWORD_LOCALID
};
+enum keyword keyword_local = KEYWORD_ID;
/* Convert an RCS date string into a readable string. This is like
the RCS date2str function. */
@@ -3118,7 +2550,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
slen = s - srch;
for (keyword = keywords; keyword->string != NULL; keyword++)
{
- if (keyword->len == slen
+ if (keyword->expandit
+ && keyword->len == slen
&& strncmp (keyword->string, srch, slen) == 0)
{
break;
@@ -3165,15 +2598,25 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
free_value = 1;
break;
+ case KEYWORD_CVSHEADER:
case KEYWORD_HEADER:
case KEYWORD_ID:
+ case KEYWORD_LOCALID:
{
char *path;
int free_path;
char *date;
+ char *old_path;
- if (kw == KEYWORD_HEADER)
+ old_path = NULL;
+ if (kw == KEYWORD_HEADER ||
+ (kw == KEYWORD_LOCALID &&
+ keyword_local == KEYWORD_HEADER))
path = rcs->path;
+ else if (kw == KEYWORD_CVSHEADER ||
+ (kw == KEYWORD_LOCALID &&
+ keyword_local == KEYWORD_CVSHEADER))
+ path = getfullCVSname(rcs->path, &old_path);
else
path = last_component (rcs->path);
path = escape_keyword_value (path, &free_path);
@@ -3193,6 +2636,8 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
locker != NULL ? locker : "");
if (free_path)
free (path);
+ if (old_path)
+ free (old_path);
free (date);
free_value = 1;
}
@@ -3490,16 +2935,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
OPTIONS is a string such as "-kb" or "-kv" for keyword expansion
options. It may be NULL to use the default expansion mode of the
- file, typically "-kkv".
-
- On an error which prevented checking out the file, either print a
- nonfatal error and return 1, or give a fatal error. On success,
- return 0. */
-
-/* This function mimics the behavior of `rcs co' almost exactly. The
- chief difference is in its support for preserving file ownership,
- permissions, and special files across checkin and checkout -- see
- comments in RCS_checkin for some issues about this. -twp */
+ file, typically "-kkv". */
int
RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
@@ -3514,27 +2950,15 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
{
int free_rev = 0;
enum kflag expand;
- FILE *fp, *ofp;
+ FILE *fp;
struct stat sb;
- struct rcsbuffer rcsbuf;
char *key;
char *value;
size_t len;
int free_value = 0;
char *log = NULL;
size_t loglen;
- Node *vp = NULL;
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- uid_t rcs_owner;
- gid_t rcs_group;
- mode_t rcs_mode;
- int change_rcs_owner = 0;
- int change_rcs_group = 0;
- int change_rcs_mode = 0;
- int special_file = 0;
- unsigned long devnum_long;
- dev_t devnum = 0;
-#endif
+ FILE *ofp;
if (trace)
{
@@ -3571,25 +2995,34 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
free_rev = 1;
}
- if (rev == NULL || STREQ (rev, rcs->head))
+ if (rev == NULL || strcmp (rev, rcs->head) == 0)
{
int gothead;
/* We want the head revision. Try to read it directly. */
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+ RCS_reparsercsfile (rcs, &fp);
else
- rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf);
+ {
+ fp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
+ if (fp == NULL)
+ error (1, 0, "unable to reopen `%s'", rcs->path);
+ if (fseek (fp, rcs->delta_pos, SEEK_SET) != 0)
+ error (1, 0, "cannot fseek RCS file");
+ }
gothead = 0;
- if (! rcsbuf_getrevnum (&rcsbuf, &key))
- error (1, 0, "unexpected EOF reading %s", rcs->path);
- while (rcsbuf_getkey (&rcsbuf, &key, &value))
+ getrcsrev (fp, &key);
+ while (getrcskey (fp, &key, &value, &len) >= 0)
{
- if (STREQ (key, "log"))
- log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen);
- else if (STREQ (key, "text"))
+ if (strcmp (key, "log") == 0)
+ {
+ log = xmalloc (len);
+ memcpy (log, value, len);
+ loglen = len;
+ }
+ if (strcmp (key, "text") == 0)
{
gothead = 1;
break;
@@ -3604,23 +3037,20 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
return 1;
}
- rcsbuf_valpolish (&rcsbuf, value, 0, &len);
-
if (fstat (fileno (fp), &sb) < 0)
error (1, errno, "cannot fstat %s", rcs->path);
- rcsbuf_cache (rcs, &rcsbuf);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", rcs->path);
}
else
{
- struct rcsbuffer *rcsbufp;
-
/* It isn't the head revision of the trunk. We'll need to
walk through the deltas. */
fp = NULL;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, &fp, &rcsbuf);
+ RCS_reparsercsfile (rcs, &fp);
if (fp == NULL)
{
@@ -3628,17 +3058,14 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
here too. Probably should change it thusly.... */
if (stat (rcs->path, &sb) < 0)
error (1, errno, "cannot stat %s", rcs->path);
- rcsbufp = NULL;
}
else
{
if (fstat (fileno (fp), &sb) < 0)
error (1, errno, "cannot fstat %s", rcs->path);
- rcsbufp = &rcsbuf;
}
- RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len,
- &log, &loglen);
+ RCS_deltas (rcs, fp, rev, RCS_FETCH, &value, &len, &log, &loglen);
free_value = 1;
}
@@ -3661,7 +3088,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
ouroptions = rcs->expand;
for (cpp = kflags; *cpp != NULL; cpp++)
- if (STREQ (*cpp, ouroptions))
+ if (strcmp (*cpp, ouroptions) == 0)
break;
if (*cpp != NULL)
@@ -3675,186 +3102,17 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
}
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Handle special files and permissions, if that is desired. */
- if (preserve_perms)
- {
- RCSVers *vers;
- Node *info;
- struct hardlink_info *hlinfo;
-
- vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
- if (vp == NULL)
- error (1, 0, "internal error: no revision information for %s",
- rev == NULL ? rcs->head : rev);
- vers = (RCSVers *) vp->data;
-
- /* First we look for symlinks, which are simplest to handle. */
- info = findnode (vers->other_delta, "symlink");
- if (info != NULL)
- {
- char *dest;
-
- if (pfn != NULL || (workfile == NULL && sout == RUN_TTY))
- error (1, 0, "symbolic link %s:%s cannot be piped",
- rcs->path, vers->version);
- if (workfile == NULL)
- dest = sout;
- else
- dest = workfile;
-
- /* Remove `dest', just in case. It's okay to get ENOENT here,
- since we just want the file not to be there. (TODO: decide
- whether it should be considered an error for `dest' to exist
- at this point. If so, the unlink call should be removed and
- `symlink' should signal the error. -twp) */
- if (unlink (dest) < 0 && existence_error (errno))
- error (1, errno, "cannot remove %s", dest);
- if (symlink (info->data, dest) < 0)
- error (1, errno, "cannot create symbolic link from %s to %s",
- dest, info->data);
- if (free_value)
- free (value);
- if (free_rev)
- free (rev);
- return 0;
- }
-
- /* Next, we look at this file's hardlinks field, and see whether
- it is linked to any other file that has been checked out.
- If so, we don't do anything else -- just link it to that file.
-
- If we are checking out a file to a pipe or temporary storage,
- none of this should matter. Hence the `workfile != NULL'
- wrapper around the whole thing. -twp */
-
- if (workfile != NULL)
- {
- info = findnode (vers->other_delta, "hardlinks");
- if (info != NULL)
- {
- char *links = xstrdup (info->data);
- char *working_dir = xgetwd();
- char *p, *file = NULL;
- Node *n, *uptodate_link;
-
- /* For each file in the hardlinks field, check to see
- if it exists, and if so, if it has been checked out
- this iteration. */
- uptodate_link = NULL;
- for (p = strtok (links, " ");
- p != NULL && uptodate_link == NULL;
- p = strtok (NULL, " "))
- {
- file = (char *)
- xmalloc (sizeof(char) *
- (strlen(working_dir) + strlen(p) + 2));
- sprintf (file, "%s/%s", working_dir, p);
- n = lookup_file_by_inode (file);
- if (n == NULL)
- {
- if (strcmp (p, workfile) != 0)
- {
- /* One of the files that WORKFILE should be
- linked to is not even in the working directory.
- The user should probably be warned. */
- error (0, 0,
- "warning: %s should be hardlinked to %s, but is missing",
- p, workfile);
- }
- free (file);
- continue;
- }
-
- /* hlinfo may be NULL if, for instance, a file is being
- removed. */
- hlinfo = (struct hardlink_info *) n->data;
- if (hlinfo && hlinfo->checked_out)
- uptodate_link = n;
- free (file);
- }
- free (links);
- free (working_dir);
-
- /* If we've found a file that `workfile' is supposed to be
- linked to, and it has been checked out since CVS was
- invoked, then simply link workfile to that file.
-
- If one of these conditions is not met, then we're
- checking out workfile to a temp file or stdout, or
- workfile is the first one in its hardlink group to be
- checked out. Either way we must continue with a full
- checkout. */
-
- if (uptodate_link != NULL)
- {
- if (link (uptodate_link->key, workfile) < 0)
- error (1, errno, "cannot link %s to %s",
- workfile, uptodate_link->key);
- hlinfo->checked_out = 1; /* probably unnecessary */
- if (free_value)
- free (value);
- if (free_rev)
- free (rev);
- return 0;
- }
- }
- }
-
- info = findnode (vers->other_delta, "owner");
- if (info != NULL)
- {
- change_rcs_owner = 1;
- rcs_owner = (uid_t) strtoul (info->data, NULL, 10);
- }
- info = findnode (vers->other_delta, "group");
- if (info != NULL)
- {
- change_rcs_group = 1;
- rcs_group = (gid_t) strtoul (info->data, NULL, 10);
- }
- info = findnode (vers->other_delta, "permissions");
- if (info != NULL)
- {
- change_rcs_mode = 1;
- rcs_mode = (mode_t) strtoul (info->data, NULL, 8);
- }
- info = findnode (vers->other_delta, "special");
- if (info != NULL)
- {
- /* If the size of `devtype' changes, fix the sscanf call also */
- char devtype[16];
-
- if (sscanf (info->data, "%16s %lu",
- devtype, &devnum_long) < 2)
- error (1, 0, "%s:%s has bad `special' newphrase %s",
- workfile, vers->version, info->data);
- devnum = devnum_long;
- if (strcmp (devtype, "character") == 0)
- special_file = S_IFCHR;
- else if (strcmp (devtype, "block") == 0)
- special_file = S_IFBLK;
- else
- error (0, 0, "%s is a special file of unsupported type `%s'",
- workfile, info->data);
- }
- }
-#endif
-
if (expand != KFLAG_O && expand != KFLAG_B)
{
+ Node *p;
char *newvalue;
- /* Don't fetch the delta node again if we already have it. */
- if (vp == NULL)
- {
- vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
- if (vp == NULL)
- error (1, 0, "internal error: no revision information for %s",
- rev == NULL ? rcs->head : rev);
- }
+ p = findnode (rcs->versions, rev == NULL ? rcs->head : rev);
+ if (p == NULL)
+ error (1, 0, "internal error: no revision information for %s",
+ rev == NULL ? rcs->head : rev);
- expand_keywords (rcs, (RCSVers *) vp->data, nametag, log, loglen,
+ expand_keywords (rcs, (RCSVers *) p->data, nametag, log, loglen,
expand, value, len, &newvalue, &len);
if (newvalue != value)
@@ -3874,55 +3132,19 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (pfn != NULL)
{
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (special_file)
- error (1, 0, "special file %s cannot be piped to anything",
- rcs->path);
-#endif
/* The PFN interface is very simple to implement right now, as
we always have the entire file in memory. */
if (len != 0)
pfn (callerdat, value, len);
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- else if (special_file)
- {
- char *dest;
-
- /* Can send either to WORKFILE or to SOUT, as long as SOUT is
- not RUN_TTY. */
- dest = workfile;
- if (dest == NULL)
- {
- if (sout == RUN_TTY)
- error (1, 0, "special file %s cannot be written to stdout",
- rcs->path);
- dest = sout;
- }
-
- /* Unlink `dest', just in case. It's okay if this provokes a
- ENOENT error. */
- if (unlink (dest) < 0 && existence_error (errno))
- error (1, errno, "cannot remove %s", dest);
- if (mknod (dest, special_file, devnum) < 0)
- error (1, errno, "could not create special file %s",
- dest);
- }
-#endif
else
{
- /* Not a special file: write to WORKFILE or SOUT. */
if (workfile == NULL)
{
if (sout == RUN_TTY)
ofp = stdout;
else
{
- /* Symbolic links should be removed before replacement, so that
- `fopen' doesn't follow the link and open the wrong file. */
- if (islink (sout))
- if (unlink_file (sout) < 0)
- error (1, errno, "cannot remove %s", sout);
ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w");
if (ofp == NULL)
error (1, errno, "cannot open %s", sout);
@@ -3930,11 +3152,6 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
}
else
{
- /* Output is supposed to go to WORKFILE, so we should open that
- file. Symbolic links should be removed first (see above). */
- if (islink (workfile))
- if (unlink_file (workfile) < 0)
- error (1, errno, "cannot remove %s", workfile);
ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w");
if (ofp == NULL)
error (1, errno, "cannot open %s", workfile);
@@ -3979,56 +3196,22 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
nstep = nleft;
}
}
- }
-
- if (workfile != NULL)
- {
- int ret;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (!special_file && fclose (ofp) < 0)
- error (1, errno, "cannot close %s", workfile);
- if (change_rcs_owner || change_rcs_group)
+ if (workfile != NULL)
{
- if (chown (workfile, rcs_owner, rcs_group) < 0)
- error (0, errno, "could not change file ownership on %s",
+ if (fclose (ofp) < 0)
+ error (1, errno, "cannot close %s", workfile);
+ if (chmod (workfile,
+ sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)) < 0)
+ error (0, errno, "cannot change mode of file %s",
workfile);
}
-
- ret = chmod (workfile,
- change_rcs_mode
- ? rcs_mode
- : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
-#else
- if (fclose (ofp) < 0)
- error (1, errno, "cannot close %s", workfile);
-
- ret = chmod (workfile,
- sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH));
-#endif
- if (ret < 0)
+ else if (sout != RUN_TTY)
{
- error (0, errno, "cannot change mode of file %s",
- workfile);
+ if (fclose (ofp) < 0)
+ error (1, errno, "cannot close %s", sout);
}
}
- else if (sout != RUN_TTY)
- {
- if (
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- !special_file &&
-#endif
- fclose (ofp) < 0)
- error (1, errno, "cannot close %s", sout);
- }
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* If we are in the business of preserving hardlinks, then
- mark this file as having been checked out. */
- if (preserve_perms && workfile != NULL)
- update_hardlink_info (workfile);
-#endif
if (free_value)
free (value);
@@ -4077,7 +3260,7 @@ RCS_findlock_or_tip (rcs)
lock = NULL;
for (p = locklist->list->next; p != locklist->list; p = p->next)
{
- if (STREQ (p->data, user))
+ if (strcmp (p->data, user) == 0)
{
if (lock != NULL)
{
@@ -4183,11 +3366,8 @@ compare_truncated_revnums (r, s)
FIXME: isn't the max rev always the last one?
If so, we don't even need a loop. */
-static char *max_rev PROTO ((const RCSVers *));
-
static char *
-max_rev (branchnode)
- const RCSVers *branchnode;
+max_rev (const RCSVers *branchnode)
{
Node *head;
Node *bp;
@@ -4322,27 +3502,22 @@ RCS_addbranch (rcs, branch)
return newrevnum;
}
-/* Check in to RCSFILE with revision REV (which must be greater than
- the largest revision) and message MESSAGE (which is checked for
- legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
- If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS &
- RCS_FLAGS_MODTIME, use the working file's modification time for the
- checkin time. WORKFILE is the working file to check in from, or
- NULL to use the usual RCS rules for deriving it from the RCSFILE.
- If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file;
- unlinking the working file is standard RCS behavior, but is rarely
- appropriate for CVS.
-
- This function should almost exactly mimic the behavior of `rcs ci'. The
- principal point of difference is the support here for preserving file
- ownership and permissions in the delta nodes. This is not a clean
- solution -- precisely because it diverges from RCS's behavior -- but
- it doesn't seem feasible to do this anywhere else in the code. [-twp]
+/* Check in to RCSFILE with revision REV (which must be greater than the
+ largest revision) and message MESSAGE (which is checked for legality).
+ If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. If FLAGS &
+ RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & RCS_FLAGS_MODTIME,
+ use the working file's modification time for the checkin time.
+ WORKFILE is the working file to check in from, or NULL to use the usual
+ RCS rules for deriving it from the RCSFILE.
Return value is -1 for error (and errno is set to indicate the
error), positive for error (and an error message has been printed),
or zero for success. */
+/* TODO: RCS_checkin always unlinks the working file after checkin --
+ then RCS_checkout checks it out again. The logic should probably
+ be reversed here. */
+
int
RCS_checkin (rcs, workfile, message, rev, flags)
RCSNode *rcs;
@@ -4365,7 +3540,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
commitpt = NULL;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* Get basename of working file. Is there a library function to
do this? I couldn't find one. -twp */
@@ -4419,92 +3594,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
else
delta->state = xstrdup ("Exp");
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* If permissions should be preserved on this project, then
- save the permission info. */
- if (preserve_perms)
- {
- Node *np;
- struct stat sb;
- char buf[64]; /* static buffer should be safe: see usage. -twp */
- char *fullpath;
-
- delta->other_delta = getlist();
-
- if (CVS_LSTAT (workfile, &sb) < 0)
- error (1, 1, "cannot lstat %s", workfile);
-
- if (S_ISLNK (sb.st_mode))
- {
- np = getnode();
- np->key = xstrdup ("symlink");
- np->data = xreadlink (workfile);
- addnode (delta->other_delta, np);
- }
- else
- {
- (void) sprintf (buf, "%u", sb.st_uid);
- np = getnode();
- np->key = xstrdup ("owner");
- np->data = xstrdup (buf);
- addnode (delta->other_delta, np);
-
- (void) sprintf (buf, "%u", sb.st_gid);
- np = getnode();
- np->key = xstrdup ("group");
- np->data = xstrdup (buf);
- addnode (delta->other_delta, np);
-
- (void) sprintf (buf, "%o", sb.st_mode & 07777);
- np = getnode();
- np->key = xstrdup ("permissions");
- np->data = xstrdup (buf);
- addnode (delta->other_delta, np);
-
- /* Save device number. */
- switch (sb.st_mode & S_IFMT)
- {
- case S_IFREG: break;
- case S_IFCHR:
- case S_IFBLK:
- np = getnode();
- np->key = xstrdup ("special");
- sprintf (buf, "%s %lu",
- ((sb.st_mode & S_IFMT) == S_IFCHR
- ? "character" : "block"),
- (unsigned long) sb.st_rdev);
- np->data = xstrdup (buf);
- addnode (delta->other_delta, np);
- break;
-
- default:
- error (0, 0, "special file %s has unknown type", workfile);
- }
-
- /* Save hardlinks. */
- fullpath = xgetwd();
- fullpath = xrealloc (fullpath,
- strlen(fullpath) + strlen(workfile) + 2);
- sprintf (fullpath + strlen(fullpath), "/%s", workfile);
-
- np = lookup_file_by_inode (fullpath);
- if (np == NULL)
- {
- error (1, 0, "lost information on %s's linkage", workfile);
- }
- else
- {
- struct hardlink_info *hlinfo;
- hlinfo = (struct hardlink_info *) np->data;
- np = getnode();
- np->key = xstrdup ("hardlinks");
- np->data = xstrdup (hlinfo->links);
- (void) addnode (delta->other_delta, np);
- }
- }
- }
-#endif
-
/* Create a new deltatext node. */
dtext = (Deltatext *) xmalloc (sizeof (Deltatext));
memset (dtext, 0, sizeof (Deltatext));
@@ -4543,9 +3632,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
dtext->version = xstrdup (newrev);
bufsize = 0;
- get_file (workfile, workfile,
- rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
- &dtext->text, &bufsize, &dtext->len);
+ get_file(workfile, workfile, "r", &dtext->text, &bufsize, &dtext->len);
if (!checkin_quiet)
{
@@ -4554,9 +3641,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
cvs_output ("\n", 1);
}
- /* We are probably about to invalidate any cached file. */
- rcsbuf_cache_close ();
-
fout = rcs_internal_lockfile (rcs->path);
RCS_putadmin (rcs, fout);
RCS_putdtree (rcs, rcs->head, fout);
@@ -4568,12 +3652,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
rcs_internal_unlockfile (fout, rcs->path);
freedeltatext (dtext);
- if ((flags & RCS_FLAGS_KEEPFILE) == 0)
- {
- if (unlink_file (workfile) < 0)
- /* FIXME-update-dir: message does not include update_dir. */
- error (0, errno, "cannot remove %s", workfile);
- }
+ /* Removing the file here is an RCS user-visible behavior which
+ we almost surely do not need in the CVS case. In fact, getting
+ rid of it should clean up link_file and friends in import.c. */
+ if (unlink_file (workfile) < 0)
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (0, errno, "cannot remove %s", workfile);
if (!checkin_quiet)
cvs_output ("done\n", 5);
@@ -4613,7 +3697,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
goto checkin_done;
}
else if (commitpt->next == NULL
- || STREQ (commitpt->version, rcs->head))
+ || strcmp (commitpt->version, rcs->head) == 0)
delta->version = increment_revnum (commitpt->version);
else
delta->version = RCS_addbranch (rcs, commitpt->version);
@@ -4717,7 +3801,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
nodep = findnode (RCS_getlocks (rcs), commitpt->version);
if (nodep != NULL)
{
- if (! STREQ (nodep->data, delta->author))
+ if (strcmp (nodep->data, delta->author) != 0)
{
error (0, 0, "%s: revision %s locked by %s",
rcs->path,
@@ -4739,13 +3823,13 @@ RCS_checkin (rcs, workfile, message, rev, flags)
tmpfile = cvs_temp_name();
status = RCS_checkout (rcs, NULL, commitpt->version, NULL,
((rcs->expand != NULL
- && STREQ (rcs->expand, "b"))
+ && strcmp (rcs->expand, "b") == 0)
? "-kb"
: "-ko"),
tmpfile,
(RCSCHECKOUTPROC)0, NULL);
if (status != 0)
- error (1, 0,
+ error (1, status < 0 ? errno : 0,
"could not check out revision %s of `%s'",
commitpt->version, rcs->path);
@@ -4756,18 +3840,18 @@ RCS_checkin (rcs, workfile, message, rev, flags)
/* Diff options should include --binary if the RCS file has -kb set
in its `expand' field. */
- diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b")
+ diffopts = (rcs->expand != NULL && strcmp (rcs->expand, "b") == 0
? "-a -n --binary"
: "-a -n");
- if (STREQ (commitpt->version, rcs->head) &&
+ if (strcmp (commitpt->version, rcs->head) == 0 &&
numdots (delta->version) == 1)
{
/* 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;
get_file (workfile, workfile,
- rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ rcs->expand != NULL && strcmp (rcs->expand, "b") == 0 ? "rb" : "r",
&dtext->text, &bufsize, &dtext->len);
/* ... and the change text for the old delta should be a diff. */
@@ -4803,7 +3887,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
This should cause no harm, but doesn't strike me as
immensely clean. */
get_file (changefile, changefile,
- rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ rcs->expand != NULL && strcmp (rcs->expand, "b") == 0 ? "rb" : "r",
&commitpt->text->text, &bufsize, &commitpt->text->len);
/* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE
@@ -4840,7 +3924,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
/* See the comment above, at the other get_file invocation,
regarding binary vs. text. */
get_file (changefile, changefile,
- rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r",
+ rcs->expand != NULL && strcmp (rcs->expand, "b") == 0 ? "rb" : "r",
&dtext->text, &bufsize,
&dtext->len);
if (dtext->text == NULL)
@@ -4864,7 +3948,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (numdots (commitpt->version) == numdots (delta->version))
{
- if (STREQ (commitpt->version, rcs->head))
+ if (strcmp (commitpt->version, rcs->head) == 0)
{
delta->next = rcs->head;
rcs->head = xstrdup (delta->version);
@@ -4894,12 +3978,12 @@ RCS_checkin (rcs, workfile, message, rev, flags)
RCS_rewrite (rcs, dtext, commitpt->version);
- if ((flags & RCS_FLAGS_KEEPFILE) == 0)
- {
- if (unlink_file (workfile) < 0)
- /* FIXME-update-dir: message does not include update_dir. */
- error (1, errno, "cannot remove %s", workfile);
- }
+ /* Removing the file here is an RCS user-visible behavior which
+ we almost surely do not need in the CVS case. In fact, getting
+ rid of it should clean up link_file and friends in import.c. */
+ if (unlink_file (workfile) < 0)
+ /* FIXME-update-dir: message does not include update_dir. */
+ error (1, errno, "cannot remove %s", workfile);
if (unlink_file (tmpfile) < 0)
error (0, errno, "cannot remove %s", tmpfile);
if (unlink_file (changefile) < 0)
@@ -4952,70 +4036,42 @@ RCS_cmp_file (rcs, rev, options, filename)
int retcode;
if (options != NULL && options[0] != '\0')
- binary = STREQ (options, "-kb");
+ binary = (strcmp (options, "-kb") == 0);
else
{
char *expand;
expand = RCS_getexpand (rcs);
- if (expand != NULL && STREQ (expand, "b"))
+ if (expand != NULL && strcmp (expand, "b") == 0)
binary = 1;
else
binary = 0;
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* If CVS is to deal properly with special files (when
- PreservePermissions is on), the best way is to check out the
- revision to a temporary file and call `xcmp' on the two disk
- files. xcmp needs to handle non-regular files properly anyway,
- so calling it simplifies RCS_cmp_file. We *could* just yank
- the delta node out of the version tree and look for device
- numbers, but writing to disk and calling xcmp is a better
- abstraction (therefore probably more robust). -twp */
+ fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
- if (preserve_perms)
- {
- char *tmp;
+ data.filename = filename;
+ data.fp = fp;
+ data.different = 0;
- tmp = cvs_temp_name();
- retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL);
- if (retcode != 0)
- return 1;
+ retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
+ options, RUN_TTY, cmp_file_buffer,
+ (void *) &data);
- retcode = xcmp (tmp, filename);
- if (CVS_UNLINK (tmp) < 0)
- error (0, errno, "cannot remove %s", tmp);
- return retcode;
- }
- else
-#endif
+ /* If we have not yet found a difference, make sure that we are at
+ the end of the file. */
+ if (! data.different)
{
- fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r");
-
- data.filename = filename;
- data.fp = fp;
- data.different = 0;
-
- retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL,
- options, RUN_TTY, cmp_file_buffer,
- (void *) &data);
-
- /* If we have not yet found a difference, make sure that we are at
- the end of the file. */
- if (! data.different)
- {
- if (getc (fp) != EOF)
- data.different = 1;
- }
-
- fclose (fp);
-
- if (retcode != 0)
- return 1;
-
- return data.different;
+ if (getc (fp) != EOF)
+ data.different = 1;
}
+
+ fclose (fp);
+
+ if (retcode != 0)
+ return 1;
+
+ return data.different;
}
/* This is a subroutine of RCS_cmp_file. It is passed to
@@ -5083,12 +4139,12 @@ RCS_settag (rcs, tag, rev)
Node *node;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* FIXME: This check should be moved to RCS_check_tag. There is no
reason for it to be here. */
- if (STREQ (tag, TAG_BASE)
- || STREQ (tag, TAG_HEAD))
+ if (strcmp (tag, TAG_BASE) == 0
+ || strcmp (tag, TAG_HEAD) == 0)
{
/* Print the name of the tag might be considered redundant
with the caller, which also prints it. Perhaps this helps
@@ -5142,7 +4198,7 @@ RCS_deltag (rcs, tag)
List *symbols;
Node *node;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
symbols = RCS_symbols (rcs);
if (symbols == NULL)
@@ -5165,14 +4221,11 @@ RCS_setbranch (rcs, rev)
const char *rev;
{
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
-
- if (rev && ! *rev)
- rev = NULL;
+ RCS_reparsercsfile (rcs, NULL);
if (rev == NULL && rcs->branch == NULL)
return 0;
- if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch))
+ if (rev != NULL && rcs->branch != NULL && strcmp (rev, rcs->branch) == 0)
return 0;
if (rcs->branch != NULL)
@@ -5202,7 +4255,7 @@ RCS_lock (rcs, rev, lock_quiet)
char *xrev = NULL;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
locks = RCS_getlocks (rcs);
if (locks == NULL)
@@ -5246,7 +4299,7 @@ RCS_lock (rcs, rev, lock_quiet)
p = findnode (locks, xrev);
if (p != NULL)
{
- if (STREQ (p->data, user))
+ if (strcmp (p->data, user) == 0)
{
/* We already own the lock on this revision, so do nothing. */
free (xrev);
@@ -5298,7 +4351,7 @@ RCS_unlock (rcs, rev, unlock_quiet)
user = getcaller();
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
/* If rev is NULL, unlock the latest revision (first in
rcs->locks) held by the caller. */
@@ -5325,7 +4378,7 @@ RCS_unlock (rcs, rev, unlock_quiet)
lock = NULL;
for (p = locks->list->next; p != locks->list; p = p->next)
{
- if (STREQ (p->data, user))
+ if (strcmp (p->data, user) == 0)
{
if (lock != NULL)
{
@@ -5364,7 +4417,7 @@ RCS_unlock (rcs, rev, unlock_quiet)
return 0;
}
- if (! STREQ (lock->data, user))
+ if (strcmp (lock->data, user) != 0)
{
/* If the revision is locked by someone else, notify
them. Note that this shouldn't ever happen if RCS_unlock
@@ -5400,7 +4453,7 @@ RCS_addaccess (rcs, user)
char *access, *a;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->access == NULL)
rcs->access = xstrdup (user);
@@ -5409,7 +4462,7 @@ RCS_addaccess (rcs, user)
access = xstrdup (rcs->access);
for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " "))
{
- if (STREQ (a, user))
+ if (strcmp (a, user) == 0)
{
free (access);
return;
@@ -5433,7 +4486,7 @@ RCS_delaccess (rcs, user)
int ulen;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->access == NULL)
return;
@@ -5464,7 +4517,7 @@ RCS_getaccess (rcs)
RCSNode *rcs;
{
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
+ RCS_reparsercsfile (rcs, NULL);
return rcs->access;
}
@@ -5480,7 +4533,7 @@ findtag (node, arg)
{
char *rev = (char *)arg;
- if (STREQ (node->data, rev))
+ if (strcmp (node->data, rev) == 0)
return 1;
else
return 0;
@@ -5573,7 +4626,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
{
/* A range consisting of a branch number means the latest revision
on that branch. */
- if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2))
+ if (RCS_isbranch (rcs, rev1) && strcmp (rev1, rev2) == 0)
rev1 = rev2 = RCS_getbranch (rcs, rev1, 0);
else
{
@@ -5664,12 +4717,12 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
*bp = '.';
}
}
- else if (! STREQ (rev1, branchpoint))
+ else if (strcmp (rev1, branchpoint) != 0)
{
/* Walk deltas from BRANCHPOINT on, looking for REV1. */
nodep = findnode (rcs->versions, branchpoint);
revp = (RCSVers *) nodep->data;
- while (revp->next != NULL && ! STREQ (revp->next, rev1))
+ while (revp->next != NULL && strcmp (revp->next, rev1) != 0)
{
revp = (RCSVers *) nodep->data;
nodep = findnode (rcs->versions, revp->next);
@@ -5718,7 +4771,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
revp = (RCSVers *) nodep->data;
if (rev2 != NULL)
- found = STREQ (revp->version, rev2);
+ found = (strcmp (revp->version, rev2) == 0);
next = revp->next;
if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL)
@@ -5815,6 +4868,13 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
if (status > 0)
goto delrev_done;
+ else if (status < 0)
+ {
+ error (0, errno,
+ "cannot check out revision %s of %s", after, rcs->path);
+ goto delrev_done;
+ }
+
if (before == NULL)
{
/* We are deleting revisions from the head of the tree,
@@ -5842,6 +4902,12 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
(RCSCHECKOUTPROC)0, NULL);
if (status > 0)
goto delrev_done;
+ else if (status < 0)
+ {
+ error (0, errno, "cannot check out revision %s of %s",
+ before, rcs->path);
+ goto delrev_done;
+ }
outfile = cvs_temp_name();
status = diff_exec (beforefile, afterfile, "-n", outfile);
@@ -5886,7 +4952,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
outdated. (FIXME: would it be safe to use the `dead' field for
this? Doubtful.) */
for (next = rev1;
- next != NULL && (after == NULL || ! STREQ (next, after));
+ next != NULL && (after == NULL || strcmp (next, after) != 0);
next = revp->next)
{
nodep = findnode (rcs->versions, next);
@@ -5911,13 +4977,13 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
/* beforep's ->next field already should be equal to after,
which I think is always NULL in this case. */
;
- else if (STREQ (rev1, branchpoint))
+ else if (strcmp (rev1, branchpoint) == 0)
{
nodep = findnode (rcs->versions, before);
revp = (RCSVers *) nodep->data;
nodep = revp->branches->list->next;
while (nodep != revp->branches->list &&
- ! STREQ (nodep->key, rev1))
+ strcmp (nodep->key, rev1) != 0)
nodep = nodep->next;
assert (nodep != revp->branches->list);
if (after == NULL)
@@ -6437,10 +5503,9 @@ rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen)
On error, give a fatal error. */
static void
-RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
+RCS_deltas (rcs, fp, version, op, text, len, log, loglen)
RCSNode *rcs;
FILE *fp;
- struct rcsbuffer *rcsbuf;
char *version;
enum rcs_delta_op op;
char **text;
@@ -6448,7 +5513,6 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
char **log;
size_t *loglen;
{
- struct rcsbuffer rcsbuf_local;
char *branchversion;
char *cpversion;
char *key;
@@ -6458,6 +5522,7 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
RCSVers *prev_vers;
RCSVers *trunk_vers;
char *next;
+ int n;
int ishead, isnext, isversion, onbranch;
Node *node;
struct linevector headlines;
@@ -6467,8 +5532,11 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
if (fp == NULL)
{
- rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local);
- rcsbuf = &rcsbuf_local;
+ fp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
+ if (fp == NULL)
+ error (1, 0, "unable to reopen `%s'", rcs->path);
+ if (fseek (fp, rcs->delta_pos, SEEK_SET) != 0)
+ error (1, 0, "cannot fseek RCS file");
}
ishead = 1;
@@ -6495,10 +5563,9 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
*cpversion = '\0';
do {
- if (! rcsbuf_getrevnum (rcsbuf, &key))
- error (1, 0, "unexpected EOF reading RCS file %s", rcs->path);
+ getrcsrev (fp, &key);
- if (next != NULL && ! STREQ (next, key))
+ if (next != NULL && strcmp (next, key) != 0)
{
/* This is not the next version we need. It is a branch
version which we want to ignore. */
@@ -6523,30 +5590,27 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
next = vers->next;
/* Compare key and trunkversion now, because key points to
- storage controlled by rcsbuf_getkey. */
- if (STREQ (branchversion, key))
+ storage controlled by getrcskey. */
+ if (strcmp (branchversion, key) == 0)
isversion = 1;
else
isversion = 0;
}
- while (1)
+ while ((n = getrcskey (fp, &key, &value, &vallen)) >= 0)
{
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- error (1, 0, "%s does not appear to be a valid rcs file",
- rcs->path);
-
if (log != NULL
&& isversion
- && STREQ (key, "log")
- && STREQ (branchversion, version))
+ && strcmp (key, "log") == 0
+ && strcmp (branchversion, version) == 0)
{
- *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen);
+ *log = xmalloc (vallen);
+ memcpy (*log, value, vallen);
+ *loglen = vallen;
}
- if (STREQ (key, "text"))
+ if (strcmp (key, "text") == 0)
{
- rcsbuf_valpolish (rcsbuf, value, 0, &vallen);
if (ishead)
{
if (! linevector_add (&curlines, value, vallen, NULL, 0))
@@ -6565,12 +5629,14 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
break;
}
}
+ if (n < 0)
+ goto l_error;
if (isversion)
{
/* This is either the version we want, or it is the
branchpoint to the version we want. */
- if (STREQ (branchversion, version))
+ if (strcmp (branchversion, version) == 0)
{
/* This is the version we want. */
linevector_copy (&headlines, &curlines);
@@ -6650,8 +5716,9 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
} while (next != NULL);
free (branchversion);
-
- rcsbuf_cache (rcs, rcsbuf);
+
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", rcs->path);
if (! foundhead)
error (1, 0, "could not find desired version %s in %s",
@@ -6755,148 +5822,125 @@ RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen)
linevector_free (&trunklines);
return;
+
+ l_error:
+ if (ferror (fp))
+ error (1, errno, "cannot read %s", rcs->path);
+ else
+ error (1, 0, "%s does not appear to be a valid rcs file",
+ rcs->path);
}
-/* Read the information for a single delta from the RCS buffer RCSBUF,
- whose name is RCSFILE. *KEYP and *VALP are either NULL, or the
- first key/value pair to read, as set by rcsbuf_getkey. Return NULL
- if there are no more deltas. Store the key/value pair which
- terminated the read in *KEYP and *VALP. */
-
static RCSVers *
-getdelta (rcsbuf, rcsfile, keyp, valp)
- struct rcsbuffer *rcsbuf;
+getdelta (fp, rcsfile)
+ FILE *fp;
char *rcsfile;
- char **keyp;
- char **valp;
{
RCSVers *vnode;
char *key, *value, *cp;
+ long fpos;
Node *kv;
- /* Get revision number if it wasn't passed in. This uses
- rcsbuf_getkey because it doesn't croak when encountering
- unexpected input. As a result, we have to play unholy games
- with `key' and `value'. */
- if (*keyp != NULL)
- {
- key = *keyp;
- value = *valp;
- }
- else
- {
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- error (1, 0, "%s: unexpected EOF", rcsfile);
- }
+ vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
+ memset (vnode, 0, sizeof (RCSVers));
+
+ /* Get revision number. This uses getrcskey because it doesn't
+ croak when encountering unexpected input. As a result, we have
+ to play unholy games with `key' and `value'. */
+ fpos = ftell (fp);
+ getrcskey (fp, &key, &value, NULL);
/* Make sure that it is a revision number and not a cabbage
or something. */
for (cp = key; (isdigit (*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
- we know exactly what to expect. */
- if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0)
+ if (*cp != '\0' || strncmp (RCSDATE, value, strlen (RCSDATE)) != 0)
{
- *keyp = key;
- *valp = value;
+ (void) fseek (fp, fpos, SEEK_SET);
+ free (vnode);
return NULL;
}
-
- vnode = (RCSVers *) xmalloc (sizeof (RCSVers));
- memset (vnode, 0, sizeof (RCSVers));
-
vnode->version = xstrdup (key);
- /* Grab the value of the date from value. Note that we are not
- massaging VALUE from the string found in the RCS file. */
- cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */
+ /* grab the value of the date from value */
+ cp = value + strlen (RCSDATE);/* skip the "date" keyword */
while (whitespace (*cp)) /* take space off front of value */
cp++;
vnode->date = xstrdup (cp);
/* Get author field. */
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- {
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- }
- if (! STREQ (key, "author"))
+ (void) getrcskey (fp, &key, &value, NULL);
+ /* FIXME: should be using errno in case of ferror. */
+ if (key == NULL || strcmp (key, "author") != 0)
error (1, 0, "\
-unable to parse %s; `author' not in the expected place", rcsfile);
- vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
+unable to parse rcs file; `author' not in the expected place");
+ vnode->author = xstrdup (value);
/* Get state field. */
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- {
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- }
- if (! STREQ (key, "state"))
+ (void) getrcskey (fp, &key, &value, NULL);
+ /* FIXME: should be using errno in case of ferror. */
+ if (key == NULL || strcmp (key, "state") != 0)
error (1, 0, "\
-unable to parse %s; `state' not in the expected place", rcsfile);
- vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
- if (STREQ (value, "dead"))
+unable to parse rcs file; `state' not in the expected place");
+ vnode->state = xstrdup (value);
+ if (strcmp (value, "dead") == 0)
{
vnode->dead = 1;
}
/* Note that "branches" and "next" are in fact mandatory, according
- to doc/RCSFILES. */
+ to doc/RCSFILES. We perhaps should be giving an error if they
+ are not there. */
/* fill in the branch list (if any branches exist) */
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- {
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- }
- if (STREQ (key, RCSDESC))
+ fpos = ftell (fp);
+ (void) getrcskey (fp, &key, &value, NULL);
+ /* FIXME: should be handling various error conditions better. */
+ if (key != NULL && strcmp (key, RCSDESC) == 0)
{
- *keyp = key;
- *valp = value;
- /* Probably could/should be a fatal error. */
- error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile);
+ (void) fseek (fp, fpos, SEEK_SET);
return vnode;
}
if (value != (char *) NULL)
{
vnode->branches = getlist ();
- /* Note that we are not massaging VALUE from the string found
- in the RCS file. */
do_branches (vnode->branches, value);
}
/* fill in the next field if there is a next revision */
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ fpos = ftell (fp);
+ (void) getrcskey (fp, &key, &value, NULL);
+ /* FIXME: should be handling various error conditions better. */
+ if (key != NULL && strcmp (key, RCSDESC) == 0)
{
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- }
- if (STREQ (key, RCSDESC))
- {
- *keyp = key;
- *valp = value;
- /* Probably could/should be a fatal error. */
- error (0, 0, "warning: 'next' keyword missing from %s", rcsfile);
+ (void) fseek (fp, fpos, SEEK_SET);
return vnode;
}
if (value != (char *) NULL)
- vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
+ vnode->next = xstrdup (value);
/*
* XXX - this is where we put the symbolic link stuff???
* (into newphrases in the deltas).
*/
+ /* FIXME: Does not correctly handle errors, e.g. from stdio. */
while (1)
{
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
+ fpos = ftell (fp);
+ if (getrcskey (fp, &key, &value, NULL) < 0)
+ break;
- if (STREQ (key, RCSDESC))
+ assert (key != NULL);
+
+ if (strcmp (key, RCSDESC) == 0)
break;
/* Enable use of repositories created by certain obsolete
versions of CVS. This code should remain indefinately;
there is no procedure for converting old repositories, and
checking for it is harmless. */
- if (STREQ (key, RCSDEAD))
+ if (strcmp(key, RCSDEAD) == 0)
{
vnode->dead = 1;
if (vnode->state != NULL)
@@ -6907,9 +5951,6 @@ unable to parse %s; `state' not in the expected place", rcsfile);
/* if we have a new revision number, we're done with this delta */
for (cp = key; (isdigit (*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 we know exactly what to expect. */
if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0)
break;
@@ -6920,7 +5961,7 @@ unable to parse %s; `state' not in the expected place", rcsfile);
kv = getnode ();
kv->type = RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = xstrdup (value);
if (addnode (vnode->other_delta, kv) != 0)
{
/* Complaining about duplicate keys in newphrases seems
@@ -6932,11 +5973,11 @@ unable to parse %s; `state' not in the expected place", rcsfile);
key, rcsfile);
freenode (kv);
}
- }
+ }
- /* Return the key which caused us to fail back to the caller. */
- *keyp = key;
- *valp = value;
+ /* We got here because we read beyond the end of a delta. Seek back
+ to the beginning of the erroneous read. */
+ (void) fseek (fp, fpos, SEEK_SET);
return vnode;
}
@@ -6957,21 +5998,25 @@ freedeltatext (d)
}
static Deltatext *
-RCS_getdeltatext (rcs, fp, rcsbuf)
+RCS_getdeltatext (rcs, fp)
RCSNode *rcs;
FILE *fp;
- struct rcsbuffer *rcsbuf;
{
char *num;
char *key, *value;
+ int n;
Node *p;
Deltatext *d;
+ size_t textlen;
/* Get the revision number. */
- if (! rcsbuf_getrevnum (rcsbuf, &num))
+ n = getrevnum (fp, &num);
+ if (ferror (fp))
+ error (1, errno, "%s: cannot read", rcs->path);
+ if (n == EOF)
{
- /* If num == NULL, it means we reached EOF naturally. That's
- fine. */
+ /* If n == EOF and num == NULL, it means we reached EOF
+ naturally. That's fine. */
if (num == NULL)
return NULL;
else
@@ -6987,36 +6032,36 @@ RCS_getdeltatext (rcs, fp, rcsbuf)
d->version = xstrdup (num);
/* Get the log message. */
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
+ if (getrcskey (fp, &key, &value, NULL) < 0)
error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
- if (! STREQ (key, "log"))
+ if (strcmp (key, "log") != 0)
error (1, 0, "%s, delta %s: expected `log', got `%s'",
rcs->path, num, key);
- d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL);
+ d->log = xstrdup (value);
/* Get random newphrases. */
d->other = getlist();
- while (1)
+ for (n = getrcskey (fp, &key, &value, &textlen);
+ n >= 0 && strcmp (key, "text") != 0;
+ n = getrcskey (fp, &key, &value, &textlen))
{
- if (! rcsbuf_getkey (rcsbuf, &key, &value))
- error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
-
- if (STREQ (key, "text"))
- break;
-
p = getnode();
p->type = RCSFIELD;
p->key = xstrdup (key);
- p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
+ p->data = xstrdup (value);
if (addnode (d->other, p) < 0)
{
error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
rcs->path, num, key);
}
}
+ if (n < 0)
+ error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num);
/* Get the change text. We already know that this key is `text'. */
- d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len);
+ d->text = (char *) malloc (textlen + 1);
+ d->len = textlen;
+ memcpy (d->text, value, textlen);
return d;
}
@@ -7033,23 +6078,11 @@ RCS_getdeltatext (rcs, fp, rcsbuf)
not get corrupted. */
static int
-putsymbol_proc (symnode, fparg)
+putsymbol_proc (symnode, fp)
Node *symnode;
- void *fparg;
+ void *fp;
{
- FILE *fp = (FILE *) fparg;
-
- /* A fiddly optimization: this code used to just call fprintf, but
- in an old repository with hundreds of tags this can get called
- hundreds of thousands of times when doing a cvs tag. Since
- tagging is a relatively common operation, and using putc and
- fputs is just as comprehensible, the change is worthwhile. */
- putc ('\n', fp);
- putc ('\t', fp);
- fputs (symnode->key, fp);
- putc (':', fp);
- fputs (symnode->data, fp);
- return 0;
+ return fprintf ((FILE *) fp, "\n\t%s:%s", symnode->key, symnode->data);
}
static int putlock_proc PROTO ((Node *, void *));
@@ -7101,9 +6134,9 @@ putrcsfield_proc (node, vfp)
/* desc, log and text fields should not be terminated with semicolon;
all other fields should be. */
- if (! STREQ (node->key, "desc") &&
- ! STREQ (node->key, "log") &&
- ! STREQ (node->key, "text"))
+ if (strcmp (node->key, "desc") != 0 &&
+ strcmp (node->key, "log") != 0 &&
+ strcmp (node->key, "text") != 0)
{
putc (';', fp);
}
@@ -7133,15 +6166,7 @@ RCS_putadmin (rcs, fp)
fputs (";\n", fp);
fputs (RCSSYMBOLS, fp);
- /* If we haven't had to convert the symbols to a list yet, don't
- force a conversion now; just write out the string. */
- if (rcs->symbols == NULL && rcs->symbols_data != NULL)
- {
- fputs ("\n\t", fp);
- fputs (rcs->symbols_data, fp);
- }
- else
- walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp);
+ walklist (RCS_symbols(rcs), putsymbol_proc, (void *) fp);
fputs (";\n", fp);
fputs ("locks", fp);
@@ -7159,7 +6184,7 @@ RCS_putadmin (rcs, fp)
expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp);
fputs ("@;\n", fp);
}
- if (rcs->expand && ! STREQ (rcs->expand, "kv"))
+ if (rcs->expand && strcmp (rcs->expand, "kv") != 0)
fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand);
walklist (rcs->other, putrcsfield_proc, (void *) fp);
@@ -7281,68 +6306,40 @@ putdeltatext (fp, d)
increasing order.) */
static void
-RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
+RCS_copydeltas (rcs, fin, fout, newdtext, insertpt)
RCSNode *rcs;
FILE *fin;
- struct rcsbuffer *rcsbufin;
FILE *fout;
Deltatext *newdtext;
char *insertpt;
{
- int actions;
+ Deltatext *dtext;
RCSVers *dadmin;
Node *np;
int insertbefore, found;
- char *bufrest;
- int nls;
- size_t buflen;
- char buf[8192];
- int got;
-
- /* Count the number of versions for which we have to do some
- special operation. */
- actions = walklist (rcs->versions, count_delta_actions, (void *) NULL);
/* Make a note of whether NEWDTEXT should be inserted
before or after its INSERTPT. */
insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1);
- while (actions != 0 || newdtext != NULL)
+ found = 0;
+ while ((dtext = RCS_getdeltatext (rcs, fin)) != NULL)
{
- Deltatext *dtext;
-
- dtext = RCS_getdeltatext (rcs, fin, rcsbufin);
-
- /* We shouldn't hit EOF here, because that would imply that
- some action was not taken, or that we could not insert
- NEWDTEXT. */
- if (dtext == NULL)
- error (1, 0, "internal error: EOF too early in RCS_copydeltas");
-
- found = (insertpt != NULL && STREQ (dtext->version, insertpt));
+ found = (insertpt != NULL && strcmp (dtext->version, insertpt) == 0);
if (found && insertbefore)
- {
putdeltatext (fout, newdtext);
- newdtext = NULL;
- insertpt = NULL;
- }
np = findnode (rcs->versions, dtext->version);
dadmin = (RCSVers *) np->data;
/* If this revision has been outdated, just skip it. */
if (dadmin->outdated)
- {
- --actions;
continue;
- }
/* Update the change text for this delta. New change text
data may come from cvs admin -m, cvs admin -o, or cvs ci. */
if (dadmin->text != NULL)
{
- if (dadmin->text->log != NULL || dadmin->text->text != NULL)
- --actions;
if (dadmin->text->log != NULL)
{
free (dtext->log);
@@ -7361,92 +6358,9 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
freedeltatext (dtext);
if (found && !insertbefore)
- {
putdeltatext (fout, newdtext);
- newdtext = NULL;
- insertpt = NULL;
- }
- }
-
- /* Copy the rest of the file directly, without bothering to
- interpret it. The caller will handle error checking by calling
- ferror.
-
- We just wrote a newline to the file, either in putdeltatext or
- in the caller. However, we may not have read the corresponding
- newline from the file, because rcsbuf_getkey returns as soon as
- it finds the end of the '@' string for the desc or text key.
- Therefore, we may read three newlines when we should really
- only write two, and we check for that case here. This is not
- an semantically important issue; we only do it to make our RCS
- files look traditional. */
-
- nls = 3;
-
- rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen);
- if (buflen > 0)
- {
- if (bufrest[0] != '\n'
- || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0)
- {
- nls = 0;
- }
- else
- {
- if (buflen < 3)
- nls -= buflen;
- else
- {
- ++bufrest;
- --buflen;
- nls = 0;
- }
- }
-
- fwrite (bufrest, 1, buflen, fout);
- }
-
- while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
- {
- if (nls > 0
- && got >= nls
- && buf[0] == '\n'
- && strncmp (buf, "\n\n\n", nls) == 0)
- {
- fwrite (buf + 1, 1, got - 1, fout);
- }
- else
- {
- fwrite (buf, 1, got, fout);
- }
-
- nls = 0;
}
-}
-
-/* A helper procedure for RCS_copydeltas. This is called via walklist
- to count the number of RCS revisions for which some special action
- is required. */
-
-int
-count_delta_actions (np, ignore)
- Node *np;
- void *ignore;
-{
- RCSVers *dadmin;
-
- dadmin = (RCSVers *) np->data;
-
- if (dadmin->outdated)
- return 1;
-
- if (dadmin->text != NULL
- && (dadmin->text->log != NULL || dadmin->text->text != NULL))
- {
- return 1;
- }
-
- return 0;
+ putc ('\n', fout);
}
/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
@@ -7554,12 +6468,6 @@ rcs_internal_unlockfile (fp, rcsfile)
corrupting the repository. */
if (ferror (fp))
- /* The only case in which using errno here would be meaningful
- is if we happen to have left errno unmolested since the call
- which produced the error (e.g. fprintf). That is pretty
- 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);
if (fclose (fp) == EOF)
error (1, errno, "error closing lock file %s", lockfile);
@@ -7603,7 +6511,6 @@ RCS_rewrite (rcs, newdtext, insertpt)
char *insertpt;
{
FILE *fin, *fout;
- struct rcsbuffer rcsbufin;
if (noexec)
return;
@@ -7615,7 +6522,10 @@ RCS_rewrite (rcs, newdtext, insertpt)
RCS_putdesc (rcs, fout);
/* Open the original RCS file and seek to the first delta text. */
- rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin);
+ if ((fin = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ)) == NULL)
+ error (1, errno, "cannot open RCS file `%s' for reading", rcs->path);
+ if (fseek (fin, rcs->delta_pos, SEEK_SET) < 0)
+ error (1, errno, "cannot fseek in RCS file %s", rcs->path);
/* Update delta_pos to the current position in the output file.
Do NOT move these statements: they must be done after fin has
@@ -7625,19 +6535,10 @@ RCS_rewrite (rcs, newdtext, insertpt)
if (rcs->delta_pos == -1)
error (1, errno, "cannot ftell in RCS file %s", rcs->path);
- RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt);
+ RCS_copydeltas (rcs, fin, fout, newdtext, insertpt);
- /* We don't want to call rcsbuf_cache here, since we're about to
- delete the file. */
- rcsbuf_close (&rcsbufin);
if (ferror (fin))
- /* The only case in which using errno here would be meaningful
- is if we happen to have left errno unmolested since the call
- which produced the error (e.g. fread). That is pretty
- fragile even if it happens to sometimes be true. The real
- solution is to make sure that all the code which reads
- from fin checks for errors itself (some does, some doesn't). */
- error (0, 0, "warning: when closing RCS file `%s'", rcs->path);
+ error (0, errno, "warning: when closing RCS file `%s'", rcs->path);
if (fclose (fin) < 0)
error (0, errno, "warning: closing RCS file `%s'", rcs->path);
@@ -7662,18 +6563,13 @@ annotate_fileproc (callerdat, finfo)
struct file_info *finfo;
{
FILE *fp = NULL;
- struct rcsbuffer *rcsbufp = NULL;
- struct rcsbuffer rcsbuf;
char *version;
if (finfo->rcs == NULL)
return (1);
if (finfo->rcs->flags & PARTIAL)
- {
- RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf);
- rcsbufp = &rcsbuf;
- }
+ RCS_reparsercsfile (finfo->rcs, &fp);
version = RCS_getversion (finfo->rcs, tag, date, force_tag_match,
(int *) NULL);
@@ -7686,7 +6582,7 @@ 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,
+ RCS_deltas (finfo->rcs, fp, version, RCS_ANNOTATE, (char **) NULL,
(size_t) NULL, (char **) NULL, (size_t *) NULL);
free (version);
return 0;
@@ -7826,3 +6722,104 @@ make_file_label (path, rev, rcs)
return label;
}
+void
+RCS_setlocalid (arg)
+ const char *arg;
+{
+ char *copy, *next, *key;
+
+ copy = xstrdup(arg);
+ next = copy;
+ key = strtok(next, "=");
+
+ keywords[KEYWORD_LOCALID].string = xstrdup(key);
+ keywords[KEYWORD_LOCALID].len = strlen(key);
+ keywords[KEYWORD_LOCALID].expandit = 1;
+
+ /* options? */
+ while (key = strtok(NULL, ",")) {
+ if (!strcmp(key, keywords[KEYWORD_ID].string))
+ keyword_local = KEYWORD_ID;
+ else if (!strcmp(key, keywords[KEYWORD_HEADER].string))
+ keyword_local = KEYWORD_HEADER;
+ else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string))
+ keyword_local = KEYWORD_CVSHEADER;
+ else
+ error(1, 0, "Unknown LocalId mode: %s", key);
+ }
+ free(copy);
+}
+
+void
+RCS_setincexc (arg)
+ const char *arg;
+{
+ char *key;
+ char *copy, *next;
+ int include = 0;
+ struct rcs_keyword *keyword;
+
+ copy = xstrdup(arg);
+ next = copy;
+ switch (*next++) {
+ case 'e':
+ include = 0;
+ break;
+ case 'i':
+ include = 1;
+ break;
+ default:
+ free(copy);
+ return;
+ }
+
+ if (include)
+ for (keyword = keywords; keyword->string != NULL; keyword++)
+ {
+ keyword->expandit = 0;
+ }
+
+ key = strtok(next, ",");
+ while (key) {
+ for (keyword = keywords; keyword->string != NULL; keyword++) {
+ if (strcmp (keyword->string, key) == 0)
+ keyword->expandit = include;
+ }
+ key = strtok(NULL, ",");
+ }
+ free(copy);
+ return;
+}
+
+#define ATTIC "/" CVSATTIC
+static char *
+getfullCVSname(CVSname, pathstore)
+ char *CVSname, **pathstore;
+{
+ if (CVSroot_directory) {
+ int rootlen;
+ char *c = NULL;
+ int alen = sizeof(ATTIC) - 1;
+
+ *pathstore = xstrdup(CVSname);
+ if ((c = strrchr(*pathstore, '/')) != NULL) {
+ if (c - *pathstore >= alen) {
+ if (!strncmp(c - alen, ATTIC, alen)) {
+ while (*c != '\0') {
+ *(c - alen) = *c;
+ c++;
+ }
+ *(c - alen) = '\0';
+ }
+ }
+ }
+
+ rootlen = strlen(CVSroot_directory);
+ if (!strncmp(*pathstore, CVSroot_directory, rootlen) &&
+ (*pathstore)[rootlen] == '/')
+ CVSname = (*pathstore + rootlen + 1);
+ else
+ CVSname = (*pathstore);
+ }
+ return CVSname;
+}
diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h
index 400d1a0..60c4f3f 100644
--- a/contrib/cvs/src/rcs.h
+++ b/contrib/cvs/src/rcs.h
@@ -169,17 +169,13 @@ typedef struct rcsversnode RCSVers;
/* The type of a function passed to RCS_checkout. */
typedef void (*RCSCHECKOUTPROC) PROTO ((void *, const char *, size_t));
-#ifdef __STDC__
-struct rcsbuffer;
-#endif
-
/*
* exported interfaces
*/
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 *));
+void RCS_reparsercsfile PROTO((RCSNode *, FILE **));
char *RCS_check_kflag PROTO((const char *arg));
char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match));
@@ -219,9 +215,10 @@ char *RCS_getaccess PROTO ((RCSNode *));
void RCS_rewrite PROTO ((RCSNode *, Deltatext *, char *));
int rcs_change_text PROTO ((const char *, char *, size_t, const char *,
size_t, char **, size_t *));
-char *make_file_label PROTO ((char *, char *, RCSNode *));
+void RCS_setincexc PROTO ((const char *arg));
-extern int preserve_perms;
+void RCS_setlocalid PROTO ((const char *arg));
+char *make_file_label PROTO ((char *, char *, RCSNode *));
/* From import.c. */
extern int add_rcs_file PROTO ((char *, char *, char *, char *, char *,
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index 3086b57..ea638b3 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -135,10 +135,29 @@ call_diff_add_arg (s)
/* diff_run is imported from libdiff.a. */
extern int diff_run PROTO ((int argc, char **argv, char *out));
+#if defined(__FreeBSD__) && defined(SERVER_SUPPORT)
+/* Some 4.4BSD Glue to hack stdout and stderr to call cvs_output */
+
+static
+int writehook(cookie, buf, len)
+ void *cookie; /* really [struct bufcookie *] */
+ const char *buf; /* characters to copy */
+ int len; /* length to copy */
+{
+ void (*fn)(const char *, size_t) =
+ (void (*)(const char *, size_t))cookie;
+
+ (*fn)(buf, len);
+
+ return 0;
+}
+#endif
+
static int
call_diff (out)
char *out;
{
+#if !defined(__FreeBSD__) || !defined(SERVER_SUPPORT)
/* Try to keep the out-of-order bugs at bay (protocol_pipe for cvs_output
with has "Index: foo" and such; stdout and/or stderr for diff's
output). I think the only reason that this used to not be such
@@ -148,12 +167,58 @@ call_diff (out)
The real fix, of course, will be to have the diff library do all
its output through callbacks (which CVS will supply as cvs_output
and cvs_outerr). */
- sleep (1);
+#if defined(SERVER_SUPPORT)
+ /* only do this on the server if it's in protocol mode */
+ if (error_use_protocol || server_active)
+ sleep (1);
+#endif
if (out == RUN_TTY)
return diff_run (call_diff_argc, call_diff_argv, NULL);
else
return diff_run (call_diff_argc, call_diff_argv, out);
+#else
+ /* avoid that sleep "by any means necessary".. */
+ void *save_out, *save_err;
+ void *cookie_out, *cookie_err;
+ int rv;
+
+ /* XXX: the cvs_out*() funcs call the buf routines which can call
+ cvs_outerr(), and also calls malloc which might printf something.
+ FreeBSD's malloc doesn't do this at the moment, so recursion should
+ be avoided. No guarantees for other BSD4.4-Lite* systems though. */
+ if (error_use_protocol || server_active) {
+ save_out = stdout->_write;
+ save_err = stderr->_write;
+ cookie_out = stdout->_cookie;
+ cookie_err = stderr->_cookie;
+
+ fflush(stdout);
+ fflush(stderr);
+
+ stdout->_write = writehook;
+ stderr->_write = writehook;
+ stdout->_cookie = cvs_output;
+ stderr->_cookie = cvs_outerr;
+ }
+
+ if (out == RUN_TTY)
+ rv = diff_run (call_diff_argc, call_diff_argv, NULL);
+ else
+ rv = diff_run (call_diff_argc, call_diff_argv, out);
+
+ if (error_use_protocol || server_active) {
+ fflush(stdout);
+ fflush(stderr);
+
+ stdout->_write = save_out;
+ stderr->_write = save_err;
+ stdout->_cookie = cookie_out;
+ stderr->_cookie = cookie_err;
+ }
+
+ return (rv);
+#endif
}
extern int diff3_run PROTO ((int argc, char **argv, char *out));
@@ -162,6 +227,7 @@ static int
call_diff3 (out)
char *out;
{
+#if !defined(__FreeBSD__) || !defined(SERVER_SUPPORT)
/* Try to keep the out-of-order bugs at bay (protocol_pipe for cvs_output
with has "Index: foo" and such; stdout and/or stderr for diff's
output). I think the only reason that this used to not be such
@@ -171,12 +237,58 @@ call_diff3 (out)
The real fix, of course, will be to have the diff library do all
its output through callbacks (which CVS will supply as cvs_output
and cvs_outerr). */
- sleep (1);
+#if defined(SERVER_SUPPORT)
+ /* only do this on the server if it's in protocol mode */
+ if (error_use_protocol || server_active)
+ sleep (1);
+#endif
if (out == RUN_TTY)
return diff3_run (call_diff_argc, call_diff_argv, NULL);
else
return diff3_run (call_diff_argc, call_diff_argv, out);
+#else
+ /* avoid that sleep "by any means necessary".. */
+ void *save_out, *save_err;
+ void *cookie_out, *cookie_err;
+ int rv;
+
+ /* XXX: the cvs_out*() funcs call the buf routines which can call
+ cvs_outerr(), and also calls malloc which might printf something.
+ FreeBSD's malloc doesn't do this at the moment, so recursion should
+ be avoided. No guarantees for other BSD4.4-Lite* systems though. */
+ if (error_use_protocol || server_active) {
+ save_out = stdout->_write;
+ save_err = stderr->_write;
+ cookie_out = stdout->_cookie;
+ cookie_err = stderr->_cookie;
+
+ fflush(stdout);
+ fflush(stderr);
+
+ stdout->_write = writehook;
+ stderr->_write = writehook;
+ stdout->_cookie = cvs_output;
+ stderr->_cookie = cvs_outerr;
+ }
+
+ if (out == RUN_TTY)
+ rv = diff3_run (call_diff_argc, call_diff_argv, NULL);
+ else
+ rv = diff3_run (call_diff_argc, call_diff_argv, out);
+
+ if (error_use_protocol || server_active) {
+ fflush(stdout);
+ fflush(stderr);
+
+ stdout->_write = save_out;
+ stderr->_write = save_err;
+ stdout->_cookie = cookie_out;
+ stderr->_cookie = cookie_err;
+ }
+
+ return (rv);
+#endif
}
@@ -487,42 +599,7 @@ diff_exec (file1, file2, options, out)
char *options;
char *out;
{
- char *args;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* If either file1 or file2 are special files, pretend they are
- /dev/null. Reason: suppose a file that represents a block
- special device in one revision becomes a regular file. CVS
- must find the `difference' between these files, but a special
- file contains no data useful for calculating this metric. The
- safe thing to do is to treat the special file as an empty file,
- thus recording the regular file's full contents. Doing so will
- create extremely large deltas at the point of transition
- between device files and regular files, but this is probably
- very rare anyway.
-
- There may be ways around this, but I think they are fraught
- with danger. -twp */
-
- if (preserve_perms &&
- strcmp (file1, DEVNULL) != 0 &&
- strcmp (file2, DEVNULL) != 0)
- {
- struct stat sb1, sb2;
-
- if (CVS_LSTAT (file1, &sb1) < 0)
- error (1, errno, "cannot get file information for %s", file1);
- if (CVS_LSTAT (file2, &sb2) < 0)
- error (1, errno, "cannot get file information for %s", file2);
-
- if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
- file1 = DEVNULL;
- if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
- file2 = DEVNULL;
- }
-#endif
-
- args = xmalloc (strlen (options) + 10);
+ char *args = xmalloc (strlen (options) + 10);
/* The first word in this string is used only for error reporting. */
sprintf (args, "diff %s", options);
call_diff_setup (args);
@@ -542,31 +619,7 @@ diff_execv (file1, file2, label1, label2, options, out)
char *options;
char *out;
{
- char *args;
-
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* Pretend that special files are /dev/null for purposes of making
- diffs. See comments in diff_exec. */
-
- if (preserve_perms &&
- strcmp (file1, DEVNULL) != 0 &&
- strcmp (file2, DEVNULL) != 0)
- {
- struct stat sb1, sb2;
-
- if (CVS_LSTAT (file1, &sb1) < 0)
- error (1, errno, "cannot get file information for %s", file1);
- if (CVS_LSTAT (file2, &sb2) < 0)
- error (1, errno, "cannot get file information for %s", file2);
-
- if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
- file1 = DEVNULL;
- if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
- file2 = DEVNULL;
- }
-#endif
-
- args = xmalloc (strlen (options) + 10);
+ char *args = xmalloc (strlen (options) + 10);
/* The first word in this string is used only for error reporting. */
/* I guess we are pretty confident that options starts with a space. */
sprintf (args, "diff%s", options);
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c
index 3896bc7..25b5b71 100644
--- a/contrib/cvs/src/recurse.c
+++ b/contrib/cvs/src/recurse.c
@@ -448,7 +448,7 @@ do_recursion (frame)
{
/* we will process files, so pre-parse entries */
if (frame->which & W_LOCAL)
- entries = Entries_Open (frame->aflag, NULL);
+ entries = Entries_Open (frame->aflag);
}
}
@@ -790,6 +790,7 @@ but CVS uses %s for its own purposes; skipping %s directory",
repository = srepository;
}
+#if 0
/* Put back update_dir. I think this is the same as just setting
update_dir back to saved_update_dir, but there are a few cases I'm
not sure about (in particular, if DIR is "." and update_dir is
@@ -800,6 +801,14 @@ but CVS uses %s for its own purposes; skipping %s directory",
else
update_dir[0] = '\0';
free (saved_update_dir);
+#else
+ /* The above code is cactus!!! - it doesn't handle descending
+ multiple directories at once! ie: it recurses down several
+ dirs and then back up one. This breaks 'diff', 'update',
+ 'commit', etc. */
+ free (update_dir);
+ update_dir = saved_update_dir;
+#endif
return (err);
}
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index a005646..e820388 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -584,6 +584,9 @@ serve_root (arg)
nothing. But for rsh, we need to do it now. */
parse_config (CVSroot_directory);
+ /* Now is a good time to read CVSROOT/options too. */
+ parseopts(CVSroot_directory);
+
path = xmalloc (strlen (CVSroot_directory)
+ sizeof (CVSROOTADM)
+ sizeof (CVSROOTADM_HISTORY)
@@ -599,7 +602,7 @@ serve_root (arg)
}
(void) strcat (path, "/");
(void) strcat (path, CVSROOTADM_HISTORY);
- if (isfile (path) && !isaccessible (path, R_OK | W_OK))
+ if (readonlyfs == 0 && isfile (path) && !isaccessible (path, R_OK | W_OK))
{
save_errno = errno;
pending_error_text = malloc (80 + strlen (path));
@@ -1194,7 +1197,7 @@ serve_modified (arg)
}
{
- int status = change_mode (arg, mode_text, 0);
+ int status = change_mode (arg, mode_text);
free (mode_text);
if (status)
{
@@ -3355,13 +3358,12 @@ server_modtime (finfo, vers_ts)
/* See server.h for description. */
void
-server_updated (finfo, vers, updated, mode, checksum, filebuf)
+server_updated (finfo, vers, updated, file_info, checksum)
struct file_info *finfo;
Vers_TS *vers;
enum server_updated_arg4 updated;
- mode_t mode;
+ struct stat *file_info;
unsigned char *checksum;
- struct buffer *filebuf;
{
if (noexec)
{
@@ -3380,43 +3382,25 @@ server_updated (finfo, vers, updated, mode, checksum, filebuf)
if (entries_line != NULL && scratched_file == NULL)
{
FILE *f;
+ struct stat sb;
struct buffer_data *list, *last;
unsigned long size;
char size_text[80];
- if (filebuf != NULL)
- {
- size = buf_length (filebuf);
- if (mode == (mode_t) -1)
- error (1, 0, "\
-CVS server internal error: no mode in server_updated");
- }
- else
+ if ( CVS_STAT (finfo->file, &sb) < 0)
{
- struct stat sb;
-
- if ( CVS_STAT (finfo->file, &sb) < 0)
- {
- if (existence_error (errno))
- {
- /* If we have a sticky tag for a branch on which
- the file is dead, and cvs update the directory,
- it gets a T_CHECKOUT but no file. So in this
- case just forget the whole thing. */
- free (entries_line);
- entries_line = NULL;
- goto done;
- }
- error (1, errno, "reading %s", finfo->fullname);
- }
- size = sb.st_size;
- if (mode == (mode_t) -1)
+ if (existence_error (errno))
{
- /* FIXME: When we check out files the umask of the
- server (set in .bashrc if rsh is in use) affects
- what mode we send, and it shouldn't. */
- mode = sb.st_mode;
+ /*
+ * If we have a sticky tag for a branch on which the
+ * file is dead, and cvs update the directory, it gets
+ * a T_CHECKOUT but no file. So in this case just
+ * forget the whole thing. */
+ free (entries_line);
+ entries_line = NULL;
+ goto done;
}
+ error (1, errno, "reading %s", finfo->fullname);
}
if (checksum != NULL)
@@ -3485,14 +3469,21 @@ CVS server internal error: no mode in server_updated");
{
char *mode_string;
- mode_string = mode_to_string (mode);
+ /* FIXME: When we check out files the umask of the server
+ (set in .bashrc if rsh is in use) affects what mode we
+ send, and it shouldn't. */
+ if (file_info != NULL)
+ mode_string = mode_to_string (file_info->st_mode);
+ else
+ mode_string = mode_to_string (sb.st_mode);
buf_output0 (protocol, mode_string);
buf_output0 (protocol, "\n");
free (mode_string);
}
list = last = NULL;
- if (size > 0)
+ size = 0;
+ if (sb.st_size > 0)
{
/* Throughout this section we use binary mode to read the
file we are sending. The client handles any line ending
@@ -3505,19 +3496,11 @@ CVS server internal error: no mode in server_updated");
* might be computable somehow; using 100 here is just
* a first approximation.
*/
- && size > 100)
+ && sb.st_size > 100)
{
int status, fd, gzip_status;
pid_t gzip_pid;
- /* Callers must avoid passing us a buffer if
- file_gzip_level is set. We could handle this case,
- but it's not worth it since this case never arises
- with a current client and server. */
- if (filebuf != NULL)
- error (1, 0, "\
-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);
@@ -3540,14 +3523,15 @@ CVS server internal error: unhandled case in server_updated");
/* Prepending length with "z" is flag for using gzip here. */
buf_output0 (protocol, "z");
}
- else if (filebuf == NULL)
+ else
{
long status;
+ size = sb.st_size;
f = CVS_FOPEN (finfo->file, "rb");
if (f == NULL)
error (1, errno, "reading %s", finfo->fullname);
- status = buf_read_file (f, size, &list, &last);
+ status = buf_read_file (f, sb.st_size, &list, &last);
if (status == -2)
(*protocol->memory_error) (protocol);
else if (status != 0)
@@ -3561,13 +3545,7 @@ CVS server internal error: unhandled case in server_updated");
sprintf (size_text, "%lu\n", size);
buf_output0 (protocol, size_text);
- if (filebuf == NULL)
- buf_append_data (protocol, list, last);
- else
- {
- buf_append_buffer (protocol, filebuf);
- buf_free (filebuf);
- }
+ buf_append_data (protocol, list, last);
/* Note we only send a newline here if the file ended with one. */
/*
@@ -3580,7 +3558,6 @@ CVS server internal error: unhandled case in server_updated");
if ((updated == SERVER_UPDATED
|| updated == SERVER_PATCHED
|| updated == SERVER_RCS_DIFF)
- && filebuf != NULL
/* But if we are joining, we'll need the file when we call
join_file. */
&& !joining ())
@@ -5634,7 +5611,7 @@ this client does not support writing binary files to stdout");
I assume that what they are talking about can also be helped
by flushing the stream before changing the mode. */
fflush (stdout);
- oldmode = _setmode (_fileno (stdout), OPEN_BINARY);
+ oldmode = _setmode (_fileno (stdout), _O_BINARY);
if (oldmode < 0)
error (0, errno, "failed to setmode on stdout");
#endif
@@ -5649,7 +5626,7 @@ this client does not support writing binary files to stdout");
}
#ifdef USE_SETMODE_STDOUT
fflush (stdout);
- if (_setmode (_fileno (stdout), oldmode) != OPEN_BINARY)
+ if (_setmode (_fileno (stdout), oldmode) != _O_BINARY)
error (0, errno, "failed to setmode on stdout");
#endif
}
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index 2e7bda3..2aa3032 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -42,14 +42,9 @@
#include "fileattr.h"
#include "edit.h"
#include "getline.h"
-#include "buffer.h"
-#include "hardlink.h"
static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts,
- int adding, int merging, int update_server));
-#ifdef SERVER_SUPPORT
-static void checkout_to_buffer PROTO ((void *, const char *, size_t));
-#endif
+ int adding));
#ifdef SERVER_SUPPORT
static int patch_file PROTO ((struct file_info *finfo,
Vers_TS *vers_ts,
@@ -69,9 +64,6 @@ static int update_fileproc PROTO ((void *callerdat, struct file_info *));
static int update_filesdone_proc PROTO ((void *callerdat, int err,
char *repository, char *update_dir,
List *entries));
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
-static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *));
-#endif
static void write_letter PROTO ((struct file_info *finfo, int letter));
static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts));
@@ -87,10 +79,6 @@ static char *date = NULL;
static int rewrite_tag;
static int nonbranch;
-/* If we set the tag or date for a subdirectory, we use this to undo
- the setting. See update_dirent_proc. */
-static char *tag_update_dir;
-
static char *join_rev1, *date_rev1;
static char *join_rev2, *date_rev2;
static int aflag = 0;
@@ -449,32 +437,6 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
else
date_rev2 = (char *) NULL;
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- if (preserve_perms)
- {
- /* We need to do an extra recursion, bleah. It's to make sure
- that we know as much as possible about file linkage. */
- hardlist = getlist();
- working_dir = xgetwd(); /* save top-level working dir */
-
- /* FIXME-twp: the arguments to start_recursion make me dizzy. This
- function call was copied from the update_fileproc call that
- follows it; someone should make sure that I did it right. */
- err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
- argc, argv, local, which, aflag, 1,
- preload_update_dir, 1);
- if (err)
- return (err);
-
- /* FIXME-twp: at this point we should walk the hardlist
- and update the `links' field of each hardlink_info struct
- to list the files that are linked on dist. That would make
- it easier & more efficient to compare the disk linkage with
- the repository linkage (a simple strcmp). */
- }
-#endif
-
/* call the recursion processor */
err = start_recursion (update_fileproc, update_filesdone_proc,
update_dirent_proc, update_dirleave_proc, NULL,
@@ -494,50 +456,6 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
return (err);
}
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
-/*
- * The get_linkinfo_proc callback adds each file to the hardlist
- * (see hardlink.c).
- */
-
-static int
-get_linkinfo_proc (callerdat, finfo)
- void *callerdat;
- struct file_info *finfo;
-{
- char *fullpath;
- Node *linkp;
- struct hardlink_info *hlinfo;
-
- /* Get the full pathname of the current file. */
- fullpath = xmalloc (strlen(working_dir) +
- strlen(finfo->fullname) + 2);
- sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
-
- /* To permit recursing into subdirectories, files
- are keyed on the full pathname and not on the basename. */
- linkp = lookup_file_by_inode (fullpath);
- if (linkp == NULL)
- {
- /* The file isn't on disk; we are probably restoring
- a file that was removed. */
- return 0;
- }
-
- /* Create a new, empty hardlink_info node. */
- hlinfo = (struct hardlink_info *)
- xmalloc (sizeof (struct hardlink_info));
-
- hlinfo->status = (Ctype) 0; /* is this dumb? */
- hlinfo->checked_out = 0;
- hlinfo->links = NULL;
-
- linkp->data = (char *) hlinfo;
-
- return 0;
-}
-#endif
-
/*
* This is the callback proc for update. It is called for each file in each
* directory by the recursion code. The current directory is the local
@@ -572,7 +490,7 @@ update_fileproc (callerdat, finfo)
&& tag != NULL
&& finfo->rcs != NULL)
{
- char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
+ char *rev = RCS_getversion (finfo->rcs, tag, date, 1, NULL);
if (rev != NULL
&& !RCS_nodeisbranch (finfo->rcs, tag))
nonbranch = 1;
@@ -608,7 +526,7 @@ update_fileproc (callerdat, finfo)
#ifdef SERVER_SUPPORT
case T_PATCH: /* needs patch */
#endif
- retval = checkout_file (finfo, vers, 0, 0, 0);
+ retval = checkout_file (finfo, vers, 0);
break;
default: /* can't ever happen :-) */
@@ -711,8 +629,7 @@ update_fileproc (callerdat, finfo)
(rcs_diff_patches
? SERVER_RCS_DIFF
: SERVER_PATCHED),
- file_info.st_mode, checksum,
- (struct buffer *) NULL);
+ &file_info, checksum);
break;
}
}
@@ -722,7 +639,13 @@ update_fileproc (callerdat, finfo)
/* Fall through. */
#endif
case T_CHECKOUT: /* needs checkout */
- retval = checkout_file (finfo, vers, 0, 0, 1);
+ retval = checkout_file (finfo, vers, 0);
+#ifdef SERVER_SUPPORT
+ if (server_active && retval == 0)
+ server_updated (finfo, vers,
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
+#endif
break;
case T_ADDED: /* added but not committed */
write_letter (finfo, 'A');
@@ -740,9 +663,8 @@ update_fileproc (callerdat, finfo)
if (vers->ts_user == NULL)
server_scratch_entry_only ();
server_updated (finfo, vers,
- SERVER_UPDATED, (mode_t) -1,
- (unsigned char *) NULL,
- (struct buffer *) NULL);
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
}
#endif
break;
@@ -884,26 +806,6 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
else
{
/* otherwise, create the dir and appropriate adm files */
-
- /* If no tag or date were specified on the command line,
- and we're not using -A, we want the subdirectory to use
- the tag and date, if any, of the current directory.
- That way, update -d will work correctly when working on
- a branch.
-
- We use TAG_UPDATE_DIR to undo the tag setting in
- update_dirleave_proc. If we did not do this, we would
- not correctly handle a working directory with multiple
- tags (and maybe we should prohibit such working
- directories, but they work now and we shouldn't make
- them stop working without more thought). */
- if ((tag == NULL && date == NULL) && ! aflag)
- {
- ParseTag (&tag, &date, &nonbranch);
- if (tag != NULL || date != NULL)
- tag_update_dir = xstrdup (update_dir);
- }
-
make_directory (dir);
Create_Admin (dir, update_dir, repository, tag, date,
/* This is a guess. We will rewrite it later
@@ -995,27 +897,6 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
{
FILE *fp;
- /* If we set the tag or date for a new subdirectory in
- update_dirent_proc, and we're now done with that subdirectory,
- undo the tag/date setting. Note that we know that the tag and
- date were both originally NULL in this case. */
- if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
- {
- if (tag != NULL)
- {
- free (tag);
- tag = NULL;
- }
- if (date != NULL)
- {
- free (date);
- date = NULL;
- }
- nonbranch = 0;
- free (tag_update_dir);
- tag_update_dir = NULL;
- }
-
/* run the update_prog if there is one */
/* FIXME: should be checking for errors from CVS_FOPEN and printing
them if not existence_error. */
@@ -1135,7 +1016,7 @@ isemptydir (dir, might_not_exist)
if (CVS_CHDIR (dir) < 0)
error (1, errno, "cannot change directory to %s", dir);
- l = Entries_Open (0, NULL);
+ l = Entries_Open (0);
files_removed = walklist (l, isremoved, 0);
Entries_Close (l);
@@ -1182,29 +1063,22 @@ scratch_file (finfo)
* Check out a file.
*/
static int
-checkout_file (finfo, vers_ts, adding, merging, update_server)
+checkout_file (finfo, vers_ts, adding)
struct file_info *finfo;
Vers_TS *vers_ts;
int adding;
- int merging;
- int update_server;
{
char *backup;
int set_time, retval = 0;
+ int retcode = 0;
int status;
int file_is_dead;
- struct buffer *revbuf;
+ /* Solely to suppress a warning from gcc -Wall. */
backup = NULL;
- revbuf = NULL;
- /* Don't screw with backup files if we're going to stdout, or if
- we are the server. */
- if (!pipeout
-#ifdef SERVER_SUPPORT
- && ! server_active
-#endif
- )
+ /* don't screw with backup files if we're going to stdout */
+ if (!pipeout)
{
backup = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
@@ -1214,7 +1088,6 @@ checkout_file (finfo, vers_ts, adding, merging, update_server)
if (isfile (finfo->file))
rename_file (finfo->file, backup);
else
- {
/* If -f/-t wrappers are being used to wrap up a directory,
then backup might be a directory instead of just a file. */
if (unlink_file_dir (backup) < 0)
@@ -1224,9 +1097,6 @@ checkout_file (finfo, vers_ts, adding, merging, update_server)
/* FIXME: should include update_dir in message. */
error (0, errno, "error removing %s", backup);
}
- free (backup);
- backup = NULL;
- }
}
file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
@@ -1254,64 +1124,22 @@ VERS: ", 0);
}
}
-#ifdef SERVER_SUPPORT
- if (update_server
- && server_active
- && ! pipeout
- && ! file_gzip_level
- && ! joining ()
- && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
- {
- revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL);
- status = RCS_checkout (vers_ts->srcfile, (char *) NULL,
- vers_ts->vn_rcs, vers_ts->vn_tag,
- vers_ts->options, RUN_TTY,
- checkout_to_buffer, revbuf);
- }
- else
-#endif
- status = RCS_checkout (vers_ts->srcfile,
- pipeout ? NULL : finfo->file,
- vers_ts->vn_rcs, vers_ts->vn_tag,
- vers_ts->options, RUN_TTY,
- (RCSCHECKOUTPROC) NULL, (void *) NULL);
+ status = RCS_checkout (vers_ts->srcfile,
+ pipeout ? NULL : finfo->file,
+ vers_ts->vn_rcs, vers_ts->vn_tag,
+ vers_ts->options, RUN_TTY,
+ (RCSCHECKOUTPROC) NULL, (void *) NULL);
}
if (file_is_dead || status == 0)
{
- mode_t mode;
-
- mode = (mode_t) -1;
-
if (!pipeout)
{
Vers_TS *xvers_ts;
- if (revbuf != NULL)
- {
- struct stat sb;
-
- /* FIXME: We should have RCS_checkout return the mode. */
- if (stat (vers_ts->srcfile->path, &sb) < 0)
- error (1, errno, "cannot stat %s",
- vers_ts->srcfile->path);
- mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
- }
-
if (cvswrite
&& !file_is_dead
&& !fileattr_get (finfo->file, "_watched"))
- {
- if (revbuf == NULL)
- xchmod (finfo->file, 1);
- else
- {
- /* We know that we are the server here, so
- although xchmod checks umask, we don't bother. */
- mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
- | ((mode & S_IRGRP) ? S_IWGRP : 0)
- | ((mode & S_IROTH) ? S_IWOTH : 0));
- }
- }
+ xchmod (finfo->file, 1);
{
/* A newly checked out file is never under the spell
@@ -1343,27 +1171,6 @@ VERS: ", 0);
if (strcmp (xvers_ts->options, "-V4") == 0)
xvers_ts->options[0] = '\0';
- if (revbuf != NULL)
- {
- /* If we stored the file data into a buffer, then we
- didn't create a file at all, so xvers_ts->ts_user
- is wrong. The correct value is to have it be the
- same as xvers_ts->ts_rcs, meaning that the working
- file is unchanged from the RCS file.
-
- FIXME: We should tell Version_TS not to waste time
- statting the nonexistent file.
-
- FIXME: Actually, I don't think the ts_user value
- matters at all here. The only use I know of is
- that it is printed in a trace message by
- Server_Register. */
-
- if (xvers_ts->ts_user != NULL)
- free (xvers_ts->ts_user);
- xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
- }
-
(void) time (&last_register_time);
if (file_is_dead)
@@ -1372,7 +1179,7 @@ VERS: ", 0);
{
error (0, 0,
"warning: %s is not (any longer) pertinent",
- finfo->fullname);
+ finfo->fullname);
}
Scratch_Entry (finfo->entries, finfo->file);
#ifdef SERVER_SUPPORT
@@ -1419,29 +1226,21 @@ VERS: ", 0);
write_letter (finfo, 'U');
}
}
-
-#ifdef SERVER_SUPPORT
- if (update_server && server_active)
- server_updated (finfo, vers_ts,
- merging ? SERVER_MERGED : SERVER_UPDATED,
- mode, (unsigned char *) NULL, revbuf);
-#endif
}
else
{
- if (backup != NULL)
- {
+ int old_errno = errno; /* save errno value over the rename */
+
+ if (!pipeout && isfile (backup))
rename_file (backup, finfo->file);
- free (backup);
- backup = NULL;
- }
- error (0, 0, "could not check out %s", finfo->fullname);
+ error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
+ "could not check out %s", finfo->fullname);
- retval = status;
+ retval = retcode;
}
- if (backup != NULL)
+ if (!pipeout)
{
/* If -f/-t wrappers are being used to wrap up a directory,
then backup might be a directory instead of just a file. */
@@ -1460,24 +1259,6 @@ VERS: ", 0);
#ifdef SERVER_SUPPORT
-/* This function is used to write data from a file being checked out
- into a buffer. */
-
-static void
-checkout_to_buffer (callerdat, data, len)
- void *callerdat;
- const char *data;
- size_t len;
-{
- struct buffer *buf = (struct buffer *) callerdat;
-
- buf_output (buf, data, len);
-}
-
-#endif /* SERVER_SUPPORT */
-
-#ifdef SERVER_SUPPORT
-
/* This structure is used to pass information between patch_file and
patch_file_write. */
@@ -1553,14 +1334,6 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
free (rev);
}
- /* If the revision is dead, let checkout_file handle it rather
- than duplicating the processing here. */
- if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
- {
- *docheckout = 1;
- return 0;
- }
-
backup = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSPREFIX)
@@ -1865,32 +1638,25 @@ merge_file (finfo, vers)
xchmod (finfo->file, 1);
if (strcmp (vers->options, "-kb") == 0
- || wrap_merge_is_copy (finfo->file)
- || special_file_mismatch (finfo, NULL, vers->vn_rcs))
+ || wrap_merge_is_copy (finfo->file))
{
- /* For binary files, a merge is always a conflict. Same for
- files whose permissions or linkage do not match. We give the
+ /* For binary files, a merge is always a conflict. We give the
user the two files, and let them resolve it. It is possible
that we should require a "touch foo" or similar step before
we allow a checkin. */
-
- /* TODO: it may not always be necessary to regard a permission
- mismatch as a conflict. The working file and the RCS file
- have a common ancestor `A'; if the working file's permissions
- match A's, then it's probably safe to overwrite them with the
- RCS permissions. Only if the working file, the RCS file, and
- A all disagree should this be considered a conflict. But more
- thought needs to go into this, and in the meantime it is safe
- to treat any such mismatch as an automatic conflict. -twp */
-
+ status = checkout_file (finfo, vers, 0);
#ifdef SERVER_SUPPORT
+ /* Send the new contents of the file before the message. If we
+ wanted to be totally correct, we would have the client write
+ the message only after the file has safely been written. */
if (server_active)
+ {
server_copy_file (finfo->file, finfo->update_dir,
finfo->repository, backup);
+ server_updated (finfo, vers, SERVER_MERGED,
+ (struct stat *) NULL, (unsigned char *) NULL);
+ }
#endif
-
- status = checkout_file (finfo, vers, 0, 1, 1);
-
/* Is there a better term than "nonmergeable file"? What we
really mean is, not something that CVS cannot or does not
want to merge (there might be an external manual or
@@ -1951,8 +1717,7 @@ merge_file (finfo, vers)
server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
backup);
server_updated (finfo, vers, SERVER_MERGED,
- (mode_t) -1, (unsigned char *) NULL,
- (struct buffer *) NULL);
+ (struct stat *) NULL, (unsigned char *) NULL);
}
#endif
@@ -2186,8 +1951,8 @@ join_file (finfo, vers)
if (server_active)
{
server_scratch (finfo->file);
- server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
- (unsigned char *) NULL, (struct buffer *) NULL);
+ server_updated (finfo, vers, SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
}
#endif
mrev = xmalloc (strlen (vers->vn_user) + 2);
@@ -2240,7 +2005,14 @@ join_file (finfo, vers)
/* FIXME: If checkout_file fails, we should arrange to
return a non-zero exit status. */
- status = checkout_file (finfo, xvers, 1, 0, 1);
+ status = checkout_file (finfo, xvers, 1);
+
+#ifdef SERVER_SUPPORT
+ if (server_active && status == 0)
+ server_updated (finfo, xvers,
+ SERVER_UPDATED, (struct stat *) NULL,
+ (unsigned char *) NULL);
+#endif
freevers_ts (&xvers);
@@ -2302,7 +2074,7 @@ join_file (finfo, vers)
(char *) NULL, RUN_TTY,
(RCSCHECKOUTPROC) NULL, (void *) NULL);
if (retcode != 0)
- error (1, 0,
+ error (1, retcode == -1 ? errno : 0,
"failed to check out %s file", finfo->fullname);
}
#endif
@@ -2375,11 +2147,9 @@ join_file (finfo, vers)
write_letter (finfo, 'U');
}
else if (strcmp (options, "-kb") == 0
- || wrap_merge_is_copy (finfo->file)
- || special_file_mismatch (finfo, rev1, rev2))
+ || wrap_merge_is_copy (finfo->file))
{
- /* We are dealing with binary files, or files with a
- permission/linkage mismatch, and real merging would
+ /* We are dealing with binary files, but real merging would
need to take place. This is a conflict. We give the user
the two files, and let them resolve it. It is possible
that we should require a "touch foo" or similar step before
@@ -2457,318 +2227,12 @@ join_file (finfo, vers)
server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
backup);
server_updated (finfo, vers, SERVER_MERGED,
- (mode_t) -1, (unsigned char *) NULL,
- (struct buffer *) NULL);
+ (struct stat *) NULL, (unsigned char *) NULL);
}
#endif
free (backup);
}
-/*
- * Report whether revisions REV1 and REV2 of FINFO agree on:
- * . file ownership
- * . permissions
- * . major and minor device numbers
- * . symbolic links
- * . hard links
- *
- * If either REV1 or REV2 is NULL, the working copy is used instead.
- *
- * Return 1 if the files differ on these data.
- */
-
-int
-special_file_mismatch (finfo, rev1, rev2)
- struct file_info *finfo;
- char *rev1;
- char *rev2;
-{
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- struct stat sb;
- RCSVers *vp;
- Node *n;
- uid_t rev1_uid, rev2_uid;
- gid_t rev1_gid, rev2_gid;
- mode_t rev1_mode, rev2_mode;
- unsigned long dev_long;
- dev_t rev1_dev, rev2_dev;
- char *rev1_symlink = NULL;
- char *rev2_symlink = NULL;
- char *rev1_hardlinks = NULL;
- char *rev2_hardlinks = NULL;
- int check_uids, check_gids, check_modes;
- int result;
-
- /* If we don't care about special file info, then
- don't report a mismatch in any case. */
- if (!preserve_perms)
- return 0;
-
- /* When special_file_mismatch is called from No_Difference, the
- RCS file has been only partially parsed. We must read the
- delta tree in order to compare special file info recorded in
- the delta nodes. (I think this is safe. -twp) */
- if (finfo->rcs->flags & PARTIAL)
- RCS_reparsercsfile (finfo->rcs, NULL, NULL);
-
- check_uids = check_gids = check_modes = 1;
-
- /* Obtain file information for REV1. If this is null, then stat
- finfo->file and use that info. */
- /* If a revision does not know anything about its status,
- then presumably it doesn't matter, and indicates no conflict. */
-
- if (rev1 == NULL)
- {
- if (islink (finfo->file))
- rev1_symlink = xreadlink (finfo->file);
- else
- {
- if (CVS_LSTAT (finfo->file, &sb) < 0)
- error (1, errno, "could not get file information for %s",
- finfo->file);
- rev1_uid = sb.st_uid;
- rev1_gid = sb.st_gid;
- rev1_mode = sb.st_mode;
- if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
- rev1_dev = sb.st_rdev;
- }
- rev1_hardlinks = list_files_linked_to (finfo->file);
- }
- else
- {
- n = findnode (finfo->rcs->versions, rev1);
- vp = (RCSVers *) n->data;
-
- n = findnode (vp->other_delta, "symlink");
- if (n != NULL)
- rev1_symlink = xstrdup (n->data);
- else
- {
- n = findnode (vp->other_delta, "owner");
- if (n == NULL)
- check_uids = 0; /* don't care */
- else
- rev1_uid = strtoul (n->data, NULL, 10);
-
- n = findnode (vp->other_delta, "group");
- if (n == NULL)
- check_gids = 0; /* don't care */
- else
- rev1_gid = strtoul (n->data, NULL, 10);
-
- n = findnode (vp->other_delta, "permissions");
- if (n == NULL)
- check_modes = 0; /* don't care */
- else
- rev1_mode = strtoul (n->data, NULL, 8);
-
- n = findnode (vp->other_delta, "special");
- if (n == NULL)
- rev1_mode |= S_IFREG;
- else
- {
- /* If the size of `ftype' changes, fix the sscanf call also */
- char ftype[16];
- if (sscanf (n->data, "%16s %lu", ftype,
- &dev_long) < 2)
- error (1, 0, "%s:%s has bad `special' newphrase %s",
- finfo->file, rev1, n->data);
- rev1_dev = dev_long;
- if (strcmp (ftype, "character") == 0)
- rev1_mode |= S_IFCHR;
- else if (strcmp (ftype, "block") == 0)
- rev1_mode |= S_IFBLK;
- else
- error (0, 0, "%s:%s unknown file type `%s'",
- finfo->file, rev1, ftype);
- }
-
- n = findnode (vp->other_delta, "hardlinks");
- if (n == NULL)
- rev1_hardlinks = xstrdup ("");
- else
- rev1_hardlinks = xstrdup (n->data);
- }
- }
-
- /* Obtain file information for REV2. */
- if (rev2 == NULL)
- {
- if (islink (finfo->file))
- rev2_symlink = xreadlink (finfo->file);
- else
- {
- if (CVS_LSTAT (finfo->file, &sb) < 0)
- error (1, errno, "could not get file information for %s",
- finfo->file);
- rev2_uid = sb.st_uid;
- rev2_gid = sb.st_gid;
- rev2_mode = sb.st_mode;
- if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
- rev2_dev = sb.st_rdev;
- }
- rev2_hardlinks = list_files_linked_to (finfo->file);
- }
- else
- {
- n = findnode (finfo->rcs->versions, rev2);
- vp = (RCSVers *) n->data;
-
- n = findnode (vp->other_delta, "symlink");
- if (n != NULL)
- rev2_symlink = xstrdup (n->data);
- else
- {
- n = findnode (vp->other_delta, "owner");
- if (n == NULL)
- check_uids = 0; /* don't care */
- else
- rev2_uid = strtoul (n->data, NULL, 10);
-
- n = findnode (vp->other_delta, "group");
- if (n == NULL)
- check_gids = 0; /* don't care */
- else
- rev2_gid = strtoul (n->data, NULL, 10);
-
- n = findnode (vp->other_delta, "permissions");
- if (n == NULL)
- check_modes = 0; /* don't care */
- else
- rev2_mode = strtoul (n->data, NULL, 8);
-
- n = findnode (vp->other_delta, "special");
- if (n == NULL)
- rev2_mode |= S_IFREG;
- else
- {
- /* If the size of `ftype' changes, fix the sscanf call also */
- char ftype[16];
- if (sscanf (n->data, "%16s %lu", ftype,
- &dev_long) < 2)
- error (1, 0, "%s:%s has bad `special' newphrase %s",
- finfo->file, rev2, n->data);
- rev2_dev = dev_long;
- if (strcmp (ftype, "character") == 0)
- rev2_mode |= S_IFCHR;
- else if (strcmp (ftype, "block") == 0)
- rev2_mode |= S_IFBLK;
- else
- error (0, 0, "%s:%s unknown file type `%s'",
- finfo->file, rev2, ftype);
- }
-
- n = findnode (vp->other_delta, "hardlinks");
- if (n == NULL)
- rev2_hardlinks = xstrdup ("");
- else
- rev2_hardlinks = xstrdup (n->data);
- }
- }
-
- /* Check the user/group ownerships and file permissions, printing
- an error for each mismatch found. Return 0 if all characteristics
- matched, and 1 otherwise. */
-
- result = 0;
-
- /* Compare symlinks first, since symlinks are simpler (don't have
- any other characteristics). */
- if (rev1_symlink != NULL && rev2_symlink == NULL)
- {
- error (0, 0, "%s is a symbolic link",
- (rev1 == NULL ? "working file" : rev1));
- result = 1;
- }
- else if (rev1_symlink == NULL && rev2_symlink != NULL)
- {
- error (0, 0, "%s is a symbolic link",
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
- else if (rev1_symlink != NULL)
- result = (strcmp (rev1_symlink, rev2_symlink) == 0);
- else
- {
- /* Compare user ownership. */
- if (check_uids && rev1_uid != rev2_uid)
- {
- error (0, 0, "%s: owner mismatch between %s and %s",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
-
- /* Compare group ownership. */
- if (check_gids && rev1_gid != rev2_gid)
- {
- error (0, 0, "%s: group mismatch between %s and %s",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
-
- /* Compare permissions. */
- if (check_modes &&
- (rev1_mode & 07777) != (rev2_mode & 07777))
- {
- error (0, 0, "%s: permission mismatch between %s and %s",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
-
- /* Compare device file characteristics. */
- if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
- {
- error (0, 0, "%s: %s and %s are different file types",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
- else if (S_ISBLK (rev1_mode))
- {
- if (rev1_dev != rev2_dev)
- {
- error (0, 0, "%s: device numbers of %s and %s do not match",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
- }
-
- /* Compare hard links. */
- if (strcmp (rev1_hardlinks, rev2_hardlinks) != 0)
- {
- error (0, 0, "%s: hard linkage of %s and %s do not match",
- finfo->file,
- (rev1 == NULL ? "working file" : rev1),
- (rev2 == NULL ? "working file" : rev2));
- result = 1;
- }
- }
-
- if (rev1_symlink != NULL)
- free (rev1_symlink);
- if (rev2_symlink != NULL)
- free (rev2_symlink);
- if (rev1_hardlinks != NULL)
- free (rev1_hardlinks);
- if (rev2_hardlinks != NULL)
- free (rev2_hardlinks);
-
- return result;
-#else
- return 0;
-#endif
-}
-
int
joining ()
{
OpenPOWER on IntegriCloud