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

Annotation of src/usr.bin/cvs/proto.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:  * CVS client/server protocol
                     28:  * ==========================
                     29:  *
                     30:  * The following code implements the CVS client/server protocol, which is
                     31:  * documented at the following URL:
                     32:  *     http://www.loria.fr/~molli/cvs/doc/cvsclient_toc.html
                     33:  *
                     34:  * The protocol is split up into two parts; the first part is the client side
                     35:  * of things and is composed of all the response handlers, which are all named
                     36:  * with a prefix of "cvs_resp_".  The second part is the set of request
                     37:  * handlers used by the server.  These handlers process the request and
                     38:  * generate the appropriate response to send back.  The prefix for request
                     39:  * handlers is "cvs_req_".
                     40:  *
                     41:  */
                     42:
                     43: #include <sys/types.h>
                     44: #include <sys/stat.h>
                     45:
                     46: #include <fcntl.h>
                     47: #include <stdio.h>
                     48: #include <errno.h>
                     49: #include <stdlib.h>
                     50: #include <unistd.h>
                     51: #include <signal.h>
                     52: #include <string.h>
                     53: #include <sysexits.h>
                     54: #ifdef CVS_ZLIB
                     55: #include <zlib.h>
                     56: #endif
                     57:
                     58: #include "buf.h"
                     59: #include "cvs.h"
                     60: #include "log.h"
                     61:
                     62:
                     63:
                     64: extern int   verbosity;
                     65: extern int   cvs_compress;
                     66: extern char *cvs_rsh;
                     67: extern int   cvs_trace;
                     68: extern int   cvs_nolog;
                     69: extern int   cvs_readonly;
                     70:
                     71: extern struct cvsroot *cvs_root;
                     72:
                     73:
                     74:
                     75: /*
                     76:  * Local and remote directory used by the `Directory' request.
                     77:  */
                     78: char  cvs_ldir[MAXPATHLEN];
                     79: char  cvs_rdir[MAXPATHLEN];
                     80:
                     81:
                     82:
                     83: char *cvs_fcksum = NULL;
                     84:
                     85: mode_t  cvs_lastmode = 0;
                     86:
                     87:
                     88: static int  cvs_resp_validreq  (int, char *);
                     89: static int  cvs_resp_cksum     (int, char *);
                     90: static int  cvs_resp_m         (int, char *);
                     91: static int  cvs_resp_ok        (int, char *);
                     92: static int  cvs_resp_error     (int, char *);
                     93: static int  cvs_resp_statdir   (int, char *);
                     94: static int  cvs_resp_newentry  (int, char *);
                     95: static int  cvs_resp_updated   (int, char *);
                     96: static int  cvs_resp_removed   (int, char *);
                     97: static int  cvs_resp_mode      (int, char *);
                     98:
                     99:
                    100:
                    101:
                    102: struct cvs_req {
                    103:        int      req_id;
                    104:        char     req_str[32];
                    105:        u_int    req_flags;
                    106:        int    (*req_hdlr)(int, char *);
                    107: } cvs_requests[] = {
                    108:        { CVS_REQ_DIRECTORY,     "Directory",         0,  NULL },
                    109:        { CVS_REQ_MAXDOTDOT,     "Max-dotdot",        0,  NULL },
                    110:        { CVS_REQ_STATICDIR,     "Static-directory",  0,  NULL },
                    111:        { CVS_REQ_STICKY,        "Sticky",            0,  NULL },
                    112:        { CVS_REQ_ENTRY,         "Entry",             0,  NULL },
                    113:        { CVS_REQ_ENTRYEXTRA,    "EntryExtra",        0,  NULL },
                    114:        { CVS_REQ_CHECKINTIME,   "Checkin-time",      0,  NULL },
                    115:        { CVS_REQ_MODIFIED,      "Modified",          0,  NULL },
                    116:        { CVS_REQ_ISMODIFIED,    "Is-modified",       0,  NULL },
                    117:        { CVS_REQ_UNCHANGED,     "Unchanged",         0,  NULL },
                    118:        { CVS_REQ_USEUNCHANGED,  "UseUnchanged",      0,  NULL },
                    119:        { CVS_REQ_NOTIFY,        "Notify",            0,  NULL },
                    120:        { CVS_REQ_NOTIFYUSER,    "NotifyUser",        0,  NULL },
                    121:        { CVS_REQ_QUESTIONABLE,  "Questionable",      0,  NULL },
                    122:        { CVS_REQ_CASE,          "Case",              0,  NULL },
                    123:        { CVS_REQ_UTF8,          "Utf8",              0,  NULL },
                    124:        { CVS_REQ_ARGUMENT,      "Argument",          0,  NULL },
                    125:        { CVS_REQ_ARGUMENTX,     "Argumentx",         0,  NULL },
                    126:        { CVS_REQ_GLOBALOPT,     "Global_option",     0,  NULL },
                    127:        { CVS_REQ_GZIPSTREAM,    "Gzip-stream",       0,  NULL },
                    128:        { CVS_REQ_READCVSRC2,    "read-cvsrc2",       0,  NULL },
                    129:        { CVS_REQ_READWRAP,      "read-cvswrappers",  0,  NULL },
                    130:        { CVS_REQ_READIGNORE,    "read-cvsignore",    0,  NULL },
                    131:        { CVS_REQ_ERRIFREADER,   "Error-If-Reader",   0,  NULL },
                    132:        { CVS_REQ_VALIDRCSOPT,   "Valid-RcsOptions",  0,  NULL },
                    133:        { CVS_REQ_SET,           "Set",               0,  NULL },
                    134:        { CVS_REQ_XPANDMOD,      "expand-modules",    0,  NULL },
                    135:        { CVS_REQ_LOG,           "log",               0,  NULL },
                    136:        { CVS_REQ_CO,            "co",                0,  NULL },
                    137:        { CVS_REQ_EXPORT,        "export",            0,  NULL },
                    138:        { CVS_REQ_RANNOTATE,     "rannotate",         0,  NULL },
                    139:        { CVS_REQ_RDIFF,         "rdiff",             0,  NULL },
                    140:        { CVS_REQ_RLOG,          "rlog",              0,  NULL },
                    141:        { CVS_REQ_RTAG,          "rtag",              0,  NULL },
                    142:        { CVS_REQ_INIT,          "init",              0,  NULL },
                    143:        { CVS_REQ_UPDATE,        "update",            0,  NULL },
                    144:        { CVS_REQ_HISTORY,       "history",           0,  NULL },
                    145:        { CVS_REQ_IMPORT,        "import",            0,  NULL },
                    146:        { CVS_REQ_ADD,           "add",               0,  NULL },
                    147:        { CVS_REQ_REMOVE,        "remove",            0,  NULL },
                    148:        { CVS_REQ_RELEASE,       "release",           0,  NULL },
                    149:        { CVS_REQ_ROOT,          "Root",              0,  NULL },
                    150:        { CVS_REQ_VALIDRESP,     "Valid-responses",   0,  NULL },
                    151:        { CVS_REQ_VALIDREQ,      "valid-requests",    0,  NULL },
                    152:        { CVS_REQ_VERSION,       "version",           0,  NULL },
                    153:        { CVS_REQ_NOOP,          "noop",              0,  NULL },
                    154:        { CVS_REQ_DIFF,          "diff",              0,  NULL },
                    155: };
                    156:
                    157:
                    158: struct cvs_resp {
                    159:        u_int  resp_id;
                    160:        char   resp_str[32];
                    161:        int  (*resp_hdlr)(int, char *);
                    162: } cvs_responses[] = {
                    163:        { CVS_RESP_OK,         "ok",                     cvs_resp_ok       },
                    164:        { CVS_RESP_ERROR,      "error",                  cvs_resp_error    },
                    165:        { CVS_RESP_VALIDREQ,   "Valid-requests",         cvs_resp_validreq },
                    166:        { CVS_RESP_M,          "M",                      cvs_resp_m        },
                    167:        { CVS_RESP_MBINARY,    "Mbinary",                cvs_resp_m        },
                    168:        { CVS_RESP_MT,         "MT",                     cvs_resp_m        },
                    169:        { CVS_RESP_E,          "E",                      cvs_resp_m        },
                    170:        { CVS_RESP_F,          "F",                      cvs_resp_m        },
                    171:        { CVS_RESP_CREATED,    "Created",                cvs_resp_updated  },
                    172:        { CVS_RESP_UPDATED,    "Updated",                cvs_resp_updated  },
                    173:        { CVS_RESP_UPDEXIST,   "Update-existing",        cvs_resp_updated  },
                    174:        { CVS_RESP_REMOVED,    "Removed",                cvs_resp_removed  },
                    175:        { CVS_RESP_MERGED,     "Merged",                 NULL              },
                    176:        { CVS_RESP_CKSUM,      "Checksum",               cvs_resp_cksum    },
                    177:        { CVS_RESP_CLRSTATDIR, "Clear-static-directory", cvs_resp_statdir  },
                    178:        { CVS_RESP_SETSTATDIR, "Set-static-directory",   cvs_resp_statdir  },
                    179:        { CVS_RESP_NEWENTRY,   "New-entry",              cvs_resp_newentry },
                    180:        { CVS_RESP_CHECKEDIN,  "Checked-in",             cvs_resp_newentry },
                    181:        { CVS_RESP_MODE,       "Mode",                   cvs_resp_mode     },
                    182: };
                    183:
                    184:
                    185: #define CVS_NBREQ   (sizeof(cvs_requests)/sizeof(cvs_requests[0]))
                    186: #define CVS_NBRESP  (sizeof(cvs_responses)/sizeof(cvs_responses[0]))
                    187:
                    188: /* mask of requets supported by server */
                    189: static u_char  cvs_server_validreq[CVS_REQ_MAX + 1];
                    190:
                    191:
                    192: /*
                    193:  * cvs_req_getbyid()
                    194:  *
                    195:  */
                    196:
                    197: const char*
                    198: cvs_req_getbyid(int reqid)
                    199: {
                    200:        u_int i;
                    201:
                    202:        for (i = 0; i < CVS_NBREQ; i++)
                    203:                if (cvs_requests[i].req_id == reqid)
                    204:                        return (cvs_requests[i].req_str);
                    205:        return (NULL);
                    206: }
                    207:
                    208:
                    209: /*
                    210:  * cvs_req_getbyname()
                    211:  */
                    212:
                    213: int
                    214: cvs_req_getbyname(const char *rname)
                    215: {
                    216:        u_int i;
                    217:
                    218:        for (i = 0; i < CVS_NBREQ; i++)
                    219:                if (strcmp(cvs_requests[i].req_str, rname) == 0)
                    220:                        return (cvs_requests[i].req_id);
                    221:
                    222:        return (-1);
                    223: }
                    224:
                    225:
                    226: /*
                    227:  * cvs_req_getvalid()
                    228:  *
                    229:  * Build a space-separated list of all the requests that this protocol
                    230:  * implementation supports.
                    231:  */
                    232:
                    233: char*
                    234: cvs_req_getvalid(void)
                    235: {
                    236:        u_int i;
                    237:        size_t len;
                    238:        char *vrstr;
                    239:        BUF *buf;
                    240:
                    241:        buf = cvs_buf_alloc(512, BUF_AUTOEXT);
                    242:        if (buf == NULL)
                    243:                return (NULL);
                    244:
                    245:        cvs_buf_set(buf, cvs_requests[0].req_str,
                    246:            strlen(cvs_requests[0].req_str), 0);
                    247:
                    248:        for (i = 1; i < CVS_NBREQ; i++) {
                    249:                if ((cvs_buf_putc(buf, ' ') < 0) ||
                    250:                    (cvs_buf_append(buf, cvs_requests[i].req_str,
                    251:                    strlen(cvs_requests[i].req_str)) < 0)) {
                    252:                        cvs_buf_free(buf);
                    253:                        return (NULL);
                    254:                }
                    255:        }
                    256:
                    257:        /* NUL-terminate */
                    258:        if (cvs_buf_putc(buf, '\0') < 0) {
                    259:                cvs_buf_free(buf);
                    260:                return (NULL);
                    261:        }
                    262:
                    263:        len = cvs_buf_size(buf);
                    264:        vrstr = (char *)malloc(len);
                    265:
                    266:        cvs_buf_copy(buf, 0, vrstr, len);
                    267:
                    268:        cvs_buf_free(buf);
                    269:
                    270:        return (vrstr);
                    271: }
                    272:
                    273:
                    274: /*
                    275:  * cvs_req_handle()
                    276:  *
                    277:  * Generic request handler dispatcher.
                    278:  */
                    279:
                    280: int
                    281: cvs_req_handle(char *line)
                    282: {
                    283:        return (0);
                    284: }
                    285:
                    286:
                    287: /*
                    288:  * cvs_resp_getbyid()
                    289:  *
                    290:  */
                    291:
                    292: const char*
                    293: cvs_resp_getbyid(int respid)
                    294: {
                    295:        u_int i;
                    296:
                    297:        for (i = 0; i < CVS_NBREQ; i++)
                    298:                if (cvs_responses[i].resp_id == respid)
                    299:                        return (cvs_responses[i].resp_str);
                    300:        return (NULL);
                    301: }
                    302:
                    303:
                    304: /*
                    305:  * cvs_resp_getbyname()
                    306:  */
                    307:
                    308: int
                    309: cvs_resp_getbyname(const char *rname)
                    310: {
                    311:        u_int i;
                    312:
                    313:        for (i = 0; i < CVS_NBREQ; i++)
                    314:                if (strcmp(cvs_responses[i].resp_str, rname) == 0)
                    315:                        return (cvs_responses[i].resp_id);
                    316:
                    317:        return (-1);
                    318: }
                    319:
                    320:
                    321: /*
                    322:  * cvs_resp_getvalid()
                    323:  *
                    324:  * Build a space-separated list of all the responses that this protocol
                    325:  * implementation supports.
                    326:  */
                    327:
                    328: char*
                    329: cvs_resp_getvalid(void)
                    330: {
                    331:        u_int i;
                    332:        size_t len;
                    333:        char *vrstr;
                    334:        BUF *buf;
                    335:
                    336:        buf = cvs_buf_alloc(512, BUF_AUTOEXT);
                    337:        if (buf == NULL)
                    338:                return (NULL);
                    339:
                    340:        cvs_buf_set(buf, cvs_responses[0].resp_str,
                    341:            strlen(cvs_responses[0].resp_str), 0);
                    342:
                    343:        for (i = 1; i < CVS_NBRESP; i++) {
                    344:                if ((cvs_buf_putc(buf, ' ') < 0) ||
                    345:                    (cvs_buf_append(buf, cvs_responses[i].resp_str,
                    346:                    strlen(cvs_responses[i].resp_str)) < 0)) {
                    347:                        cvs_buf_free(buf);
                    348:                        return (NULL);
                    349:                }
                    350:        }
                    351:
                    352:        /* NUL-terminate */
                    353:        if (cvs_buf_putc(buf, '\0') < 0) {
                    354:                cvs_buf_free(buf);
                    355:                return (NULL);
                    356:        }
                    357:
                    358:        len = cvs_buf_size(buf);
                    359:        vrstr = (char *)malloc(len);
                    360:
                    361:        cvs_buf_copy(buf, 0, vrstr, len);
                    362:        cvs_buf_free(buf);
                    363:
                    364:        return (vrstr);
                    365: }
                    366:
                    367:
                    368: /*
                    369:  * cvs_resp_handle()
                    370:  *
                    371:  * Generic response handler dispatcher.  The handler expects the first line
                    372:  * of the command as single argument.
                    373:  * Returns the return value of the command on success, or -1 on failure.
                    374:  */
                    375:
                    376: int
                    377: cvs_resp_handle(char *line)
                    378: {
                    379:        u_int i;
                    380:        size_t len;
                    381:        char *cp, *cmd;
                    382:
                    383:        cmd = line;
                    384:
                    385:        cp = strchr(cmd, ' ');
                    386:        if (cp != NULL)
                    387:                *(cp++) = '\0';
                    388:
                    389:        for (i = 0; i < CVS_NBRESP; i++) {
                    390:                if (strcmp(cvs_responses[i].resp_str, cmd) == 0)
                    391:                        return (*cvs_responses[i].resp_hdlr)
                    392:                            (cvs_responses[i].resp_id, cp);
                    393:        }
                    394:
                    395:        /* unhandled */
                    396:        return (-1);
                    397: }
                    398:
                    399:
                    400: /*
                    401:  * cvs_client_sendinfo()
                    402:  *
                    403:  * Initialize the connection status by first requesting the list of
                    404:  * supported requests from the server.  Then, we send the CVSROOT variable
                    405:  * with the `Root' request.
                    406:  * Returns 0 on success, or -1 on failure.
                    407:  */
                    408:
                    409: static int
                    410: cvs_client_sendinfo(void)
                    411: {
                    412:        /* first things first, get list of valid requests from server */
                    413:        if (cvs_client_sendreq(CVS_REQ_VALIDREQ, NULL, 1) < 0) {
                    414:                cvs_log(LP_ERR, "failed to get valid requests from server");
                    415:                return (-1);
                    416:        }
                    417:
                    418:        /* now share our global options with the server */
                    419:        if (verbosity == 1)
                    420:                cvs_client_sendreq(CVS_REQ_GLOBALOPT, "-q", 0);
                    421:        else if (verbosity == 0)
                    422:                cvs_client_sendreq(CVS_REQ_GLOBALOPT, "-Q", 0);
                    423:
                    424:        if (cvs_nolog)
                    425:                cvs_client_sendreq(CVS_REQ_GLOBALOPT, "-l", 0);
                    426:        if (cvs_readonly)
                    427:                cvs_client_sendreq(CVS_REQ_GLOBALOPT, "-r", 0);
                    428:        if (cvs_trace)
                    429:                cvs_client_sendreq(CVS_REQ_GLOBALOPT, "-t", 0);
                    430:
                    431:        /* now send the CVSROOT to the server */
                    432:        if (cvs_client_sendreq(CVS_REQ_ROOT, cvs_root->cr_dir, 0) < 0)
                    433:                return (-1);
                    434:
                    435:        /* not sure why, but we have to send this */
                    436:        if (cvs_client_sendreq(CVS_REQ_USEUNCHANGED, NULL, 0) < 0)
                    437:                return (-1);
                    438:
                    439:        return (0);
                    440: }
                    441:
                    442:
                    443: /*
                    444:  * cvs_resp_validreq()
                    445:  *
                    446:  * Handler for the `Valid-requests' response.  The list of valid requests is
                    447:  * split on spaces and each request's entry in the valid request array is set
                    448:  * to 1 to indicate the validity.
                    449:  * Returns 0 on success, or -1 on failure.
                    450:  */
                    451:
                    452: static int
                    453: cvs_resp_validreq(int type, char *line)
                    454: {
                    455:        int i;
                    456:        char *sp, *ep;
                    457:
                    458:        /* parse the requests */
                    459:        sp = line;
                    460:        do {
                    461:                ep = strchr(sp, ' ');
                    462:                if (ep != NULL)
                    463:                        *ep = '\0';
                    464:
                    465:                i = cvs_req_getbyname(sp);
                    466:                if (i != -1)
                    467:                        cvs_server_validreq[i] = 1;
                    468:
                    469:                if (ep != NULL)
                    470:                        sp = ep + 1;
                    471:        } while (ep != NULL);
                    472:
                    473:        return (0);
                    474: }
                    475:
                    476:
                    477: /*
                    478:  * cvs_resp_m()
                    479:  *
                    480:  * Handler for the `M', `F' and `E' responses.
                    481:  */
                    482:
                    483: static int
                    484: cvs_resp_m(int type, char *line)
                    485: {
                    486:        FILE *stream;
                    487:
                    488:        stream = NULL;
                    489:
                    490:        switch (type) {
                    491:        case CVS_RESP_F:
                    492:                fflush(stderr);
                    493:                return (0);
                    494:        case CVS_RESP_M:
                    495:                stream = stdout;
                    496:                break;
                    497:        case CVS_RESP_E:
                    498:                stream = stderr;
                    499:                break;
                    500:        case CVS_RESP_MT:
                    501:        case CVS_RESP_MBINARY:
                    502:                cvs_log(LP_WARN, "MT and Mbinary not supported in client yet");
                    503:                break;
                    504:        }
                    505:
                    506:        fputs(line, stream);
                    507:        fputc('\n', stream);
                    508:
                    509:        return (0);
                    510: }
                    511:
                    512:
                    513: /*
                    514:  * cvs_resp_ok()
                    515:  *
                    516:  * Handler for the `ok' response.  This handler's job is to
                    517:  */
                    518:
                    519: static int
                    520: cvs_resp_ok(int type, char *line)
                    521: {
                    522:        return (1);
                    523: }
                    524:
                    525:
                    526: /*
                    527:  * cvs_resp_error()
                    528:  *
                    529:  * Handler for the `error' response.  This handler's job is to
                    530:  */
                    531:
                    532: static int
                    533: cvs_resp_error(int type, char *line)
                    534: {
                    535:        return (1);
                    536: }
                    537:
                    538:
                    539: /*
                    540:  * cvs_resp_statdir()
                    541:  *
                    542:  * Handler for the `Clear-static-directory' and `Set-static-directory'
                    543:  * responses.
                    544:  */
                    545:
                    546: static int
                    547: cvs_resp_statdir(int type, char *line)
                    548: {
                    549:        int fd;
                    550:        char statpath[MAXPATHLEN];
                    551:
                    552:        snprintf(statpath, sizeof(statpath), "%s/%s", line,
                    553:            CVS_PATH_STATICENTRIES);
                    554:
                    555:        if ((type == CVS_RESP_CLRSTATDIR) &&
                    556:            (unlink(statpath) == -1)) {
                    557:                cvs_log(LP_ERRNO, "failed to unlink %s file",
                    558:                    CVS_PATH_STATICENTRIES);
                    559:                return (-1);
                    560:        }
                    561:        else if (type == CVS_RESP_SETSTATDIR) {
                    562:                fd = open(statpath, O_CREAT|O_TRUNC|O_WRONLY, 0400);
                    563:                if (fd == -1) {
                    564:                        cvs_log(LP_ERRNO, "failed to create %s file",
                    565:                            CVS_PATH_STATICENTRIES);
                    566:                        return (-1);
                    567:                }
                    568:                (void)close(fd);
                    569:        }
                    570:
                    571:        return (0);
                    572: }
                    573:
                    574:
                    575: /*
                    576:  * cvs_resp_newentry()
                    577:  *
                    578:  * Handler for the `New-entry' response and `Checked-in' responses.
                    579:  */
                    580:
                    581: static int
                    582: cvs_resp_newentry(int type, char *line)
                    583: {
                    584:        char entbuf[128], path[MAXPATHLEN];
                    585:        struct cvs_ent *entp;
                    586:        CVSENTRIES *entfile;
                    587:
1.2     ! jfb       588:        snprintf(path, sizeof(path), "%s/" CVS_PATH_ENTRIES, line);
1.1       jfb       589:
                    590:        /* get the remote path */
                    591:        cvs_client_getln(entbuf, sizeof(entbuf));
                    592:
                    593:        /* get the new Entries line */
                    594:        if (cvs_client_getln(entbuf, sizeof(entbuf)) < 0)
                    595:                return (-1);
                    596:
                    597:        entp = cvs_ent_parse(entbuf);
                    598:        if (entp == NULL)
                    599:                return (-1);
                    600:
1.2     ! jfb       601:        entfile = cvs_ent_open(path, O_WRONLY);
1.1       jfb       602:        if (entfile == NULL)
                    603:                return (-1);
                    604:
                    605:        cvs_ent_add(entfile, entp);
                    606:
                    607:        cvs_ent_close(entfile);
                    608:
                    609:        return (0);
                    610: }
                    611:
                    612:
                    613: /*
                    614:  * cvs_resp_cksum()
                    615:  *
                    616:  * Handler for the `Checksum' response.  We store the checksum received for
                    617:  * the next file in a dynamically-allocated buffer pointed to by <cvs_fcksum>.
                    618:  * Upon next file reception, the handler checks to see if there is a stored
                    619:  * checksum.
                    620:  * The file handler must make sure that the checksums match and free the
                    621:  * checksum buffer once it's done to indicate there is no further checksum.
                    622:  */
                    623:
                    624: static int
                    625: cvs_resp_cksum(int type, char *line)
                    626: {
                    627:        if (cvs_fcksum != NULL) {
                    628:                cvs_log(LP_WARN, "unused checksum");
                    629:                free(cvs_fcksum);
                    630:        }
                    631:
                    632:        cvs_fcksum = strdup(line);
                    633:        if (cvs_fcksum == NULL) {
                    634:                cvs_log(LP_ERRNO, "failed to copy checksum string");
                    635:                return (-1);
                    636:        }
                    637:
                    638:        return (0);
                    639: }
                    640:
                    641:
                    642: /*
                    643:  * cvs_resp_updated()
                    644:  *
                    645:  * Handler for the `Updated' response.
                    646:  */
                    647:
                    648: static int
                    649: cvs_resp_updated(int type, char *line)
                    650: {
                    651:        char cksum_buf[CVS_CKSUM_LEN];
                    652:
                    653:        if (type == CVS_RESP_CREATED) {
                    654:        }
                    655:        else if (type == CVS_RESP_UPDEXIST) {
                    656:        }
                    657:        else if (type == CVS_RESP_UPDATED) {
                    658:        }
                    659:
                    660:        if (cvs_recvfile(line) < 0) {
                    661:                return (-1);
                    662:        }
                    663:
                    664:        /* now see if there is a checksum */
                    665:        if (cvs_cksum(line, cksum_buf, sizeof(cksum_buf)) < 0) {
                    666:        }
                    667:
                    668:        if (strcmp(cksum_buf, cvs_fcksum) != 0) {
                    669:                cvs_log(LP_ERR, "checksum error on received file");
                    670:                (void)unlink(line);
                    671:        }
                    672:
                    673:        free(cvs_fcksum);
                    674:        cvs_fcksum = NULL;
                    675:
                    676:        return (0);
                    677: }
                    678:
                    679:
                    680: /*
                    681:  * cvs_resp_removed()
                    682:  *
                    683:  * Handler for the `Updated' response.
                    684:  */
                    685:
                    686: static int
                    687: cvs_resp_removed(int type, char *line)
                    688: {
                    689:        return (0);
                    690: }
                    691:
                    692:
                    693: /*
                    694:  * cvs_resp_mode()
                    695:  *
                    696:  * Handler for the `Mode' response.
                    697:  */
                    698:
                    699: static int
                    700: cvs_resp_mode(int type, char *line)
                    701: {
                    702:        if (cvs_strtomode(line, &cvs_lastmode) < 0) {
                    703:                return (-1);
                    704:        }
                    705:        return (0);
                    706: }
                    707:
                    708:
                    709: /*
                    710:  * cvs_sendfile()
                    711:  *
                    712:  * Send the mode and size of a file followed by the file's contents.
                    713:  * Returns 0 on success, or -1 on failure.
                    714:  */
                    715:
                    716: int
                    717: cvs_sendfile(const char *path)
                    718: {
                    719:        int fd;
                    720:        ssize_t ret;
                    721:        char buf[4096];
                    722:        struct stat st;
                    723:
                    724:        if (stat(path, &st) == -1) {
                    725:                cvs_log(LP_ERRNO, "failed to stat `%s'", path);
                    726:                return (-1);
                    727:        }
                    728:
                    729:        fd = open(path, O_RDONLY, 0);
                    730:        if (fd == -1) {
                    731:                return (-1);
                    732:        }
                    733:
                    734:        if (cvs_modetostr(st.st_mode, buf, sizeof(buf)) < 0)
                    735:                return (-1);
                    736:
                    737:        cvs_client_sendln(buf);
                    738:        snprintf(buf, sizeof(buf), "%lld\n", st.st_size);
                    739:        cvs_client_sendln(buf);
                    740:
                    741:        while ((ret = read(fd, buf, sizeof(buf))) != 0) {
                    742:                if (ret == -1) {
                    743:                        cvs_log(LP_ERRNO, "failed to read file `%s'", path);
                    744:                        return (-1);
                    745:                }
                    746:
                    747:                cvs_client_sendraw(buf, (size_t)ret);
                    748:
                    749:        }
                    750:
                    751:        (void)close(fd);
                    752:
                    753:        return (0);
                    754: }
                    755:
                    756:
                    757: /*
                    758:  * cvs_recvfile()
                    759:  *
                    760:  * Receive the mode and size of a file followed the file's contents and
                    761:  * create or update the file whose path is <path> with the received
                    762:  * information.
                    763:  */
                    764:
                    765: int
                    766: cvs_recvfile(const char *path)
                    767: {
                    768:        int fd;
                    769:        mode_t mode;
                    770:        size_t len;
                    771:        ssize_t ret;
                    772:        off_t fsz, cnt;
                    773:        char buf[4096], *ep;
                    774:
                    775:        if ((cvs_client_getln(buf, sizeof(buf)) < 0) ||
                    776:            (cvs_strtomode(buf, &mode) < 0)) {
                    777:                return (-1);
                    778:        }
                    779:
                    780:        cvs_client_getln(buf, sizeof(buf));
                    781:
                    782:        fsz = (off_t)strtol(buf, &ep, 10);
                    783:        if (*ep != '\0') {
                    784:                cvs_log(LP_ERR, "parse error in file size transmission");
                    785:                return (-1);
                    786:        }
                    787:
                    788:        fd = open(path, O_RDONLY, mode);
                    789:        if (fd == -1) {
                    790:                cvs_log(LP_ERRNO, "failed to open `%s'", path);
                    791:                return (-1);
                    792:        }
                    793:
                    794:        cnt = 0;
                    795:        do {
                    796:                len = MIN(sizeof(buf), (size_t)(fsz - cnt));
                    797:                ret = cvs_client_recvraw(buf, len);
                    798:                if (ret == -1) {
                    799:                        (void)close(fd);
                    800:                        (void)unlink(path);
                    801:                        return (-1);
                    802:                }
                    803:
                    804:                if (write(fd, buf, (size_t)ret) == -1) {
                    805:                        cvs_log(LP_ERRNO,
                    806:                            "failed to write contents to file `%s'", path);
                    807:                        (void)close(fd);
                    808:                        (void)unlink(path);
                    809:                        return (-1);
                    810:                }
                    811:
                    812:                cnt += (off_t)ret;
                    813:        } while (cnt < fsz);
                    814:
                    815:        (void)close(fd);
                    816:
                    817:        return (0);
                    818: }