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.
12 static void time_stamp_server PROTO((char *, Vers_TS *, Entnode *));
15 /* Fill in and return a Vers_TS structure for the file FINFO. TAG and
16 DATE are from the command line. */
19 Version_TS (finfo, options, tag, date, force_tag_match, set_time)
20 struct file_info *finfo;
22 /* Keyword expansion options, I think generally from the command
23 line. Can be either NULL or "" to indicate none are specified
34 struct stickydirtag *sdtp;
37 /* get a new Vers_TS struct */
38 vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
39 memset ((char *) vers_ts, 0, sizeof (*vers_ts));
42 * look up the entries file entry and fill in the version and timestamp
43 * if entries is NULL, there is no entries file so don't bother trying to
44 * look it up (used by checkout -P)
46 if (finfo->entries == NULL)
53 p = findnode_fn (finfo->entries, finfo->file);
54 sdtp = (struct stickydirtag *) finfo->entries->list->data; /* list-private */
60 entdata = (Entnode *) p->data;
62 if (entdata->type == ENT_SUBDIR)
64 /* According to cvs.texinfo, the various fields in the Entries
65 file for a directory (other than the name) do not have a
66 defined meaning. We need to pass them along without getting
67 confused based on what is in them. Therefore we make sure
68 not to set vn_user and the like from Entries, add.c and
69 perhaps other code will expect these fields to be NULL for
71 vers_ts->entdata = entdata;
75 /* An entries line with "D" in the timestamp indicates that the
76 client sent Is-modified without sending Entry. So we want to
77 use the entries line for the sole purpose of telling
78 time_stamp_server what is up; we don't want the rest of CVS
79 to think there is an entries line. */
80 if (strcmp (entdata->timestamp, "D") != 0)
83 vers_ts->vn_user = xstrdup (entdata->version);
84 vers_ts->ts_rcs = xstrdup (entdata->timestamp);
85 vers_ts->ts_conflict = xstrdup (entdata->conflict);
88 if (!(sdtp && sdtp->aflag))
89 vers_ts->tag = xstrdup (entdata->tag);
93 if (!(sdtp && sdtp->aflag))
94 vers_ts->date = xstrdup (entdata->date);
96 vers_ts->entdata = entdata;
98 /* Even if we don't have an "entries line" as such
99 (vers_ts->entdata), we want to pick up options which could
100 have been from a Kopt protocol request. */
101 if (!options || (options && *options == '\0'))
103 if (!(sdtp && sdtp->aflag))
104 vers_ts->options = xstrdup (entdata->options);
109 * -k options specified on the command line override (and overwrite)
110 * options stored in the entries file
112 if (options && *options != '\0')
113 vers_ts->options = xstrdup (options);
114 else if (!vers_ts->options || *vers_ts->options == '\0')
116 if (finfo->rcs != NULL)
118 /* If no keyword expansion was specified on command line,
119 use whatever was in the rcs file (if there is one). This
120 is how we, if we are the server, tell the client whether
122 char *rcsexpand = RCS_getexpand (finfo->rcs);
123 if (rcsexpand != NULL)
125 vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
126 strcpy (vers_ts->options, "-k");
127 strcat (vers_ts->options, rcsexpand);
131 if (!vers_ts->options)
132 vers_ts->options = xstrdup ("");
135 * if tags were specified on the command line, they override what is in
140 vers_ts->tag = xstrdup (tag);
141 vers_ts->date = xstrdup (date);
143 else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
147 vers_ts->tag = xstrdup (sdtp->tag);
148 vers_ts->nonbranch = sdtp->nonbranch;
151 vers_ts->date = xstrdup (sdtp->date);
154 /* Now look up the info on the source controlled file */
155 if (finfo->rcs != NULL)
157 rcsdata = finfo->rcs;
160 else if (finfo->repository != NULL)
161 rcsdata = RCS_parse (finfo->file, finfo->repository);
167 /* squirrel away the rcsdata pointer for others */
168 vers_ts->srcfile = rcsdata;
170 if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
172 vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
173 vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
179 vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
180 vers_ts->date, force_tag_match,
182 if (vers_ts->vn_rcs == NULL)
183 vers_ts->vn_tag = NULL;
185 vers_ts->vn_tag = xstrdup (vers_ts->tag);
187 vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
191 * If the source control file exists and has the requested revision,
192 * get the Date the revision was checked in. If "user" exists, set
195 if (set_time && vers_ts->vn_rcs != NULL)
197 #ifdef SERVER_SUPPORT
199 server_modtime (finfo, vers_ts);
205 memset (&t, 0, sizeof (t));
207 RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
208 if (t.modtime != (time_t) -1)
210 t.actime = t.modtime;
212 /* This used to need to ignore existence_errors
213 (for cases like where update.c now clears
214 set_time if noexec, but didn't used to). I
215 think maybe now it doesn't (server_modtime does
216 not like those kinds of cases). */
217 (void) utime (finfo->file, &t);
223 /* get user file time-stamp in ts_user */
224 if (finfo->entries != (List *) NULL)
226 #ifdef SERVER_SUPPORT
228 time_stamp_server (finfo->file, vers_ts, entdata);
231 vers_ts->ts_user = time_stamp (finfo->file);
237 #ifdef SERVER_SUPPORT
239 /* Set VERS_TS->TS_USER to time stamp for FILE. */
241 /* Separate these out to keep the logic below clearer. */
242 #define mark_lost(V) ((V)->ts_user = 0)
243 #define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
246 time_stamp_server (file, vers_ts, entdata)
254 if (CVS_LSTAT (file, &sb) < 0)
256 if (! existence_error (errno))
257 error (1, errno, "cannot stat temp file");
259 /* Missing file means lost or unmodified; check entries
262 XXX FIXME - If there's no entries file line, we
263 wouldn't be getting the file at all, so consider it
264 lost. I don't know that that's right, but it's not
265 clear to me that either choice is. Besides, would we
266 have an RCS string in that case anyways? */
269 else if (entdata->timestamp
270 && entdata->timestamp[0] == '=')
271 mark_unchanged (vers_ts);
272 else if (entdata->timestamp != NULL
273 && (entdata->timestamp[0] == 'M'
274 || entdata->timestamp[0] == 'D')
275 && entdata->timestamp[1] == '\0')
276 vers_ts->ts_user = xstrdup ("Is-modified");
280 else if (sb.st_mtime == 0)
282 /* We shouldn't reach this case any more! */
290 vers_ts->ts_user = xmalloc (25);
291 /* We want to use the same timestamp format as is stored in the
292 st_mtime. For unix (and NT I think) this *must* be universal
293 time (UT), so that files don't appear to be modified merely
294 because the timezone has changed. For VMS, or hopefully other
295 systems where gmtime returns NULL, the modification time is
296 stored in local time, and therefore it is not possible to cause
297 st_mtime to be out of sync by changing the timezone. */
298 tm_p = gmtime (&sb.st_mtime);
301 memcpy (&local_tm, tm_p, sizeof (local_tm));
302 cp = asctime (&local_tm); /* copy in the modify time */
305 cp = ctime (&sb.st_mtime);
308 (void) strcpy (vers_ts->ts_user, cp);
312 #endif /* SERVER_SUPPORT */
314 * Gets the time-stamp for the file "file" and returns it in space it
325 if (CVS_LSTAT (file, &sb) < 0)
334 /* We want to use the same timestamp format as is stored in the
335 st_mtime. For unix (and NT I think) this *must* be universal
336 time (UT), so that files don't appear to be modified merely
337 because the timezone has changed. For VMS, or hopefully other
338 systems where gmtime returns NULL, the modification time is
339 stored in local time, and therefore it is not possible to cause
340 st_mtime to be out of sync by changing the timezone. */
341 tm_p = gmtime (&sb.st_mtime);
344 memcpy (&local_tm, tm_p, sizeof (local_tm));
345 cp = asctime (&local_tm); /* copy in the modify time */
348 cp = ctime(&sb.st_mtime);
351 (void) strcpy (ts, cp);
358 * free up a Vers_TS struct
364 if ((*versp)->srcfile)
365 freercsnode (&((*versp)->srcfile));
366 if ((*versp)->vn_user)
367 free ((*versp)->vn_user);
368 if ((*versp)->vn_rcs)
369 free ((*versp)->vn_rcs);
370 if ((*versp)->vn_tag)
371 free ((*versp)->vn_tag);
372 if ((*versp)->ts_user)
373 free ((*versp)->ts_user);
374 if ((*versp)->ts_rcs)
375 free ((*versp)->ts_rcs);
376 if ((*versp)->options)
377 free ((*versp)->options);
379 free ((*versp)->tag);
381 free ((*versp)->date);
382 if ((*versp)->ts_conflict)
383 free ((*versp)->ts_conflict);
384 free ((char *) *versp);
385 *versp = (Vers_TS *) NULL;