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

Annotation of src/usr.bin/cvs/resp.c, Revision 1.2

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:
                     28: #include <sys/types.h>
                     29: #include <sys/stat.h>
1.2     ! jfb        30: #include <sys/time.h>
1.1       jfb        31:
                     32: #include <fcntl.h>
                     33: #include <stdio.h>
                     34: #include <errno.h>
                     35: #include <dirent.h>
                     36: #include <stdlib.h>
                     37: #include <unistd.h>
                     38: #include <string.h>
                     39: #include <sysexits.h>
                     40:
                     41: #include "buf.h"
                     42: #include "cvs.h"
                     43: #include "log.h"
                     44: #include "file.h"
                     45: #include "proto.h"
                     46:
                     47:
                     48: #define CVS_MTSTK_MAXDEPTH   16
                     49:
                     50:
                     51: static int  cvs_resp_validreq  (struct cvsroot *, int, char *);
                     52: static int  cvs_resp_cksum     (struct cvsroot *, int, char *);
                     53: static int  cvs_resp_modtime   (struct cvsroot *, int, char *);
                     54: static int  cvs_resp_m         (struct cvsroot *, int, char *);
                     55: static int  cvs_resp_ok        (struct cvsroot *, int, char *);
                     56: static int  cvs_resp_error     (struct cvsroot *, int, char *);
                     57: static int  cvs_resp_statdir   (struct cvsroot *, int, char *);
                     58: static int  cvs_resp_sticky    (struct cvsroot *, int, char *);
                     59: static int  cvs_resp_newentry  (struct cvsroot *, int, char *);
                     60: static int  cvs_resp_updated   (struct cvsroot *, int, char *);
                     61: static int  cvs_resp_removed   (struct cvsroot *, int, char *);
                     62: static int  cvs_resp_mode      (struct cvsroot *, int, char *);
                     63: static int  cvs_resp_modxpand  (struct cvsroot *, int, char *);
                     64: static int  cvs_resp_rcsdiff   (struct cvsroot *, int, char *);
                     65: static int  cvs_resp_template  (struct cvsroot *, int, char *);
                     66:
                     67: static const char *cvs_months[] = {
                     68:        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     69:        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                     70: };
                     71:
                     72:
                     73:
                     74: struct cvs_resphdlr {
                     75:        int (*hdlr)(struct cvsroot *, int, char *);
                     76: } cvs_resp_swtab[CVS_RESP_MAX + 1] = {
                     77:        { NULL              },
                     78:        { cvs_resp_ok       },
                     79:        { cvs_resp_error    },
                     80:        { cvs_resp_validreq },
                     81:        { cvs_resp_newentry },
                     82:        { cvs_resp_newentry },
                     83:        { cvs_resp_cksum    },
                     84:        { NULL              },
                     85:        { cvs_resp_updated  },
                     86:        { cvs_resp_updated  },
                     87:        { cvs_resp_updated  },  /* 10 */
                     88:        { cvs_resp_updated  },
                     89:        { cvs_resp_updated  },
                     90:        { cvs_resp_rcsdiff  },
                     91:        { cvs_resp_mode     },
                     92:        { cvs_resp_modtime  },
                     93:        { cvs_resp_removed  },
                     94:        { cvs_resp_removed  },
                     95:        { cvs_resp_statdir  },
                     96:        { cvs_resp_statdir  },
                     97:        { cvs_resp_sticky   },  /* 20 */
                     98:        { cvs_resp_sticky   },
                     99:        { cvs_resp_template },
                    100:        { NULL              },
                    101:        { NULL              },
                    102:        { NULL              },
                    103:        { cvs_resp_modxpand },
                    104:        { NULL              },
                    105:        { cvs_resp_m        },
                    106:        { cvs_resp_m        },
                    107:        { cvs_resp_m        },  /* 30 */
                    108:        { cvs_resp_m        },
                    109:        { cvs_resp_m        },
                    110: };
                    111:
                    112:
                    113:
                    114: /*
                    115:  * The MT command uses scoping to tag the data.  Whenever we encouter a '+',
                    116:  * we push the name of the tag on the stack, and we pop it when we encounter
                    117:  * a '-' with the same name.
                    118:  */
                    119:
                    120: static char *cvs_mt_stack[CVS_MTSTK_MAXDEPTH];
                    121: static u_int cvs_mtstk_depth = 0;
                    122:
                    123: static time_t cvs_modtime = 0;
                    124:
                    125:
                    126: /* last checksum received */
                    127: char *cvs_fcksum = NULL;
                    128:
                    129: mode_t  cvs_lastmode = 0;
                    130:
                    131: /* hack to receive the remote version without outputting it */
                    132: extern u_int cvs_version_sent;
                    133:
                    134:
                    135: /*
                    136:  * cvs_resp_handle()
                    137:  *
                    138:  * Generic response handler dispatcher.  The handler expects the first line
                    139:  * of the command as single argument.
                    140:  * Returns the return value of the command on success, or -1 on failure.
                    141:  */
                    142:
                    143: int
                    144: cvs_resp_handle(struct cvsroot *root, char *line)
                    145: {
                    146:        char *cp, *cmd;
                    147:        struct cvs_resp *resp;
                    148:
                    149:        cmd = line;
                    150:
                    151:        cp = strchr(cmd, ' ');
                    152:        if (cp != NULL)
                    153:                *(cp++) = '\0';
                    154:
                    155:        resp = cvs_resp_getbyname(cmd);
                    156:        if (resp == NULL) {
                    157:                return (-1);
                    158:        }
                    159:        else if (cvs_resp_swtab[resp->resp_id].hdlr == NULL) {
                    160:                cvs_log(LP_ERRNO, "handler for `%s' not implemented", cmd);
                    161:                return (-1);
                    162:        }
                    163:
                    164:        return (*cvs_resp_swtab[resp->resp_id].hdlr)(root, resp->resp_id, cp);
                    165: }
                    166:
                    167:
                    168: /*
                    169:  * cvs_resp_validreq()
                    170:  *
                    171:  * Handler for the `Valid-requests' response.  The list of valid requests is
                    172:  * split on spaces and each request's entry in the valid request array is set
                    173:  * to 1 to indicate the validity.
                    174:  * Returns 0 on success, or -1 on failure.
                    175:  */
                    176:
                    177: static int
                    178: cvs_resp_validreq(struct cvsroot *root, int type, char *line)
                    179: {
                    180:        char *sp, *ep;
                    181:        struct cvs_req *req;
                    182:
                    183:        /* parse the requests */
                    184:        sp = line;
                    185:        do {
                    186:                ep = strchr(sp, ' ');
                    187:                if (ep != NULL)
                    188:                        *ep = '\0';
                    189:
                    190:                req = cvs_req_getbyname(sp);
                    191:                if (req != NULL)
                    192:                        CVS_SETVR(root, req->req_id);
                    193:
                    194:                if (ep != NULL)
                    195:                        sp = ep + 1;
                    196:        } while (ep != NULL);
                    197:
                    198:        return (0);
                    199: }
                    200:
                    201:
                    202: /*
                    203:  * cvs_resp_m()
                    204:  *
                    205:  * Handler for the `M', 'MT', `F' and `E' responses.
                    206:  */
                    207:
                    208: static int
                    209: cvs_resp_m(struct cvsroot *root, int type, char *line)
                    210: {
                    211:        char *cp;
                    212:        FILE *stream;
                    213:
                    214:        stream = NULL;
                    215:
                    216:        switch (type) {
                    217:        case CVS_RESP_F:
                    218:                fflush(stderr);
                    219:                return (0);
                    220:        case CVS_RESP_M:
                    221:                if (cvs_version_sent) {
                    222:                        /*
                    223:                         * Instead of outputting the line, we save it as the
                    224:                         * remote server's version string.
                    225:                         */
                    226:                        cvs_version_sent = 0;
                    227:                        root->cr_version = strdup(line);
                    228:                        return (0);
                    229:                }
                    230:                stream = stdout;
                    231:                break;
                    232:        case CVS_RESP_E:
                    233:                stream = stderr;
                    234:                break;
                    235:        case CVS_RESP_MT:
                    236:                if (*line == '+') {
                    237:                        if (cvs_mtstk_depth == CVS_MTSTK_MAXDEPTH) {
                    238:                                cvs_log(LP_ERR,
                    239:                                    "MT scope stack has reached max depth");
                    240:                                return (-1);
                    241:                        }
                    242:                        cvs_mt_stack[cvs_mtstk_depth] = strdup(line + 1);
                    243:                        if (cvs_mt_stack[cvs_mtstk_depth] == NULL)
                    244:                                return (-1);
                    245:                        cvs_mtstk_depth++;
                    246:                }
                    247:                else if (*line == '-') {
                    248:                        if (cvs_mtstk_depth == 0) {
                    249:                                cvs_log(LP_ERR, "MT scope stack underflow");
                    250:                                return (-1);
                    251:                        }
                    252:                        else if (strcmp(line + 1,
                    253:                            cvs_mt_stack[cvs_mtstk_depth - 1]) != 0) {
                    254:                                cvs_log(LP_ERR, "mismatch in MT scope stack");
                    255:                                return (-1);
                    256:                        }
                    257:                        free(cvs_mt_stack[cvs_mtstk_depth--]);
                    258:                }
                    259:                else {
                    260:                        if (strcmp(line, "newline") == 0)
                    261:                                putc('\n', stdout);
                    262:                        else if (strncmp(line, "fname ", 6) == 0)
                    263:                                printf("%s", line + 6);
                    264:                        else {
                    265:                                /* assume text */
                    266:                                cp = strchr(line, ' ');
                    267:                                if (cp != NULL)
                    268:                                        printf("%s", cp + 1);
                    269:                        }
                    270:                }
                    271:
                    272:                return (0);
                    273:        case CVS_RESP_MBINARY:
                    274:                cvs_log(LP_WARN, "Mbinary not supported in client yet");
                    275:                break;
                    276:        }
                    277:
                    278:        fputs(line, stream);
                    279:        fputc('\n', stream);
                    280:
                    281:        return (0);
                    282: }
                    283:
                    284:
                    285: /*
                    286:  * cvs_resp_ok()
                    287:  *
                    288:  * Handler for the `ok' response.  This handler's job is to
                    289:  */
                    290:
                    291: static int
                    292: cvs_resp_ok(struct cvsroot *root, int type, char *line)
                    293: {
                    294:        return (1);
                    295: }
                    296:
                    297:
                    298: /*
                    299:  * cvs_resp_error()
                    300:  *
                    301:  * Handler for the `error' response.  This handler's job is to
                    302:  */
                    303:
                    304: static int
                    305: cvs_resp_error(struct cvsroot *root, int type, char *line)
                    306: {
                    307:        return (1);
                    308: }
                    309:
                    310:
                    311: /*
                    312:  * cvs_resp_statdir()
                    313:  *
                    314:  * Handler for the `Clear-static-directory' and `Set-static-directory'
                    315:  * responses.
                    316:  */
                    317:
                    318: static int
                    319: cvs_resp_statdir(struct cvsroot *root, int type, char *line)
                    320: {
                    321:        int fd;
                    322:        char rpath[MAXPATHLEN], statpath[MAXPATHLEN];
                    323:
                    324:        cvs_getln(root, rpath, sizeof(rpath));
                    325:
                    326:        snprintf(statpath, sizeof(statpath), "%s/%s", line,
                    327:            CVS_PATH_STATICENTRIES);
                    328:
                    329:        if ((type == CVS_RESP_CLRSTATDIR) &&
                    330:            (unlink(statpath) == -1) && (errno != ENOENT)) {
                    331:                cvs_log(LP_ERRNO, "failed to unlink %s file",
                    332:                    CVS_PATH_STATICENTRIES);
                    333:                return (-1);
                    334:        }
                    335:        else if (type == CVS_RESP_SETSTATDIR) {
                    336:                fd = open(statpath, O_CREAT|O_TRUNC|O_WRONLY, 0400);
                    337:                if (fd == -1) {
                    338:                        cvs_log(LP_ERRNO, "failed to create %s file",
                    339:                            CVS_PATH_STATICENTRIES);
                    340:                        return (-1);
                    341:                }
                    342:                (void)close(fd);
                    343:
                    344:        }
                    345:
                    346:        return (0);
                    347: }
                    348:
                    349: /*
                    350:  * cvs_resp_sticky()
                    351:  *
                    352:  * Handler for the `Clear-sticky' and `Set-sticky' responses.
                    353:  */
                    354:
                    355: static int
                    356: cvs_resp_sticky(struct cvsroot *root, int type, char *line)
                    357: {
                    358:        size_t len;
                    359:        char rpath[MAXPATHLEN];
                    360:        struct stat st;
                    361:        CVSFILE *cf;
                    362:
                    363:        /* remove trailing slash */
                    364:        len = strlen(line);
                    365:        if ((len > 0) && (line[len - 1] == '/'))
                    366:                line[--len] = '\0';
                    367:
                    368:        /* get the remote path */
                    369:        cvs_getln(root, rpath, sizeof(rpath));
                    370:
                    371:        /* if the directory doesn't exist, create it */
                    372:        if (stat(line, &st) == -1) {
                    373:                /* attempt to create it */
                    374:                if (errno != ENOENT) {
                    375:                        cvs_log(LP_ERRNO, "failed to stat %s", line);
                    376:                }
                    377:                else {
                    378:                        cf = cvs_file_create(line, DT_DIR, 0755);
                    379:                        if (cf == NULL)
                    380:                                return (-1);
                    381:                        cf->cf_ddat->cd_repo = strdup(line);
                    382:                        cf->cf_ddat->cd_root = root;
                    383:                        root->cr_ref++;
                    384:                        cvs_mkadmin(cf, 0755);
                    385:
                    386:                        cvs_file_free(cf);
                    387:                }
                    388:        }
                    389:
                    390:        if (type == CVS_RESP_CLRSTICKY) {
                    391:        }
                    392:        else if (type == CVS_RESP_SETSTICKY) {
                    393:        }
                    394:
                    395:        return (0);
                    396: }
                    397:
                    398:
                    399: /*
                    400:  * cvs_resp_newentry()
                    401:  *
                    402:  * Handler for the `New-entry' response and `Checked-in' responses.
                    403:  */
                    404:
                    405: static int
                    406: cvs_resp_newentry(struct cvsroot *root, int type, char *line)
                    407: {
                    408:        char entbuf[128];
                    409:        CVSENTRIES *entfile;
                    410:
                    411:        /* get the remote path */
                    412:        cvs_getln(root, entbuf, sizeof(entbuf));
                    413:
                    414:        /* get the new Entries line */
                    415:        if (cvs_getln(root, entbuf, sizeof(entbuf)) < 0)
                    416:                return (-1);
                    417:
                    418:        entfile = cvs_ent_open(line, O_WRONLY);
                    419:        if (entfile == NULL)
                    420:                return (-1);
                    421:        cvs_ent_addln(entfile, entbuf);
                    422:        cvs_ent_close(entfile);
                    423:
                    424:        return (0);
                    425: }
                    426:
                    427:
                    428: /*
                    429:  * cvs_resp_cksum()
                    430:  *
                    431:  * Handler for the `Checksum' response.  We store the checksum received for
                    432:  * the next file in a dynamically-allocated buffer pointed to by <cvs_fcksum>.
                    433:  * Upon next file reception, the handler checks to see if there is a stored
                    434:  * checksum.
                    435:  * The file handler must make sure that the checksums match and free the
                    436:  * checksum buffer once it's done to indicate there is no further checksum.
                    437:  */
                    438:
                    439: static int
                    440: cvs_resp_cksum(struct cvsroot *root, int type, char *line)
                    441: {
                    442:        if (cvs_fcksum != NULL) {
                    443:                cvs_log(LP_WARN, "unused checksum");
                    444:                free(cvs_fcksum);
                    445:        }
                    446:
                    447:        cvs_fcksum = strdup(line);
                    448:        if (cvs_fcksum == NULL) {
                    449:                cvs_log(LP_ERRNO, "failed to copy checksum string");
                    450:                return (-1);
                    451:        }
                    452:
                    453:        return (0);
                    454: }
                    455:
                    456:
                    457: /*
                    458:  * cvs_resp_modtime()
                    459:  *
                    460:  * Handler for the `Mod-time' file update modifying response.  The timestamp
                    461:  * given is used to set the last modification time on the next file that
                    462:  * will be received.
                    463:  */
                    464:
                    465: static int
                    466: cvs_resp_modtime(struct cvsroot *root, int type, char *line)
                    467: {
                    468:        int i;
                    469:        long off;
                    470:        char sign, mon[8], gmt[8], hr[4], min[4], *ep;
                    471:        struct tm cvs_tm;
                    472:
                    473:        memset(&cvs_tm, 0, sizeof(cvs_tm));
                    474:        sscanf(line, "%d %3s %d %2d:%2d:%2d %5s", &cvs_tm.tm_mday, mon,
                    475:            &cvs_tm.tm_year, &cvs_tm.tm_hour, &cvs_tm.tm_min,
                    476:            &cvs_tm.tm_sec, gmt);
                    477:        cvs_tm.tm_year -= 1900;
                    478:        cvs_tm.tm_isdst = -1;
                    479:
                    480:        if (*gmt == '-') {
                    481:                sscanf(gmt, "%c%2s%2s", &sign, hr, min);
                    482:                cvs_tm.tm_gmtoff = strtol(hr, &ep, 10);
                    483:                if ((cvs_tm.tm_gmtoff == LONG_MIN) ||
                    484:                    (cvs_tm.tm_gmtoff == LONG_MAX) ||
                    485:                    (*ep != '\0')) {
                    486:                        cvs_log(LP_ERR,
                    487:                            "parse error in GMT hours specification `%s'", hr);
                    488:                        cvs_tm.tm_gmtoff = 0;
                    489:                }
                    490:                else {
                    491:                        /* get seconds */
                    492:                        cvs_tm.tm_gmtoff *= 3600;
                    493:
                    494:                        /* add the minutes */
                    495:                        off = strtol(min, &ep, 10);
                    496:                        if ((cvs_tm.tm_gmtoff == LONG_MIN) ||
                    497:                            (cvs_tm.tm_gmtoff == LONG_MAX) ||
                    498:                            (*ep != '\0')) {
                    499:                                cvs_log(LP_ERR,
                    500:                                    "parse error in GMT minutes "
                    501:                                    "specification `%s'", min);
                    502:                        }
                    503:                        else
                    504:                                cvs_tm.tm_gmtoff += off * 60;
                    505:                }
                    506:        }
                    507:        if (sign == '-')
                    508:                cvs_tm.tm_gmtoff = -cvs_tm.tm_gmtoff;
                    509:
                    510:        for (i = 0; i < (int)(sizeof(cvs_months)/sizeof(cvs_months[0])); i++) {
                    511:                if (strcmp(cvs_months[i], mon) == 0) {
                    512:                        cvs_tm.tm_mon = i;
                    513:                        break;
                    514:                }
                    515:        }
                    516:
                    517:        cvs_modtime = mktime(&cvs_tm);
                    518:        return (0);
                    519: }
                    520:
                    521:
                    522: /*
                    523:  * cvs_resp_updated()
                    524:  *
                    525:  * Handler for the `Updated' and `Created' responses.
                    526:  */
                    527:
                    528: static int
                    529: cvs_resp_updated(struct cvsroot *root, int type, char *line)
                    530: {
                    531:        size_t len;
                    532:        mode_t fmode;
                    533:        char tbuf[32], path[MAXPATHLEN], cksum_buf[CVS_CKSUM_LEN];
                    534:        BUF *fbuf;
                    535:        CVSENTRIES *ef;
                    536:        struct cvs_ent *ep;
1.2     ! jfb       537:        struct timeval tv[2];
1.1       jfb       538:
                    539:        ep = NULL;
                    540:
                    541:        /* read the remote path of the file */
                    542:        cvs_getln(root, path, sizeof(path));
                    543:
                    544:        /* read the new entry */
                    545:        cvs_getln(root, path, sizeof(path));
                    546:        ep = cvs_ent_parse(path);
                    547:        if (ep == NULL)
                    548:                return (-1);
                    549:        snprintf(path, sizeof(path), "%s%s", line, ep->ce_name);
                    550:
                    551:        if (type == CVS_RESP_CREATED) {
                    552:                /* set the timestamp as the last one received from Mod-time */
                    553:                ep->ce_timestamp = ctime_r(&cvs_modtime, tbuf);
                    554:                len = strlen(tbuf);
                    555:                if ((len > 0) && (tbuf[len - 1] == '\n'))
                    556:                        tbuf[--len] = '\0';
                    557:
                    558:                ef = cvs_ent_open(line, O_WRONLY);
                    559:                if (ef == NULL)
                    560:                        return (-1);
                    561:
                    562:                cvs_ent_add(ef, ep);
                    563:                cvs_ent_close(ef);
                    564:        }
                    565:        else if (type == CVS_RESP_UPDEXIST) {
                    566:        }
                    567:        else if (type == CVS_RESP_UPDATED) {
                    568:        }
                    569:
                    570:        fbuf = cvs_recvfile(root, &fmode);
                    571:        if (fbuf == NULL)
                    572:                return (-1);
                    573:
                    574:        cvs_buf_write(fbuf, path, fmode);
1.2     ! jfb       575:
        !           576:        tv[0].tv_sec = (long)cvs_modtime;
        !           577:        tv[0].tv_usec = 0;
        !           578:        tv[1].tv_sec = (long)cvs_modtime;
        !           579:        tv[1].tv_usec = 0;
        !           580:        if (utimes(path, tv) == -1)
        !           581:                cvs_log(LP_ERRNO, "failed to set file timestamps");
1.1       jfb       582:
                    583:        /* now see if there is a checksum */
                    584:        if (cvs_fcksum != NULL) {
                    585:                if (cvs_cksum(path, cksum_buf, sizeof(cksum_buf)) < 0) {
                    586:                }
                    587:
                    588:                if (strcmp(cksum_buf, cvs_fcksum) != 0) {
                    589:                        cvs_log(LP_ERR, "checksum error on received file");
                    590:                        (void)unlink(line);
                    591:                }
                    592:
                    593:                free(cvs_fcksum);
                    594:                cvs_fcksum = NULL;
                    595:        }
                    596:
                    597:        return (0);
                    598: }
                    599:
                    600:
                    601: /*
                    602:  * cvs_resp_removed()
                    603:  *
                    604:  * Handler for the `Removed' and `Remove-entry' responses.
                    605:  */
                    606:
                    607: static int
                    608: cvs_resp_removed(struct cvsroot *root, int type, char *line)
                    609: {
                    610:        char base[MAXPATHLEN], file[MAXNAMLEN];
                    611:        CVSENTRIES *ef;
                    612:
                    613:        cvs_splitpath(line, base, sizeof(base), file, sizeof(file));
                    614:
                    615:        ef = cvs_ent_open(base, O_RDWR);
                    616:        if (ef == NULL)
                    617:                return (-1);
                    618:
                    619:        printf("Received a `Remove' on %s\n", line);
                    620:        cvs_ent_remove(ef, file);
                    621:        cvs_ent_close(ef);
                    622:
                    623:        return (0);
                    624: }
                    625:
                    626:
                    627: /*
                    628:  * cvs_resp_mode()
                    629:  *
                    630:  * Handler for the `Mode' response.
                    631:  */
                    632:
                    633: static int
                    634: cvs_resp_mode(struct cvsroot *root, int type, char *line)
                    635: {
                    636:        if (cvs_strtomode(line, &cvs_lastmode) < 0) {
                    637:                return (-1);
                    638:        }
                    639:        return (0);
                    640: }
                    641:
                    642:
                    643: /*
                    644:  * cvs_resp_modxpand()
                    645:  *
                    646:  * Handler for the `Module-expansion' response.
                    647:  */
                    648:
                    649: static int
                    650: cvs_resp_modxpand(struct cvsroot *root, int type, char *line)
                    651: {
                    652:        return (0);
                    653: }
                    654:
                    655: /*
                    656:  * cvs_resp_rcsdiff()
                    657:  *
                    658:  * Handler for the `Rcs-diff' response.
                    659:  */
                    660:
                    661: static int
                    662: cvs_resp_rcsdiff(struct cvsroot *root, int type, char *line)
                    663: {
                    664:        char file[MAXPATHLEN], buf[MAXPATHLEN], cksum_buf[CVS_CKSUM_LEN];
                    665:        char *fname, *orig, *patch;
                    666:        mode_t fmode;
                    667:        BUF *res, *fcont, *patchbuf;
                    668:        CVSENTRIES *entf;
                    669:        struct cvs_ent *ent;
                    670:
                    671:        /* get remote path and build local path of file to be patched */
                    672:        cvs_getln(root, buf, sizeof(buf));
                    673:        fname = strrchr(buf, '/');
                    674:        if (fname == NULL)
                    675:                fname = buf;
                    676:        snprintf(file, sizeof(file), "%s%s", line, fname);
                    677:
                    678:        /* get updated entry fields */
                    679:        cvs_getln(root, buf, sizeof(buf));
                    680:        ent = cvs_ent_parse(buf);
                    681:        if (ent == NULL) {
                    682:                return (-1);
                    683:        }
                    684:
                    685:        patchbuf = cvs_recvfile(root, &fmode);
                    686:        fcont = cvs_buf_load(file, BUF_AUTOEXT);
                    687:        if (fcont == NULL)
                    688:                return (-1);
                    689:
                    690:        cvs_buf_putc(patchbuf, '\0');
                    691:        cvs_buf_putc(fcont, '\0');
                    692:        orig = cvs_buf_release(fcont);
                    693:        patch = cvs_buf_release(patchbuf);
                    694:
                    695:        res = rcs_patch(orig, patch);
                    696:        if (res == NULL)
                    697:                return (-1);
                    698:
                    699:        cvs_buf_write(res, file, fmode);
                    700:
                    701:        /* now see if there is a checksum */
                    702:        if (cvs_fcksum != NULL) {
                    703:                if (cvs_cksum(file, cksum_buf, sizeof(cksum_buf)) < 0) {
                    704:                }
                    705:
                    706:                if (strcmp(cksum_buf, cvs_fcksum) != 0) {
                    707:                        cvs_log(LP_ERR, "checksum error on received file");
                    708:                        (void)unlink(file);
                    709:                }
                    710:
                    711:                free(cvs_fcksum);
                    712:                cvs_fcksum = NULL;
                    713:        }
                    714:
                    715:        /* update revision in entries */
                    716:        entf = cvs_ent_open(line, O_WRONLY);
                    717:        if (entf == NULL)
                    718:                return (-1);
                    719:
                    720:        cvs_ent_close(entf);
                    721:
                    722:        return (0);
                    723: }
                    724:
                    725:
                    726: /*
                    727:  * cvs_resp_template()
                    728:  *
                    729:  * Handler for the `Template' response.
                    730:  */
                    731:
                    732: static int
                    733: cvs_resp_template(struct cvsroot *root, int type, char *line)
                    734: {
                    735:        mode_t mode;
                    736:        BUF *tmpl;
                    737:
                    738:        tmpl = cvs_recvfile(root, &mode);
                    739:        if (tmpl == NULL)
                    740:                return (-1);
                    741:
                    742:        return (0);
                    743: }