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.
17 static void time_stamp_server PROTO((const char *, Vers_TS *, Entnode *));
22 /* Fill in and return a Vers_TS structure for the file FINFO. TAG and
23 DATE are from the command line. */
26 Version_TS (finfo, options, tag, date, force_tag_match, set_time)
27 struct file_info *finfo;
29 /* Keyword expansion options, I think generally from the command
30 line. Can be either NULL or "" to indicate none are specified
41 struct stickydirtag *sdtp;
43 char *rcsexpand = NULL;
45 #ifdef UTIME_EXPECTS_WRITABLE
46 int change_it_back = 0;
49 /* get a new Vers_TS struct */
50 vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
51 memset ((char *) vers_ts, 0, sizeof (*vers_ts));
54 * look up the entries file entry and fill in the version and timestamp
55 * if entries is NULL, there is no entries file so don't bother trying to
56 * look it up (used by checkout -P)
58 if (finfo->entries == NULL)
65 p = findnode_fn (finfo->entries, finfo->file);
66 sdtp = finfo->entries->list->data; /* list-private */
74 if (entdata->type == ENT_SUBDIR)
76 /* According to cvs.texinfo, the various fields in the Entries
77 file for a directory (other than the name) do not have a
78 defined meaning. We need to pass them along without getting
79 confused based on what is in them. Therefore we make sure
80 not to set vn_user and the like from Entries, add.c and
81 perhaps other code will expect these fields to be NULL for
83 vers_ts->entdata = entdata;
87 /* An entries line with "D" in the timestamp indicates that the
88 client sent Is-modified without sending Entry. So we want to
89 use the entries line for the sole purpose of telling
90 time_stamp_server what is up; we don't want the rest of CVS
91 to think there is an entries line. */
92 if (strcmp (entdata->timestamp, "D") != 0)
95 vers_ts->vn_user = xstrdup (entdata->version);
96 vers_ts->ts_rcs = xstrdup (entdata->timestamp);
97 vers_ts->ts_conflict = xstrdup (entdata->conflict);
98 if (!(tag || date) && !(sdtp && sdtp->aflag))
100 vers_ts->tag = xstrdup (entdata->tag);
101 vers_ts->date = xstrdup (entdata->date);
103 vers_ts->entdata = entdata;
105 /* Even if we don't have an "entries line" as such
106 (vers_ts->entdata), we want to pick up options which could
107 have been from a Kopt protocol request. */
108 if (!options || *options == '\0')
110 if (!(sdtp && sdtp->aflag))
111 vers_ts->options = xstrdup (entdata->options);
115 /* Always look up the RCS keyword mode when we have an RCS archive. It
116 * will either be needed as a default or to avoid allowing the -k options
117 * specified on the command line from overriding binary mode (-kb).
119 if (finfo->rcs != NULL)
120 rcsexpand = RCS_getexpand (finfo->rcs);
123 * -k options specified on the command line override (and overwrite)
124 * options stored in the entries file and default options from the RCS
125 * archive, except for binary mode (-kb).
127 if (options && *options != '\0')
129 if (vers_ts->options != NULL)
130 free (vers_ts->options);
131 if (rcsexpand != NULL && strcmp (rcsexpand, "b") == 0)
132 vers_ts->options = xstrdup ("-kb");
134 vers_ts->options = xstrdup (options);
136 else if ((!vers_ts->options || *vers_ts->options == '\0')
137 && rcsexpand != NULL)
139 /* If no keyword expansion was specified on command line,
140 use whatever was in the rcs file (if there is one). This
141 is how we, if we are the server, tell the client whether
143 if (vers_ts->options != NULL)
144 free (vers_ts->options);
145 vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
146 strcpy (vers_ts->options, "-k");
147 strcat (vers_ts->options, rcsexpand);
149 if (!vers_ts->options)
150 vers_ts->options = xstrdup ("");
153 * if tags were specified on the command line, they override what is in
158 vers_ts->tag = xstrdup (tag);
159 vers_ts->date = xstrdup (date);
161 else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
165 vers_ts->tag = xstrdup (sdtp->tag);
166 vers_ts->nonbranch = sdtp->nonbranch;
169 vers_ts->date = xstrdup (sdtp->date);
172 /* Now look up the info on the source controlled file */
173 if (finfo->rcs != NULL)
175 rcsdata = finfo->rcs;
178 else if (finfo->repository != NULL)
179 rcsdata = RCS_parse (finfo->file, finfo->repository);
185 /* squirrel away the rcsdata pointer for others */
186 vers_ts->srcfile = rcsdata;
188 if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
190 vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
191 vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
197 vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
198 vers_ts->date, force_tag_match,
200 if (vers_ts->vn_rcs == NULL)
201 vers_ts->vn_tag = NULL;
203 vers_ts->vn_tag = xstrdup (vers_ts->tag);
205 vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
209 * If the source control file exists and has the requested revision,
210 * get the Date the revision was checked in. If "user" exists, set
213 if (set_time && vers_ts->vn_rcs != NULL)
215 #ifdef SERVER_SUPPORT
217 server_modtime (finfo, vers_ts);
223 memset (&t, 0, sizeof (t));
224 t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
225 if (t.modtime != (time_t) -1)
227 (void) time (&t.actime);
229 #ifdef UTIME_EXPECTS_WRITABLE
230 if (!iswritable (finfo->file))
232 xchmod (finfo->file, 1);
235 #endif /* UTIME_EXPECTS_WRITABLE */
237 /* This used to need to ignore existence_errors
238 (for cases like where update.c now clears
239 set_time if noexec, but didn't used to). I
240 think maybe now it doesn't (server_modtime does
241 not like those kinds of cases). */
242 (void) utime (finfo->file, &t);
244 #ifdef UTIME_EXPECTS_WRITABLE
247 xchmod (finfo->file, 0);
250 #endif /* UTIME_EXPECTS_WRITABLE */
256 /* get user file time-stamp in ts_user */
257 if (finfo->entries != (List *) NULL)
259 #ifdef SERVER_SUPPORT
261 time_stamp_server (finfo->file, vers_ts, entdata);
264 vers_ts->ts_user = time_stamp (finfo->file);
270 #ifdef SERVER_SUPPORT
272 /* Set VERS_TS->TS_USER to time stamp for FILE. */
274 /* Separate these out to keep the logic below clearer. */
275 #define mark_lost(V) ((V)->ts_user = 0)
276 #define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs))
279 time_stamp_server (file, vers_ts, entdata)
287 if (CVS_LSTAT (file, &sb) < 0)
289 if (! existence_error (errno))
290 error (1, errno, "cannot stat temp file");
292 /* Missing file means lost or unmodified; check entries
295 XXX FIXME - If there's no entries file line, we
296 wouldn't be getting the file at all, so consider it
297 lost. I don't know that that's right, but it's not
298 clear to me that either choice is. Besides, would we
299 have an RCS string in that case anyways? */
302 else if (entdata->timestamp
303 && entdata->timestamp[0] == '=')
304 mark_unchanged (vers_ts);
305 else if (entdata->conflict
306 && entdata->conflict[0] == '=')
308 /* These just need matching content. Might as well minimize it. */
309 vers_ts->ts_user = xstrdup ("");
310 vers_ts->ts_conflict = xstrdup ("");
312 else if (entdata->timestamp
313 && (entdata->timestamp[0] == 'M'
314 || entdata->timestamp[0] == 'D')
315 && entdata->timestamp[1] == '\0')
316 vers_ts->ts_user = xstrdup ("Is-modified");
320 else if (sb.st_mtime == 0)
322 /* We shouldn't reach this case any more! */
329 vers_ts->ts_user = xmalloc (25);
330 /* We want to use the same timestamp format as is stored in the
331 st_mtime. For unix (and NT I think) this *must* be universal
332 time (UT), so that files don't appear to be modified merely
333 because the timezone has changed. For VMS, or hopefully other
334 systems where gmtime returns NULL, the modification time is
335 stored in local time, and therefore it is not possible to cause
336 st_mtime to be out of sync by changing the timezone. */
337 tm_p = gmtime (&sb.st_mtime);
338 cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
340 /* Fix non-standard format. */
341 if (cp[8] == '0') cp[8] = ' ';
342 (void) strcpy (vers_ts->ts_user, cp);
346 #endif /* SERVER_SUPPORT */
348 * Gets the time-stamp for the file "file" and returns it in space it
360 if (!CVS_LSTAT (file, &sb))
364 else if (! existence_error (errno))
365 error (0, errno, "cannot lstat %s", file);
367 /* If it's a symlink, return whichever is the newest mtime of
368 the link and its target, for safety.
370 if (!CVS_STAT (file, &sb))
372 if (mtime < sb.st_mtime)
375 else if (! existence_error (errno))
376 error (0, errno, "cannot stat %s", file);
382 /* We want to use the same timestamp format as is stored in the
383 st_mtime. For unix (and NT I think) this *must* be universal
384 time (UT), so that files don't appear to be modified merely
385 because the timezone has changed. For VMS, or hopefully other
386 systems where gmtime returns NULL, the modification time is
387 stored in local time, and therefore it is not possible to cause
388 st_mtime to be out of sync by changing the timezone. */
389 tm_p = gmtime (&sb.st_mtime);
390 cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
392 /* Fix non-standard format. */
393 if (cp[8] == '0') cp[8] = ' ';
394 (void) strcpy (ts, cp);
401 * free up a Vers_TS struct
407 if ((*versp)->srcfile)
408 freercsnode (&((*versp)->srcfile));
409 if ((*versp)->vn_user)
410 free ((*versp)->vn_user);
411 if ((*versp)->vn_rcs)
412 free ((*versp)->vn_rcs);
413 if ((*versp)->vn_tag)
414 free ((*versp)->vn_tag);
415 if ((*versp)->ts_user)
416 free ((*versp)->ts_user);
417 if ((*versp)->ts_rcs)
418 free ((*versp)->ts_rcs);
419 if ((*versp)->options)
420 free ((*versp)->options);
422 free ((*versp)->tag);
424 free ((*versp)->date);
425 if ((*versp)->ts_conflict)
426 free ((*versp)->ts_conflict);
427 free ((char *) *versp);
428 *versp = (Vers_TS *) NULL;