| 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 | } |