summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/entries.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-01-26 03:09:57 +0000
committerpeter <peter@FreeBSD.org>1998-01-26 03:09:57 +0000
commite6e45661e44f15cb8c5c6f063080509bd910b98d (patch)
treea9812ba7ade0fde6f62c1626b45d522ba104c314 /contrib/cvs/src/entries.c
parent571cfa0005d94d99d1341bf8ab02be04d4df5f9f (diff)
downloadFreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.zip
FreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.tar.gz
Import cvs-1.9.23 as at 19980123. There are a number of really nice
things fixed in here, including the '-ko' vs. -A problem with remote cvs which caused all files with -ko to be resent each time (which is damn painful over a modem, I can tell you). It also found a heap of stray empty directories that should have been pruned with the -P flag to cvs update but were not for some reason. It also has the fully integrated rcs and diff, so no more fork/exec overheads for rcs,ci,patch,diff,etc. This means that it parses the control data in the rcs files only once rather than twice or more. If the 'cvs diff' vs. Index thing is going to be fixed for future patch compatability, this is the place to do it.
Diffstat (limited to 'contrib/cvs/src/entries.c')
-rw-r--r--contrib/cvs/src/entries.c282
1 files changed, 277 insertions, 5 deletions
diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c
index 03e29de..538cd21 100644
--- a/contrib/cvs/src/entries.c
+++ b/contrib/cvs/src/entries.c
@@ -3,7 +3,7 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*
* Entries file to Files file
*
@@ -117,7 +117,26 @@ write_entries (list)
/* open the new one and walk the list writing entries */
entfilename = CVSADM_ENTBAK;
- entfile = open_file (entfilename, "w+");
+ entfile = CVS_FOPEN (entfilename, "w+");
+ if (entfile == NULL)
+ {
+ /* Make this a warning, not an error. For example, one user might
+ have checked out a working directory which, for whatever reason,
+ contains an Entries.Log file. A second user, without write access
+ to that working directory, might want to do a "cvs log". The
+ problem rewriting Entries shouldn't affect the ability of "cvs log"
+ to work, although the warning is probably a good idea so that
+ whether Entries gets rewritten is not an inexplicable process. */
+ /* FIXME: should be including update_dir in message. */
+ error (0, errno, "cannot rewrite %s", entfilename);
+
+ /* Now just return. We leave the Entries.Log file around. As far
+ as I know, there is never any data lying around in 'list' that
+ is not in Entries.Log at this time (if there is an error writing
+ Entries.Log that is a separate problem). */
+ return;
+ }
+
(void) walklist (list, write_ent_proc, (void *) &sawdir);
if (! sawdir)
{
@@ -262,6 +281,9 @@ freesdt (p)
free ((char *) sdtp);
}
+/* Return the next real Entries line. On end of file, returns NULL.
+ On error, prints an error message and returns NULL. */
+
static Entnode *
fgetentent(fpin, cmd, sawdir)
FILE *fpin;
@@ -275,12 +297,13 @@ fgetentent(fpin, cmd, sawdir)
enum ent_type type;
char *l, *user, *vn, *ts, *options;
char *tag_or_date, *tag, *date, *ts_conflict;
+ int line_length;
line = NULL;
line_chars_allocated = 0;
ent = NULL;
- while (getline (&line, &line_chars_allocated, fpin) > 0)
+ while ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0)
{
l = line;
@@ -375,6 +398,9 @@ fgetentent(fpin, cmd, sawdir)
break;
}
+ if (line_length < 0 && !feof (fpin))
+ error (0, errno, "cannot read entries file");
+
free (line);
return ent;
}
@@ -668,7 +694,10 @@ WriteTag (dir, tag, date, nonbranch, update_dir, repository)
If it does not exist, or contains something unrecognized by this
version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
- an unspecified value. */
+ an unspecified value.
+
+ If there is an error, print an error message, set *DATEP and *TAGP
+ to NULL, and return. */
void
ParseTag (tagp, datep, nonbranchp)
char **tagp;
@@ -724,9 +753,25 @@ ParseTag (tagp, datep, nonbranchp)
break;
}
}
- (void) fclose (fp);
+
+ if (line_length < 0)
+ {
+ /* FIXME-update-dir: should include update_dir in messages. */
+ if (feof (fp))
+ error (0, 0, "cannot read %s: end of file", CVSADM_TAG);
+ else
+ error (0, errno, "cannot read %s", CVSADM_TAG);
+ }
+
+ if (fclose (fp) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_TAG);
+
free (line);
}
+ else if (!existence_error (errno))
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot open %s", CVSADM_TAG);
}
/*
@@ -887,3 +932,230 @@ Subdir_Deregister (entries, parent, dir)
delnode (p);
}
}
+
+
+
+/* OK, the following base_* code tracks the revisions of the files in
+ CVS/Base. We do this in a file CVS/Baserev. Separate from
+ CVS/Entries because it needs to go in separate data structures
+ anyway (the name in Entries must be unique), so this seemed
+ cleaner. The business of rewriting the whole file in
+ base_deregister and base_register is the kind of thing we used to
+ do for Entries and which turned out to be slow, which is why there
+ is now the Entries.Log machinery. So maybe from that point of
+ view it is a mistake to do this separately from Entries, I dunno.
+
+ We also need something analogous for:
+
+ 1. CVS/Template (so we can update the Template file automagically
+ without the user needing to check out a new working directory).
+ Updating would probably print a message (that part might be
+ optional, although probably it should be visible because not all
+ cvs commands would make the update happen and so it is a
+ user-visible behavior). Constructing version number for template
+ is a bit hairy (base it on the timestamp on the server? Or see if
+ the template is in checkoutlist and if yes use its versioning and
+ if no don't version it?)....
+
+ 2. cvsignore (need to keep a copy in the working directory to do
+ "cvs release" on the client side; see comment at src/release.c
+ (release). Would also allow us to stop needing Questionable. */
+
+enum base_walk {
+ /* Set the revision for FILE to *REV. */
+ BASE_REGISTER,
+ /* Get the revision for FILE and put it in a newly malloc'd string
+ in *REV, or put NULL if not mentioned. */
+ BASE_GET,
+ /* Remove FILE. */
+ BASE_DEREGISTER
+};
+
+static void base_walk PROTO ((enum base_walk, struct file_info *, char **));
+
+/* Read through the lines in CVS/Baserev, taking the actions as documented
+ for CODE. */
+
+static void
+base_walk (code, finfo, rev)
+ enum base_walk code;
+ struct file_info *finfo;
+ char **rev;
+{
+ FILE *fp;
+ char *line;
+ size_t line_allocated;
+ FILE *newf;
+ char *baserev_fullname;
+ char *baserevtmp_fullname;
+
+ line = NULL;
+ line_allocated = 0;
+ newf = NULL;
+
+ /* First compute the fullnames for the error messages. This
+ computation probably should be broken out into a separate function,
+ as recurse.c does it too and places like Entries_Open should be
+ doing it. */
+ baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV)
+ + strlen (finfo->update_dir)
+ + 2);
+ baserev_fullname[0] = '\0';
+ baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP)
+ + strlen (finfo->update_dir)
+ + 2);
+ baserevtmp_fullname[0] = '\0';
+ if (finfo->update_dir[0] != '\0')
+ {
+ strcat (baserev_fullname, finfo->update_dir);
+ strcat (baserev_fullname, "/");
+ strcat (baserevtmp_fullname, finfo->update_dir);
+ strcat (baserevtmp_fullname, "/");
+ }
+ strcat (baserev_fullname, CVSADM_BASEREV);
+ strcat (baserevtmp_fullname, CVSADM_BASEREVTMP);
+
+ fp = CVS_FOPEN (CVSADM_BASEREV, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ {
+ error (0, errno, "cannot open %s for reading", baserev_fullname);
+ goto out;
+ }
+ }
+
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
+ if (newf == NULL)
+ {
+ error (0, errno, "cannot open %s for writing",
+ baserevtmp_fullname);
+ goto out;
+ }
+ break;
+ case BASE_GET:
+ *rev = NULL;
+ break;
+ }
+
+ if (fp != NULL)
+ {
+ while (getline (&line, &line_allocated, fp) >= 0)
+ {
+ char *linefile;
+ char *p;
+ char *linerev;
+
+ if (line[0] != 'B')
+ /* Ignore, for future expansion. */
+ continue;
+
+ linefile = line + 1;
+ p = strchr (linefile, '/');
+ if (p == NULL)
+ /* Syntax error, ignore. */
+ continue;
+ linerev = p + 1;
+ p = strchr (linerev, '/');
+ if (p == NULL)
+ continue;
+
+ linerev[-1] = '\0';
+ if (fncmp (linefile, finfo->file) == 0)
+ {
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ /* Don't copy over the old entry, we don't want it. */
+ break;
+ case BASE_GET:
+ *p = '\0';
+ *rev = xstrdup (linerev);
+ *p = '/';
+ goto got_it;
+ }
+ }
+ else
+ {
+ linerev[-1] = '/';
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ if (fprintf (newf, "%s\n", line) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ break;
+ case BASE_GET:
+ break;
+ }
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", baserev_fullname);
+ }
+ got_it:
+
+ if (code == BASE_REGISTER)
+ {
+ if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ }
+
+ out:
+
+ if (line != NULL)
+ free (line);
+
+ if (fp != NULL)
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", baserev_fullname);
+ }
+ if (newf != NULL)
+ {
+ if (fclose (newf) < 0)
+ error (0, errno, "cannot close %s", baserevtmp_fullname);
+ rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
+ }
+
+ free (baserev_fullname);
+ free (baserevtmp_fullname);
+}
+
+/* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
+ or NULL if not listed. */
+
+char *
+base_get (finfo)
+ struct file_info *finfo;
+{
+ char *rev;
+ base_walk (BASE_GET, finfo, &rev);
+ return rev;
+}
+
+/* Set the revision for FILE to REV. */
+
+void
+base_register (finfo, rev)
+ struct file_info *finfo;
+ char *rev;
+{
+ base_walk (BASE_REGISTER, finfo, &rev);
+}
+
+/* Remove FILE. */
+
+void
+base_deregister (finfo)
+ struct file_info *finfo;
+{
+ base_walk (BASE_DEREGISTER, finfo, NULL);
+}
OpenPOWER on IntegriCloud