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