Annotation of src/usr.bin/cvs/entries.c, Revision 1.57
1.57 ! joris 1: /* $OpenBSD$ */
1.1 jfb 2: /*
1.57 ! joris 3: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1 jfb 4: *
1.57 ! joris 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.
1.1 jfb 16: */
17:
1.54 xsa 18: #include "includes.h"
1.1 jfb 19:
1.34 xsa 20: #include "cvs.h"
1.1 jfb 21: #include "log.h"
22:
1.42 xsa 23: #define CVS_ENTRIES_NFIELDS 6
24: #define CVS_ENTRIES_DELIM '/'
1.1 jfb 25:
1.57 ! joris 26: static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
1.1 jfb 27:
1.42 xsa 28: CVSENTRIES *
1.57 ! joris 29: cvs_ent_open(const char *dir)
1.1 jfb 30: {
1.57 ! joris 31: FILE *fp;
1.1 jfb 32: size_t len;
1.57 ! joris 33: CVSENTRIES *ep;
! 34: char *p, buf[MAXPATHLEN];
1.1 jfb 35: struct cvs_ent *ent;
1.57 ! joris 36: struct cvs_ent_line *line;
1.36 xsa 37:
1.57 ! joris 38: ep = (CVSENTRIES *)xmalloc(sizeof(*ep));
! 39: memset(ep, 0, sizeof(*ep));
1.52 joris 40:
1.57 ! joris 41: cvs_path_cat(dir, CVS_PATH_ENTRIES, buf, sizeof(buf));
! 42: ep->cef_path = xstrdup(buf);
1.8 jfb 43:
1.57 ! joris 44: cvs_path_cat(dir, CVS_PATH_BACKUPENTRIES, buf, sizeof(buf));
! 45: ep->cef_bpath = xstrdup(buf);
1.3 jfb 46:
1.57 ! joris 47: cvs_path_cat(dir, CVS_PATH_LOGENTRIES, buf, sizeof(buf));
! 48: ep->cef_lpath = xstrdup(buf);
1.1 jfb 49:
1.4 jfb 50: TAILQ_INIT(&(ep->cef_ent));
1.3 jfb 51:
1.57 ! joris 52: if ((fp = fopen(ep->cef_path, "r")) != NULL) {
! 53: while (fgets(buf, sizeof(buf), fp)) {
! 54: len = strlen(buf);
! 55: if (len > 0 && buf[len - 1] == '\n')
! 56: buf[len - 1] = '\0';
! 57:
! 58: if (buf[0] == 'D' && buf[1] == '\0')
! 59: break;
! 60:
! 61: line = (struct cvs_ent_line *)xmalloc(sizeof(*line));
! 62: line->buf = xstrdup(buf);
! 63: TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
! 64: }
1.52 joris 65:
1.25 jfb 66: (void)fclose(fp);
1.12 jfb 67: }
1.1 jfb 68:
1.57 ! joris 69: if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
! 70: while (fgets(buf, sizeof(buf), fp)) {
! 71: len = strlen(buf);
! 72: if (len > 0 && buf[strlen(buf) - 1] == '\n')
! 73: buf[strlen(buf) - 1] = '\0';
! 74:
! 75: p = &buf[1];
! 76:
! 77: if (buf[0] == 'A') {
! 78: line = xmalloc(sizeof(*line));
! 79: line->buf = xstrdup(p);
! 80: TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
! 81: entries_list);
! 82: } else if (buf[0] == 'R') {
! 83: ent = cvs_ent_parse(p);
! 84: line = ent_get_line(ep, ent->ce_name);
! 85: if (line != NULL)
! 86: TAILQ_REMOVE(&(ep->cef_ent), line,
! 87: entries_list);
! 88: cvs_ent_free(ent);
! 89: }
! 90: }
1.4 jfb 91:
1.52 joris 92: (void)fclose(fp);
93: }
1.12 jfb 94:
1.1 jfb 95: return (ep);
96: }
97:
1.57 ! joris 98: struct cvs_ent *
! 99: cvs_ent_parse(const char *entry)
1.1 jfb 100: {
1.57 ! joris 101: int i;
1.5 jfb 102: struct cvs_ent *ent;
1.57 ! joris 103: char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp;
1.5 jfb 104:
1.57 ! joris 105: buf = xstrdup(entry);
! 106: sp = buf;
! 107: i = 0;
! 108: do {
! 109: dp = strchr(sp, CVS_ENTRIES_DELIM);
! 110: if (dp != NULL)
! 111: *(dp++) = '\0';
! 112: fields[i++] = sp;
! 113: sp = dp;
! 114: } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
1.8 jfb 115:
1.57 ! joris 116: if (i < CVS_ENTRIES_NFIELDS)
! 117: fatal("missing fields in entry line '%s'", entry);
1.5 jfb 118:
1.57 ! joris 119: ent = (struct cvs_ent *)xmalloc(sizeof(*ent));
! 120: ent->ce_buf = buf;
1.52 joris 121:
1.57 ! joris 122: if (*fields[0] == '\0')
! 123: ent->ce_type = CVS_ENT_FILE;
! 124: else if (*fields[0] == 'D')
! 125: ent->ce_type = CVS_ENT_DIR;
! 126: else
! 127: ent->ce_type = CVS_ENT_NONE;
! 128:
! 129: ent->ce_status = CVS_ENT_REG;
! 130: ent->ce_name = fields[1];
! 131: ent->ce_rev = NULL;
1.5 jfb 132:
1.57 ! joris 133: if (ent->ce_type == CVS_ENT_FILE) {
! 134: if (*fields[2] == '-') {
! 135: ent->ce_status = CVS_ENT_REMOVED;
! 136: sp = fields[2] + 1;
! 137: } else {
! 138: sp = fields[2];
! 139: if (fields[2][0] == '0' && fields[2][1] == '\0')
! 140: ent->ce_status = CVS_ENT_ADDED;
! 141: }
1.1 jfb 142:
1.57 ! joris 143: if ((ent->ce_rev = rcsnum_parse(sp)) == NULL)
! 144: fatal("failed to parse entry revision '%s'", entry);
1.1 jfb 145:
1.57 ! joris 146: if (strcmp(fields[3], CVS_DATE_DUMMY) == 0 ||
! 147: strncmp(fields[3], "Initial ", 8) == 0 ||
! 148: strncmp(fields[3], "Result of merge", 15) == 0)
! 149: ent->ce_mtime = CVS_DATE_DMSEC;
! 150: else
! 151: ent->ce_mtime = cvs_date_parse(fields[3]);
1.3 jfb 152: }
1.1 jfb 153:
1.57 ! joris 154: ent->ce_conflict = fields[3];
! 155: if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
! 156: *dp = '\0';
! 157: else
! 158: ent->ce_conflict = NULL;
1.1 jfb 159:
1.57 ! joris 160: if (strcmp(fields[4], ""))
! 161: ent->ce_opts = fields[4];
! 162: else
! 163: ent->ce_opts = NULL;
1.8 jfb 164:
1.57 ! joris 165: if (strcmp(fields[5], ""))
! 166: ent->ce_tag = fields[5];
! 167: else
! 168: ent->ce_tag = NULL;
1.3 jfb 169:
1.57 ! joris 170: return (ent);
1.3 jfb 171: }
172:
1.57 ! joris 173: struct cvs_ent *
! 174: cvs_ent_get(CVSENTRIES *ep, const char *name)
1.3 jfb 175: {
176: struct cvs_ent *ent;
1.57 ! joris 177: struct cvs_ent_line *l;
1.3 jfb 178:
1.57 ! joris 179: l = ent_get_line(ep, name);
! 180: if (l == NULL)
! 181: return (NULL);
1.3 jfb 182:
1.57 ! joris 183: ent = cvs_ent_parse(l->buf);
! 184: return (ent);
! 185: }
1.3 jfb 186:
1.57 ! joris 187: int
! 188: cvs_ent_exists(CVSENTRIES *ep, const char *name)
! 189: {
! 190: struct cvs_ent_line *l;
1.1 jfb 191:
1.57 ! joris 192: l = ent_get_line(ep, name);
! 193: if (l == NULL)
! 194: return (0);
1.8 jfb 195:
1.57 ! joris 196: return (1);
1.1 jfb 197: }
198:
1.57 ! joris 199: void
! 200: cvs_ent_close(CVSENTRIES *ep, int writefile)
1.9 jfb 201: {
1.57 ! joris 202: FILE *fp;
! 203: struct cvs_ent_line *l;
1.44 xsa 204:
1.57 ! joris 205: if (writefile) {
! 206: if ((fp = fopen(ep->cef_bpath, "w")) == NULL)
! 207: fatal("cvs_ent_close: failed to write %s",
! 208: ep->cef_path);
! 209: }
1.16 jfb 210:
1.57 ! joris 211: while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
! 212: if (writefile) {
! 213: fputs(l->buf, fp);
! 214: fputc('\n', fp);
1.51 joris 215: }
1.57 ! joris 216:
! 217: TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
! 218: xfree(l->buf);
! 219: xfree(l);
1.22 jfb 220: }
1.9 jfb 221:
1.57 ! joris 222: if (writefile) {
! 223: fputc('D', fp);
! 224: (void)fclose(fp);
! 225:
! 226: if (rename(ep->cef_bpath, ep->cef_path) == -1)
! 227: fatal("cvs_ent_close: %s: %s", ep->cef_path,
! 228: strerror(errno));
! 229:
! 230: (void)unlink(ep->cef_lpath);
! 231: }
1.9 jfb 232:
1.57 ! joris 233: xfree(ep->cef_path);
! 234: xfree(ep->cef_bpath);
! 235: xfree(ep->cef_lpath);
! 236: xfree(ep);
1.9 jfb 237: }
238:
1.57 ! joris 239: void
! 240: cvs_ent_add(CVSENTRIES *ep, const char *line)
1.1 jfb 241: {
1.57 ! joris 242: FILE *fp;
! 243: struct cvs_ent_line *l;
1.39 xsa 244: struct cvs_ent *ent;
1.1 jfb 245:
1.57 ! joris 246: if ((ent = cvs_ent_parse(line)) == NULL)
! 247: fatal("cvs_ent_add: parsing failed '%s'", line);
1.1 jfb 248:
1.57 ! joris 249: l = ent_get_line(ep, ent->ce_name);
! 250: if (l != NULL)
! 251: cvs_ent_remove(ep, ent->ce_name);
1.1 jfb 252:
1.57 ! joris 253: cvs_ent_free(ent);
1.1 jfb 254:
1.57 ! joris 255: cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
1.1 jfb 256:
1.57 ! joris 257: if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
! 258: fatal("cvs_ent_add: failed to open '%s'", ep->cef_lpath);
1.1 jfb 259:
1.57 ! joris 260: fputc('A', fp);
! 261: fputs(line, fp);
! 262: fputc('\n', fp);
1.1 jfb 263:
1.57 ! joris 264: (void)fclose(fp);
1.10 jfb 265:
1.57 ! joris 266: l = (struct cvs_ent_line *)xmalloc(sizeof(*l));
! 267: l->buf = xstrdup(line);
! 268: TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
! 269: }
1.10 jfb 270:
1.57 ! joris 271: void
! 272: cvs_ent_remove(CVSENTRIES *ep, const char *name)
! 273: {
! 274: FILE *fp;
! 275: struct cvs_ent_line *l;
1.1 jfb 276:
1.57 ! joris 277: cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
1.1 jfb 278:
1.57 ! joris 279: l = ent_get_line(ep, name);
! 280: if (l == NULL)
! 281: return;
1.1 jfb 282:
1.57 ! joris 283: if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
! 284: fatal("cvs_ent_remove: failed to open '%s'",
! 285: ep->cef_lpath);
1.38 joris 286:
1.57 ! joris 287: fputc('R', fp);
! 288: fputs(l->buf, fp);
! 289: fputc('\n', fp);
1.24 jfb 290:
1.57 ! joris 291: (void)fclose(fp);
1.24 jfb 292:
1.57 ! joris 293: TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
! 294: xfree(l->buf);
! 295: xfree(l);
1.5 jfb 296: }
297:
298: void
299: cvs_ent_free(struct cvs_ent *ent)
300: {
301: if (ent->ce_rev != NULL)
302: rcsnum_free(ent->ce_rev);
1.57 ! joris 303: xfree(ent->ce_buf);
1.53 joris 304: xfree(ent);
1.5 jfb 305: }
1.8 jfb 306:
1.57 ! joris 307: static struct cvs_ent_line *
! 308: ent_get_line(CVSENTRIES *ep, const char *name)
1.8 jfb 309: {
1.57 ! joris 310: char *p, *s;
! 311: struct cvs_ent_line *l;
1.8 jfb 312:
1.57 ! joris 313: TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
! 314: if (l->buf[0] == 'D')
! 315: p = &(l->buf[2]);
! 316: else
! 317: p = &(l->buf[1]);
! 318:
! 319: if ((s = strchr(p, '/')) == NULL)
! 320: fatal("ent_get_line: bad entry line '%s'", l->buf);
! 321:
! 322: *s = '\0';
! 323:
! 324: if (!strcmp(p, name)) {
! 325: *s = '/';
! 326: return (l);
1.15 jfb 327: }
1.8 jfb 328:
1.57 ! joris 329: *s = '/';
1.8 jfb 330: }
331:
1.57 ! joris 332: return (NULL);
1.1 jfb 333: }