xref: /openbsd/gnu/usr.bin/cvs/src/vers_ts.c (revision 43c1707e)
11e72d8d2Sderaadt /*
21e72d8d2Sderaadt  * Copyright (c) 1992, Brian Berliner and Jeff Polk
31e72d8d2Sderaadt  * Copyright (c) 1989-1992, Brian Berliner
41e72d8d2Sderaadt  *
51e72d8d2Sderaadt  * You may distribute under the terms of the GNU General Public License as
62286d8edStholo  * specified in the README file that comes with the CVS source distribution.
71e72d8d2Sderaadt  */
81e72d8d2Sderaadt 
91e72d8d2Sderaadt #include "cvs.h"
101e72d8d2Sderaadt 
111e72d8d2Sderaadt #ifdef SERVER_SUPPORT
12b6c02222Stholo static void time_stamp_server PROTO((char *, Vers_TS *, Entnode *));
131e72d8d2Sderaadt #endif
141e72d8d2Sderaadt 
152286d8edStholo /* Fill in and return a Vers_TS structure for the file FINFO.  TAG and
162286d8edStholo    DATE are from the command line.  */
172286d8edStholo 
181e72d8d2Sderaadt Vers_TS *
Version_TS(finfo,options,tag,date,force_tag_match,set_time)1950bf276cStholo Version_TS (finfo, options, tag, date, force_tag_match, set_time)
2050bf276cStholo     struct file_info *finfo;
212286d8edStholo 
222286d8edStholo     /* Keyword expansion options, I think generally from the command
232286d8edStholo        line.  Can be either NULL or "" to indicate none are specified
242286d8edStholo        here.  */
251e72d8d2Sderaadt     char *options;
261e72d8d2Sderaadt     char *tag;
271e72d8d2Sderaadt     char *date;
281e72d8d2Sderaadt     int force_tag_match;
291e72d8d2Sderaadt     int set_time;
301e72d8d2Sderaadt {
311e72d8d2Sderaadt     Node *p;
321e72d8d2Sderaadt     RCSNode *rcsdata;
331e72d8d2Sderaadt     Vers_TS *vers_ts;
341e72d8d2Sderaadt     struct stickydirtag *sdtp;
35b6c02222Stholo     Entnode *entdata;
361e72d8d2Sderaadt 
37c71bc7e2Stholo #ifdef UTIME_EXPECTS_WRITABLE
38c71bc7e2Stholo     int change_it_back = 0;
39c71bc7e2Stholo #endif
40c71bc7e2Stholo 
411e72d8d2Sderaadt     /* get a new Vers_TS struct */
421e72d8d2Sderaadt     vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
431e72d8d2Sderaadt     memset ((char *) vers_ts, 0, sizeof (*vers_ts));
441e72d8d2Sderaadt 
451e72d8d2Sderaadt     /*
461e72d8d2Sderaadt      * look up the entries file entry and fill in the version and timestamp
471e72d8d2Sderaadt      * if entries is NULL, there is no entries file so don't bother trying to
481e72d8d2Sderaadt      * look it up (used by checkout -P)
491e72d8d2Sderaadt      */
5050bf276cStholo     if (finfo->entries == NULL)
511e72d8d2Sderaadt     {
521e72d8d2Sderaadt 	sdtp = NULL;
531e72d8d2Sderaadt 	p = NULL;
541e72d8d2Sderaadt     }
551e72d8d2Sderaadt     else
561e72d8d2Sderaadt     {
5750bf276cStholo 	p = findnode_fn (finfo->entries, finfo->file);
5850bf276cStholo 	sdtp = (struct stickydirtag *) finfo->entries->list->data; /* list-private */
591e72d8d2Sderaadt     }
601e72d8d2Sderaadt 
61b6c02222Stholo     entdata = NULL;
621e72d8d2Sderaadt     if (p != NULL)
631e72d8d2Sderaadt     {
64b6c02222Stholo 	entdata = (Entnode *) p->data;
651e72d8d2Sderaadt 
662286d8edStholo 	if (entdata->type == ENT_SUBDIR)
672286d8edStholo 	{
682286d8edStholo 	    /* According to cvs.texinfo, the various fields in the Entries
692286d8edStholo 	       file for a directory (other than the name) do not have a
702286d8edStholo 	       defined meaning.  We need to pass them along without getting
712286d8edStholo 	       confused based on what is in them.  Therefore we make sure
722286d8edStholo 	       not to set vn_user and the like from Entries, add.c and
732286d8edStholo 	       perhaps other code will expect these fields to be NULL for
742286d8edStholo 	       a directory.  */
752286d8edStholo 	    vers_ts->entdata = entdata;
762286d8edStholo 	}
772286d8edStholo 	else
78b6c02222Stholo #ifdef SERVER_SUPPORT
79b6c02222Stholo 	/* An entries line with "D" in the timestamp indicates that the
80b6c02222Stholo 	   client sent Is-modified without sending Entry.  So we want to
81b6c02222Stholo 	   use the entries line for the sole purpose of telling
82b6c02222Stholo 	   time_stamp_server what is up; we don't want the rest of CVS
83b6c02222Stholo 	   to think there is an entries line.  */
84b6c02222Stholo 	if (strcmp (entdata->timestamp, "D") != 0)
85b6c02222Stholo #endif
86b6c02222Stholo 	{
871e72d8d2Sderaadt 	    vers_ts->vn_user = xstrdup (entdata->version);
881e72d8d2Sderaadt 	    vers_ts->ts_rcs = xstrdup (entdata->timestamp);
891e72d8d2Sderaadt 	    vers_ts->ts_conflict = xstrdup (entdata->conflict);
90e77048c1Stholo 	    if (!(tag || date) && !(sdtp && sdtp->aflag))
911e72d8d2Sderaadt 	    {
921e72d8d2Sderaadt 		vers_ts->tag = xstrdup (entdata->tag);
931e72d8d2Sderaadt 		vers_ts->date = xstrdup (entdata->date);
941e72d8d2Sderaadt 	    }
952286d8edStholo 	    vers_ts->entdata = entdata;
962286d8edStholo 	}
972286d8edStholo 	/* Even if we don't have an "entries line" as such
982286d8edStholo 	   (vers_ts->entdata), we want to pick up options which could
992286d8edStholo 	   have been from a Kopt protocol request.  */
100e77048c1Stholo 	if (!options || *options == '\0')
1011e72d8d2Sderaadt 	{
1021e72d8d2Sderaadt 	    if (!(sdtp && sdtp->aflag))
1031e72d8d2Sderaadt 		vers_ts->options = xstrdup (entdata->options);
1041e72d8d2Sderaadt 	}
105b6c02222Stholo     }
1061e72d8d2Sderaadt 
1071e72d8d2Sderaadt     /*
1081e72d8d2Sderaadt      * -k options specified on the command line override (and overwrite)
1091e72d8d2Sderaadt      * options stored in the entries file
1101e72d8d2Sderaadt      */
1112286d8edStholo     if (options && *options != '\0')
1121e72d8d2Sderaadt 	vers_ts->options = xstrdup (options);
1132286d8edStholo     else if (!vers_ts->options || *vers_ts->options == '\0')
1141e72d8d2Sderaadt     {
11550bf276cStholo 	if (finfo->rcs != NULL)
116c2c61682Stholo 	{
117c2c61682Stholo 	    /* If no keyword expansion was specified on command line,
118c2c61682Stholo 	       use whatever was in the rcs file (if there is one).  This
119c2c61682Stholo 	       is how we, if we are the server, tell the client whether
120c2c61682Stholo 	       a file is binary.  */
12150bf276cStholo 	    char *rcsexpand = RCS_getexpand (finfo->rcs);
122c2c61682Stholo 	    if (rcsexpand != NULL)
123c2c61682Stholo 	    {
124e77048c1Stholo 		if (vers_ts->options != NULL)
125e77048c1Stholo 		    free (vers_ts->options);
126c2c61682Stholo 		vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
127c2c61682Stholo 		strcpy (vers_ts->options, "-k");
128c2c61682Stholo 		strcat (vers_ts->options, rcsexpand);
129c2c61682Stholo 	    }
130c2c61682Stholo 	}
1311e72d8d2Sderaadt     }
1321e72d8d2Sderaadt     if (!vers_ts->options)
1331e72d8d2Sderaadt 	vers_ts->options = xstrdup ("");
1341e72d8d2Sderaadt 
1351e72d8d2Sderaadt     /*
1361e72d8d2Sderaadt      * if tags were specified on the command line, they override what is in
1371e72d8d2Sderaadt      * the Entries file
1381e72d8d2Sderaadt      */
1391e72d8d2Sderaadt     if (tag || date)
1401e72d8d2Sderaadt     {
1411e72d8d2Sderaadt 	vers_ts->tag = xstrdup (tag);
1421e72d8d2Sderaadt 	vers_ts->date = xstrdup (date);
1431e72d8d2Sderaadt     }
1441e72d8d2Sderaadt     else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
1451e72d8d2Sderaadt     {
1461e72d8d2Sderaadt 	if (!vers_ts->tag)
147b6c02222Stholo 	{
1481e72d8d2Sderaadt 	    vers_ts->tag = xstrdup (sdtp->tag);
149b6c02222Stholo 	    vers_ts->nonbranch = sdtp->nonbranch;
150b6c02222Stholo 	}
1511e72d8d2Sderaadt 	if (!vers_ts->date)
1521e72d8d2Sderaadt 	    vers_ts->date = xstrdup (sdtp->date);
1531e72d8d2Sderaadt     }
1541e72d8d2Sderaadt 
1551e72d8d2Sderaadt     /* Now look up the info on the source controlled file */
15650bf276cStholo     if (finfo->rcs != NULL)
1571e72d8d2Sderaadt     {
15850bf276cStholo 	rcsdata = finfo->rcs;
1591e72d8d2Sderaadt 	rcsdata->refcount++;
1601e72d8d2Sderaadt     }
16150bf276cStholo     else if (finfo->repository != NULL)
16250bf276cStholo 	rcsdata = RCS_parse (finfo->file, finfo->repository);
1631e72d8d2Sderaadt     else
1641e72d8d2Sderaadt 	rcsdata = NULL;
1651e72d8d2Sderaadt 
1661e72d8d2Sderaadt     if (rcsdata != NULL)
1671e72d8d2Sderaadt     {
1681e72d8d2Sderaadt 	/* squirrel away the rcsdata pointer for others */
1691e72d8d2Sderaadt 	vers_ts->srcfile = rcsdata;
1701e72d8d2Sderaadt 
1711e72d8d2Sderaadt 	if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
17213571821Stholo 	{
1731e72d8d2Sderaadt 	    vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
17413571821Stholo 	    vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
17513571821Stholo 	}
1761e72d8d2Sderaadt 	else
17713571821Stholo 	{
17850bf276cStholo 	    int simple;
17950bf276cStholo 
1801e72d8d2Sderaadt 	    vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
18150bf276cStholo 					      vers_ts->date, force_tag_match,
18250bf276cStholo 					      &simple);
18313571821Stholo 	    if (vers_ts->vn_rcs == NULL)
18413571821Stholo 		vers_ts->vn_tag = NULL;
18550bf276cStholo 	    else if (simple)
18650bf276cStholo 		vers_ts->vn_tag = xstrdup (vers_ts->tag);
18713571821Stholo 	    else
18813571821Stholo 		vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
18913571821Stholo 	}
1901e72d8d2Sderaadt 
1911e72d8d2Sderaadt 	/*
1921e72d8d2Sderaadt 	 * If the source control file exists and has the requested revision,
1931e72d8d2Sderaadt 	 * get the Date the revision was checked in.  If "user" exists, set
1941e72d8d2Sderaadt 	 * its mtime.
1951e72d8d2Sderaadt 	 */
1962286d8edStholo 	if (set_time && vers_ts->vn_rcs != NULL)
1971e72d8d2Sderaadt 	{
1982770ece5Stholo #ifdef SERVER_SUPPORT
1992770ece5Stholo 	    if (server_active)
2002770ece5Stholo 		server_modtime (finfo, vers_ts);
2012770ece5Stholo 	    else
2022770ece5Stholo #endif
2032770ece5Stholo 	    {
2041e72d8d2Sderaadt 		struct utimbuf t;
2051e72d8d2Sderaadt 
2062770ece5Stholo 		memset (&t, 0, sizeof (t));
2072770ece5Stholo 		t.modtime =
2082770ece5Stholo 		    RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
2092770ece5Stholo 		if (t.modtime != (time_t) -1)
2102770ece5Stholo 		{
2112770ece5Stholo 		    t.actime = t.modtime;
2122286d8edStholo 
213c71bc7e2Stholo #ifdef UTIME_EXPECTS_WRITABLE
214c71bc7e2Stholo 		    if (!iswritable (finfo->file))
215c71bc7e2Stholo 		    {
216c71bc7e2Stholo 			xchmod (finfo->file, 1);
217c71bc7e2Stholo 			change_it_back = 1;
218c71bc7e2Stholo 		    }
219c71bc7e2Stholo #endif  /* UTIME_EXPECTS_WRITABLE  */
220c71bc7e2Stholo 
2212286d8edStholo 		    /* This used to need to ignore existence_errors
2222286d8edStholo 		       (for cases like where update.c now clears
2232286d8edStholo 		       set_time if noexec, but didn't used to).  I
2242286d8edStholo 		       think maybe now it doesn't (server_modtime does
2252286d8edStholo 		       not like those kinds of cases).  */
22650bf276cStholo 		    (void) utime (finfo->file, &t);
227c71bc7e2Stholo 
228c71bc7e2Stholo #ifdef UTIME_EXPECTS_WRITABLE
229c71bc7e2Stholo 		    if (change_it_back == 1)
230c71bc7e2Stholo 		    {
231c71bc7e2Stholo 			xchmod (finfo->file, 0);
232c71bc7e2Stholo 			change_it_back = 0;
233c71bc7e2Stholo 		    }
234c71bc7e2Stholo #endif  /*  UTIME_EXPECTS_WRITABLE  */
2351e72d8d2Sderaadt 		}
2361e72d8d2Sderaadt 	    }
2372770ece5Stholo 	}
2382770ece5Stholo     }
2391e72d8d2Sderaadt 
2401e72d8d2Sderaadt     /* get user file time-stamp in ts_user */
24150bf276cStholo     if (finfo->entries != (List *) NULL)
2421e72d8d2Sderaadt     {
2431e72d8d2Sderaadt #ifdef SERVER_SUPPORT
2441e72d8d2Sderaadt 	if (server_active)
245b6c02222Stholo 	    time_stamp_server (finfo->file, vers_ts, entdata);
2461e72d8d2Sderaadt 	else
2471e72d8d2Sderaadt #endif
24850bf276cStholo 	    vers_ts->ts_user = time_stamp (finfo->file);
2491e72d8d2Sderaadt     }
2501e72d8d2Sderaadt 
2511e72d8d2Sderaadt     return (vers_ts);
2521e72d8d2Sderaadt }
2531e72d8d2Sderaadt 
2541e72d8d2Sderaadt #ifdef SERVER_SUPPORT
2551e72d8d2Sderaadt 
2561e72d8d2Sderaadt /* Set VERS_TS->TS_USER to time stamp for FILE.  */
2571e72d8d2Sderaadt 
2581e72d8d2Sderaadt /* Separate these out to keep the logic below clearer.  */
2591e72d8d2Sderaadt #define mark_lost(V)		((V)->ts_user = 0)
2601e72d8d2Sderaadt #define mark_unchanged(V)	((V)->ts_user = xstrdup ((V)->ts_rcs))
2611e72d8d2Sderaadt 
2621e72d8d2Sderaadt static void
time_stamp_server(file,vers_ts,entdata)263b6c02222Stholo time_stamp_server (file, vers_ts, entdata)
2641e72d8d2Sderaadt     char *file;
2651e72d8d2Sderaadt     Vers_TS *vers_ts;
266b6c02222Stholo     Entnode *entdata;
2671e72d8d2Sderaadt {
2681e72d8d2Sderaadt     struct stat sb;
2691e72d8d2Sderaadt     char *cp;
2701e72d8d2Sderaadt 
2715e617892Stholo     if (CVS_LSTAT (file, &sb) < 0)
2721e72d8d2Sderaadt     {
27313571821Stholo 	if (! existence_error (errno))
2741e72d8d2Sderaadt 	    error (1, errno, "cannot stat temp file");
275461cc63eStholo 
2761e72d8d2Sderaadt 	/* Missing file means lost or unmodified; check entries
2771e72d8d2Sderaadt 	   file to see which.
2781e72d8d2Sderaadt 
2791e72d8d2Sderaadt 	   XXX FIXME - If there's no entries file line, we
2801e72d8d2Sderaadt 	   wouldn't be getting the file at all, so consider it
2811e72d8d2Sderaadt 	   lost.  I don't know that that's right, but it's not
2821e72d8d2Sderaadt 	   clear to me that either choice is.  Besides, would we
2831e72d8d2Sderaadt 	   have an RCS string in that case anyways?  */
284b6c02222Stholo 	if (entdata == NULL)
2851e72d8d2Sderaadt 	    mark_lost (vers_ts);
286b6c02222Stholo 	else if (entdata->timestamp
287b6c02222Stholo 		 && entdata->timestamp[0] == '=')
2881e72d8d2Sderaadt 	    mark_unchanged (vers_ts);
289b6c02222Stholo 	else if (entdata->timestamp != NULL
290b6c02222Stholo 		 && (entdata->timestamp[0] == 'M'
291b6c02222Stholo 		     || entdata->timestamp[0] == 'D')
292b6c02222Stholo 		 && entdata->timestamp[1] == '\0')
293b6c02222Stholo 	    vers_ts->ts_user = xstrdup ("Is-modified");
2941e72d8d2Sderaadt 	else
2951e72d8d2Sderaadt 	    mark_lost (vers_ts);
2961e72d8d2Sderaadt     }
2971e72d8d2Sderaadt     else if (sb.st_mtime == 0)
2981e72d8d2Sderaadt     {
2991e72d8d2Sderaadt 	/* We shouldn't reach this case any more!  */
3001e72d8d2Sderaadt 	abort ();
3011e72d8d2Sderaadt     }
3021e72d8d2Sderaadt     else
3031e72d8d2Sderaadt     {
304c2c61682Stholo         struct tm *tm_p;
305c2c61682Stholo         struct tm local_tm;
306c2c61682Stholo 
3071e72d8d2Sderaadt 	vers_ts->ts_user = xmalloc (25);
308c2c61682Stholo 	/* We want to use the same timestamp format as is stored in the
309c2c61682Stholo 	   st_mtime.  For unix (and NT I think) this *must* be universal
310c2c61682Stholo 	   time (UT), so that files don't appear to be modified merely
311c2c61682Stholo 	   because the timezone has changed.  For VMS, or hopefully other
312c2c61682Stholo 	   systems where gmtime returns NULL, the modification time is
313c2c61682Stholo 	   stored in local time, and therefore it is not possible to cause
314c2c61682Stholo 	   st_mtime to be out of sync by changing the timezone.  */
315c2c61682Stholo 	tm_p = gmtime (&sb.st_mtime);
316c2c61682Stholo 	if (tm_p)
317c2c61682Stholo 	{
318c2c61682Stholo 	    memcpy (&local_tm, tm_p, sizeof (local_tm));
319c2c61682Stholo 	    cp = asctime (&local_tm);	/* copy in the modify time */
320c2c61682Stholo 	}
321c2c61682Stholo 	else
322c2c61682Stholo 	    cp = ctime (&sb.st_mtime);
323c2c61682Stholo 
3241e72d8d2Sderaadt 	cp[24] = 0;
325*43c1707eStholo 	/* Fix non-standard format.  */
326*43c1707eStholo 	if (cp[8] == '0') cp[8] = ' ';
3271e72d8d2Sderaadt 	(void) strcpy (vers_ts->ts_user, cp);
3281e72d8d2Sderaadt     }
3291e72d8d2Sderaadt }
3301e72d8d2Sderaadt 
3311e72d8d2Sderaadt #endif /* SERVER_SUPPORT */
3321e72d8d2Sderaadt /*
3331e72d8d2Sderaadt  * Gets the time-stamp for the file "file" and returns it in space it
3341e72d8d2Sderaadt  * allocates
3351e72d8d2Sderaadt  */
3361e72d8d2Sderaadt char *
time_stamp(file)3371e72d8d2Sderaadt time_stamp (file)
3381e72d8d2Sderaadt     char *file;
3391e72d8d2Sderaadt {
3401e72d8d2Sderaadt     struct stat sb;
3411e72d8d2Sderaadt     char *cp;
3421e72d8d2Sderaadt     char *ts;
3431e72d8d2Sderaadt 
3445e617892Stholo     if (CVS_LSTAT (file, &sb) < 0)
3451e72d8d2Sderaadt     {
3461e72d8d2Sderaadt 	ts = NULL;
3471e72d8d2Sderaadt     }
3481e72d8d2Sderaadt     else
3491e72d8d2Sderaadt     {
350c2c61682Stholo 	struct tm *tm_p;
351c2c61682Stholo         struct tm local_tm;
3521e72d8d2Sderaadt 	ts = xmalloc (25);
353c2c61682Stholo 	/* We want to use the same timestamp format as is stored in the
354c2c61682Stholo 	   st_mtime.  For unix (and NT I think) this *must* be universal
355c2c61682Stholo 	   time (UT), so that files don't appear to be modified merely
356c2c61682Stholo 	   because the timezone has changed.  For VMS, or hopefully other
357c2c61682Stholo 	   systems where gmtime returns NULL, the modification time is
358c2c61682Stholo 	   stored in local time, and therefore it is not possible to cause
359c2c61682Stholo 	   st_mtime to be out of sync by changing the timezone.  */
360c2c61682Stholo 	tm_p = gmtime (&sb.st_mtime);
361c2c61682Stholo 	if (tm_p)
362c2c61682Stholo 	{
363c2c61682Stholo 	    memcpy (&local_tm, tm_p, sizeof (local_tm));
364c2c61682Stholo 	    cp = asctime (&local_tm);	/* copy in the modify time */
365c2c61682Stholo 	}
366c2c61682Stholo 	else
367c2c61682Stholo 	    cp = ctime(&sb.st_mtime);
368c2c61682Stholo 
3691e72d8d2Sderaadt 	cp[24] = 0;
370*43c1707eStholo 	/* Fix non-standard format.  */
371*43c1707eStholo 	if (cp[8] == '0') cp[8] = ' ';
3721e72d8d2Sderaadt 	(void) strcpy (ts, cp);
3731e72d8d2Sderaadt     }
3741e72d8d2Sderaadt 
3751e72d8d2Sderaadt     return (ts);
3761e72d8d2Sderaadt }
3771e72d8d2Sderaadt 
3781e72d8d2Sderaadt /*
3791e72d8d2Sderaadt  * free up a Vers_TS struct
3801e72d8d2Sderaadt  */
3811e72d8d2Sderaadt void
freevers_ts(versp)3821e72d8d2Sderaadt freevers_ts (versp)
3831e72d8d2Sderaadt     Vers_TS **versp;
3841e72d8d2Sderaadt {
3851e72d8d2Sderaadt     if ((*versp)->srcfile)
3861e72d8d2Sderaadt 	freercsnode (&((*versp)->srcfile));
3871e72d8d2Sderaadt     if ((*versp)->vn_user)
3881e72d8d2Sderaadt 	free ((*versp)->vn_user);
3891e72d8d2Sderaadt     if ((*versp)->vn_rcs)
3901e72d8d2Sderaadt 	free ((*versp)->vn_rcs);
39113571821Stholo     if ((*versp)->vn_tag)
39213571821Stholo 	free ((*versp)->vn_tag);
3931e72d8d2Sderaadt     if ((*versp)->ts_user)
3941e72d8d2Sderaadt 	free ((*versp)->ts_user);
3951e72d8d2Sderaadt     if ((*versp)->ts_rcs)
3961e72d8d2Sderaadt 	free ((*versp)->ts_rcs);
3971e72d8d2Sderaadt     if ((*versp)->options)
3981e72d8d2Sderaadt 	free ((*versp)->options);
3991e72d8d2Sderaadt     if ((*versp)->tag)
4001e72d8d2Sderaadt 	free ((*versp)->tag);
4011e72d8d2Sderaadt     if ((*versp)->date)
4021e72d8d2Sderaadt 	free ((*versp)->date);
4031e72d8d2Sderaadt     if ((*versp)->ts_conflict)
4041e72d8d2Sderaadt 	free ((*versp)->ts_conflict);
4051e72d8d2Sderaadt     free ((char *) *versp);
4061e72d8d2Sderaadt     *versp = (Vers_TS *) NULL;
4071e72d8d2Sderaadt }
408