summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/entries.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/entries.c')
-rw-r--r--contrib/cvs/src/entries.c1263
1 files changed, 0 insertions, 1263 deletions
diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c
deleted file mode 100644
index 9592c3c637ad1..0000000000000
--- a/contrib/cvs/src/entries.c
+++ /dev/null
@@ -1,1263 +0,0 @@
-/*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
- *
- * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
- * and others.
- *
- * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
- * Portions Copyright (C) 1989-1992, Brian Berliner
- *
- * You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS source distribution.
- *
- * Entries file to Files file
- *
- * Creates the file Files containing the names that comprise the project, from
- * the Entries file.
- */
-
-/*
- * $FreeBSD$
- */
-#include "cvs.h"
-#include "getline.h"
-
-static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
-
-static Entnode *fgetentent PROTO((FILE *, char *, int *));
-static int fputentent PROTO((FILE *, Entnode *));
-
-static Entnode *subdir_record PROTO((int, const char *, const char *));
-
-static FILE *entfile;
-static char *entfilename; /* for error messages */
-
-
-
-/*
- * Construct an Entnode
- */
-static Entnode *Entnode_Create PROTO ((enum ent_type, const char *,
- const char *, const char *,
- const char *, const char *,
- const char *, const char *));
-
-static Entnode *
-Entnode_Create(type, user, vn, ts, options, tag, date, ts_conflict)
- enum ent_type type;
- const char *user;
- const char *vn;
- const char *ts;
- const char *options;
- const char *tag;
- const char *date;
- const char *ts_conflict;
-{
- Entnode *ent;
-
- /* Note that timestamp and options must be non-NULL */
- ent = (Entnode *) xmalloc (sizeof (Entnode));
- ent->type = type;
- ent->user = xstrdup (user);
- ent->version = xstrdup (vn);
- ent->timestamp = xstrdup (ts ? ts : "");
- ent->options = xstrdup (options ? options : "");
- ent->tag = xstrdup (tag);
- ent->date = xstrdup (date);
- ent->conflict = xstrdup (ts_conflict);
-
- return ent;
-}
-
-/*
- * Destruct an Entnode
- */
-static void Entnode_Destroy PROTO ((Entnode *));
-
-static void
-Entnode_Destroy (ent)
- Entnode *ent;
-{
- free (ent->user);
- free (ent->version);
- free (ent->timestamp);
- free (ent->options);
- if (ent->tag)
- free (ent->tag);
- if (ent->date)
- free (ent->date);
- if (ent->conflict)
- free (ent->conflict);
- free (ent);
-}
-
-/*
- * Write out the line associated with a node of an entries file
- */
-static int write_ent_proc PROTO ((Node *, void *));
-static int
-write_ent_proc (node, closure)
- Node *node;
- void *closure;
-{
- Entnode *entnode = node->data;
-
- if (closure != NULL && entnode->type != ENT_FILE)
- *(int *) closure = 1;
-
- if (fputentent(entfile, entnode))
- error (1, errno, "cannot write %s", entfilename);
-
- return (0);
-}
-
-/*
- * write out the current entries file given a list, making a backup copy
- * first of course
- */
-static void
-write_entries (list)
- List *list;
-{
- int sawdir;
-
- sawdir = 0;
-
- /* open the new one and walk the list writing entries */
- entfilename = CVSADM_ENTBAK;
- 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)
- {
- struct stickydirtag *sdtp;
-
- /* We didn't write out any directories. Check the list
- private data to see whether subdirectory information is
- known. If it is, we need to write out an empty D line. */
- sdtp = list->list->data;
- if (sdtp == NULL || sdtp->subdirs)
- if (fprintf (entfile, "D\n") < 0)
- error (1, errno, "cannot write %s", entfilename);
- }
- if (fclose (entfile) == EOF)
- error (1, errno, "error closing %s", entfilename);
-
- /* now, atomically (on systems that support it) rename it */
- rename_file (entfilename, CVSADM_ENT);
-
- /* now, remove the log file */
- if (unlink_file (CVSADM_ENTLOG) < 0
- && !existence_error (errno))
- error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
-}
-
-
-
-/*
- * Removes the argument file from the Entries file if necessary.
- */
-void
-Scratch_Entry (list, fname)
- List *list;
- const char *fname;
-{
- Node *node;
-
- if (trace)
- (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n",
- CLIENT_SERVER_STR, fname);
-
- /* hashlookup to see if it is there */
- if ((node = findnode_fn (list, fname)) != NULL)
- {
- if (!noexec)
- {
- entfilename = CVSADM_ENTLOG;
- entfile = open_file (entfilename, "a");
-
- if (fprintf (entfile, "R ") < 0)
- error (1, errno, "cannot write %s", entfilename);
-
- write_ent_proc (node, NULL);
-
- if (fclose (entfile) == EOF)
- error (1, errno, "error closing %s", entfilename);
- }
-
- delnode (node); /* delete the node */
-
-#ifdef SERVER_SUPPORT
- if (server_active)
- server_scratch (fname);
-#endif
- }
-}
-
-
-
-/*
- * Enters the given file name/version/time-stamp into the Entries file,
- * removing the old entry first, if necessary.
- */
-void
-Register (list, fname, vn, ts, options, tag, date, ts_conflict)
- List *list;
- const char *fname;
- const char *vn;
- const char *ts;
- const char *options;
- const char *tag;
- const char *date;
- const char *ts_conflict;
-{
- Entnode *entnode;
- Node *node;
-
-#ifdef SERVER_SUPPORT
- if (server_active)
- {
- server_register (fname, vn, ts, options, tag, date, ts_conflict);
- }
-#endif
-
- if (trace)
- {
- (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
- CLIENT_SERVER_STR,
- fname, vn, ts ? ts : "",
- ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
- options, tag ? tag : "", date ? date : "");
- }
-
- entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
- ts_conflict);
- node = AddEntryNode (list, entnode);
-
- if (!noexec)
- {
- entfilename = CVSADM_ENTLOG;
- entfile = CVS_FOPEN (entfilename, "a");
-
- if (entfile == NULL)
- {
- /* Warning, not error, as in write_entries. */
- /* FIXME-update-dir: should be including update_dir in message. */
- error (0, errno, "cannot open %s", entfilename);
- return;
- }
-
- if (fprintf (entfile, "A ") < 0)
- error (1, errno, "cannot write %s", entfilename);
-
- write_ent_proc (node, NULL);
-
- if (fclose (entfile) == EOF)
- error (1, errno, "error closing %s", entfilename);
- }
-}
-
-/*
- * Node delete procedure for list-private sticky dir tag/date info
- */
-static void
-freesdt (p)
- Node *p;
-{
- struct stickydirtag *sdtp = p->data;
-
- if (sdtp->tag)
- free (sdtp->tag);
- if (sdtp->date)
- free (sdtp->date);
- 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;
- char *cmd;
- int *sawdir;
-{
- Entnode *ent;
- char *line;
- size_t line_chars_allocated;
- register char *cp;
- 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 ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0)
- {
- l = line;
-
- /* If CMD is not NULL, we are reading an Entries.Log file.
- Each line in the Entries.Log file starts with a single
- character command followed by a space. For backward
- compatibility, the absence of a space indicates an add
- command. */
- if (cmd != NULL)
- {
- if (l[1] != ' ')
- *cmd = 'A';
- else
- {
- *cmd = l[0];
- l += 2;
- }
- }
-
- type = ENT_FILE;
-
- if (l[0] == 'D')
- {
- type = ENT_SUBDIR;
- *sawdir = 1;
- ++l;
- /* An empty D line is permitted; it is a signal that this
- Entries file lists all known subdirectories. */
- }
-
- if (l[0] != '/')
- continue;
-
- user = l + 1;
- if ((cp = strchr (user, '/')) == NULL)
- continue;
- *cp++ = '\0';
- vn = cp;
- if ((cp = strchr (vn, '/')) == NULL)
- continue;
- *cp++ = '\0';
- ts = cp;
- if ((cp = strchr (ts, '/')) == NULL)
- continue;
- *cp++ = '\0';
- options = cp;
- if ((cp = strchr (options, '/')) == NULL)
- continue;
- *cp++ = '\0';
- tag_or_date = cp;
- if ((cp = strchr (tag_or_date, '\n')) == NULL)
- continue;
- *cp = '\0';
- tag = (char *) NULL;
- date = (char *) NULL;
- if (*tag_or_date == 'T')
- tag = tag_or_date + 1;
- else if (*tag_or_date == 'D')
- date = tag_or_date + 1;
-
- if ((ts_conflict = strchr (ts, '+')))
- *ts_conflict++ = '\0';
-
- /*
- * XXX - Convert timestamp from old format to new format.
- *
- * If the timestamp doesn't match the file's current
- * mtime, we'd have to generate a string that doesn't
- * match anyways, so cheat and base it on the existing
- * string; it doesn't have to match the same mod time.
- *
- * For an unmodified file, write the correct timestamp.
- */
- {
- struct stat sb;
- if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0)
- {
- char *c = ctime (&sb.st_mtime);
- /* Fix non-standard format. */
- if (c[8] == '0') c[8] = ' ';
-
- if (!strncmp (ts + 25, c, 24))
- ts = time_stamp (user);
- else
- {
- ts += 24;
- ts[0] = '*';
- }
- }
- }
-
- ent = Entnode_Create (type, user, vn, ts, options, tag, date,
- ts_conflict);
- break;
- }
-
- if (line_length < 0 && !feof (fpin))
- error (0, errno, "cannot read entries file");
-
- free (line);
- return ent;
-}
-
-static int
-fputentent(fp, p)
- FILE *fp;
- Entnode *p;
-{
- switch (p->type)
- {
- case ENT_FILE:
- break;
- case ENT_SUBDIR:
- if (fprintf (fp, "D") < 0)
- return 1;
- break;
- }
-
- if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
- return 1;
- if (p->conflict)
- {
- if (fprintf (fp, "+%s", p->conflict) < 0)
- return 1;
- }
- if (fprintf (fp, "/%s/", p->options) < 0)
- return 1;
-
- if (p->tag)
- {
- if (fprintf (fp, "T%s\n", p->tag) < 0)
- return 1;
- }
- else if (p->date)
- {
- if (fprintf (fp, "D%s\n", p->date) < 0)
- return 1;
- }
- else
- {
- if (fprintf (fp, "\n") < 0)
- return 1;
- }
-
- return 0;
-}
-
-
-/* Read the entries file into a list, hashing on the file name.
-
- UPDATE_DIR is the name of the current directory, for use in error
- messages, or NULL if not known (that is, noone has gotten around
- to updating the caller to pass in the information). */
-List *
-Entries_Open (aflag, update_dir)
- int aflag;
- char *update_dir;
-{
- List *entries;
- struct stickydirtag *sdtp = NULL;
- Entnode *ent;
- char *dirtag, *dirdate;
- int dirnonbranch;
- int do_rewrite = 0;
- FILE *fpin;
- int sawdir;
-
- /* get a fresh list... */
- entries = getlist ();
-
- /*
- * Parse the CVS/Tag file, to get any default tag/date settings. Use
- * list-private storage to tuck them away for Version_TS().
- */
- ParseTag (&dirtag, &dirdate, &dirnonbranch);
- if (aflag || dirtag || dirdate)
- {
- sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
- memset ((char *) sdtp, 0, sizeof (*sdtp));
- sdtp->aflag = aflag;
- sdtp->tag = xstrdup (dirtag);
- sdtp->date = xstrdup (dirdate);
- sdtp->nonbranch = dirnonbranch;
-
- /* feed it into the list-private area */
- entries->list->data = sdtp;
- entries->list->delproc = freesdt;
- }
-
- sawdir = 0;
-
- fpin = CVS_FOPEN (CVSADM_ENT, "r");
- if (fpin == NULL)
- {
- if (update_dir != NULL)
- error (0, 0, "in directory %s:", update_dir);
- error (0, errno, "cannot open %s for reading", CVSADM_ENT);
- }
- else
- {
- while ((ent = fgetentent (fpin, (char *) NULL, &sawdir)) != NULL)
- {
- (void) AddEntryNode (entries, ent);
- }
-
- if (fclose (fpin) < 0)
- /* FIXME-update-dir: should include update_dir in message. */
- error (0, errno, "cannot close %s", CVSADM_ENT);
- }
-
- fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
- if (fpin != NULL)
- {
- char cmd;
- Node *node;
-
- while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL)
- {
- switch (cmd)
- {
- case 'A':
- (void) AddEntryNode (entries, ent);
- break;
- case 'R':
- node = findnode_fn (entries, ent->user);
- if (node != NULL)
- delnode (node);
- Entnode_Destroy (ent);
- break;
- default:
- /* Ignore unrecognized commands. */
- Entnode_Destroy (ent);
- break;
- }
- }
- do_rewrite = 1;
- if (fclose (fpin) < 0)
- /* FIXME-update-dir: should include update_dir in message. */
- error (0, errno, "cannot close %s", CVSADM_ENTLOG);
- }
-
- /* Update the list private data to indicate whether subdirectory
- information is known. Nonexistent list private data is taken
- to mean that it is known. */
- if (sdtp != NULL)
- sdtp->subdirs = sawdir;
- else if (! sawdir)
- {
- sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
- memset ((char *) sdtp, 0, sizeof (*sdtp));
- sdtp->subdirs = 0;
- entries->list->data = sdtp;
- entries->list->delproc = freesdt;
- }
-
- if (do_rewrite && !noexec)
- write_entries (entries);
-
- /* clean up and return */
- if (dirtag)
- free (dirtag);
- if (dirdate)
- free (dirdate);
- return (entries);
-}
-
-void
-Entries_Close(list)
- List *list;
-{
- if (list)
- {
- if (!noexec)
- {
- if (isfile (CVSADM_ENTLOG))
- write_entries (list);
- }
- dellist(&list);
- }
-}
-
-
-/*
- * Free up the memory associated with the data section of an ENTRIES type
- * node
- */
-static void
-Entries_delproc (node)
- Node *node;
-{
- Entnode *p = node->data;
-
- Entnode_Destroy(p);
-}
-
-/*
- * Get an Entries file list node, initialize it, and add it to the specified
- * list
- */
-static Node *
-AddEntryNode (list, entdata)
- List *list;
- Entnode *entdata;
-{
- Node *p;
-
- /* was it already there? */
- if ((p = findnode_fn (list, entdata->user)) != NULL)
- {
- /* take it out */
- delnode (p);
- }
-
- /* get a node and fill in the regular stuff */
- p = getnode ();
- p->type = ENTRIES;
- p->delproc = Entries_delproc;
-
- /* this one gets a key of the name for hashing */
- /* FIXME This results in duplicated data --- the hash package shouldn't
- assume that the key is dynamically allocated. The user's free proc
- should be responsible for freeing the key. */
- p->key = xstrdup (entdata->user);
- p->data = entdata;
-
- /* put the node into the list */
- addnode (list, p);
- return (p);
-}
-
-static char *root_template;
-
-static int
-get_root_template(const char *repository, const char *path)
-{
- if (root_template) {
- if (strcmp(path, root_template) == 0)
- return(0);
- free(root_template);
- }
- if ((root_template = strdup(path)) == NULL)
- return(-1);
- return(0);
-}
-
-/*
- * Write out/Clear the CVS/Template file.
- */
-void
-WriteTemplate (dir, update_dir)
- const char *dir;
- const char *update_dir;
-{
- char *tmp = NULL;
- struct stat st1;
- struct stat st2;
-
- if (Parse_Info(CVSROOTADM_RCSINFO, "cvs", get_root_template, 1) < 0)
- return;
-
- if (asprintf(&tmp, "%s/%s", dir, CVSADM_TEMPLATE) < 0)
- error (1, errno, "out of memory");
-
- if (stat(root_template, &st1) == 0) {
- if (stat(tmp, &st2) < 0 || st1.st_mtime != st2.st_mtime) {
- FILE *fi;
- FILE *fo;
-
- if ((fi = open_file(root_template, "r")) != NULL) {
- if ((fo = open_file(tmp, "w")) != NULL) {
- int n;
- char buf[256];
-
- while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
- fwrite(buf, 1, n, fo);
- fflush(fo);
- if (ferror(fi) || ferror(fo)) {
- fclose(fo);
- remove(tmp);
- error (1, errno, "error copying Template");
- } else {
- struct timeval times[2];
- fclose(fo);
- times[0].tv_sec = st1.st_mtime;
- times[0].tv_usec = 0;
- times[1] = times[0];
- utimes(tmp, times);
- }
- }
- fclose(fi);
- }
- }
- }
- free(tmp);
-}
-
-/*
- * Write out/Clear the CVS/Tag file.
- */
-void
-WriteTag (dir, tag, date, nonbranch, update_dir, repository)
- const char *dir;
- const char *tag;
- const char *date;
- int nonbranch;
- const char *update_dir;
- const char *repository;
-{
- FILE *fout;
- char *tmp;
-
- if (noexec)
- return;
-
- tmp = xmalloc ((dir ? strlen (dir) : 0)
- + sizeof (CVSADM_TAG)
- + 10);
- if (dir == NULL)
- (void) strcpy (tmp, CVSADM_TAG);
- else
- (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
-
- if (tag || date)
- {
- fout = open_file (tmp, "w+");
- if (tag)
- {
- if (nonbranch)
- {
- if (fprintf (fout, "N%s\n", tag) < 0)
- error (1, errno, "write to %s failed", tmp);
- }
- else
- {
- if (fprintf (fout, "T%s\n", tag) < 0)
- error (1, errno, "write to %s failed", tmp);
- }
- }
- else
- {
- if (fprintf (fout, "D%s\n", date) < 0)
- error (1, errno, "write to %s failed", tmp);
- }
- if (fclose (fout) == EOF)
- error (1, errno, "cannot close %s", tmp);
- }
- else
- if (unlink_file (tmp) < 0 && ! existence_error (errno))
- error (1, errno, "cannot remove %s", tmp);
- free (tmp);
-#ifdef SERVER_SUPPORT
- if (server_active)
- server_set_sticky (update_dir, repository, tag, date, nonbranch);
-#endif
-}
-
-/* Parse the CVS/Tag file for the current directory.
-
- If it contains a date, sets *DATEP to the date in a newly malloc'd
- string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
-
- If it contains a branch tag, sets *TAGP to the tag in a newly
- malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
-
- If it contains a nonbranch tag, sets *TAGP to the tag in a newly
- malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
-
- 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.
-
- If there is an error, print an error message, set *DATEP and *TAGP
- to NULL, and return. */
-void
-ParseTag (tagp, datep, nonbranchp)
- char **tagp;
- char **datep;
- int *nonbranchp;
-{
- FILE *fp;
-
- if (tagp)
- *tagp = (char *) NULL;
- if (datep)
- *datep = (char *) NULL;
- /* Always store a value here, even in the 'D' case where the value
- is unspecified. Shuts up tools which check for references to
- uninitialized memory. */
- if (nonbranchp != NULL)
- *nonbranchp = 0;
- fp = CVS_FOPEN (CVSADM_TAG, "r");
- if (fp)
- {
- char *line;
- int line_length;
- size_t line_chars_allocated;
-
- line = NULL;
- line_chars_allocated = 0;
-
- if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
- {
- /* Remove any trailing newline. */
- if (line[line_length - 1] == '\n')
- line[--line_length] = '\0';
- switch (*line)
- {
- case 'T':
- if (tagp != NULL)
- *tagp = xstrdup (line + 1);
- break;
- case 'D':
- if (datep != NULL)
- *datep = xstrdup (line + 1);
- break;
- case 'N':
- if (tagp != NULL)
- *tagp = xstrdup (line + 1);
- if (nonbranchp != NULL)
- *nonbranchp = 1;
- break;
- default:
- /* Silently ignore it; it may have been
- written by a future version of CVS which extends the
- syntax. */
- break;
- }
- }
-
- 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);
-}
-
-/*
- * This is called if all subdirectory information is known, but there
- * aren't any subdirectories. It records that fact in the list
- * private data.
- */
-
-void
-Subdirs_Known (entries)
- List *entries;
-{
- struct stickydirtag *sdtp = entries->list->data;
-
- /* If there is no list private data, that means that the
- subdirectory information is known. */
- if (sdtp != NULL && ! sdtp->subdirs)
- {
- FILE *fp;
-
- sdtp->subdirs = 1;
- if (!noexec)
- {
- /* Create Entries.Log so that Entries_Close will do something. */
- entfilename = CVSADM_ENTLOG;
- fp = CVS_FOPEN (entfilename, "a");
- if (fp == NULL)
- {
- int save_errno = errno;
-
- /* As in subdir_record, just silently skip the whole thing
- if there is no CVSADM directory. */
- if (! isdir (CVSADM))
- return;
- error (1, save_errno, "cannot open %s", entfilename);
- }
- else
- {
- if (fclose (fp) == EOF)
- error (1, errno, "cannot close %s", entfilename);
- }
- }
- }
-}
-
-/* Record subdirectory information. */
-
-static Entnode *
-subdir_record (cmd, parent, dir)
- int cmd;
- const char *parent;
- const char *dir;
-{
- Entnode *entnode;
-
- /* None of the information associated with a directory is
- currently meaningful. */
- entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "",
- (char *) NULL, (char *) NULL,
- (char *) NULL);
-
- if (!noexec)
- {
- if (parent == NULL)
- entfilename = CVSADM_ENTLOG;
- else
- {
- entfilename = xmalloc (strlen (parent)
- + sizeof CVSADM_ENTLOG
- + 10);
- sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG);
- }
-
- entfile = CVS_FOPEN (entfilename, "a");
- if (entfile == NULL)
- {
- int save_errno = errno;
-
- /* It is not an error if there is no CVS administration
- directory. Permitting this case simplifies some
- calling code. */
-
- if (parent == NULL)
- {
- if (! isdir (CVSADM))
- return entnode;
- }
- else
- {
- sprintf (entfilename, "%s/%s", parent, CVSADM);
- if (! isdir (entfilename))
- {
- free (entfilename);
- entfilename = NULL;
- return entnode;
- }
- }
-
- error (1, save_errno, "cannot open %s", entfilename);
- }
-
- if (fprintf (entfile, "%c ", cmd) < 0)
- error (1, errno, "cannot write %s", entfilename);
-
- if (fputentent (entfile, entnode) != 0)
- error (1, errno, "cannot write %s", entfilename);
-
- if (fclose (entfile) == EOF)
- error (1, errno, "error closing %s", entfilename);
-
- if (parent != NULL)
- {
- free (entfilename);
- entfilename = NULL;
- }
- }
-
- return entnode;
-}
-
-/*
- * Record the addition of a new subdirectory DIR in PARENT. PARENT
- * may be NULL, which means the current directory. ENTRIES is the
- * current entries list; it may be NULL, which means that it need not
- * be updated.
- */
-
-void
-Subdir_Register (entries, parent, dir)
- List *entries;
- const char *parent;
- const char *dir;
-{
- Entnode *entnode;
-
- /* Ignore attempts to register ".". These can happen in the
- server code. */
- if (dir[0] == '.' && dir[1] == '\0')
- return;
-
- entnode = subdir_record ('A', parent, dir);
-
- if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
- (void) AddEntryNode (entries, entnode);
- else
- Entnode_Destroy (entnode);
-}
-
-/*
- * Record the removal of a subdirectory. The arguments are the same
- * as for Subdir_Register.
- */
-
-void
-Subdir_Deregister (entries, parent, dir)
- List *entries;
- const char *parent;
- const char *dir;
-{
- Entnode *entnode;
-
- entnode = subdir_record ('R', parent, dir);
- Entnode_Destroy (entnode);
-
- if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
- {
- Node *p;
-
- p = findnode_fn (entries, dir);
- if (p != NULL)
- 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);
-}