File: | src/usr.bin/cvs/entries.c |
Warning: | line 272, column 8 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: entries.c,v 1.107 2016/10/13 20:51:25 fcambus Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2006 Joris Vink <joris@openbsd.org> | |||
4 | * | |||
5 | * Permission to use, copy, modify, and distribute this software for any | |||
6 | * purpose with or without fee is hereby granted, provided that the above | |||
7 | * copyright notice and this permission notice appear in all copies. | |||
8 | * | |||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
16 | */ | |||
17 | ||||
18 | #include <errno(*__errno()).h> | |||
19 | #include <stdlib.h> | |||
20 | #include <string.h> | |||
21 | #include <time.h> | |||
22 | #include <unistd.h> | |||
23 | ||||
24 | #include "cvs.h" | |||
25 | #include "remote.h" | |||
26 | ||||
27 | #define CVS_ENTRIES_NFIELDS6 6 | |||
28 | #define CVS_ENTRIES_DELIM'/' '/' | |||
29 | ||||
30 | static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *); | |||
31 | ||||
32 | CVSENTRIES *current_list = NULL((void *)0); | |||
33 | ||||
34 | CVSENTRIES * | |||
35 | cvs_ent_open(const char *dir) | |||
36 | { | |||
37 | FILE *fp; | |||
38 | CVSENTRIES *ep; | |||
39 | char *p, buf[PATH_MAX1024]; | |||
40 | struct cvs_ent *ent; | |||
41 | struct cvs_ent_line *line; | |||
42 | ||||
43 | cvs_log(LP_TRACE4, "cvs_ent_open(%s)", dir); | |||
44 | ||||
45 | (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_ENTRIES"CVS" "/Entries"); | |||
46 | ||||
47 | if (current_list != NULL((void *)0) && !strcmp(current_list->cef_path, buf)) | |||
| ||||
48 | return (current_list); | |||
49 | ||||
50 | if (current_list
| |||
51 | cvs_ent_close(current_list, ENT_SYNC1); | |||
52 | current_list = NULL((void *)0); | |||
53 | } | |||
54 | ||||
55 | ep = xcalloc(1, sizeof(*ep)); | |||
56 | ep->cef_path = xstrdup(buf); | |||
57 | ||||
58 | (void)xsnprintf(buf, sizeof(buf), "%s/%s", | |||
59 | dir, CVS_PATH_BACKUPENTRIES"CVS" "/Entries.Backup"); | |||
60 | ||||
61 | ep->cef_bpath = xstrdup(buf); | |||
62 | ||||
63 | (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_LOGENTRIES"CVS" "/Entries.Log"); | |||
64 | ||||
65 | ep->cef_lpath = xstrdup(buf); | |||
66 | ||||
67 | TAILQ_INIT(&(ep->cef_ent))do { (&(ep->cef_ent))->tqh_first = ((void *)0); (& (ep->cef_ent))->tqh_last = &(&(ep->cef_ent)) ->tqh_first; } while (0); | |||
68 | ||||
69 | if ((fp = fopen(ep->cef_path, "r")) != NULL((void *)0)) { | |||
70 | while (fgets(buf, sizeof(buf), fp)) { | |||
71 | buf[strcspn(buf, "\n")] = '\0'; | |||
72 | ||||
73 | if (buf[0] == 'D' && buf[1] == '\0') | |||
74 | break; | |||
75 | ||||
76 | line = xmalloc(sizeof(*line)); | |||
77 | line->buf = xstrdup(buf); | |||
78 | TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list)do { (line)->entries_list.tqe_next = ((void *)0); (line)-> entries_list.tqe_prev = (&(ep->cef_ent))->tqh_last; *(&(ep->cef_ent))->tqh_last = (line); (&(ep-> cef_ent))->tqh_last = &(line)->entries_list.tqe_next ; } while (0); | |||
79 | } | |||
80 | ||||
81 | (void)fclose(fp); | |||
82 | } | |||
83 | ||||
84 | if ((fp = fopen(ep->cef_lpath, "r")) != NULL((void *)0)) { | |||
85 | while (fgets(buf, sizeof(buf), fp)) { | |||
86 | buf[strcspn(buf, "\n")] = '\0'; | |||
87 | ||||
88 | if (strlen(buf) < 2) | |||
89 | fatal("cvs_ent_open: %s: malformed line %s", | |||
90 | ep->cef_lpath, buf); | |||
91 | ||||
92 | p = &buf[2]; | |||
93 | ||||
94 | if (buf[0] == 'A') { | |||
95 | line = xmalloc(sizeof(*line)); | |||
96 | line->buf = xstrdup(p); | |||
97 | TAILQ_INSERT_TAIL(&(ep->cef_ent), line,do { (line)->entries_list.tqe_next = ((void *)0); (line)-> entries_list.tqe_prev = (&(ep->cef_ent))->tqh_last; *(&(ep->cef_ent))->tqh_last = (line); (&(ep-> cef_ent))->tqh_last = &(line)->entries_list.tqe_next ; } while (0) | |||
98 | entries_list)do { (line)->entries_list.tqe_next = ((void *)0); (line)-> entries_list.tqe_prev = (&(ep->cef_ent))->tqh_last; *(&(ep->cef_ent))->tqh_last = (line); (&(ep-> cef_ent))->tqh_last = &(line)->entries_list.tqe_next ; } while (0); | |||
99 | } else if (buf[0] == 'R') { | |||
100 | ent = cvs_ent_parse(p); | |||
101 | line = ent_get_line(ep, ent->ce_name); | |||
102 | if (line != NULL((void *)0)) { | |||
103 | TAILQ_REMOVE(&(ep->cef_ent), line,do { if (((line)->entries_list.tqe_next) != ((void *)0)) ( line)->entries_list.tqe_next->entries_list.tqe_prev = ( line)->entries_list.tqe_prev; else (&(ep->cef_ent)) ->tqh_last = (line)->entries_list.tqe_prev; *(line)-> entries_list.tqe_prev = (line)->entries_list.tqe_next; ; ; } while (0) | |||
104 | entries_list)do { if (((line)->entries_list.tqe_next) != ((void *)0)) ( line)->entries_list.tqe_next->entries_list.tqe_prev = ( line)->entries_list.tqe_prev; else (&(ep->cef_ent)) ->tqh_last = (line)->entries_list.tqe_prev; *(line)-> entries_list.tqe_prev = (line)->entries_list.tqe_next; ; ; } while (0); | |||
105 | free(line->buf); | |||
106 | free(line); | |||
107 | } | |||
108 | cvs_ent_free(ent); | |||
109 | } | |||
110 | } | |||
111 | ||||
112 | (void)fclose(fp); | |||
113 | } | |||
114 | ||||
115 | current_list = ep; | |||
116 | return (ep); | |||
117 | } | |||
118 | ||||
119 | struct cvs_ent * | |||
120 | cvs_ent_parse(const char *entry) | |||
121 | { | |||
122 | int i; | |||
123 | struct tm t, dt; | |||
124 | struct cvs_ent *ent; | |||
125 | char *fields[CVS_ENTRIES_NFIELDS6], *buf, *sp, *dp, *p; | |||
126 | ||||
127 | buf = sp = xstrdup(entry); | |||
128 | i = 0; | |||
129 | do { | |||
130 | dp = strchr(sp, CVS_ENTRIES_DELIM'/'); | |||
131 | if (dp != NULL((void *)0)) | |||
132 | *(dp++) = '\0'; | |||
133 | fields[i++] = sp; | |||
134 | sp = dp; | |||
135 | } while (dp != NULL((void *)0) && i < CVS_ENTRIES_NFIELDS6); | |||
136 | ||||
137 | if (i < CVS_ENTRIES_NFIELDS6) | |||
138 | fatal("missing fields in entry line '%s'", entry); | |||
139 | ||||
140 | ent = xmalloc(sizeof(*ent)); | |||
141 | ent->ce_buf = buf; | |||
142 | ||||
143 | if (*fields[0] == '\0') | |||
144 | ent->ce_type = CVS_ENT_FILE1; | |||
145 | else if (*fields[0] == 'D') | |||
146 | ent->ce_type = CVS_ENT_DIR2; | |||
147 | else | |||
148 | ent->ce_type = CVS_ENT_NONE0; | |||
149 | ||||
150 | ent->ce_status = CVS_ENT_REG0; | |||
151 | ent->ce_name = fields[1]; | |||
152 | ent->ce_rev = NULL((void *)0); | |||
153 | ent->ce_date = -1; | |||
154 | ent->ce_tag = NULL((void *)0); | |||
155 | ent->ce_time = NULL((void *)0); | |||
156 | ||||
157 | if (ent->ce_type == CVS_ENT_FILE1) { | |||
158 | if (*fields[2] == '-') { | |||
159 | ent->ce_status = CVS_ENT_REMOVED2; | |||
160 | sp = fields[2] + 1; | |||
161 | } else if (*fields[2] == CVS_SERVER_QUESTIONABLE'?') { | |||
162 | sp = NULL((void *)0); | |||
163 | ent->ce_status = CVS_ENT_UNKNOWN4; | |||
164 | } else { | |||
165 | sp = fields[2]; | |||
166 | if (fields[2][0] == '0' && fields[2][1] == '\0') | |||
167 | ent->ce_status = CVS_ENT_ADDED1; | |||
168 | } | |||
169 | ||||
170 | if (sp != NULL((void *)0)) { | |||
171 | if ((ent->ce_rev = rcsnum_parse(sp)) == NULL((void *)0)) { | |||
172 | fatal("failed to parse entry revision '%s'", | |||
173 | entry); | |||
174 | } | |||
175 | } | |||
176 | ||||
177 | if (fields[3][0] == '\0' || | |||
178 | strncmp(fields[3], CVS_DATE_DUMMY"dummy timestamp", | |||
179 | sizeof(CVS_DATE_DUMMY"dummy timestamp") - 1) == 0 || | |||
180 | strncmp(fields[3], "Initial ", 8) == 0 || | |||
181 | strcmp(fields[3], "Result of merge") == 0) { | |||
182 | ent->ce_mtime = CVS_DATE_DMSEC(time_t)-1; | |||
183 | } else if (cvs_server_active == 1 && | |||
184 | strncmp(fields[3], CVS_SERVER_UNCHANGED"d[o.o]b", | |||
185 | strlen(CVS_SERVER_UNCHANGED"d[o.o]b")) == 0) { | |||
186 | ent->ce_mtime = CVS_SERVER_UPTODATE(time_t)-2; | |||
187 | } else { | |||
188 | p = fields[3]; | |||
189 | if (strncmp(fields[3], "Result of merge+", 16) == 0) | |||
190 | p += 16; | |||
191 | ||||
192 | ent->ce_time = xstrdup(p); | |||
193 | ||||
194 | /* Date field can be a '+=' with remote to indicate | |||
195 | * conflict. In this case do nothing. */ | |||
196 | if (strptime(p, "%a %b %d %T %Y", &t) != NULL((void *)0)) { | |||
197 | t.tm_isdst = -1; /* Figure out DST. */ | |||
198 | t.tm_gmtoff = 0; | |||
199 | ent->ce_mtime = mktime(&t); | |||
200 | ent->ce_mtime += t.tm_gmtoff; | |||
201 | } | |||
202 | } | |||
203 | } | |||
204 | ||||
205 | ent->ce_conflict = fields[3]; | |||
206 | if ((dp = strchr(ent->ce_conflict, '+')) != NULL((void *)0)) | |||
207 | *dp = '\0'; | |||
208 | else | |||
209 | ent->ce_conflict = NULL((void *)0); | |||
210 | ||||
211 | if (strcmp(fields[4], "")) | |||
212 | ent->ce_opts = fields[4]; | |||
213 | else | |||
214 | ent->ce_opts = NULL((void *)0); | |||
215 | ||||
216 | if (strcmp(fields[5], "")) { | |||
217 | switch (*fields[5]) { | |||
218 | case 'D': | |||
219 | if (sscanf(fields[5] + 1, "%d.%d.%d.%d.%d.%d", | |||
220 | &dt.tm_year, &dt.tm_mon, &dt.tm_mday, | |||
221 | &dt.tm_hour, &dt.tm_min, &dt.tm_sec) != 6) | |||
222 | fatal("wrong date specification"); | |||
223 | dt.tm_year -= 1900; | |||
224 | dt.tm_mon -= 1; | |||
225 | ent->ce_date = timegm(&dt); | |||
226 | ent->ce_tag = NULL((void *)0); | |||
227 | break; | |||
228 | case 'T': | |||
229 | ent->ce_tag = fields[5] + 1; | |||
230 | break; | |||
231 | default: | |||
232 | fatal("invalid sticky entry"); | |||
233 | } | |||
234 | } | |||
235 | ||||
236 | return (ent); | |||
237 | } | |||
238 | ||||
239 | struct cvs_ent * | |||
240 | cvs_ent_get(CVSENTRIES *ep, const char *name) | |||
241 | { | |||
242 | struct cvs_ent *ent; | |||
243 | struct cvs_ent_line *l; | |||
244 | ||||
245 | l = ent_get_line(ep, name); | |||
246 | if (l == NULL((void *)0)) | |||
247 | return (NULL((void *)0)); | |||
248 | ||||
249 | ent = cvs_ent_parse(l->buf); | |||
250 | return (ent); | |||
251 | } | |||
252 | ||||
253 | void | |||
254 | cvs_ent_close(CVSENTRIES *ep, int writefile) | |||
255 | { | |||
256 | FILE *fp; | |||
257 | struct cvs_ent_line *l; | |||
258 | int dflag; | |||
259 | ||||
260 | dflag = 1; | |||
261 | cvs_log(LP_TRACE4, "cvs_ent_close(%s, %d)", ep->cef_bpath, writefile); | |||
262 | ||||
263 | if (cvs_cmdop == CVS_OP_EXPORT9) | |||
264 | writefile = 0; | |||
265 | ||||
266 | fp = NULL((void *)0); | |||
267 | if (writefile
| |||
268 | fp = fopen(ep->cef_bpath, "w"); | |||
269 | ||||
270 | while ((l = TAILQ_FIRST(&(ep->cef_ent))((&(ep->cef_ent))->tqh_first)) != NULL((void *)0)) { | |||
271 | if (fp
| |||
272 | if (l->buf[0] == 'D') | |||
| ||||
273 | dflag = 0; | |||
274 | ||||
275 | fputs(l->buf, fp); | |||
276 | fputc('\n', fp); | |||
277 | } | |||
278 | ||||
279 | TAILQ_REMOVE(&(ep->cef_ent), l, entries_list)do { if (((l)->entries_list.tqe_next) != ((void *)0)) (l)-> entries_list.tqe_next->entries_list.tqe_prev = (l)->entries_list .tqe_prev; else (&(ep->cef_ent))->tqh_last = (l)-> entries_list.tqe_prev; *(l)->entries_list.tqe_prev = (l)-> entries_list.tqe_next; ; ; } while (0); | |||
280 | free(l->buf); | |||
281 | free(l); | |||
282 | } | |||
283 | ||||
284 | if (fp != NULL((void *)0)) { | |||
285 | if (dflag) { | |||
286 | fputc('D', fp); | |||
287 | fputc('\n', fp); | |||
288 | } | |||
289 | (void)fclose(fp); | |||
290 | ||||
291 | if (rename(ep->cef_bpath, ep->cef_path) == -1) | |||
292 | fatal("cvs_ent_close: rename: `%s'->`%s': %s", | |||
293 | ep->cef_bpath, ep->cef_path, strerror(errno(*__errno()))); | |||
294 | ||||
295 | (void)unlink(ep->cef_lpath); | |||
296 | } | |||
297 | ||||
298 | free(ep->cef_path); | |||
299 | free(ep->cef_bpath); | |||
300 | free(ep->cef_lpath); | |||
301 | free(ep); | |||
302 | } | |||
303 | ||||
304 | void | |||
305 | cvs_ent_add(CVSENTRIES *ep, const char *line) | |||
306 | { | |||
307 | FILE *fp; | |||
308 | struct cvs_ent_line *l; | |||
309 | struct cvs_ent *ent; | |||
310 | ||||
311 | if ((ent = cvs_ent_parse(line)) == NULL((void *)0)) | |||
312 | fatal("cvs_ent_add: parsing failed '%s'", line); | |||
313 | ||||
314 | l = ent_get_line(ep, ent->ce_name); | |||
315 | if (l != NULL((void *)0)) | |||
316 | cvs_ent_remove(ep, ent->ce_name); | |||
317 | ||||
318 | cvs_ent_free(ent); | |||
319 | ||||
320 | if (cvs_server_active == 0) | |||
321 | cvs_log(LP_TRACE4, "cvs_ent_add(%s, %s)", ep->cef_path, line); | |||
322 | ||||
323 | if ((fp = fopen(ep->cef_lpath, "a")) == NULL((void *)0)) | |||
324 | fatal("cvs_ent_add: fopen: `%s': %s", | |||
325 | ep->cef_lpath, strerror(errno(*__errno()))); | |||
326 | ||||
327 | fputs("A ", fp); | |||
328 | fputs(line, fp); | |||
329 | fputc('\n', fp); | |||
330 | ||||
331 | (void)fclose(fp); | |||
332 | ||||
333 | l = xmalloc(sizeof(*l)); | |||
334 | l->buf = xstrdup(line); | |||
335 | TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list)do { (l)->entries_list.tqe_next = ((void *)0); (l)->entries_list .tqe_prev = (&(ep->cef_ent))->tqh_last; *(&(ep-> cef_ent))->tqh_last = (l); (&(ep->cef_ent))->tqh_last = &(l)->entries_list.tqe_next; } while (0); | |||
336 | } | |||
337 | ||||
338 | void | |||
339 | cvs_ent_remove(CVSENTRIES *ep, const char *name) | |||
340 | { | |||
341 | FILE *fp; | |||
342 | struct cvs_ent_line *l; | |||
343 | ||||
344 | if (cvs_server_active == 0) | |||
345 | cvs_log(LP_TRACE4, "cvs_ent_remove(%s, %s)", ep->cef_path, name); | |||
346 | ||||
347 | l = ent_get_line(ep, name); | |||
348 | if (l == NULL((void *)0)) | |||
349 | return; | |||
350 | ||||
351 | if ((fp = fopen(ep->cef_lpath, "a")) == NULL((void *)0)) | |||
352 | fatal("cvs_ent_remove: fopen: `%s': %s", ep->cef_lpath, | |||
353 | strerror(errno(*__errno()))); | |||
354 | ||||
355 | fputs("R ", fp); | |||
356 | fputs(l->buf, fp); | |||
357 | fputc('\n', fp); | |||
358 | ||||
359 | (void)fclose(fp); | |||
360 | ||||
361 | TAILQ_REMOVE(&(ep->cef_ent), l, entries_list)do { if (((l)->entries_list.tqe_next) != ((void *)0)) (l)-> entries_list.tqe_next->entries_list.tqe_prev = (l)->entries_list .tqe_prev; else (&(ep->cef_ent))->tqh_last = (l)-> entries_list.tqe_prev; *(l)->entries_list.tqe_prev = (l)-> entries_list.tqe_next; ; ; } while (0); | |||
362 | free(l->buf); | |||
363 | free(l); | |||
364 | } | |||
365 | ||||
366 | /* | |||
367 | * cvs_ent_line_str() | |||
368 | * | |||
369 | * Build CVS/Entries line. | |||
370 | * | |||
371 | */ | |||
372 | void | |||
373 | cvs_ent_line_str(const char *name, char *rev, char *tstamp, char *opts, | |||
374 | char *sticky, int isdir, int isremoved, char *buf, size_t len) | |||
375 | { | |||
376 | if (isdir == 1) { | |||
377 | (void)xsnprintf(buf, len, "D/%s////", name); | |||
378 | return; | |||
379 | } | |||
380 | ||||
381 | (void)xsnprintf(buf, len, "/%s/%s%s/%s/%s/%s", | |||
382 | name, isremoved == 1 ? "-" : "", rev, tstamp, opts, sticky); | |||
383 | } | |||
384 | ||||
385 | void | |||
386 | cvs_ent_free(struct cvs_ent *ent) | |||
387 | { | |||
388 | free(ent->ce_rev); | |||
389 | free(ent->ce_time); | |||
390 | free(ent->ce_buf); | |||
391 | free(ent); | |||
392 | } | |||
393 | ||||
394 | static struct cvs_ent_line * | |||
395 | ent_get_line(CVSENTRIES *ep, const char *name) | |||
396 | { | |||
397 | char *p, *s; | |||
398 | struct cvs_ent_line *l; | |||
399 | ||||
400 | TAILQ_FOREACH(l, &(ep->cef_ent), entries_list)for((l) = ((&(ep->cef_ent))->tqh_first); (l) != ((void *)0); (l) = ((l)->entries_list.tqe_next)) { | |||
401 | if (l->buf[0] == 'D') | |||
402 | p = &(l->buf[2]); | |||
403 | else | |||
404 | p = &(l->buf[1]); | |||
405 | ||||
406 | if ((s = strchr(p, '/')) == NULL((void *)0)) | |||
407 | fatal("ent_get_line: bad entry line '%s'", l->buf); | |||
408 | ||||
409 | *s = '\0'; | |||
410 | ||||
411 | if (!strcmp(p, name)) { | |||
412 | *s = '/'; | |||
413 | return (l); | |||
414 | } | |||
415 | ||||
416 | *s = '/'; | |||
417 | } | |||
418 | ||||
419 | return (NULL((void *)0)); | |||
420 | } | |||
421 | ||||
422 | void | |||
423 | cvs_parse_tagfile(char *dir, char **tagp, char **datep, int *nbp) | |||
424 | { | |||
425 | FILE *fp; | |||
426 | int i, linenum; | |||
427 | size_t len; | |||
428 | struct tm datetm; | |||
429 | char linebuf[128], tagpath[PATH_MAX1024]; | |||
430 | ||||
431 | cvs_directory_date = -1; | |||
432 | ||||
433 | if (tagp != NULL((void *)0)) | |||
434 | *tagp = NULL((void *)0); | |||
435 | ||||
436 | if (datep != NULL((void *)0)) | |||
437 | *datep = NULL((void *)0); | |||
438 | ||||
439 | if (nbp != NULL((void *)0)) | |||
440 | *nbp = 0; | |||
441 | ||||
442 | i = snprintf(tagpath, PATH_MAX1024, "%s/%s", dir, CVS_PATH_TAG"CVS" "/Tag"); | |||
443 | if (i < 0 || i >= PATH_MAX1024) | |||
444 | return; | |||
445 | ||||
446 | if ((fp = fopen(tagpath, "r")) == NULL((void *)0)) { | |||
447 | if (errno(*__errno()) != ENOENT2) | |||
448 | cvs_log(LP_NOTICE0, "failed to open `%s' : %s", tagpath, | |||
449 | strerror(errno(*__errno()))); | |||
450 | return; | |||
451 | } | |||
452 | ||||
453 | linenum = 0; | |||
454 | ||||
455 | while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL((void *)0)) { | |||
456 | linenum++; | |||
457 | if ((len = strlen(linebuf)) == 0) | |||
458 | continue; | |||
459 | if (linebuf[len - 1] != '\n') { | |||
460 | cvs_log(LP_NOTICE0, "line too long in `%s:%d'", | |||
461 | tagpath, linenum); | |||
462 | break; | |||
463 | } | |||
464 | linebuf[--len] = '\0'; | |||
465 | ||||
466 | switch (*linebuf) { | |||
467 | case 'T': | |||
468 | if (tagp != NULL((void *)0)) | |||
469 | *tagp = xstrdup(linebuf + 1); | |||
470 | break; | |||
471 | case 'D': | |||
472 | if (sscanf(linebuf + 1, "%d.%d.%d.%d.%d.%d", | |||
473 | &datetm.tm_year, &datetm.tm_mon, &datetm.tm_mday, | |||
474 | &datetm.tm_hour, &datetm.tm_min, &datetm.tm_sec) != | |||
475 | 6) | |||
476 | fatal("wrong date specification"); | |||
477 | datetm.tm_year -= 1900; | |||
478 | datetm.tm_mon -= 1; | |||
479 | ||||
480 | cvs_directory_date = timegm(&datetm); | |||
481 | ||||
482 | if (datep != NULL((void *)0)) | |||
483 | *datep = xstrdup(linebuf + 1); | |||
484 | break; | |||
485 | case 'N': | |||
486 | if (tagp != NULL((void *)0)) | |||
487 | *tagp = xstrdup(linebuf + 1); | |||
488 | if (nbp != NULL((void *)0)) | |||
489 | *nbp = 1; | |||
490 | break; | |||
491 | default: | |||
492 | break; | |||
493 | } | |||
494 | } | |||
495 | if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror )(fp))) | |||
496 | cvs_log(LP_NOTICE0, "failed to read line from `%s'", tagpath); | |||
497 | ||||
498 | (void)fclose(fp); | |||
499 | } | |||
500 | ||||
501 | void | |||
502 | cvs_write_tagfile(const char *dir, char *tag, char *date) | |||
503 | { | |||
504 | FILE *fp; | |||
505 | RCSNUM *rev; | |||
506 | char tagpath[PATH_MAX1024]; | |||
507 | char sticky[CVS_REV_BUFSZ32]; | |||
508 | struct tm datetm; | |||
509 | int i; | |||
510 | ||||
511 | cvs_log(LP_TRACE4, "cvs_write_tagfile(%s, %s, %s)", dir, | |||
512 | tag != NULL((void *)0) ? tag : "", date != NULL((void *)0) ? date : ""); | |||
513 | ||||
514 | if (cvs_noexec == 1) | |||
515 | return; | |||
516 | ||||
517 | i = snprintf(tagpath, PATH_MAX1024, "%s/%s", dir, CVS_PATH_TAG"CVS" "/Tag"); | |||
518 | if (i < 0 || i >= PATH_MAX1024) | |||
519 | return; | |||
520 | ||||
521 | if (tag != NULL((void *)0) || cvs_specified_date != -1 || | |||
522 | cvs_directory_date != -1) { | |||
523 | if ((fp = fopen(tagpath, "w+")) == NULL((void *)0)) { | |||
524 | if (errno(*__errno()) != ENOENT2) { | |||
525 | cvs_log(LP_NOTICE0, "failed to open `%s' : %s", | |||
526 | tagpath, strerror(errno(*__errno()))); | |||
527 | } | |||
528 | return; | |||
529 | } | |||
530 | ||||
531 | if (tag != NULL((void *)0)) { | |||
532 | if ((rev = rcsnum_parse(tag)) != NULL((void *)0)) { | |||
533 | (void)xsnprintf(sticky, sizeof(sticky), | |||
534 | "N%s", tag); | |||
535 | free(rev); | |||
536 | } else { | |||
537 | (void)xsnprintf(sticky, sizeof(sticky), | |||
538 | "T%s", tag); | |||
539 | } | |||
540 | } else { | |||
541 | if (cvs_specified_date != -1) | |||
542 | gmtime_r(&cvs_specified_date, &datetm); | |||
543 | else | |||
544 | gmtime_r(&cvs_directory_date, &datetm); | |||
545 | (void)strftime(sticky, sizeof(sticky), | |||
546 | "D"CVS_DATE_FMT"%Y.%m.%d.%H.%M.%S", &datetm); | |||
547 | } | |||
548 | ||||
549 | (void)fprintf(fp, "%s\n", sticky); | |||
550 | (void)fclose(fp); | |||
551 | } | |||
552 | } |