]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/vers_ts.c
This commit was generated by cvs2svn to compensate for changes in r49795,
[FreeBSD/FreeBSD.git] / contrib / cvs / src / vers_ts.c
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  * 
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.
7  */
8
9 #include "cvs.h"
10
11 #ifdef SERVER_SUPPORT
12 static void time_stamp_server PROTO((char *, Vers_TS *, Entnode *));
13 #endif
14
15 /* Fill in and return a Vers_TS structure for the file FINFO.  TAG and
16    DATE are from the command line.  */
17
18 Vers_TS *
19 Version_TS (finfo, options, tag, date, force_tag_match, set_time)
20     struct file_info *finfo;
21
22     /* Keyword expansion options, I think generally from the command
23        line.  Can be either NULL or "" to indicate none are specified
24        here.  */
25     char *options;
26     char *tag;
27     char *date;
28     int force_tag_match;
29     int set_time;
30 {
31     Node *p;
32     RCSNode *rcsdata;
33     Vers_TS *vers_ts;
34     struct stickydirtag *sdtp;
35     Entnode *entdata;
36
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));
40
41     /*
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)
45      */
46     if (finfo->entries == NULL)
47     {
48         sdtp = NULL;
49         p = NULL;
50     }
51     else
52     {
53         p = findnode_fn (finfo->entries, finfo->file);
54         sdtp = (struct stickydirtag *) finfo->entries->list->data; /* list-private */
55     }
56
57     entdata = NULL;
58     if (p != NULL)
59     {
60         entdata = (Entnode *) p->data;
61
62         if (entdata->type == ENT_SUBDIR)
63         {
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
70                a directory.  */
71             vers_ts->entdata = entdata;
72         }
73         else
74 #ifdef SERVER_SUPPORT
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)
81 #endif
82         {
83             vers_ts->vn_user = xstrdup (entdata->version);
84             vers_ts->ts_rcs = xstrdup (entdata->timestamp);
85             vers_ts->ts_conflict = xstrdup (entdata->conflict);
86             if (!tag)
87             {
88                 if (!(sdtp && sdtp->aflag))
89                     vers_ts->tag = xstrdup (entdata->tag);
90             }
91             if (!date)
92             {
93                 if (!(sdtp && sdtp->aflag))
94                     vers_ts->date = xstrdup (entdata->date);
95             }
96             vers_ts->entdata = entdata;
97         }
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'))
102         {
103             if (!(sdtp && sdtp->aflag))
104                 vers_ts->options = xstrdup (entdata->options);
105         }
106     }
107
108     /*
109      * -k options specified on the command line override (and overwrite)
110      * options stored in the entries file
111      */
112     if (options && *options != '\0')
113         vers_ts->options = xstrdup (options);
114     else if (!vers_ts->options || *vers_ts->options == '\0')
115     {
116         if (finfo->rcs != NULL)
117         {
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
121                a file is binary.  */
122             char *rcsexpand = RCS_getexpand (finfo->rcs);
123             if (rcsexpand != NULL)
124             {
125                 vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
126                 strcpy (vers_ts->options, "-k");
127                 strcat (vers_ts->options, rcsexpand);
128             }
129         }
130     }
131     if (!vers_ts->options)
132         vers_ts->options = xstrdup ("");
133
134     /*
135      * if tags were specified on the command line, they override what is in
136      * the Entries file
137      */
138     if (tag || date)
139     {
140         vers_ts->tag = xstrdup (tag);
141         vers_ts->date = xstrdup (date);
142     }
143     else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
144     {
145         if (!vers_ts->tag)
146         {
147             vers_ts->tag = xstrdup (sdtp->tag);
148             vers_ts->nonbranch = sdtp->nonbranch;
149         }
150         if (!vers_ts->date)
151             vers_ts->date = xstrdup (sdtp->date);
152     }
153
154     /* Now look up the info on the source controlled file */
155     if (finfo->rcs != NULL)
156     {
157         rcsdata = finfo->rcs;
158         rcsdata->refcount++;
159     }
160     else if (finfo->repository != NULL)
161         rcsdata = RCS_parse (finfo->file, finfo->repository);
162     else
163         rcsdata = NULL;
164
165     if (rcsdata != NULL)
166     {
167         /* squirrel away the rcsdata pointer for others */
168         vers_ts->srcfile = rcsdata;
169
170         if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
171         {
172             vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
173             vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
174         }
175         else
176         {
177             int simple;
178
179             vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
180                                               vers_ts->date, force_tag_match,
181                                               &simple);
182             if (vers_ts->vn_rcs == NULL)
183                 vers_ts->vn_tag = NULL;
184             else if (simple)
185                 vers_ts->vn_tag = xstrdup (vers_ts->tag);
186             else
187                 vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
188         }
189
190         /*
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
193          * its mtime.
194          */
195         if (set_time && vers_ts->vn_rcs != NULL)
196         {
197 #ifdef SERVER_SUPPORT
198             if (server_active)
199                 server_modtime (finfo, vers_ts);
200             else
201 #endif
202             {
203                 struct utimbuf t;
204
205                 memset (&t, 0, sizeof (t));
206                 t.modtime =
207                     RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
208                 if (t.modtime != (time_t) -1)
209                 {
210                     t.actime = t.modtime;
211
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);
218                 }
219             }
220         }
221     }
222
223     /* get user file time-stamp in ts_user */
224     if (finfo->entries != (List *) NULL)
225     {
226 #ifdef SERVER_SUPPORT
227         if (server_active)
228             time_stamp_server (finfo->file, vers_ts, entdata);
229         else
230 #endif
231             vers_ts->ts_user = time_stamp (finfo->file);
232     }
233
234     return (vers_ts);
235 }
236
237 #ifdef SERVER_SUPPORT
238
239 /* Set VERS_TS->TS_USER to time stamp for FILE.  */
240
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))
244
245 static void
246 time_stamp_server (file, vers_ts, entdata)
247     char *file;
248     Vers_TS *vers_ts;
249     Entnode *entdata;
250 {
251     struct stat sb;
252     char *cp;
253
254     if (CVS_LSTAT (file, &sb) < 0)
255     {
256         if (! existence_error (errno))
257             error (1, errno, "cannot stat temp file");
258
259         /* Missing file means lost or unmodified; check entries
260            file to see which.
261
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?  */
267         if (entdata == NULL)
268             mark_lost (vers_ts);
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");
277         else
278             mark_lost (vers_ts);
279     }
280     else if (sb.st_mtime == 0)
281     {
282         /* We shouldn't reach this case any more!  */
283         abort ();
284     }
285     else
286     {
287         struct tm *tm_p;
288         struct tm local_tm;
289
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);
299         if (tm_p)
300         {
301             memcpy (&local_tm, tm_p, sizeof (local_tm));
302             cp = asctime (&local_tm);   /* copy in the modify time */
303         }
304         else
305             cp = ctime (&sb.st_mtime);
306
307         cp[24] = 0;
308         (void) strcpy (vers_ts->ts_user, cp);
309     }
310 }
311
312 #endif /* SERVER_SUPPORT */
313 /*
314  * Gets the time-stamp for the file "file" and returns it in space it
315  * allocates
316  */
317 char *
318 time_stamp (file)
319     char *file;
320 {
321     struct stat sb;
322     char *cp;
323     char *ts;
324
325     if (CVS_LSTAT (file, &sb) < 0)
326     {
327         ts = NULL;
328     }
329     else
330     {
331         struct tm *tm_p;
332         struct tm local_tm;
333         ts = xmalloc (25);
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);
342         if (tm_p)
343         {
344             memcpy (&local_tm, tm_p, sizeof (local_tm));
345             cp = asctime (&local_tm);   /* copy in the modify time */
346         }
347         else
348             cp = ctime(&sb.st_mtime);
349
350         cp[24] = 0;
351         (void) strcpy (ts, cp);
352     }
353
354     return (ts);
355 }
356
357 /*
358  * free up a Vers_TS struct
359  */
360 void
361 freevers_ts (versp)
362     Vers_TS **versp;
363 {
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);
378     if ((*versp)->tag)
379         free ((*versp)->tag);
380     if ((*versp)->date)
381         free ((*versp)->date);
382     if ((*versp)->ts_conflict)
383         free ((*versp)->ts_conflict);
384     free ((char *) *versp);
385     *versp = (Vers_TS *) NULL;
386 }