[BACK]Return to entries.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/entries.c, Revision 1.63

1.63    ! xsa         1: /*     $OpenBSD: entries.c,v 1.62 2006/10/24 06:25:10 ray 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);
1.62      ray        72:                        if (len > 0 && buf[len - 1] == '\n')
                     73:                                buf[len - 1] = '\0';
1.57      joris      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)
1.63    ! xsa       207:                        fatal("cvs_ent_close: fopen: `%s': %s",
        !           208:                            ep->cef_path, strerror(errno));
1.57      joris     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)
1.63    ! xsa       227:                        fatal("cvs_ent_close: rename: `%s'->`%s': %s",
        !           228:                            ep->cef_bpath, ep->cef_path, strerror(errno));
1.57      joris     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.61      joris     255:        if (cvs_server_active == 0)
                    256:                cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
1.1       jfb       257:
1.57      joris     258:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63    ! xsa       259:                fatal("cvs_ent_add: fopen: `%s': %s",
        !           260:                    ep->cef_lpath, strerror(errno));
1.1       jfb       261:
1.57      joris     262:        fputc('A', fp);
                    263:        fputs(line, fp);
                    264:        fputc('\n', fp);
1.1       jfb       265:
1.57      joris     266:        (void)fclose(fp);
1.10      jfb       267:
1.57      joris     268:        l = (struct cvs_ent_line *)xmalloc(sizeof(*l));
                    269:        l->buf = xstrdup(line);
                    270:        TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
                    271: }
1.10      jfb       272:
1.57      joris     273: void
                    274: cvs_ent_remove(CVSENTRIES *ep, const char *name)
                    275: {
                    276:        FILE *fp;
                    277:        struct cvs_ent_line *l;
1.1       jfb       278:
1.61      joris     279:        if (cvs_server_active == 0)
                    280:                cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
1.1       jfb       281:
1.57      joris     282:        l = ent_get_line(ep, name);
                    283:        if (l == NULL)
                    284:                return;
1.1       jfb       285:
1.57      joris     286:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63    ! xsa       287:                fatal("cvs_ent_remove: fopen: `%s': %s", ep->cef_lpath,
        !           288:                    strerror(errno));
1.38      joris     289:
1.57      joris     290:        fputc('R', fp);
                    291:        fputs(l->buf, fp);
                    292:        fputc('\n', fp);
1.24      jfb       293:
1.57      joris     294:        (void)fclose(fp);
1.24      jfb       295:
1.57      joris     296:        TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
                    297:        xfree(l->buf);
                    298:        xfree(l);
1.5       jfb       299: }
                    300:
                    301: void
                    302: cvs_ent_free(struct cvs_ent *ent)
                    303: {
                    304:        if (ent->ce_rev != NULL)
                    305:                rcsnum_free(ent->ce_rev);
1.57      joris     306:        xfree(ent->ce_buf);
1.53      joris     307:        xfree(ent);
1.5       jfb       308: }
1.8       jfb       309:
1.57      joris     310: static struct cvs_ent_line *
                    311: ent_get_line(CVSENTRIES *ep, const char *name)
1.8       jfb       312: {
1.57      joris     313:        char *p, *s;
                    314:        struct cvs_ent_line *l;
1.8       jfb       315:
1.57      joris     316:        TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
                    317:                if (l->buf[0] == 'D')
                    318:                        p = &(l->buf[2]);
                    319:                else
                    320:                        p = &(l->buf[1]);
                    321:
                    322:                if ((s = strchr(p, '/')) == NULL)
                    323:                        fatal("ent_get_line: bad entry line '%s'", l->buf);
                    324:
                    325:                *s = '\0';
                    326:
                    327:                if (!strcmp(p, name)) {
                    328:                        *s = '/';
                    329:                        return (l);
1.15      jfb       330:                }
1.8       jfb       331:
1.57      joris     332:                *s = '/';
1.8       jfb       333:        }
                    334:
1.57      joris     335:        return (NULL);
1.59      xsa       336: }
                    337:
                    338: void
                    339: cvs_parse_tagfile(char *dir, char **tagp, char **datep, int *nbp)
                    340: {
                    341:        FILE *fp;
                    342:        int linenum;
                    343:        size_t len;
                    344:        char linebuf[128], *tagpath;
                    345:
                    346:        if (tagp != NULL)
1.60      joris     347:                *tagp = NULL;
1.59      xsa       348:
                    349:        if (datep != NULL)
1.60      joris     350:                *datep = NULL;
1.59      xsa       351:
                    352:        if (nbp != NULL)
                    353:                *nbp = 0;
                    354:
                    355:        tagpath = xmalloc(MAXPATHLEN);
                    356:
                    357:        if (cvs_path_cat(dir, CVS_PATH_TAG, tagpath, MAXPATHLEN) >= MAXPATHLEN)
                    358:                goto out;
                    359:
                    360:        if ((fp = fopen(tagpath, "r")) == NULL) {
                    361:                if (errno != ENOENT)
                    362:                        cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath,
                    363:                            strerror(errno));
                    364:                goto out;
                    365:         }
                    366:
                    367:        linenum = 0;
                    368:
                    369:        while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) {
                    370:                linenum++;
                    371:                if ((len = strlen(linebuf)) == 0)
                    372:                        continue;
                    373:                if (linebuf[len - 1] != '\n') {
                    374:                        cvs_log(LP_NOTICE, "line too long in `%s:%d'",
                    375:                            tagpath, linenum);
                    376:                        break;
                    377:                }
                    378:                linebuf[--len] = '\0';
                    379:
                    380:                switch (*linebuf) {
                    381:                case 'T':
                    382:                        if (tagp != NULL)
                    383:                                *tagp = xstrdup(linebuf + 1);
                    384:                        break;
                    385:                case 'D':
                    386:                        if (datep != NULL)
                    387:                                *datep = xstrdup(linebuf + 1);
                    388:                        break;
                    389:                case 'N':
                    390:                        if (tagp != NULL)
                    391:                                *tagp = xstrdup(linebuf + 1);
                    392:                        if (nbp != NULL)
                    393:                                *nbp = 1;
                    394:                        break;
                    395:                default:
                    396:                        break;
                    397:                }
                    398:        }
                    399:        if (ferror(fp))
                    400:                cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath);
                    401:
                    402:        (void)fclose(fp);
                    403: out:
                    404:        xfree(tagpath);
                    405: }
                    406:
                    407: void
                    408: cvs_write_tagfile(char *dir, char *tag, char *date, int nb)
                    409: {
                    410:        FILE *fp;
                    411:        char *tagpath;
                    412:
                    413:        if (cvs_noexec == 1)
                    414:                return;
                    415:
                    416:        tagpath = xmalloc(MAXPATHLEN);
                    417:
                    418:        if (cvs_path_cat(dir, CVS_PATH_TAG, tagpath, MAXPATHLEN) >= MAXPATHLEN)
                    419:                goto out;
                    420:
                    421:        if ((tag != NULL) || (date != NULL)) {
                    422:                if ((fp = fopen(tagpath, "w+")) == NULL) {
                    423:                        if (errno != ENOENT) {
                    424:                                cvs_log(LP_NOTICE, "failed to open `%s' : %s",
                    425:                                    tagpath, strerror(errno));
                    426:                        }
                    427:                        goto out;
                    428:                }
                    429:                if (tag != NULL) {
                    430:                        if (nb != 0)
                    431:                                (void)fprintf(fp, "N%s\n", tag);
                    432:                        else
                    433:                                (void)fprintf(fp, "T%s\n", tag);
                    434:                } else
                    435:                        (void)fprintf(fp, "D%s\n", date);
                    436:
                    437:                (void)fclose(fp);
                    438:        } else {
                    439:                (void)cvs_unlink(tagpath);
                    440:                goto out;
                    441:        }
                    442: out:
                    443:        xfree(tagpath);
1.1       jfb       444: }