[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.85

1.85    ! tobias      1: /*     $OpenBSD: entries.c,v 1.84 2007/10/05 19:28:23 gilles 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.75      otto       18: #include <errno.h>
                     19: #include <string.h>
1.83      chl        20: #include <time.h>
1.75      otto       21: #include <unistd.h>
1.1       jfb        22:
1.34      xsa        23: #include "cvs.h"
1.81      joris      24: #include "remote.h"
1.1       jfb        25:
1.42      xsa        26: #define CVS_ENTRIES_NFIELDS    6
                     27: #define CVS_ENTRIES_DELIM      '/'
1.1       jfb        28:
1.57      joris      29: static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
1.1       jfb        30:
1.42      xsa        31: CVSENTRIES *
1.57      joris      32: cvs_ent_open(const char *dir)
1.1       jfb        33: {
1.57      joris      34:        FILE *fp;
                     35:        CVSENTRIES *ep;
                     36:        char *p, buf[MAXPATHLEN];
1.1       jfb        37:        struct cvs_ent *ent;
1.57      joris      38:        struct cvs_ent_line *line;
1.36      xsa        39:
1.57      joris      40:        ep = (CVSENTRIES *)xmalloc(sizeof(*ep));
                     41:        memset(ep, 0, sizeof(*ep));
1.52      joris      42:
1.73      xsa        43:        (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_ENTRIES);
1.64      xsa        44:
1.57      joris      45:        ep->cef_path = xstrdup(buf);
1.8       jfb        46:
1.73      xsa        47:        (void)xsnprintf(buf, sizeof(buf), "%s/%s",
                     48:            dir, CVS_PATH_BACKUPENTRIES);
1.64      xsa        49:
1.57      joris      50:        ep->cef_bpath = xstrdup(buf);
1.3       jfb        51:
1.73      xsa        52:        (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_LOGENTRIES);
1.64      xsa        53:
1.57      joris      54:        ep->cef_lpath = xstrdup(buf);
1.1       jfb        55:
1.4       jfb        56:        TAILQ_INIT(&(ep->cef_ent));
1.3       jfb        57:
1.57      joris      58:        if ((fp = fopen(ep->cef_path, "r")) != NULL) {
                     59:                while (fgets(buf, sizeof(buf), fp)) {
1.84      gilles     60:                        buf[strcspn(buf, "\n")] = '\0';
1.57      joris      61:
                     62:                        if (buf[0] == 'D' && buf[1] == '\0')
                     63:                                break;
                     64:
                     65:                        line = (struct cvs_ent_line *)xmalloc(sizeof(*line));
                     66:                        line->buf = xstrdup(buf);
                     67:                        TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
                     68:                }
1.52      joris      69:
1.25      jfb        70:                (void)fclose(fp);
1.12      jfb        71:        }
1.1       jfb        72:
1.57      joris      73:        if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
                     74:                while (fgets(buf, sizeof(buf), fp)) {
1.84      gilles     75:                        buf[strcspn(buf, "\n")] = '\0';
1.57      joris      76:
                     77:                        p = &buf[1];
                     78:
                     79:                        if (buf[0] == 'A') {
                     80:                                line = xmalloc(sizeof(*line));
                     81:                                line->buf = xstrdup(p);
                     82:                                TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
                     83:                                    entries_list);
                     84:                        } else if (buf[0] == 'R') {
                     85:                                ent = cvs_ent_parse(p);
                     86:                                line = ent_get_line(ep, ent->ce_name);
1.65      joris      87:                                if (line != NULL) {
1.57      joris      88:                                        TAILQ_REMOVE(&(ep->cef_ent), line,
                     89:                                            entries_list);
1.65      joris      90:                                        xfree(line->buf);
                     91:                                        xfree(line);
                     92:                                }
1.57      joris      93:                                cvs_ent_free(ent);
                     94:                        }
                     95:                }
1.4       jfb        96:
1.52      joris      97:                (void)fclose(fp);
                     98:        }
1.12      jfb        99:
1.1       jfb       100:        return (ep);
                    101: }
                    102:
1.57      joris     103: struct cvs_ent *
                    104: cvs_ent_parse(const char *entry)
1.1       jfb       105: {
1.57      joris     106:        int i;
1.70      joris     107:        struct tm t;
1.5       jfb       108:        struct cvs_ent *ent;
1.57      joris     109:        char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp;
1.5       jfb       110:
1.72      joris     111:        buf = sp = xstrdup(entry);
1.57      joris     112:        i = 0;
                    113:        do {
                    114:                dp = strchr(sp, CVS_ENTRIES_DELIM);
                    115:                if (dp != NULL)
                    116:                        *(dp++) = '\0';
                    117:                fields[i++] = sp;
                    118:                sp = dp;
                    119:        } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
1.8       jfb       120:
1.57      joris     121:        if (i < CVS_ENTRIES_NFIELDS)
                    122:                fatal("missing fields in entry line '%s'", entry);
1.5       jfb       123:
1.72      joris     124:        ent = xmalloc(sizeof(*ent));
1.57      joris     125:        ent->ce_buf = buf;
1.52      joris     126:
1.57      joris     127:        if (*fields[0] == '\0')
                    128:                ent->ce_type = CVS_ENT_FILE;
                    129:        else if (*fields[0] == 'D')
                    130:                ent->ce_type = CVS_ENT_DIR;
                    131:        else
                    132:                ent->ce_type = CVS_ENT_NONE;
                    133:
                    134:        ent->ce_status = CVS_ENT_REG;
                    135:        ent->ce_name = fields[1];
                    136:        ent->ce_rev = NULL;
1.5       jfb       137:
1.57      joris     138:        if (ent->ce_type == CVS_ENT_FILE) {
                    139:                if (*fields[2] == '-') {
                    140:                        ent->ce_status = CVS_ENT_REMOVED;
                    141:                        sp = fields[2] + 1;
                    142:                } else {
                    143:                        sp = fields[2];
                    144:                        if (fields[2][0] == '0' && fields[2][1] == '\0')
                    145:                                ent->ce_status = CVS_ENT_ADDED;
                    146:                }
1.1       jfb       147:
1.57      joris     148:                if ((ent->ce_rev = rcsnum_parse(sp)) == NULL)
                    149:                        fatal("failed to parse entry revision '%s'", entry);
1.1       jfb       150:
1.72      joris     151:                if (fields[3][0] == '\0' ||
1.77      ray       152:                    strncmp(fields[3], CVS_DATE_DUMMY, sizeof(CVS_DATE_DUMMY) - 1) == 0 ||
1.57      joris     153:                    strncmp(fields[3], "Initial ", 8) == 0 ||
1.81      joris     154:                    strncmp(fields[3], "Result of merge", 15) == 0) {
1.57      joris     155:                        ent->ce_mtime = CVS_DATE_DMSEC;
1.81      joris     156:                } else if (cvs_server_active == 1 &&
                    157:                    strncmp(fields[3], CVS_SERVER_UNCHANGED,
                    158:                    strlen(CVS_SERVER_UNCHANGED)) == 0) {
                    159:                        ent->ce_mtime = CVS_SERVER_UPTODATE;
                    160:                } else {
1.78      niallo    161:                        /* Date field can be a '+=' with remote to indicate
                    162:                         * conflict.  In this case do nothing. */
                    163:                        if (strptime(fields[3], "%a %b %d %T %Y", &t) != NULL) {
                    164:
                    165:                                t.tm_isdst = -1;        /* Figure out DST. */
                    166:                                t.tm_gmtoff = 0;
                    167:                                ent->ce_mtime = mktime(&t);
                    168:                                ent->ce_mtime += t.tm_gmtoff;
                    169:                        }
1.70      joris     170:                }
1.3       jfb       171:        }
1.1       jfb       172:
1.57      joris     173:        ent->ce_conflict = fields[3];
                    174:        if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
                    175:                *dp = '\0';
                    176:        else
                    177:                ent->ce_conflict = NULL;
1.1       jfb       178:
1.57      joris     179:        if (strcmp(fields[4], ""))
                    180:                ent->ce_opts = fields[4];
                    181:        else
                    182:                ent->ce_opts = NULL;
1.8       jfb       183:
1.57      joris     184:        if (strcmp(fields[5], ""))
1.58      joris     185:                ent->ce_tag = fields[5] + 1;
1.57      joris     186:        else
                    187:                ent->ce_tag = NULL;
1.3       jfb       188:
1.57      joris     189:        return (ent);
1.3       jfb       190: }
                    191:
1.57      joris     192: struct cvs_ent *
                    193: cvs_ent_get(CVSENTRIES *ep, const char *name)
1.3       jfb       194: {
                    195:        struct cvs_ent *ent;
1.57      joris     196:        struct cvs_ent_line *l;
1.3       jfb       197:
1.57      joris     198:        l = ent_get_line(ep, name);
                    199:        if (l == NULL)
                    200:                return (NULL);
1.3       jfb       201:
1.57      joris     202:        ent = cvs_ent_parse(l->buf);
                    203:        return (ent);
1.1       jfb       204: }
                    205:
1.57      joris     206: void
                    207: cvs_ent_close(CVSENTRIES *ep, int writefile)
1.9       jfb       208: {
1.57      joris     209:        FILE *fp;
                    210:        struct cvs_ent_line *l;
1.85    ! tobias    211:        int dflag;
        !           212:
        !           213:        dflag = 1;
1.44      xsa       214:
1.57      joris     215:        if (writefile) {
                    216:                if ((fp = fopen(ep->cef_bpath, "w")) == NULL)
1.63      xsa       217:                        fatal("cvs_ent_close: fopen: `%s': %s",
                    218:                            ep->cef_path, strerror(errno));
1.57      joris     219:        }
1.16      jfb       220:
1.57      joris     221:        while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
                    222:                if (writefile) {
1.85    ! tobias    223:                        if (l->buf[0] == 'D')
        !           224:                                dflag = 0;
        !           225:
1.57      joris     226:                        fputs(l->buf, fp);
                    227:                        fputc('\n', fp);
1.51      joris     228:                }
1.57      joris     229:
                    230:                TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
                    231:                xfree(l->buf);
                    232:                xfree(l);
1.22      jfb       233:        }
1.9       jfb       234:
1.57      joris     235:        if (writefile) {
1.85    ! tobias    236:                if (dflag) {
        !           237:                        fputc('D', fp);
        !           238:                        fputc('\n', fp);
        !           239:                }
1.57      joris     240:                (void)fclose(fp);
                    241:
                    242:                if (rename(ep->cef_bpath, ep->cef_path) == -1)
1.63      xsa       243:                        fatal("cvs_ent_close: rename: `%s'->`%s': %s",
                    244:                            ep->cef_bpath, ep->cef_path, strerror(errno));
1.57      joris     245:
                    246:                (void)unlink(ep->cef_lpath);
                    247:        }
1.9       jfb       248:
1.57      joris     249:        xfree(ep->cef_path);
                    250:        xfree(ep->cef_bpath);
                    251:        xfree(ep->cef_lpath);
                    252:        xfree(ep);
1.9       jfb       253: }
                    254:
1.57      joris     255: void
                    256: cvs_ent_add(CVSENTRIES *ep, const char *line)
1.1       jfb       257: {
1.57      joris     258:        FILE *fp;
                    259:        struct cvs_ent_line *l;
1.39      xsa       260:        struct cvs_ent *ent;
1.1       jfb       261:
1.57      joris     262:        if ((ent = cvs_ent_parse(line)) == NULL)
                    263:                fatal("cvs_ent_add: parsing failed '%s'", line);
1.1       jfb       264:
1.57      joris     265:        l = ent_get_line(ep, ent->ce_name);
                    266:        if (l != NULL)
                    267:                cvs_ent_remove(ep, ent->ce_name);
1.1       jfb       268:
1.57      joris     269:        cvs_ent_free(ent);
1.1       jfb       270:
1.61      joris     271:        if (cvs_server_active == 0)
                    272:                cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
1.1       jfb       273:
1.57      joris     274:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63      xsa       275:                fatal("cvs_ent_add: fopen: `%s': %s",
                    276:                    ep->cef_lpath, strerror(errno));
1.1       jfb       277:
1.57      joris     278:        fputc('A', fp);
                    279:        fputs(line, fp);
                    280:        fputc('\n', fp);
1.1       jfb       281:
1.57      joris     282:        (void)fclose(fp);
1.10      jfb       283:
1.57      joris     284:        l = (struct cvs_ent_line *)xmalloc(sizeof(*l));
                    285:        l->buf = xstrdup(line);
                    286:        TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
                    287: }
1.10      jfb       288:
1.57      joris     289: void
                    290: cvs_ent_remove(CVSENTRIES *ep, const char *name)
                    291: {
                    292:        FILE *fp;
                    293:        struct cvs_ent_line *l;
1.1       jfb       294:
1.61      joris     295:        if (cvs_server_active == 0)
                    296:                cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
1.1       jfb       297:
1.57      joris     298:        l = ent_get_line(ep, name);
                    299:        if (l == NULL)
                    300:                return;
1.1       jfb       301:
1.57      joris     302:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63      xsa       303:                fatal("cvs_ent_remove: fopen: `%s': %s", ep->cef_lpath,
                    304:                    strerror(errno));
1.38      joris     305:
1.57      joris     306:        fputc('R', fp);
                    307:        fputs(l->buf, fp);
                    308:        fputc('\n', fp);
1.24      jfb       309:
1.57      joris     310:        (void)fclose(fp);
1.24      jfb       311:
1.57      joris     312:        TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
                    313:        xfree(l->buf);
                    314:        xfree(l);
1.5       jfb       315: }
                    316:
                    317: void
                    318: cvs_ent_free(struct cvs_ent *ent)
                    319: {
                    320:        if (ent->ce_rev != NULL)
                    321:                rcsnum_free(ent->ce_rev);
1.57      joris     322:        xfree(ent->ce_buf);
1.53      joris     323:        xfree(ent);
1.5       jfb       324: }
1.8       jfb       325:
1.57      joris     326: static struct cvs_ent_line *
                    327: ent_get_line(CVSENTRIES *ep, const char *name)
1.8       jfb       328: {
1.57      joris     329:        char *p, *s;
                    330:        struct cvs_ent_line *l;
1.8       jfb       331:
1.57      joris     332:        TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
                    333:                if (l->buf[0] == 'D')
                    334:                        p = &(l->buf[2]);
                    335:                else
                    336:                        p = &(l->buf[1]);
                    337:
                    338:                if ((s = strchr(p, '/')) == NULL)
                    339:                        fatal("ent_get_line: bad entry line '%s'", l->buf);
                    340:
                    341:                *s = '\0';
                    342:
                    343:                if (!strcmp(p, name)) {
                    344:                        *s = '/';
                    345:                        return (l);
1.15      jfb       346:                }
1.8       jfb       347:
1.57      joris     348:                *s = '/';
1.8       jfb       349:        }
                    350:
1.57      joris     351:        return (NULL);
1.59      xsa       352: }
                    353:
                    354: void
                    355: cvs_parse_tagfile(char *dir, char **tagp, char **datep, int *nbp)
                    356: {
                    357:        FILE *fp;
1.73      xsa       358:        int i, linenum;
1.59      xsa       359:        size_t len;
1.69      otto      360:        char linebuf[128], tagpath[MAXPATHLEN];
1.59      xsa       361:
                    362:        if (tagp != NULL)
1.60      joris     363:                *tagp = NULL;
1.59      xsa       364:
                    365:        if (datep != NULL)
1.60      joris     366:                *datep = NULL;
1.59      xsa       367:
                    368:        if (nbp != NULL)
                    369:                *nbp = 0;
                    370:
1.73      xsa       371:        i = snprintf(tagpath, MAXPATHLEN, "%s/%s", dir, CVS_PATH_TAG);
                    372:        if (i < 0 || i >= MAXPATHLEN)
1.69      otto      373:                return;
1.59      xsa       374:
                    375:        if ((fp = fopen(tagpath, "r")) == NULL) {
                    376:                if (errno != ENOENT)
                    377:                        cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath,
                    378:                            strerror(errno));
1.69      otto      379:                return;
1.59      xsa       380:         }
                    381:
                    382:        linenum = 0;
                    383:
                    384:        while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) {
                    385:                linenum++;
                    386:                if ((len = strlen(linebuf)) == 0)
                    387:                        continue;
                    388:                if (linebuf[len - 1] != '\n') {
                    389:                        cvs_log(LP_NOTICE, "line too long in `%s:%d'",
                    390:                            tagpath, linenum);
                    391:                        break;
                    392:                }
                    393:                linebuf[--len] = '\0';
                    394:
                    395:                switch (*linebuf) {
                    396:                case 'T':
                    397:                        if (tagp != NULL)
                    398:                                *tagp = xstrdup(linebuf + 1);
                    399:                        break;
                    400:                case 'D':
                    401:                        if (datep != NULL)
                    402:                                *datep = xstrdup(linebuf + 1);
                    403:                        break;
                    404:                case 'N':
                    405:                        if (tagp != NULL)
                    406:                                *tagp = xstrdup(linebuf + 1);
                    407:                        if (nbp != NULL)
                    408:                                *nbp = 1;
                    409:                        break;
                    410:                default:
                    411:                        break;
                    412:                }
                    413:        }
                    414:        if (ferror(fp))
                    415:                cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath);
                    416:
                    417:        (void)fclose(fp);
                    418: }
                    419:
                    420: void
1.74      otto      421: cvs_write_tagfile(const char *dir, char *tag, char *date, int nb)
1.59      xsa       422: {
                    423:        FILE *fp;
1.69      otto      424:        char tagpath[MAXPATHLEN];
1.82      joris     425:        char sticky[CVS_REV_BUFSZ];
1.73      xsa       426:        int i;
1.59      xsa       427:
                    428:        if (cvs_noexec == 1)
                    429:                return;
                    430:
1.73      xsa       431:        i = snprintf(tagpath, MAXPATHLEN, "%s/%s", dir, CVS_PATH_TAG);
                    432:        if (i < 0 || i >= MAXPATHLEN)
1.69      otto      433:                return;
1.59      xsa       434:
                    435:        if ((tag != NULL) || (date != NULL)) {
                    436:                if ((fp = fopen(tagpath, "w+")) == NULL) {
                    437:                        if (errno != ENOENT) {
                    438:                                cvs_log(LP_NOTICE, "failed to open `%s' : %s",
                    439:                                    tagpath, strerror(errno));
                    440:                        }
1.69      otto      441:                        return;
1.59      xsa       442:                }
1.79      joris     443:
1.59      xsa       444:                if (tag != NULL) {
1.82      joris     445:                        if (nb != 0) {
                    446:                                (void)xsnprintf(sticky, sizeof(sticky),
                    447:                                    "N%s", tag);
                    448:                        } else {
                    449:                                (void)xsnprintf(sticky, sizeof(sticky),
                    450:                                    "T%s", tag);
                    451:                        }
                    452:                } else {
                    453:                        (void)xsnprintf(sticky, sizeof(sticky), "D%s", date);
                    454:                }
                    455:
                    456:                if (cvs_server_active == 1)
                    457:                        cvs_server_set_sticky(dir, sticky);
1.59      xsa       458:
1.82      joris     459:                (void)fprintf(fp, "%s\n", sticky);
1.59      xsa       460:                (void)fclose(fp);
                    461:        } else {
                    462:                (void)cvs_unlink(tagpath);
                    463:        }
1.1       jfb       464: }