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

1.1       jfb         1: /*     $OpenBSD$       */
                      2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27: #include <sys/param.h>
                     28: #include <sys/stat.h>
                     29:
                     30: #include <stdio.h>
                     31: #include <fcntl.h>
                     32: #include <stdlib.h>
                     33: #include <unistd.h>
                     34: #include <string.h>
                     35:
                     36: #include "log.h"
                     37: #include "cvs.h"
                     38:
                     39:
                     40: #define CVS_ENTRIES_NFIELDS  5
                     41: #define CVS_ENTRIES_DELIM   '/'
                     42:
                     43:
1.3       jfb        44:
                     45: static struct cvs_ent*  cvs_ent_clone (const struct cvs_ent *);
                     46:
                     47:
                     48:
1.1       jfb        49: /*
                     50:  * cvs_ent_open()
                     51:  *
                     52:  * Open the CVS Entries file for the directory <dir>.
                     53:  * Returns a pointer to the CVSENTRIES file structure on success, or NULL
                     54:  * on failure.
                     55:  */
                     56:
                     57: CVSENTRIES*
1.2       jfb        58: cvs_ent_open(const char *dir, int flags)
1.1       jfb        59: {
                     60:        size_t len;
1.3       jfb        61:        char entpath[MAXPATHLEN], ebuf[128], mode[4];
1.1       jfb        62:        FILE *fp;
                     63:        struct cvs_ent *ent;
                     64:        CVSENTRIES *ep;
                     65:
1.3       jfb        66:        memset(mode, 0, sizeof(mode));
1.4       jfb        67:        switch (flags & O_ACCMODE) {
                     68:        case O_RDWR:
                     69:                mode[1] = '+';
                     70:                /* fallthrough */
                     71:        case O_RDONLY:
1.3       jfb        72:                mode[0] = 'r';
1.4       jfb        73:                break;
                     74:        case O_WRONLY:
1.7     ! jfb        75:                mode[0] = 'a';
1.4       jfb        76:                break;
1.3       jfb        77:        }
                     78:
1.1       jfb        79:        snprintf(entpath, sizeof(entpath), "%s/" CVS_PATH_ENTRIES, dir);
1.3       jfb        80:        fp = fopen(entpath, mode);
1.1       jfb        81:        if (fp == NULL) {
                     82:                cvs_log(LP_ERRNO, "cannot open CVS/Entries for reading",
                     83:                    entpath);
                     84:                return (NULL);
                     85:        }
                     86:
                     87:        ep = (CVSENTRIES *)malloc(sizeof(CVSENTRIES));
                     88:        if (ep == NULL) {
                     89:                cvs_log(LP_ERRNO, "failed to allocate Entries data");
                     90:                (void)fclose(fp);
                     91:                return (NULL);
                     92:        }
1.5       jfb        93:        memset(ep, 0, sizeof(*ep));
                     94:
1.1       jfb        95:        ep->cef_path = strdup(dir);
                     96:        if (ep->cef_path == NULL) {
                     97:                cvs_log(LP_ERRNO, "failed to copy Entries path");
                     98:                free(ep);
                     99:                (void)fclose(fp);
                    100:                return (NULL);
                    101:        }
                    102:
1.4       jfb       103:        ep->cef_cur = NULL;
                    104:        TAILQ_INIT(&(ep->cef_ent));
1.3       jfb       105:
1.1       jfb       106:        while (fgets(ebuf, sizeof(ebuf), fp) != NULL) {
                    107:                len = strlen(ebuf);
                    108:                if ((len > 0) && (ebuf[len - 1] == '\n'))
                    109:                        ebuf[--len] = '\0';
1.7     ! jfb       110:                if (strcmp(ebuf, "D") == 0)
        !           111:                        break;
1.1       jfb       112:                ent = cvs_ent_parse(ebuf);
                    113:                if (ent == NULL)
                    114:                        continue;
                    115:
1.4       jfb       116:                TAILQ_INSERT_TAIL(&(ep->cef_ent), ent, ce_list);
1.1       jfb       117:        }
                    118:
1.4       jfb       119:        /* only keep a pointer to the open file if we're in writing mode */
                    120:        if ((flags & O_WRONLY) || (flags & O_RDWR))
                    121:                ep->cef_file = fp;
                    122:        else
                    123:                (void)fclose(fp);
                    124:
1.1       jfb       125:        return (ep);
                    126: }
                    127:
                    128:
                    129: /*
                    130:  * cvs_ent_close()
                    131:  *
1.5       jfb       132:  * Close the Entries file <ep> and free all data.  Any reference to entries
                    133:  * structure within that file become invalid.
1.1       jfb       134:  */
                    135:
                    136: void
                    137: cvs_ent_close(CVSENTRIES *ep)
                    138: {
1.5       jfb       139:        struct cvs_ent *ent;
                    140:
                    141:        if (ep->cef_file != NULL)
1.6       jfb       142:                (void)fclose(ep->cef_file);
1.5       jfb       143:        if (ep->cef_path != NULL)
                    144:                free(ep->cef_path);
                    145:
                    146:        while (!TAILQ_EMPTY(&(ep->cef_ent))) {
                    147:                ent = TAILQ_FIRST(&(ep->cef_ent));
                    148:                TAILQ_REMOVE(&(ep->cef_ent), ent, ce_list);
                    149:                cvs_ent_free(ent);
                    150:        }
                    151:
1.1       jfb       152:        free(ep);
                    153: }
                    154:
                    155:
                    156: /*
                    157:  * cvs_ent_add()
                    158:  *
1.3       jfb       159:  * Add the entry <ent> to the Entries file <ef>.
1.7     ! jfb       160:  * Returns 0 on success, or -1 on failure.
1.1       jfb       161:  */
                    162:
                    163: int
                    164: cvs_ent_add(CVSENTRIES *ef, struct cvs_ent *ent)
                    165: {
                    166:        void *tmp;
1.7     ! jfb       167:        char nbuf[64];
1.3       jfb       168:
                    169:        if (ef->cef_file == NULL) {
                    170:                cvs_log(LP_ERR, "Entries file is opened in read-only mode");
                    171:                return (-1);
                    172:        }
1.1       jfb       173:
                    174:        if (cvs_ent_get(ef, ent->ce_name) != NULL)
                    175:                return (-1);
                    176:
1.3       jfb       177:        if (fseek(ef->cef_file, (long)0, SEEK_END) == -1) {
                    178:                cvs_log(LP_ERRNO, "failed to seek to end of CVS/Entries file");
1.1       jfb       179:                return (-1);
                    180:        }
1.7     ! jfb       181:        rcsnum_tostr(ent->ce_rev, nbuf, sizeof(nbuf));
        !           182:        fprintf(ef->cef_file, "/%s/%s/%s/%s/\n", ent->ce_name, nbuf,
        !           183:            ent->ce_timestamp, ent->ce_opts);
1.3       jfb       184:
1.4       jfb       185:        TAILQ_INSERT_TAIL(&(ef->cef_ent), ent, ce_list);
1.3       jfb       186:        return (0);
                    187: }
                    188:
                    189:
                    190: /*
                    191:  * cvs_ent_addln()
                    192:  *
                    193:  * Add a line to the Entries file.
                    194:  */
                    195:
                    196: int
                    197: cvs_ent_addln(CVSENTRIES *ef, const char *line)
                    198: {
                    199:        void *tmp;
                    200:        struct cvs_ent *ent;
                    201:
                    202:        if (ef->cef_file == NULL) {
                    203:                cvs_log(LP_ERR, "Entries file is opened in read-only mode");
                    204:                return (-1);
                    205:        }
                    206:
                    207:        ent = cvs_ent_parse(line);
                    208:        if (ent == NULL)
                    209:                return (-1);
                    210:
                    211:        if (cvs_ent_get(ef, ent->ce_name) != NULL)
                    212:                return (-1);
1.1       jfb       213:
1.4       jfb       214:        TAILQ_INSERT_TAIL(&(ef->cef_ent), ent, ce_list);
1.1       jfb       215:        return (0);
                    216: }
                    217:
                    218:
                    219: /*
                    220:  * cvs_ent_get()
                    221:  *
                    222:  * Get the CVS entry from the Entries file <ef> whose 'name' portion matches
                    223:  * <file>.
                    224:  * Returns a pointer to the cvs entry structure on success, or NULL on failure.
                    225:  */
                    226:
                    227: struct cvs_ent*
                    228: cvs_ent_get(CVSENTRIES *ef, const char *file)
                    229: {
                    230:        u_int i;
1.4       jfb       231:        struct cvs_ent *ep;
1.1       jfb       232:
1.4       jfb       233:        TAILQ_FOREACH(ep, &(ef->cef_ent), ce_list)
                    234:                if (strcmp(ep->ce_name, file) == 0)
                    235:                        return (ep);
1.1       jfb       236:
                    237:        return (NULL);
                    238: }
                    239:
                    240:
                    241: /*
                    242:  * cvs_ent_next()
                    243:  *
1.4       jfb       244:  * This function is used to iterate over the entries in an Entries file.  The
                    245:  * first call will return the first entry of the file and each subsequent call
                    246:  * will return the entry following the last one returned.
1.1       jfb       247:  * Returns a pointer to the cvs entry structure on success, or NULL on failure.
                    248:  */
                    249:
                    250: struct cvs_ent*
                    251: cvs_ent_next(CVSENTRIES *ef)
                    252: {
1.5       jfb       253:        if (ef->cef_cur == NULL)
1.4       jfb       254:                ef->cef_cur = TAILQ_FIRST(&(ef->cef_ent));
1.5       jfb       255:        else
                    256:                ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list);
                    257:        return (ef->cef_cur);
1.1       jfb       258: }
                    259:
                    260:
                    261: /*
                    262:  * cvs_ent_parse()
                    263:  *
                    264:  * Parse a single line from a CVS/Entries file and return a cvs_entry structure
                    265:  * containing all the parsed information.
                    266:  */
                    267:
                    268: struct cvs_ent*
                    269: cvs_ent_parse(const char *entry)
                    270: {
                    271:        int i;
                    272:        char *fields[CVS_ENTRIES_NFIELDS], *sp, *dp;
                    273:        struct cvs_ent *entp;
                    274:
                    275:        entp = (struct cvs_ent *)malloc(sizeof(*entp));
                    276:        if (entp == NULL) {
                    277:                cvs_log(LP_ERRNO, "failed to allocate CVS entry");
                    278:                return (NULL);
                    279:        }
1.5       jfb       280:        memset(entp, 0, sizeof(*entp));
1.1       jfb       281:
                    282:        entp->ce_rev = rcsnum_alloc();
                    283:        if (entp->ce_rev == NULL) {
                    284:                free(entp);
                    285:                return (NULL);
                    286:        }
                    287:
                    288:        entp->ce_line = strdup(entry);
                    289:        if (entp->ce_line == NULL) {
1.5       jfb       290:                cvs_ent_free(entp);
1.1       jfb       291:                return (NULL);
                    292:        }
                    293:
                    294:        entp->ce_buf = strdup(entry);
                    295:        if (entp->ce_buf == NULL) {
1.5       jfb       296:                cvs_ent_free(entp);
1.1       jfb       297:                return (NULL);
                    298:        }
                    299:        sp = entp->ce_buf;
                    300:
                    301:        if (*sp == CVS_ENTRIES_DELIM)
                    302:                entp->ce_type = CVS_ENT_FILE;
                    303:        else if (*sp == 'D') {
                    304:                entp->ce_type = CVS_ENT_DIR;
                    305:                sp++;
                    306:        }
                    307:        else {
                    308:                /* unknown entry, ignore for future expansion */
                    309:                entp->ce_type = CVS_ENT_NONE;
                    310:                sp++;
                    311:        }
                    312:
                    313:        sp++;
                    314:        i = 0;
                    315:        do {
                    316:                dp = strchr(sp, CVS_ENTRIES_DELIM);
                    317:                if (dp != NULL)
                    318:                        *(dp++) = '\0';
                    319:                fields[i++] = sp;
                    320:                sp = dp;
                    321:        } while ((dp != NULL) && (i < CVS_ENTRIES_NFIELDS));
                    322:
                    323:        entp->ce_name = fields[0];
                    324:
                    325:        if (entp->ce_type == CVS_ENT_FILE) {
                    326:                rcsnum_aton(fields[1], NULL, entp->ce_rev);
                    327:                entp->ce_timestamp = fields[2];
                    328:                entp->ce_opts = fields[3];
                    329:                entp->ce_tag = fields[4];
                    330:        }
                    331:
                    332:        return (entp);
1.5       jfb       333: }
                    334:
                    335:
                    336: /*
                    337:  * cvs_ent_free()
                    338:  *
                    339:  * Free a single CVS entries structure.
                    340:  */
                    341:
                    342: void
                    343: cvs_ent_free(struct cvs_ent *ent)
                    344: {
                    345:        if (ent->ce_rev != NULL)
                    346:                rcsnum_free(ent->ce_rev);
                    347:        if (ent->ce_line != NULL)
                    348:                free(ent->ce_line);
                    349:        if (ent->ce_buf != NULL)
                    350:                free(ent->ce_buf);
                    351:        free(ent);
                    352: }
                    353:
                    354:
                    355: /*
                    356:  * cvs_ent_getent()
                    357:  *
                    358:  * Get a single entry from the CVS/Entries file of the basename portion of
                    359:  * path <path> and return that entry.  That entry must later be freed using
                    360:  * cvs_ent_free().
                    361:  */
                    362:
                    363: struct cvs_ent*
                    364: cvs_ent_getent(const char *path)
                    365: {
                    366:        char base[MAXPATHLEN], file[MAXPATHLEN];
                    367:        CVSENTRIES *entf;
                    368:        struct cvs_ent *ep;
                    369:
                    370:        cvs_splitpath(path, base, sizeof(base), file, sizeof(file));
                    371:
                    372:        entf = cvs_ent_open(base, O_RDONLY);
                    373:        if (entf == NULL)
                    374:                return (NULL);
                    375:
                    376:        ep = cvs_ent_get(entf, file);
                    377:        if (ep != NULL) {
                    378:                /* take it out of the queue so it doesn't get freed */
                    379:                TAILQ_REMOVE(&(entf->cef_ent), ep, ce_list);
                    380:        }
                    381:
                    382:        cvs_ent_close(entf);
                    383:        return (ep);
1.1       jfb       384: }