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((const char *, Vers_TS *, Entnode *));
17 /* Fill in and return a Vers_TS structure for the file FINFO. TAG and
18 DATE are from the command line. */
21 Version_TS (finfo, options, tag, date, force_tag_match, set_time)
22 struct file_info *finfo;
24 /* Keyword expansion options, I think generally from the command
25 line. Can be either NULL or "" to indicate none are specified
36 struct stickydirtag *sdtp;
39 #ifdef UTIME_EXPECTS_WRITABLE
40 int change_it_back = 0;
43 /* get a new Vers_TS struct */
44 vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
45 memset ((char *) vers_ts, 0, sizeof (*vers_ts));
48 * look up the entries file entry and fill in the version and timestamp
49 * if entries is NULL, there is no entries file so don't bother trying to
50 * look it up (used by checkout -P)
52 if (finfo->entries == NULL)
59 p = findnode_fn (finfo->entries, finfo->file);
60 sdtp = finfo->entries->list->data; /* list-private */
68 if (entdata->type == ENT_SUBDIR)
70 /* According to cvs.texinfo, the various fields in the Entries
71 file for a directory (other than the name) do not have a
72 defined meaning. We need to pass them along without getting
73 confused based on what is in them. Therefore we make sure
74 not to set vn_user and the like from Entries, add.c and
75 perhaps other code will expect these fields to be NULL for
77 vers_ts->entdata = entdata;
81 /* An entries line with "D" in the timestamp indicates that the
82 client sent Is-modified without sending Entry. So we want to
83 use the entries line for the sole purpose of telling
84 time_stamp_server what is up; we don't want the rest of CVS
85 to think there is an entries line. */
86 if (strcmp (entdata->timestamp, "D") != 0)
89 vers_ts->vn_user = xstrdup (entdata->version);
90 vers_ts->ts_rcs = xstrdup (entdata->timestamp);
91 vers_ts->ts_conflict = xstrdup (entdata->conflict);
92 if (!(tag || date) && !(sdtp && sdtp->aflag))
94 vers_ts->tag = xstrdup (entdata->tag);
95 vers_ts->date = xstrdup (entdata->date);
97 vers_ts->entdata = entdata;
99 /* Even if we don't have an "entries line" as such
100 (vers_ts->entdata), we want to pick up options which could
101 have been from a Kopt protocol request. */
102 if (!options || *options == '\0')
104 if (!(sdtp && sdtp->aflag))
105 vers_ts->options = xstrdup (entdata->options);
110 * -k options specified on the command line override (and overwrite)
111 * options stored in the entries file
113 if (options && *options != '\0')
114 vers_ts->options = xstrdup (options);
115 else if (!vers_ts->options || *vers_ts->options == '\0')
117 if (finfo->rcs != NULL)
119 /* If no keyword expansion was specified on command line,
120 use whatever was in the rcs file (if there is one). This
121 is how we, if we are the server, tell the client whether
123 char *rcsexpand = RCS_getexpand (finfo->rcs);
124 if (rcsexpand != NULL)
126 if (vers_ts->options != NULL)
127 free (vers_ts->options);
128 vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
129 strcpy (vers_ts->options, "-k");
130 strcat (vers_ts->options, rcsexpand);
134 if (!vers_ts->options)
135 vers_ts->options = xstrdup ("");
138 * if tags were specified on the command line, they override what is in
143 vers_ts->tag = xstrdup (tag);
144 vers_ts->date = xstrdup (date);
146 else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
150 vers_ts->tag = xstrdup (sdtp->tag);
151 vers_ts->nonbranch = sdtp->nonbranch;
154 vers_ts->date = xstrdup (sdtp->date);
157 /* Now look up the info on the source controlled file */
158 if (finfo->rcs != NULL)
160 rcsdata = finfo->rcs;
163 else if (finfo->repository != NULL)
164 rcsdata = RCS_parse (finfo->file, finfo->repository);
170 /* squirrel away the rcsdata pointer for others */
171 vers_ts->srcfile = rcsdata;
173 if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
175 vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
176 vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
182 vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
183 vers_ts->date, force_tag_match,
185 if (vers_ts->vn_rcs == NULL)
186 vers_ts->vn_tag = NULL;
188 vers_ts->vn_tag = xstrdup (vers_ts->tag);
190 vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
194 * If the source control file exists and has the requested revision,
195 * get the Date the revision was checked in. If "user" exists, set
198 if (set_time && vers_ts->vn_rcs != NULL)
200 #ifdef SERVER_SUPPORT
202 server_modtime (finfo, vers_ts);
208 memset (&t, 0, sizeof (t));
209 t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
210 if (t.modtime != (time_t) -1)
212 (void) time (&t.actime);
214 #ifdef UTIME_EXPECTS_WRITABLE
215 if (!iswritable (finfo->file))
217 xchmod (finfo->file, 1);
220 #endif /* UTIME_EXPECTS_WRITABLE */
222 /* This used to need to ignore existence_errors
223 (for cases like where update.c now clears
224 set_time if noexec, but didn't used to). I
225 think maybe now it doesn't (server_modtime does
226 not like those kinds of cases). */
227 (void) utime (finfo->file, &t);
229 #ifdef UTIME_EXPECTS_WRITABLE
232 xchmod (finfo->file, 0);
235 #endif /* UTIME_EXPECTS_WRITABLE */
241 /* get user file time-stamp in ts_user */
242 if (finfo->entries != (List *) NULL)
244 #ifdef SERVER_SUPPORT
246 time_stamp_server (finfo->file, vers_ts, entdata);
249 vers_ts->ts_user = time_stamp (finfo->file);
255 #ifdef SERVER_SUPPORT
257 /* Set VERS_TS->TS_USER to time stamp for FILE. */
259 /* Separate these out to keep the logic below clearer. */
260 #define mark_lost(V) ((V)->ts_user = 0)
261 #define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
264 time_stamp_server (file, vers_ts, entdata)
272 if (CVS_LSTAT (file, &sb) < 0)
274 if (! existence_error (errno))
275 error (1, errno, "cannot stat temp file");
277 /* Missing file means lost or unmodified; check entries
280 XXX FIXME - If there's no entries file line, we
281 wouldn't be getting the file at all, so consider it
282 lost. I don't know that that's right, but it's not
283 clear to me that either choice is. Besides, would we
284 have an RCS string in that case anyways? */
287 else if (entdata->timestamp
288 && entdata->timestamp[0] == '=')
289 mark_unchanged (vers_ts);
290 else if (entdata->timestamp
291 && (entdata->timestamp[0] == 'M'
292 || entdata->timestamp[0] == 'D')
293 && entdata->timestamp[1] == '\0')
294 vers_ts->ts_user = xstrdup ("Is-modified");
298 else if (sb.st_mtime == 0)
300 /* We shouldn't reach this case any more! */
307 vers_ts->ts_user = xmalloc (25);
308 /* We want to use the same timestamp format as is stored in the
309 st_mtime. For unix (and NT I think) this *must* be universal
310 time (UT), so that files don't appear to be modified merely
311 because the timezone has changed. For VMS, or hopefully other
312 systems where gmtime returns NULL, the modification time is
313 stored in local time, and therefore it is not possible to cause
314 st_mtime to be out of sync by changing the timezone. */
315 tm_p = gmtime (&sb.st_mtime);
316 cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
318 /* Fix non-standard format. */
319 if (cp[8] == '0') cp[8] = ' ';
320 (void) strcpy (vers_ts->ts_user, cp);
324 #endif /* SERVER_SUPPORT */
326 * Gets the time-stamp for the file "file" and returns it in space it
338 if (!CVS_LSTAT (file, &sb))
342 /* If it's a symlink, return whichever is the newest mtime of
343 the link and its target, for safety.
345 if (!CVS_STAT (file, &sb))
347 if (mtime < sb.st_mtime)
354 /* We want to use the same timestamp format as is stored in the
355 st_mtime. For unix (and NT I think) this *must* be universal
356 time (UT), so that files don't appear to be modified merely
357 because the timezone has changed. For VMS, or hopefully other
358 systems where gmtime returns NULL, the modification time is
359 stored in local time, and therefore it is not possible to cause
360 st_mtime to be out of sync by changing the timezone. */
361 tm_p = gmtime (&sb.st_mtime);
362 cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
364 /* Fix non-standard format. */
365 if (cp[8] == '0') cp[8] = ' ';
366 (void) strcpy (ts, cp);
373 * free up a Vers_TS struct
379 if ((*versp)->srcfile)
380 freercsnode (&((*versp)->srcfile));
381 if ((*versp)->vn_user)
382 free ((*versp)->vn_user);
383 if ((*versp)->vn_rcs)
384 free ((*versp)->vn_rcs);
385 if ((*versp)->vn_tag)
386 free ((*versp)->vn_tag);
387 if ((*versp)->ts_user)
388 free ((*versp)->ts_user);
389 if ((*versp)->ts_rcs)
390 free ((*versp)->ts_rcs);
391 if ((*versp)->options)
392 free ((*versp)->options);
394 free ((*versp)->tag);
396 free ((*versp)->date);
397 if ((*versp)->ts_conflict)
398 free ((*versp)->ts_conflict);
399 free ((char *) *versp);
400 *versp = (Vers_TS *) NULL;