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
22 static Node
*AddEntryNode (List
* list
, Entnode
*entnode
);
24 static Entnode
*fgetentent (FILE *, char *, int *);
25 static int fputentent (FILE *, Entnode
*);
27 static Entnode
*subdir_record (int, const char *, const char *);
30 static char *entfilename
; /* for error messages */
35 * Construct an Entnode
38 Entnode_Create (enum ent_type type
, const char *user
, const char *vn
,
39 const char *ts
, const char *options
, const char *tag
,
40 const char *date
, const char *ts_conflict
)
44 /* Note that timestamp and options must be non-NULL */
45 ent
= xmalloc (sizeof (Entnode
));
47 ent
->user
= xstrdup (user
);
48 ent
->version
= xstrdup (vn
);
49 ent
->timestamp
= xstrdup (ts
? ts
: "");
50 ent
->options
= xstrdup (options
? options
: "");
51 ent
->tag
= xstrdup (tag
);
52 ent
->date
= xstrdup (date
);
53 ent
->conflict
= xstrdup (ts_conflict
);
61 static void Entnode_Destroy (Entnode
*);
64 Entnode_Destroy (Entnode
*ent
)
68 free (ent
->timestamp
);
80 * Write out the line associated with a node of an entries file
82 static int write_ent_proc (Node
*, void *);
84 write_ent_proc (Node
*node
, void *closure
)
86 Entnode
*entnode
= node
->data
;
88 if (closure
!= NULL
&& entnode
->type
!= ENT_FILE
)
91 if (fputentent (entfile
, entnode
))
92 error (1, errno
, "cannot write %s", entfilename
);
98 * write out the current entries file given a list, making a backup copy
102 write_entries (List
*list
)
108 /* open the new one and walk the list writing entries */
109 entfilename
= CVSADM_ENTBAK
;
110 entfile
= CVS_FOPEN (entfilename
, "w+");
113 /* Make this a warning, not an error. For example, one user might
114 have checked out a working directory which, for whatever reason,
115 contains an Entries.Log file. A second user, without write access
116 to that working directory, might want to do a "cvs log". The
117 problem rewriting Entries shouldn't affect the ability of "cvs log"
118 to work, although the warning is probably a good idea so that
119 whether Entries gets rewritten is not an inexplicable process. */
120 /* FIXME: should be including update_dir in message. */
121 error (0, errno
, "cannot rewrite %s", entfilename
);
123 /* Now just return. We leave the Entries.Log file around. As far
124 as I know, there is never any data lying around in 'list' that
125 is not in Entries.Log at this time (if there is an error writing
126 Entries.Log that is a separate problem). */
130 (void) walklist (list
, write_ent_proc
, (void *) &sawdir
);
133 struct stickydirtag
*sdtp
;
135 /* We didn't write out any directories. Check the list
136 private data to see whether subdirectory information is
137 known. If it is, we need to write out an empty D line. */
138 sdtp
= list
->list
->data
;
139 if (sdtp
== NULL
|| sdtp
->subdirs
)
140 if (fprintf (entfile
, "D\n") < 0)
141 error (1, errno
, "cannot write %s", entfilename
);
143 if (fclose (entfile
) == EOF
)
144 error (1, errno
, "error closing %s", entfilename
);
146 /* now, atomically (on systems that support it) rename it */
147 rename_file (entfilename
, CVSADM_ENT
);
149 /* now, remove the log file */
150 if (unlink_file (CVSADM_ENTLOG
) < 0
151 && !existence_error (errno
))
152 error (0, errno
, "cannot remove %s", CVSADM_ENTLOG
);
158 * Removes the argument file from the Entries file if necessary.
161 Scratch_Entry (List
*list
, const char *fname
)
165 TRACE (TRACE_FUNCTION
, "Scratch_Entry(%s)", fname
);
167 /* hashlookup to see if it is there */
168 if ((node
= findnode_fn (list
, fname
)) != NULL
)
172 entfilename
= CVSADM_ENTLOG
;
173 entfile
= xfopen (entfilename
, "a");
175 if (fprintf (entfile
, "R ") < 0)
176 error (1, errno
, "cannot write %s", entfilename
);
178 write_ent_proc (node
, NULL
);
180 if (fclose (entfile
) == EOF
)
181 error (1, errno
, "error closing %s", entfilename
);
184 delnode (node
); /* delete the node */
186 #ifdef SERVER_SUPPORT
188 server_scratch (fname
);
196 * Enters the given file name/version/time-stamp into the Entries file,
197 * removing the old entry first, if necessary.
200 Register (List
*list
, const char *fname
, const char *vn
, const char *ts
,
201 const char *options
, const char *tag
, const char *date
,
202 const char *ts_conflict
)
207 #ifdef SERVER_SUPPORT
210 server_register (fname
, vn
, ts
, options
, tag
, date
, ts_conflict
);
214 TRACE (TRACE_FUNCTION
, "Register(%s, %s, %s%s%s, %s, %s %s)",
215 fname
, vn
, ts
? ts
: "",
216 ts_conflict
? "+" : "", ts_conflict
? ts_conflict
: "",
217 options
, tag
? tag
: "", date
? date
: "");
219 entnode
= Entnode_Create (ENT_FILE
, fname
, vn
, ts
, options
, tag
, date
,
221 node
= AddEntryNode (list
, entnode
);
225 entfilename
= CVSADM_ENTLOG
;
226 entfile
= CVS_FOPEN (entfilename
, "a");
230 /* Warning, not error, as in write_entries. */
231 /* FIXME-update-dir: should be including update_dir in message. */
232 error (0, errno
, "cannot open %s", entfilename
);
236 if (fprintf (entfile
, "A ") < 0)
237 error (1, errno
, "cannot write %s", entfilename
);
239 write_ent_proc (node
, NULL
);
241 if (fclose (entfile
) == EOF
)
242 error (1, errno
, "error closing %s", entfilename
);
247 * Node delete procedure for list-private sticky dir tag/date info
252 struct stickydirtag
*sdtp
= p
->data
;
258 free ((char *) sdtp
);
261 /* Return the next real Entries line. On end of file, returns NULL.
262 On error, prints an error message and returns NULL. */
265 fgetentent (FILE *fpin
, char *cmd
, int *sawdir
)
269 size_t line_chars_allocated
;
272 char *l
, *user
, *vn
, *ts
, *options
;
273 char *tag_or_date
, *tag
, *date
, *ts_conflict
;
277 line_chars_allocated
= 0;
280 while ((line_length
= getline (&line
, &line_chars_allocated
, fpin
)) > 0)
284 /* If CMD is not NULL, we are reading an Entries.Log file.
285 Each line in the Entries.Log file starts with a single
286 character command followed by a space. For backward
287 compatibility, the absence of a space indicates an add
307 /* An empty D line is permitted; it is a signal that this
308 Entries file lists all known subdirectories. */
315 if ((cp
= strchr (user
, '/')) == NULL
)
319 if ((cp
= strchr (vn
, '/')) == NULL
)
323 if ((cp
= strchr (ts
, '/')) == NULL
)
327 if ((cp
= strchr (options
, '/')) == NULL
)
331 if ((cp
= strchr (tag_or_date
, '\n')) == NULL
)
336 if (*tag_or_date
== 'T')
337 tag
= tag_or_date
+ 1;
338 else if (*tag_or_date
== 'D')
339 date
= tag_or_date
+ 1;
341 if ((ts_conflict
= strchr (ts
, '+')))
342 *ts_conflict
++ = '\0';
345 * XXX - Convert timestamp from old format to new format.
347 * If the timestamp doesn't match the file's current
348 * mtime, we'd have to generate a string that doesn't
349 * match anyways, so cheat and base it on the existing
350 * string; it doesn't have to match the same mod time.
352 * For an unmodified file, write the correct timestamp.
356 if (strlen (ts
) > 30 && stat (user
, &sb
) == 0)
358 char *c
= ctime (&sb
.st_mtime
);
359 /* Fix non-standard format. */
360 if (c
[8] == '0') c
[8] = ' ';
362 if (!strncmp (ts
+ 25, c
, 24))
363 ts
= time_stamp (user
);
372 ent
= Entnode_Create (type
, user
, vn
, ts
, options
, tag
, date
,
377 if (line_length
< 0 && !feof (fpin
))
378 error (0, errno
, "cannot read entries file");
385 fputentent (FILE *fp
, Entnode
*p
)
392 if (fprintf (fp
, "D") < 0)
397 if (fprintf (fp
, "/%s/%s/%s", p
->user
, p
->version
, p
->timestamp
) < 0)
401 if (fprintf (fp
, "+%s", p
->conflict
) < 0)
404 if (fprintf (fp
, "/%s/", p
->options
) < 0)
409 if (fprintf (fp
, "T%s\n", p
->tag
) < 0)
414 if (fprintf (fp
, "D%s\n", p
->date
) < 0)
419 if (fprintf (fp
, "\n") < 0)
427 /* Read the entries file into a list, hashing on the file name.
429 UPDATE_DIR is the name of the current directory, for use in error
430 messages, or NULL if not known (that is, noone has gotten around
431 to updating the caller to pass in the information). */
433 Entries_Open (int aflag
, char *update_dir
)
436 struct stickydirtag
*sdtp
= NULL
;
438 char *dirtag
, *dirdate
;
444 /* get a fresh list... */
445 entries
= getlist ();
448 * Parse the CVS/Tag file, to get any default tag/date settings. Use
449 * list-private storage to tuck them away for Version_TS().
451 ParseTag (&dirtag
, &dirdate
, &dirnonbranch
);
452 if (aflag
|| dirtag
|| dirdate
)
454 sdtp
= xmalloc (sizeof (*sdtp
));
455 memset (sdtp
, 0, sizeof (*sdtp
));
457 sdtp
->tag
= xstrdup (dirtag
);
458 sdtp
->date
= xstrdup (dirdate
);
459 sdtp
->nonbranch
= dirnonbranch
;
461 /* feed it into the list-private area */
462 entries
->list
->data
= sdtp
;
463 entries
->list
->delproc
= freesdt
;
468 fpin
= CVS_FOPEN (CVSADM_ENT
, "r");
471 if (update_dir
!= NULL
)
472 error (0, 0, "in directory %s:", update_dir
);
473 error (0, errno
, "cannot open %s for reading", CVSADM_ENT
);
477 while ((ent
= fgetentent (fpin
, NULL
, &sawdir
)) != NULL
)
479 (void) AddEntryNode (entries
, ent
);
482 if (fclose (fpin
) < 0)
483 /* FIXME-update-dir: should include update_dir in message. */
484 error (0, errno
, "cannot close %s", CVSADM_ENT
);
487 fpin
= CVS_FOPEN (CVSADM_ENTLOG
, "r");
493 while ((ent
= fgetentent (fpin
, &cmd
, &sawdir
)) != NULL
)
498 (void) AddEntryNode (entries
, ent
);
501 node
= findnode_fn (entries
, ent
->user
);
504 Entnode_Destroy (ent
);
507 /* Ignore unrecognized commands. */
508 Entnode_Destroy (ent
);
513 if (fclose (fpin
) < 0)
514 /* FIXME-update-dir: should include update_dir in message. */
515 error (0, errno
, "cannot close %s", CVSADM_ENTLOG
);
518 /* Update the list private data to indicate whether subdirectory
519 information is known. Nonexistent list private data is taken
520 to mean that it is known. */
522 sdtp
->subdirs
= sawdir
;
525 sdtp
= xmalloc (sizeof (*sdtp
));
526 memset (sdtp
, 0, sizeof (*sdtp
));
528 entries
->list
->data
= sdtp
;
529 entries
->list
->delproc
= freesdt
;
532 if (do_rewrite
&& !noexec
)
533 write_entries (entries
);
535 /* clean up and return */
544 Entries_Close (List
*list
)
550 if (isfile (CVSADM_ENTLOG
))
551 write_entries (list
);
559 * Free up the memory associated with the data section of an ENTRIES type
563 Entries_delproc (Node
*node
)
565 Entnode
*p
= node
->data
;
571 * Get an Entries file list node, initialize it, and add it to the specified
575 AddEntryNode (List
*list
, Entnode
*entdata
)
579 /* was it already there? */
580 if ((p
= findnode_fn (list
, entdata
->user
)) != NULL
)
586 /* get a node and fill in the regular stuff */
589 p
->delproc
= Entries_delproc
;
591 /* this one gets a key of the name for hashing */
592 /* FIXME This results in duplicated data --- the hash package shouldn't
593 assume that the key is dynamically allocated. The user's free proc
594 should be responsible for freeing the key. */
595 p
->key
= xstrdup (entdata
->user
);
598 /* put the node into the list */
606 * Write out the CVS/Template file.
609 WriteTemplate (const char *update_dir
, int xdotemplate
, const char *repository
)
611 #ifdef SERVER_SUPPORT
612 TRACE (TRACE_FUNCTION
, "Write_Template (%s, %s)", update_dir
, repository
);
617 if (server_active
&& xdotemplate
)
619 /* Clear the CVS/Template if supported to allow for the case
620 * where the rcsinfo file no longer has an entry for this
623 server_clear_template (update_dir
, repository
);
624 server_template (update_dir
, repository
);
634 * Write out/Clear the CVS/Tag file.
637 WriteTag (const char *dir
, const char *tag
, const char *date
, int nonbranch
,
638 const char *update_dir
, const char *repository
)
647 tmp
= Xasprintf ("%s/%s", dir
, CVSADM_TAG
);
649 tmp
= xstrdup (CVSADM_TAG
);
654 fout
= xfopen (tmp
, "w+");
659 if (fprintf (fout
, "N%s\n", tag
) < 0)
660 error (1, errno
, "write to %s failed", tmp
);
664 if (fprintf (fout
, "T%s\n", tag
) < 0)
665 error (1, errno
, "write to %s failed", tmp
);
670 if (fprintf (fout
, "D%s\n", date
) < 0)
671 error (1, errno
, "write to %s failed", tmp
);
673 if (fclose (fout
) == EOF
)
674 error (1, errno
, "cannot close %s", tmp
);
677 if (unlink_file (tmp
) < 0 && ! existence_error (errno
))
678 error (1, errno
, "cannot remove %s", tmp
);
680 #ifdef SERVER_SUPPORT
682 server_set_sticky (update_dir
, repository
, tag
, date
, nonbranch
);
686 /* Parse the CVS/Tag file for the current directory.
688 If it contains a date, sets *DATEP to the date in a newly malloc'd
689 string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
691 If it contains a branch tag, sets *TAGP to the tag in a newly
692 malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
694 If it contains a nonbranch tag, sets *TAGP to the tag in a newly
695 malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
697 If it does not exist, or contains something unrecognized by this
698 version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
699 an unspecified value.
701 If there is an error, print an error message, set *DATEP and *TAGP
702 to NULL, and return. */
704 ParseTag (char **tagp
, char **datep
, int *nonbranchp
)
712 /* Always store a value here, even in the 'D' case where the value
713 is unspecified. Shuts up tools which check for references to
714 uninitialized memory. */
715 if (nonbranchp
!= NULL
)
717 fp
= CVS_FOPEN (CVSADM_TAG
, "r");
722 size_t line_chars_allocated
;
725 line_chars_allocated
= 0;
727 if ((line_length
= getline (&line
, &line_chars_allocated
, fp
)) > 0)
729 /* Remove any trailing newline. */
730 if (line
[line_length
- 1] == '\n')
731 line
[--line_length
] = '\0';
736 *tagp
= xstrdup (line
+ 1);
740 *datep
= xstrdup (line
+ 1);
744 *tagp
= xstrdup (line
+ 1);
745 if (nonbranchp
!= NULL
)
749 /* Silently ignore it; it may have been
750 written by a future version of CVS which extends the
758 /* FIXME-update-dir: should include update_dir in messages. */
760 error (0, 0, "cannot read %s: end of file", CVSADM_TAG
);
762 error (0, errno
, "cannot read %s", CVSADM_TAG
);
766 /* FIXME-update-dir: should include update_dir in message. */
767 error (0, errno
, "cannot close %s", CVSADM_TAG
);
771 else if (!existence_error (errno
))
772 /* FIXME-update-dir: should include update_dir in message. */
773 error (0, errno
, "cannot open %s", CVSADM_TAG
);
777 * This is called if all subdirectory information is known, but there
778 * aren't any subdirectories. It records that fact in the list
783 Subdirs_Known (List
*entries
)
785 struct stickydirtag
*sdtp
= entries
->list
->data
;
787 /* If there is no list private data, that means that the
788 subdirectory information is known. */
789 if (sdtp
!= NULL
&& ! sdtp
->subdirs
)
796 /* Create Entries.Log so that Entries_Close will do something. */
797 entfilename
= CVSADM_ENTLOG
;
798 fp
= CVS_FOPEN (entfilename
, "a");
801 int save_errno
= errno
;
803 /* As in subdir_record, just silently skip the whole thing
804 if there is no CVSADM directory. */
805 if (! isdir (CVSADM
))
807 error (1, save_errno
, "cannot open %s", entfilename
);
811 if (fclose (fp
) == EOF
)
812 error (1, errno
, "cannot close %s", entfilename
);
818 /* Record subdirectory information. */
821 subdir_record (int cmd
, const char *parent
, const char *dir
)
825 /* None of the information associated with a directory is
826 currently meaningful. */
827 entnode
= Entnode_Create (ENT_SUBDIR
, dir
, "", "", "",
833 entfilename
= CVSADM_ENTLOG
;
835 entfilename
= Xasprintf ("%s/%s", parent
, CVSADM_ENTLOG
);
837 entfile
= CVS_FOPEN (entfilename
, "a");
840 int save_errno
= errno
;
842 /* It is not an error if there is no CVS administration
843 directory. Permitting this case simplifies some
848 if (! isdir (CVSADM
))
854 entfilename
= Xasprintf ("%s/%s", parent
, CVSADM
);
855 if (! isdir (entfilename
))
863 error (1, save_errno
, "cannot open %s", entfilename
);
866 if (fprintf (entfile
, "%c ", cmd
) < 0)
867 error (1, errno
, "cannot write %s", entfilename
);
869 if (fputentent (entfile
, entnode
) != 0)
870 error (1, errno
, "cannot write %s", entfilename
);
872 if (fclose (entfile
) == EOF
)
873 error (1, errno
, "error closing %s", entfilename
);
886 * Record the addition of a new subdirectory DIR in PARENT. PARENT
887 * may be NULL, which means the current directory. ENTRIES is the
888 * current entries list; it may be NULL, which means that it need not
893 Subdir_Register (List
*entries
, const char *parent
, const char *dir
)
897 /* Ignore attempts to register ".". These can happen in the
899 if (dir
[0] == '.' && dir
[1] == '\0')
902 entnode
= subdir_record ('A', parent
, dir
);
904 if (entries
!= NULL
&& (parent
== NULL
|| strcmp (parent
, ".") == 0))
905 (void) AddEntryNode (entries
, entnode
);
907 Entnode_Destroy (entnode
);
913 * Record the removal of a subdirectory. The arguments are the same
914 * as for Subdir_Register.
918 Subdir_Deregister (List
*entries
, const char *parent
, const char *dir
)
922 entnode
= subdir_record ('R', parent
, dir
);
923 Entnode_Destroy (entnode
);
925 if (entries
!= NULL
&& (parent
== NULL
|| strcmp (parent
, ".") == 0))
929 p
= findnode_fn (entries
, dir
);
937 /* OK, the following base_* code tracks the revisions of the files in
938 CVS/Base. We do this in a file CVS/Baserev. Separate from
939 CVS/Entries because it needs to go in separate data structures
940 anyway (the name in Entries must be unique), so this seemed
941 cleaner. The business of rewriting the whole file in
942 base_deregister and base_register is the kind of thing we used to
943 do for Entries and which turned out to be slow, which is why there
944 is now the Entries.Log machinery. So maybe from that point of
945 view it is a mistake to do this separately from Entries, I dunno. */
949 /* Set the revision for FILE to *REV. */
951 /* Get the revision for FILE and put it in a newly malloc'd string
952 in *REV, or put NULL if not mentioned. */
958 static void base_walk (enum base_walk
, struct file_info
*, char **);
960 /* Read through the lines in CVS/Baserev, taking the actions as documented
964 base_walk (enum base_walk code
, struct file_info
*finfo
, char **rev
)
968 size_t line_allocated
;
970 char *baserev_fullname
;
971 char *baserevtmp_fullname
;
977 /* First compute the fullnames for the error messages. This
978 computation probably should be broken out into a separate function,
979 as recurse.c does it too and places like Entries_Open should be
981 if (finfo
->update_dir
[0] != '\0')
983 baserev_fullname
= Xasprintf ("%s/%s", finfo
->update_dir
,
985 baserevtmp_fullname
= Xasprintf ("%s/%s", finfo
->update_dir
,
990 baserev_fullname
= xstrdup (CVSADM_BASEREV
);
991 baserevtmp_fullname
= xstrdup (CVSADM_BASEREVTMP
);
994 fp
= CVS_FOPEN (CVSADM_BASEREV
, "r");
997 if (!existence_error (errno
))
999 error (0, errno
, "cannot open %s for reading", baserev_fullname
);
1007 case BASE_DEREGISTER
:
1008 newf
= CVS_FOPEN (CVSADM_BASEREVTMP
, "w");
1011 error (0, errno
, "cannot open %s for writing",
1012 baserevtmp_fullname
);
1023 while (getline (&line
, &line_allocated
, fp
) >= 0)
1030 /* Ignore, for future expansion. */
1033 linefile
= line
+ 1;
1034 p
= strchr (linefile
, '/');
1036 /* Syntax error, ignore. */
1039 p
= strchr (linerev
, '/');
1044 if (fncmp (linefile
, finfo
->file
) == 0)
1049 case BASE_DEREGISTER
:
1050 /* Don't copy over the old entry, we don't want it. */
1054 *rev
= xstrdup (linerev
);
1065 case BASE_DEREGISTER
:
1066 if (fprintf (newf
, "%s\n", line
) < 0)
1067 error (0, errno
, "error writing %s",
1068 baserevtmp_fullname
);
1076 error (0, errno
, "cannot read %s", baserev_fullname
);
1080 if (code
== BASE_REGISTER
)
1082 if (fprintf (newf
, "B%s/%s/\n", finfo
->file
, *rev
) < 0)
1083 error (0, errno
, "error writing %s",
1084 baserevtmp_fullname
);
1094 if (fclose (fp
) < 0)
1095 error (0, errno
, "cannot close %s", baserev_fullname
);
1099 if (fclose (newf
) < 0)
1100 error (0, errno
, "cannot close %s", baserevtmp_fullname
);
1101 rename_file (CVSADM_BASEREVTMP
, CVSADM_BASEREV
);
1104 free (baserev_fullname
);
1105 free (baserevtmp_fullname
);
1108 /* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
1109 or NULL if not listed. */
1112 base_get (struct file_info
*finfo
)
1115 base_walk (BASE_GET
, finfo
, &rev
);
1119 /* Set the revision for FILE to REV. */
1122 base_register (struct file_info
*finfo
, char *rev
)
1124 base_walk (BASE_REGISTER
, finfo
, &rev
);
1130 base_deregister (struct file_info
*finfo
)
1132 base_walk (BASE_DEREGISTER
, finfo
, NULL
);