2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * Entries file to Files file
15 * Creates the file Files containing the names that comprise the project, from
25 static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
27 static Entnode *fgetentent PROTO((FILE *, char *, int *));
28 static int fputentent PROTO((FILE *, Entnode *));
30 static Entnode *subdir_record PROTO((int, const char *, const char *));
33 static char *entfilename; /* for error messages */
38 * Construct an Entnode
40 static Entnode *Entnode_Create PROTO ((enum ent_type, const char *,
41 const char *, const char *,
42 const char *, const char *,
43 const char *, const char *));
46 Entnode_Create(type, user, vn, ts, options, tag, date, ts_conflict)
54 const char *ts_conflict;
58 /* Note that timestamp and options must be non-NULL */
59 ent = (Entnode *) xmalloc (sizeof (Entnode));
61 ent->user = xstrdup (user);
62 ent->version = xstrdup (vn);
63 ent->timestamp = xstrdup (ts ? ts : "");
64 ent->options = xstrdup (options ? options : "");
65 ent->tag = xstrdup (tag);
66 ent->date = xstrdup (date);
67 ent->conflict = xstrdup (ts_conflict);
75 static void Entnode_Destroy PROTO ((Entnode *));
83 free (ent->timestamp);
95 * Write out the line associated with a node of an entries file
97 static int write_ent_proc PROTO ((Node *, void *));
99 write_ent_proc (node, closure)
103 Entnode *entnode = node->data;
105 if (closure != NULL && entnode->type != ENT_FILE)
106 *(int *) closure = 1;
108 if (fputentent(entfile, entnode))
109 error (1, errno, "cannot write %s", entfilename);
115 * write out the current entries file given a list, making a backup copy
126 /* open the new one and walk the list writing entries */
127 entfilename = CVSADM_ENTBAK;
128 entfile = CVS_FOPEN (entfilename, "w+");
131 /* Make this a warning, not an error. For example, one user might
132 have checked out a working directory which, for whatever reason,
133 contains an Entries.Log file. A second user, without write access
134 to that working directory, might want to do a "cvs log". The
135 problem rewriting Entries shouldn't affect the ability of "cvs log"
136 to work, although the warning is probably a good idea so that
137 whether Entries gets rewritten is not an inexplicable process. */
138 /* FIXME: should be including update_dir in message. */
139 error (0, errno, "cannot rewrite %s", entfilename);
141 /* Now just return. We leave the Entries.Log file around. As far
142 as I know, there is never any data lying around in 'list' that
143 is not in Entries.Log at this time (if there is an error writing
144 Entries.Log that is a separate problem). */
148 (void) walklist (list, write_ent_proc, (void *) &sawdir);
151 struct stickydirtag *sdtp;
153 /* We didn't write out any directories. Check the list
154 private data to see whether subdirectory information is
155 known. If it is, we need to write out an empty D line. */
156 sdtp = list->list->data;
157 if (sdtp == NULL || sdtp->subdirs)
158 if (fprintf (entfile, "D\n") < 0)
159 error (1, errno, "cannot write %s", entfilename);
161 if (fclose (entfile) == EOF)
162 error (1, errno, "error closing %s", entfilename);
164 /* now, atomically (on systems that support it) rename it */
165 rename_file (entfilename, CVSADM_ENT);
167 /* now, remove the log file */
168 if (unlink_file (CVSADM_ENTLOG) < 0
169 && !existence_error (errno))
170 error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
176 * Removes the argument file from the Entries file if necessary.
179 Scratch_Entry (list, fname)
186 (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n",
187 CLIENT_SERVER_STR, fname);
189 /* hashlookup to see if it is there */
190 if ((node = findnode_fn (list, fname)) != NULL)
194 entfilename = CVSADM_ENTLOG;
195 entfile = open_file (entfilename, "a");
197 if (fprintf (entfile, "R ") < 0)
198 error (1, errno, "cannot write %s", entfilename);
200 write_ent_proc (node, NULL);
202 if (fclose (entfile) == EOF)
203 error (1, errno, "error closing %s", entfilename);
206 delnode (node); /* delete the node */
208 #ifdef SERVER_SUPPORT
210 server_scratch (fname);
218 * Enters the given file name/version/time-stamp into the Entries file,
219 * removing the old entry first, if necessary.
222 Register (list, fname, vn, ts, options, tag, date, ts_conflict)
230 const char *ts_conflict;
235 #ifdef SERVER_SUPPORT
238 server_register (fname, vn, ts, options, tag, date, ts_conflict);
244 (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
246 fname, vn, ts ? ts : "",
247 ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
248 options, tag ? tag : "", date ? date : "");
251 entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
253 node = AddEntryNode (list, entnode);
257 entfilename = CVSADM_ENTLOG;
258 entfile = CVS_FOPEN (entfilename, "a");
262 /* Warning, not error, as in write_entries. */
263 /* FIXME-update-dir: should be including update_dir in message. */
264 error (0, errno, "cannot open %s", entfilename);
268 if (fprintf (entfile, "A ") < 0)
269 error (1, errno, "cannot write %s", entfilename);
271 write_ent_proc (node, NULL);
273 if (fclose (entfile) == EOF)
274 error (1, errno, "error closing %s", entfilename);
279 * Node delete procedure for list-private sticky dir tag/date info
285 struct stickydirtag *sdtp = p->data;
291 free ((char *) sdtp);
294 /* Return the next real Entries line. On end of file, returns NULL.
295 On error, prints an error message and returns NULL. */
298 fgetentent(fpin, cmd, sawdir)
305 size_t line_chars_allocated;
308 char *l, *user, *vn, *ts, *options;
309 char *tag_or_date, *tag, *date, *ts_conflict;
313 line_chars_allocated = 0;
316 while ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0)
320 /* If CMD is not NULL, we are reading an Entries.Log file.
321 Each line in the Entries.Log file starts with a single
322 character command followed by a space. For backward
323 compatibility, the absence of a space indicates an add
343 /* An empty D line is permitted; it is a signal that this
344 Entries file lists all known subdirectories. */
351 if ((cp = strchr (user, '/')) == NULL)
355 if ((cp = strchr (vn, '/')) == NULL)
359 if ((cp = strchr (ts, '/')) == NULL)
363 if ((cp = strchr (options, '/')) == NULL)
367 if ((cp = strchr (tag_or_date, '\n')) == NULL)
371 date = (char *) NULL;
372 if (*tag_or_date == 'T')
373 tag = tag_or_date + 1;
374 else if (*tag_or_date == 'D')
375 date = tag_or_date + 1;
377 if ((ts_conflict = strchr (ts, '+')))
378 *ts_conflict++ = '\0';
381 * XXX - Convert timestamp from old format to new format.
383 * If the timestamp doesn't match the file's current
384 * mtime, we'd have to generate a string that doesn't
385 * match anyways, so cheat and base it on the existing
386 * string; it doesn't have to match the same mod time.
388 * For an unmodified file, write the correct timestamp.
392 if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0)
394 char *c = ctime (&sb.st_mtime);
395 /* Fix non-standard format. */
396 if (c[8] == '0') c[8] = ' ';
398 if (!strncmp (ts + 25, c, 24))
399 ts = time_stamp (user);
408 ent = Entnode_Create (type, user, vn, ts, options, tag, date,
413 if (line_length < 0 && !feof (fpin))
414 error (0, errno, "cannot read entries file");
430 if (fprintf (fp, "D") < 0)
435 if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
439 if (fprintf (fp, "+%s", p->conflict) < 0)
442 if (fprintf (fp, "/%s/", p->options) < 0)
447 if (fprintf (fp, "T%s\n", p->tag) < 0)
452 if (fprintf (fp, "D%s\n", p->date) < 0)
457 if (fprintf (fp, "\n") < 0)
465 /* Read the entries file into a list, hashing on the file name.
467 UPDATE_DIR is the name of the current directory, for use in error
468 messages, or NULL if not known (that is, noone has gotten around
469 to updating the caller to pass in the information). */
471 Entries_Open (aflag, update_dir)
476 struct stickydirtag *sdtp = NULL;
478 char *dirtag, *dirdate;
484 /* get a fresh list... */
485 entries = getlist ();
488 * Parse the CVS/Tag file, to get any default tag/date settings. Use
489 * list-private storage to tuck them away for Version_TS().
491 ParseTag (&dirtag, &dirdate, &dirnonbranch);
492 if (aflag || dirtag || dirdate)
494 sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
495 memset ((char *) sdtp, 0, sizeof (*sdtp));
497 sdtp->tag = xstrdup (dirtag);
498 sdtp->date = xstrdup (dirdate);
499 sdtp->nonbranch = dirnonbranch;
501 /* feed it into the list-private area */
502 entries->list->data = sdtp;
503 entries->list->delproc = freesdt;
508 fpin = CVS_FOPEN (CVSADM_ENT, "r");
511 if (update_dir != NULL)
512 error (0, 0, "in directory %s:", update_dir);
513 error (0, errno, "cannot open %s for reading", CVSADM_ENT);
517 while ((ent = fgetentent (fpin, (char *) NULL, &sawdir)) != NULL)
519 (void) AddEntryNode (entries, ent);
522 if (fclose (fpin) < 0)
523 /* FIXME-update-dir: should include update_dir in message. */
524 error (0, errno, "cannot close %s", CVSADM_ENT);
527 fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
533 while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL)
538 (void) AddEntryNode (entries, ent);
541 node = findnode_fn (entries, ent->user);
544 Entnode_Destroy (ent);
547 /* Ignore unrecognized commands. */
548 Entnode_Destroy (ent);
553 if (fclose (fpin) < 0)
554 /* FIXME-update-dir: should include update_dir in message. */
555 error (0, errno, "cannot close %s", CVSADM_ENTLOG);
558 /* Update the list private data to indicate whether subdirectory
559 information is known. Nonexistent list private data is taken
560 to mean that it is known. */
562 sdtp->subdirs = sawdir;
565 sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
566 memset ((char *) sdtp, 0, sizeof (*sdtp));
568 entries->list->data = sdtp;
569 entries->list->delproc = freesdt;
572 if (do_rewrite && !noexec)
573 write_entries (entries);
575 /* clean up and return */
591 if (isfile (CVSADM_ENTLOG))
592 write_entries (list);
600 * Free up the memory associated with the data section of an ENTRIES type
604 Entries_delproc (node)
607 Entnode *p = node->data;
613 * Get an Entries file list node, initialize it, and add it to the specified
617 AddEntryNode (list, entdata)
623 /* was it already there? */
624 if ((p = findnode_fn (list, entdata->user)) != NULL)
630 /* get a node and fill in the regular stuff */
633 p->delproc = Entries_delproc;
635 /* this one gets a key of the name for hashing */
636 /* FIXME This results in duplicated data --- the hash package shouldn't
637 assume that the key is dynamically allocated. The user's free proc
638 should be responsible for freeing the key. */
639 p->key = xstrdup (entdata->user);
642 /* put the node into the list */
647 static char *root_template;
650 get_root_template(const char *repository, const char *path)
653 if (strcmp(path, root_template) == 0)
657 if ((root_template = strdup(path)) == NULL)
663 * Write out/Clear the CVS/Template file.
666 WriteTemplate (dir, update_dir)
668 const char *update_dir;
674 if (Parse_Info(CVSROOTADM_RCSINFO, "cvs", get_root_template, 1) < 0)
677 if (asprintf(&tmp, "%s/%s", dir, CVSADM_TEMPLATE) < 0)
678 error (1, errno, "out of memory");
680 if (stat(root_template, &st1) == 0) {
681 if (stat(tmp, &st2) < 0 || st1.st_mtime != st2.st_mtime) {
685 if ((fi = open_file(root_template, "r")) != NULL) {
686 if ((fo = open_file(tmp, "w")) != NULL) {
690 while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
691 fwrite(buf, 1, n, fo);
693 if (ferror(fi) || ferror(fo)) {
696 error (1, errno, "error copying Template");
698 struct timeval times[2];
700 times[0].tv_sec = st1.st_mtime;
701 times[0].tv_usec = 0;
714 * Write out/Clear the CVS/Tag file.
717 WriteTag (dir, tag, date, nonbranch, update_dir, repository)
722 const char *update_dir;
723 const char *repository;
731 tmp = xmalloc ((dir ? strlen (dir) : 0)
732 + sizeof (CVSADM_TAG)
735 (void) strcpy (tmp, CVSADM_TAG);
737 (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
741 fout = open_file (tmp, "w+");
746 if (fprintf (fout, "N%s\n", tag) < 0)
747 error (1, errno, "write to %s failed", tmp);
751 if (fprintf (fout, "T%s\n", tag) < 0)
752 error (1, errno, "write to %s failed", tmp);
757 if (fprintf (fout, "D%s\n", date) < 0)
758 error (1, errno, "write to %s failed", tmp);
760 if (fclose (fout) == EOF)
761 error (1, errno, "cannot close %s", tmp);
764 if (unlink_file (tmp) < 0 && ! existence_error (errno))
765 error (1, errno, "cannot remove %s", tmp);
767 #ifdef SERVER_SUPPORT
769 server_set_sticky (update_dir, repository, tag, date, nonbranch);
773 /* Parse the CVS/Tag file for the current directory.
775 If it contains a date, sets *DATEP to the date in a newly malloc'd
776 string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
778 If it contains a branch tag, sets *TAGP to the tag in a newly
779 malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
781 If it contains a nonbranch tag, sets *TAGP to the tag in a newly
782 malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
784 If it does not exist, or contains something unrecognized by this
785 version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
786 an unspecified value.
788 If there is an error, print an error message, set *DATEP and *TAGP
789 to NULL, and return. */
791 ParseTag (tagp, datep, nonbranchp)
799 *tagp = (char *) NULL;
801 *datep = (char *) NULL;
802 /* Always store a value here, even in the 'D' case where the value
803 is unspecified. Shuts up tools which check for references to
804 uninitialized memory. */
805 if (nonbranchp != NULL)
807 fp = CVS_FOPEN (CVSADM_TAG, "r");
812 size_t line_chars_allocated;
815 line_chars_allocated = 0;
817 if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
819 /* Remove any trailing newline. */
820 if (line[line_length - 1] == '\n')
821 line[--line_length] = '\0';
826 *tagp = xstrdup (line + 1);
830 *datep = xstrdup (line + 1);
834 *tagp = xstrdup (line + 1);
835 if (nonbranchp != NULL)
839 /* Silently ignore it; it may have been
840 written by a future version of CVS which extends the
848 /* FIXME-update-dir: should include update_dir in messages. */
850 error (0, 0, "cannot read %s: end of file", CVSADM_TAG);
852 error (0, errno, "cannot read %s", CVSADM_TAG);
856 /* FIXME-update-dir: should include update_dir in message. */
857 error (0, errno, "cannot close %s", CVSADM_TAG);
861 else if (!existence_error (errno))
862 /* FIXME-update-dir: should include update_dir in message. */
863 error (0, errno, "cannot open %s", CVSADM_TAG);
867 * This is called if all subdirectory information is known, but there
868 * aren't any subdirectories. It records that fact in the list
873 Subdirs_Known (entries)
876 struct stickydirtag *sdtp = entries->list->data;
878 /* If there is no list private data, that means that the
879 subdirectory information is known. */
880 if (sdtp != NULL && ! sdtp->subdirs)
887 /* Create Entries.Log so that Entries_Close will do something. */
888 entfilename = CVSADM_ENTLOG;
889 fp = CVS_FOPEN (entfilename, "a");
892 int save_errno = errno;
894 /* As in subdir_record, just silently skip the whole thing
895 if there is no CVSADM directory. */
896 if (! isdir (CVSADM))
898 error (1, save_errno, "cannot open %s", entfilename);
902 if (fclose (fp) == EOF)
903 error (1, errno, "cannot close %s", entfilename);
909 /* Record subdirectory information. */
912 subdir_record (cmd, parent, dir)
919 /* None of the information associated with a directory is
920 currently meaningful. */
921 entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "",
922 (char *) NULL, (char *) NULL,
928 entfilename = CVSADM_ENTLOG;
931 entfilename = xmalloc (strlen (parent)
932 + sizeof CVSADM_ENTLOG
934 sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG);
937 entfile = CVS_FOPEN (entfilename, "a");
940 int save_errno = errno;
942 /* It is not an error if there is no CVS administration
943 directory. Permitting this case simplifies some
948 if (! isdir (CVSADM))
953 sprintf (entfilename, "%s/%s", parent, CVSADM);
954 if (! isdir (entfilename))
962 error (1, save_errno, "cannot open %s", entfilename);
965 if (fprintf (entfile, "%c ", cmd) < 0)
966 error (1, errno, "cannot write %s", entfilename);
968 if (fputentent (entfile, entnode) != 0)
969 error (1, errno, "cannot write %s", entfilename);
971 if (fclose (entfile) == EOF)
972 error (1, errno, "error closing %s", entfilename);
985 * Record the addition of a new subdirectory DIR in PARENT. PARENT
986 * may be NULL, which means the current directory. ENTRIES is the
987 * current entries list; it may be NULL, which means that it need not
992 Subdir_Register (entries, parent, dir)
999 /* Ignore attempts to register ".". These can happen in the
1001 if (dir[0] == '.' && dir[1] == '\0')
1004 entnode = subdir_record ('A', parent, dir);
1006 if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
1007 (void) AddEntryNode (entries, entnode);
1009 Entnode_Destroy (entnode);
1013 * Record the removal of a subdirectory. The arguments are the same
1014 * as for Subdir_Register.
1018 Subdir_Deregister (entries, parent, dir)
1025 entnode = subdir_record ('R', parent, dir);
1026 Entnode_Destroy (entnode);
1028 if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
1032 p = findnode_fn (entries, dir);
1040 /* OK, the following base_* code tracks the revisions of the files in
1041 CVS/Base. We do this in a file CVS/Baserev. Separate from
1042 CVS/Entries because it needs to go in separate data structures
1043 anyway (the name in Entries must be unique), so this seemed
1044 cleaner. The business of rewriting the whole file in
1045 base_deregister and base_register is the kind of thing we used to
1046 do for Entries and which turned out to be slow, which is why there
1047 is now the Entries.Log machinery. So maybe from that point of
1048 view it is a mistake to do this separately from Entries, I dunno.
1050 We also need something analogous for:
1052 1. CVS/Template (so we can update the Template file automagically
1053 without the user needing to check out a new working directory).
1054 Updating would probably print a message (that part might be
1055 optional, although probably it should be visible because not all
1056 cvs commands would make the update happen and so it is a
1057 user-visible behavior). Constructing version number for template
1058 is a bit hairy (base it on the timestamp on the server? Or see if
1059 the template is in checkoutlist and if yes use its versioning and
1060 if no don't version it?)....
1062 2. cvsignore (need to keep a copy in the working directory to do
1063 "cvs release" on the client side; see comment at src/release.c
1064 (release). Would also allow us to stop needing Questionable. */
1067 /* Set the revision for FILE to *REV. */
1069 /* Get the revision for FILE and put it in a newly malloc'd string
1070 in *REV, or put NULL if not mentioned. */
1076 static void base_walk PROTO ((enum base_walk, struct file_info *, char **));
1078 /* Read through the lines in CVS/Baserev, taking the actions as documented
1082 base_walk (code, finfo, rev)
1083 enum base_walk code;
1084 struct file_info *finfo;
1089 size_t line_allocated;
1091 char *baserev_fullname;
1092 char *baserevtmp_fullname;
1098 /* First compute the fullnames for the error messages. This
1099 computation probably should be broken out into a separate function,
1100 as recurse.c does it too and places like Entries_Open should be
1102 baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV)
1103 + strlen (finfo->update_dir)
1105 baserev_fullname[0] = '\0';
1106 baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP)
1107 + strlen (finfo->update_dir)
1109 baserevtmp_fullname[0] = '\0';
1110 if (finfo->update_dir[0] != '\0')
1112 strcat (baserev_fullname, finfo->update_dir);
1113 strcat (baserev_fullname, "/");
1114 strcat (baserevtmp_fullname, finfo->update_dir);
1115 strcat (baserevtmp_fullname, "/");
1117 strcat (baserev_fullname, CVSADM_BASEREV);
1118 strcat (baserevtmp_fullname, CVSADM_BASEREVTMP);
1120 fp = CVS_FOPEN (CVSADM_BASEREV, "r");
1123 if (!existence_error (errno))
1125 error (0, errno, "cannot open %s for reading", baserev_fullname);
1133 case BASE_DEREGISTER:
1134 newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
1137 error (0, errno, "cannot open %s for writing",
1138 baserevtmp_fullname);
1149 while (getline (&line, &line_allocated, fp) >= 0)
1156 /* Ignore, for future expansion. */
1159 linefile = line + 1;
1160 p = strchr (linefile, '/');
1162 /* Syntax error, ignore. */
1165 p = strchr (linerev, '/');
1170 if (fncmp (linefile, finfo->file) == 0)
1175 case BASE_DEREGISTER:
1176 /* Don't copy over the old entry, we don't want it. */
1180 *rev = xstrdup (linerev);
1191 case BASE_DEREGISTER:
1192 if (fprintf (newf, "%s\n", line) < 0)
1193 error (0, errno, "error writing %s",
1194 baserevtmp_fullname);
1202 error (0, errno, "cannot read %s", baserev_fullname);
1206 if (code == BASE_REGISTER)
1208 if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
1209 error (0, errno, "error writing %s",
1210 baserevtmp_fullname);
1220 if (fclose (fp) < 0)
1221 error (0, errno, "cannot close %s", baserev_fullname);
1225 if (fclose (newf) < 0)
1226 error (0, errno, "cannot close %s", baserevtmp_fullname);
1227 rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
1230 free (baserev_fullname);
1231 free (baserevtmp_fullname);
1234 /* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
1235 or NULL if not listed. */
1239 struct file_info *finfo;
1242 base_walk (BASE_GET, finfo, &rev);
1246 /* Set the revision for FILE to REV. */
1249 base_register (finfo, rev)
1250 struct file_info *finfo;
1253 base_walk (BASE_REGISTER, finfo, &rev);
1259 base_deregister (finfo)
1260 struct file_info *finfo;
1262 base_walk (BASE_DEREGISTER, finfo, NULL);