diff options
Diffstat (limited to 'contrib/cvs/src/entries.c')
-rw-r--r-- | contrib/cvs/src/entries.c | 1263 |
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); -} |