2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
8 * Entries file to Files file
10 * Creates the file Files containing the names that comprise the project, from
17 static Node *AddEntryNode (List * list, Entnode *entnode);
19 static Entnode *fgetentent (FILE *, char *, int *);
20 static int fputentent (FILE *, Entnode *);
22 static Entnode *subdir_record (int, const char *, const char *);
25 static char *entfilename; /* for error messages */
30 * Construct an Entnode
33 Entnode_Create (enum ent_type type, const char *user, const char *vn,
34 const char *ts, const char *options, const char *tag,
35 const char *date, const char *ts_conflict)
39 /* Note that timestamp and options must be non-NULL */
40 ent = (Entnode *) xmalloc (sizeof (Entnode));
42 ent->user = xstrdup (user);
43 ent->version = xstrdup (vn);
44 ent->timestamp = xstrdup (ts ? ts : "");
45 ent->options = xstrdup (options ? options : "");
46 ent->tag = xstrdup (tag);
47 ent->date = xstrdup (date);
48 ent->conflict = xstrdup (ts_conflict);
56 static void Entnode_Destroy (Entnode *);
59 Entnode_Destroy (Entnode *ent)
63 free (ent->timestamp);
75 * Write out the line associated with a node of an entries file
77 static int write_ent_proc (Node *, void *);
79 write_ent_proc (Node *node, void *closure)
81 Entnode *entnode = node->data;
83 if (closure != NULL && entnode->type != ENT_FILE)
86 if (fputentent(entfile, entnode))
87 error (1, errno, "cannot write %s", entfilename);
93 * write out the current entries file given a list, making a backup copy
97 write_entries (List *list)
103 /* open the new one and walk the list writing entries */
104 entfilename = CVSADM_ENTBAK;
105 entfile = CVS_FOPEN (entfilename, "w+");
108 /* Make this a warning, not an error. For example, one user might
109 have checked out a working directory which, for whatever reason,
110 contains an Entries.Log file. A second user, without write access
111 to that working directory, might want to do a "cvs log". The
112 problem rewriting Entries shouldn't affect the ability of "cvs log"
113 to work, although the warning is probably a good idea so that
114 whether Entries gets rewritten is not an inexplicable process. */
115 /* FIXME: should be including update_dir in message. */
116 error (0, errno, "cannot rewrite %s", entfilename);
118 /* Now just return. We leave the Entries.Log file around. As far
119 as I know, there is never any data lying around in 'list' that
120 is not in Entries.Log at this time (if there is an error writing
121 Entries.Log that is a separate problem). */
125 (void) walklist (list, write_ent_proc, (void *) &sawdir);
128 struct stickydirtag *sdtp;
130 /* We didn't write out any directories. Check the list
131 private data to see whether subdirectory information is
132 known. If it is, we need to write out an empty D line. */
133 sdtp = list->list->data;
134 if (sdtp == NULL || sdtp->subdirs)
135 if (fprintf (entfile, "D\n") < 0)
136 error (1, errno, "cannot write %s", entfilename);
138 if (fclose (entfile) == EOF)
139 error (1, errno, "error closing %s", entfilename);
141 /* now, atomically (on systems that support it) rename it */
142 rename_file (entfilename, CVSADM_ENT);
144 /* now, remove the log file */
145 if (unlink_file (CVSADM_ENTLOG) < 0
146 && !existence_error (errno))
147 error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
153 * Removes the argument file from the Entries file if necessary.
156 Scratch_Entry (List *list, const char *fname)
160 TRACE ( 1, "Scratch_Entry(%s)", fname );
162 /* hashlookup to see if it is there */
163 if ((node = findnode_fn (list, fname)) != NULL)
167 entfilename = CVSADM_ENTLOG;
168 entfile = open_file (entfilename, "a");
170 if (fprintf (entfile, "R ") < 0)
171 error (1, errno, "cannot write %s", entfilename);
173 write_ent_proc (node, NULL);
175 if (fclose (entfile) == EOF)
176 error (1, errno, "error closing %s", entfilename);
179 delnode (node); /* delete the node */
181 #ifdef SERVER_SUPPORT
183 server_scratch (fname);
191 * Enters the given file name/version/time-stamp into the Entries file,
192 * removing the old entry first, if necessary.
195 Register (List *list, const char *fname, const char *vn, const char *ts,
196 const char *options, const char *tag, const char *date,
197 const char *ts_conflict)
202 #ifdef SERVER_SUPPORT
205 server_register (fname, vn, ts, options, tag, date, ts_conflict);
209 TRACE ( 1, "Register(%s, %s, %s%s%s, %s, %s %s)",
210 fname, vn, ts ? ts : "",
211 ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
212 options, tag ? tag : "", date ? date : "" );
214 entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
216 node = AddEntryNode (list, entnode);
220 entfilename = CVSADM_ENTLOG;
221 entfile = CVS_FOPEN (entfilename, "a");
225 /* Warning, not error, as in write_entries. */
226 /* FIXME-update-dir: should be including update_dir in message. */
227 error (0, errno, "cannot open %s", entfilename);
231 if (fprintf (entfile, "A ") < 0)
232 error (1, errno, "cannot write %s", entfilename);
234 write_ent_proc (node, NULL);
236 if (fclose (entfile) == EOF)
237 error (1, errno, "error closing %s", entfilename);
242 * Node delete procedure for list-private sticky dir tag/date info
247 struct stickydirtag *sdtp = p->data;
253 free ((char *) sdtp);
256 /* Return the next real Entries line. On end of file, returns NULL.
257 On error, prints an error message and returns NULL. */
260 fgetentent(FILE *fpin, char *cmd, int *sawdir)
264 size_t line_chars_allocated;
267 char *l, *user, *vn, *ts, *options;
268 char *tag_or_date, *tag, *date, *ts_conflict;
272 line_chars_allocated = 0;
275 while ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0)
279 /* If CMD is not NULL, we are reading an Entries.Log file.
280 Each line in the Entries.Log file starts with a single
281 character command followed by a space. For backward
282 compatibility, the absence of a space indicates an add
302 /* An empty D line is permitted; it is a signal that this
303 Entries file lists all known subdirectories. */
310 if ((cp = strchr (user, '/')) == NULL)
314 if ((cp = strchr (vn, '/')) == NULL)
318 if ((cp = strchr (ts, '/')) == NULL)
322 if ((cp = strchr (options, '/')) == NULL)
326 if ((cp = strchr (tag_or_date, '\n')) == NULL)
330 date = (char *) NULL;
331 if (*tag_or_date == 'T')
332 tag = tag_or_date + 1;
333 else if (*tag_or_date == 'D')
334 date = tag_or_date + 1;
336 if ((ts_conflict = strchr (ts, '+')))
337 *ts_conflict++ = '\0';
340 * XXX - Convert timestamp from old format to new format.
342 * If the timestamp doesn't match the file's current
343 * mtime, we'd have to generate a string that doesn't
344 * match anyways, so cheat and base it on the existing
345 * string; it doesn't have to match the same mod time.
347 * For an unmodified file, write the correct timestamp.
351 if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0)
353 char *c = ctime (&sb.st_mtime);
354 /* Fix non-standard format. */
355 if (c[8] == '0') c[8] = ' ';
357 if (!strncmp (ts + 25, c, 24))
358 ts = time_stamp (user);
367 ent = Entnode_Create (type, user, vn, ts, options, tag, date,
372 if (line_length < 0 && !feof (fpin))
373 error (0, errno, "cannot read entries file");
380 fputentent(FILE *fp, Entnode *p)
387 if (fprintf (fp, "D") < 0)
392 if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
396 if (fprintf (fp, "+%s", p->conflict) < 0)
399 if (fprintf (fp, "/%s/", p->options) < 0)
404 if (fprintf (fp, "T%s\n", p->tag) < 0)
409 if (fprintf (fp, "D%s\n", p->date) < 0)
414 if (fprintf (fp, "\n") < 0)
422 /* Read the entries file into a list, hashing on the file name.
424 UPDATE_DIR is the name of the current directory, for use in error
425 messages, or NULL if not known (that is, noone has gotten around
426 to updating the caller to pass in the information). */
428 Entries_Open (int aflag, char *update_dir)
431 struct stickydirtag *sdtp = NULL;
433 char *dirtag, *dirdate;
439 /* get a fresh list... */
440 entries = getlist ();
443 * Parse the CVS/Tag file, to get any default tag/date settings. Use
444 * list-private storage to tuck them away for Version_TS().
446 ParseTag (&dirtag, &dirdate, &dirnonbranch);
447 if (aflag || dirtag || dirdate)
449 sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
450 memset ((char *) sdtp, 0, sizeof (*sdtp));
452 sdtp->tag = xstrdup (dirtag);
453 sdtp->date = xstrdup (dirdate);
454 sdtp->nonbranch = dirnonbranch;
456 /* feed it into the list-private area */
457 entries->list->data = sdtp;
458 entries->list->delproc = freesdt;
463 fpin = CVS_FOPEN (CVSADM_ENT, "r");
466 if (update_dir != NULL)
467 error (0, 0, "in directory %s:", update_dir);
468 error (0, errno, "cannot open %s for reading", CVSADM_ENT);
472 while ((ent = fgetentent (fpin, (char *) NULL, &sawdir)) != NULL)
474 (void) AddEntryNode (entries, ent);
477 if (fclose (fpin) < 0)
478 /* FIXME-update-dir: should include update_dir in message. */
479 error (0, errno, "cannot close %s", CVSADM_ENT);
482 fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
488 while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL)
493 (void) AddEntryNode (entries, ent);
496 node = findnode_fn (entries, ent->user);
499 Entnode_Destroy (ent);
502 /* Ignore unrecognized commands. */
507 if (fclose (fpin) < 0)
508 /* FIXME-update-dir: should include update_dir in message. */
509 error (0, errno, "cannot close %s", CVSADM_ENTLOG);
512 /* Update the list private data to indicate whether subdirectory
513 information is known. Nonexistent list private data is taken
514 to mean that it is known. */
516 sdtp->subdirs = sawdir;
519 sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
520 memset ((char *) sdtp, 0, sizeof (*sdtp));
522 entries->list->data = sdtp;
523 entries->list->delproc = freesdt;
526 if (do_rewrite && !noexec)
527 write_entries (entries);
529 /* clean up and return */
538 Entries_Close(List *list)
544 if (isfile (CVSADM_ENTLOG))
545 write_entries (list);
553 * Free up the memory associated with the data section of an ENTRIES type
557 Entries_delproc (Node *node)
559 Entnode *p = node->data;
565 * Get an Entries file list node, initialize it, and add it to the specified
569 AddEntryNode (List *list, Entnode *entdata)
573 /* was it already there? */
574 if ((p = findnode_fn (list, entdata->user)) != NULL)
580 /* get a node and fill in the regular stuff */
583 p->delproc = Entries_delproc;
585 /* this one gets a key of the name for hashing */
586 /* FIXME This results in duplicated data --- the hash package shouldn't
587 assume that the key is dynamically allocated. The user's free proc
588 should be responsible for freeing the key. */
589 p->key = xstrdup (entdata->user);
592 /* put the node into the list */
600 * Write out the CVS/Template file.
603 WriteTemplate (const char *update_dir, int xdotemplate, const char *repository)
605 #ifdef SERVER_SUPPORT
606 TRACE (1, "Write_Template (%s, %s)", update_dir, repository);
611 if (server_active && xdotemplate)
613 /* Clear the CVS/Template if supported to allow for the case
614 * where the rcsinfo file no longer has an entry for this
617 server_clear_template (update_dir, repository);
618 server_template (update_dir, repository);
628 * Write out/Clear the CVS/Tag file.
631 WriteTag (const char *dir, const char *tag, const char *date, int nonbranch,
632 const char *update_dir, const char *repository)
640 tmp = xmalloc ((dir ? strlen (dir) : 0)
641 + sizeof (CVSADM_TAG)
644 (void) strcpy (tmp, CVSADM_TAG);
646 (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
650 fout = open_file (tmp, "w+");
655 if (fprintf (fout, "N%s\n", tag) < 0)
656 error (1, errno, "write to %s failed", tmp);
660 if (fprintf (fout, "T%s\n", tag) < 0)
661 error (1, errno, "write to %s failed", tmp);
666 if (fprintf (fout, "D%s\n", date) < 0)
667 error (1, errno, "write to %s failed", tmp);
669 if (fclose (fout) == EOF)
670 error (1, errno, "cannot close %s", tmp);
673 if (unlink_file (tmp) < 0 && ! existence_error (errno))
674 error (1, errno, "cannot remove %s", tmp);
676 #ifdef SERVER_SUPPORT
678 server_set_sticky (update_dir, repository, tag, date, nonbranch);
682 /* Parse the CVS/Tag file for the current directory.
684 If it contains a date, sets *DATEP to the date in a newly malloc'd
685 string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
687 If it contains a branch tag, sets *TAGP to the tag in a newly
688 malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
690 If it contains a nonbranch tag, sets *TAGP to the tag in a newly
691 malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
693 If it does not exist, or contains something unrecognized by this
694 version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
695 an unspecified value.
697 If there is an error, print an error message, set *DATEP and *TAGP
698 to NULL, and return. */
700 ParseTag (char **tagp, char **datep, int *nonbranchp)
705 *tagp = (char *) NULL;
707 *datep = (char *) NULL;
708 /* Always store a value here, even in the 'D' case where the value
709 is unspecified. Shuts up tools which check for references to
710 uninitialized memory. */
711 if (nonbranchp != NULL)
713 fp = CVS_FOPEN (CVSADM_TAG, "r");
718 size_t line_chars_allocated;
721 line_chars_allocated = 0;
723 if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
725 /* Remove any trailing newline. */
726 if (line[line_length - 1] == '\n')
727 line[--line_length] = '\0';
732 *tagp = xstrdup (line + 1);
736 *datep = xstrdup (line + 1);
740 *tagp = xstrdup (line + 1);
741 if (nonbranchp != NULL)
745 /* Silently ignore it; it may have been
746 written by a future version of CVS which extends the
754 /* FIXME-update-dir: should include update_dir in messages. */
756 error (0, 0, "cannot read %s: end of file", CVSADM_TAG);
758 error (0, errno, "cannot read %s", CVSADM_TAG);
762 /* FIXME-update-dir: should include update_dir in message. */
763 error (0, errno, "cannot close %s", CVSADM_TAG);
767 else if (!existence_error (errno))
768 /* FIXME-update-dir: should include update_dir in message. */
769 error (0, errno, "cannot open %s", CVSADM_TAG);
773 * This is called if all subdirectory information is known, but there
774 * aren't any subdirectories. It records that fact in the list
779 Subdirs_Known (List *entries)
781 struct stickydirtag *sdtp = entries->list->data;
783 /* If there is no list private data, that means that the
784 subdirectory information is known. */
785 if (sdtp != NULL && ! sdtp->subdirs)
792 /* Create Entries.Log so that Entries_Close will do something. */
793 entfilename = CVSADM_ENTLOG;
794 fp = CVS_FOPEN (entfilename, "a");
797 int save_errno = errno;
799 /* As in subdir_record, just silently skip the whole thing
800 if there is no CVSADM directory. */
801 if (! isdir (CVSADM))
803 error (1, save_errno, "cannot open %s", entfilename);
807 if (fclose (fp) == EOF)
808 error (1, errno, "cannot close %s", entfilename);
814 /* Record subdirectory information. */
817 subdir_record (int cmd, const char *parent, const char *dir)
821 /* None of the information associated with a directory is
822 currently meaningful. */
823 entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "",
824 (char *) NULL, (char *) NULL,
830 entfilename = CVSADM_ENTLOG;
833 entfilename = xmalloc (strlen (parent)
834 + sizeof CVSADM_ENTLOG
836 sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG);
839 entfile = CVS_FOPEN (entfilename, "a");
842 int save_errno = errno;
844 /* It is not an error if there is no CVS administration
845 directory. Permitting this case simplifies some
850 if (! isdir (CVSADM))
855 sprintf (entfilename, "%s/%s", parent, CVSADM);
856 if (! isdir (entfilename))
864 error (1, save_errno, "cannot open %s", entfilename);
867 if (fprintf (entfile, "%c ", cmd) < 0)
868 error (1, errno, "cannot write %s", entfilename);
870 if (fputentent (entfile, entnode) != 0)
871 error (1, errno, "cannot write %s", entfilename);
873 if (fclose (entfile) == EOF)
874 error (1, errno, "error closing %s", entfilename);
887 * Record the addition of a new subdirectory DIR in PARENT. PARENT
888 * may be NULL, which means the current directory. ENTRIES is the
889 * current entries list; it may be NULL, which means that it need not
894 Subdir_Register (List *entries, const char *parent, const char *dir)
898 /* Ignore attempts to register ".". These can happen in the
900 if (dir[0] == '.' && dir[1] == '\0')
903 entnode = subdir_record ('A', parent, dir);
905 if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
906 (void) AddEntryNode (entries, entnode);
908 Entnode_Destroy (entnode);
914 * Record the removal of a subdirectory. The arguments are the same
915 * as for Subdir_Register.
919 Subdir_Deregister (List *entries, const char *parent, const char *dir)
923 entnode = subdir_record ('R', parent, dir);
924 Entnode_Destroy (entnode);
926 if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
930 p = findnode_fn (entries, dir);
938 /* OK, the following base_* code tracks the revisions of the files in
939 CVS/Base. We do this in a file CVS/Baserev. Separate from
940 CVS/Entries because it needs to go in separate data structures
941 anyway (the name in Entries must be unique), so this seemed
942 cleaner. The business of rewriting the whole file in
943 base_deregister and base_register is the kind of thing we used to
944 do for Entries and which turned out to be slow, which is why there
945 is now the Entries.Log machinery. So maybe from that point of
946 view it is a mistake to do this separately from Entries, I dunno.
948 We also need something analogous for:
950 1. CVS/Template (so we can update the Template file automagically
951 without the user needing to check out a new working directory).
952 Updating would probably print a message (that part might be
953 optional, although probably it should be visible because not all
954 cvs commands would make the update happen and so it is a
955 user-visible behavior). Constructing version number for template
956 is a bit hairy (base it on the timestamp on the server? Or see if
957 the template is in checkoutlist and if yes use its versioning and
958 if no don't version it?)....
960 2. cvsignore (need to keep a copy in the working directory to do
961 "cvs release" on the client side; see comment at src/release.c
962 (release). Would also allow us to stop needing Questionable. */
965 /* Set the revision for FILE to *REV. */
967 /* Get the revision for FILE and put it in a newly malloc'd string
968 in *REV, or put NULL if not mentioned. */
974 static void base_walk (enum base_walk, struct file_info *, char **);
976 /* Read through the lines in CVS/Baserev, taking the actions as documented
980 base_walk (enum base_walk code, struct file_info *finfo, char **rev)
984 size_t line_allocated;
986 char *baserev_fullname;
987 char *baserevtmp_fullname;
993 /* First compute the fullnames for the error messages. This
994 computation probably should be broken out into a separate function,
995 as recurse.c does it too and places like Entries_Open should be
997 baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV)
998 + strlen (finfo->update_dir)
1000 baserev_fullname[0] = '\0';
1001 baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP)
1002 + strlen (finfo->update_dir)
1004 baserevtmp_fullname[0] = '\0';
1005 if (finfo->update_dir[0] != '\0')
1007 strcat (baserev_fullname, finfo->update_dir);
1008 strcat (baserev_fullname, "/");
1009 strcat (baserevtmp_fullname, finfo->update_dir);
1010 strcat (baserevtmp_fullname, "/");
1012 strcat (baserev_fullname, CVSADM_BASEREV);
1013 strcat (baserevtmp_fullname, CVSADM_BASEREVTMP);
1015 fp = CVS_FOPEN (CVSADM_BASEREV, "r");
1018 if (!existence_error (errno))
1020 error (0, errno, "cannot open %s for reading", baserev_fullname);
1028 case BASE_DEREGISTER:
1029 newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
1032 error (0, errno, "cannot open %s for writing",
1033 baserevtmp_fullname);
1044 while (getline (&line, &line_allocated, fp) >= 0)
1051 /* Ignore, for future expansion. */
1054 linefile = line + 1;
1055 p = strchr (linefile, '/');
1057 /* Syntax error, ignore. */
1060 p = strchr (linerev, '/');
1065 if (fncmp (linefile, finfo->file) == 0)
1070 case BASE_DEREGISTER:
1071 /* Don't copy over the old entry, we don't want it. */
1075 *rev = xstrdup (linerev);
1086 case BASE_DEREGISTER:
1087 if (fprintf (newf, "%s\n", line) < 0)
1088 error (0, errno, "error writing %s",
1089 baserevtmp_fullname);
1097 error (0, errno, "cannot read %s", baserev_fullname);
1101 if (code == BASE_REGISTER)
1103 if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
1104 error (0, errno, "error writing %s",
1105 baserevtmp_fullname);
1115 if (fclose (fp) < 0)
1116 error (0, errno, "cannot close %s", baserev_fullname);
1120 if (fclose (newf) < 0)
1121 error (0, errno, "cannot close %s", baserevtmp_fullname);
1122 rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
1125 free (baserev_fullname);
1126 free (baserevtmp_fullname);
1129 /* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
1130 or NULL if not listed. */
1133 base_get (struct file_info *finfo)
1136 base_walk (BASE_GET, finfo, &rev);
1140 /* Set the revision for FILE to REV. */
1143 base_register (struct file_info *finfo, char *rev)
1145 base_walk (BASE_REGISTER, finfo, &rev);
1151 base_deregister (struct file_info *finfo)
1153 base_walk (BASE_DEREGISTER, finfo, NULL);