Annotation of src/usr.bin/cvs/entries.c, Revision 1.58
1.58 ! joris 1: /* $OpenBSD: entries.c,v 1.57 2006/05/27 03:30:30 joris Exp $ */
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], ""))
1.58 ! joris 166: ent->ce_tag = fields[5] + 1;
1.57 joris 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: }