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

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