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

Annotation of src/usr.bin/cvs/util.c, Revision 1.34

1.34    ! joris       1: /*     $OpenBSD: util.c,v 1.33 2005/06/14 03:56:14 pat Exp $   */
1.1       jfb         2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.9       jfb         4:  * All rights reserved.
1.1       jfb         5:  *
1.9       jfb         6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
1.1       jfb         9:  *
1.9       jfb        10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
1.1       jfb        12:  * 2. The name of the author may not be used to endorse or promote products
1.9       jfb        13:  *    derived from this software without specific prior written permission.
1.1       jfb        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
1.9       jfb        24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       jfb        25:  */
                     26:
                     27: #include <sys/types.h>
                     28: #include <sys/stat.h>
1.12      krapht     29: #include <sys/wait.h>
1.1       jfb        30:
                     31: #include <errno.h>
1.2       jfb        32: #include <fcntl.h>
1.31      xsa        33: #include <md5.h>
1.1       jfb        34: #include <stdio.h>
                     35: #include <stdlib.h>
1.31      xsa        36: #include <string.h>
1.1       jfb        37: #include <unistd.h>
                     38:
                     39: #include "cvs.h"
                     40: #include "log.h"
                     41:
                     42: /* letter -> mode type map */
                     43: static const int cvs_modetypes[26] = {
                     44:        -1, -1, -1, -1, -1, -1,  1, -1, -1, -1, -1, -1, -1,
                     45:        -1,  2, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1,
                     46: };
                     47:
                     48: /* letter -> mode map */
                     49: static const mode_t cvs_modes[3][26] = {
                     50:        {
                     51:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     52:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     53:                0,  0,       0,       S_IRUSR, 0,  0,  0,    /* n - u */
                     54:                0,  S_IWUSR, S_IXUSR, 0,       0             /* v - z */
                     55:        },
                     56:        {
                     57:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     58:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     59:                0,  0,       0,       S_IRGRP, 0,  0,  0,    /* n - u */
                     60:                0,  S_IWGRP, S_IXGRP, 0,       0             /* v - z */
                     61:        },
                     62:        {
                     63:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     64:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     65:                0,  0,       0,       S_IROTH, 0,  0,  0,    /* n - u */
                     66:                0,  S_IWOTH, S_IXOTH, 0,       0             /* v - z */
                     67:        }
                     68: };
                     69:
                     70:
                     71: /* octal -> string */
                     72: static const char *cvs_modestr[8] = {
                     73:        "", "x", "w", "wx", "r", "rx", "rw", "rwx"
                     74: };
                     75:
                     76:
1.11      krapht     77: pid_t cvs_exec_pid;
                     78:
1.1       jfb        79:
                     80: /*
                     81:  * cvs_readrepo()
                     82:  *
                     83:  * Read the path stored in the `Repository' CVS file for a given directory
                     84:  * <dir>, and store that path into the buffer pointed to by <dst>, whose size
                     85:  * is <len>.
                     86:  */
                     87: int
                     88: cvs_readrepo(const char *dir, char *dst, size_t len)
                     89: {
1.21      xsa        90:        int l;
1.1       jfb        91:        size_t dlen;
                     92:        FILE *fp;
                     93:        char repo_path[MAXPATHLEN];
                     94:
1.21      xsa        95:        l = snprintf(repo_path, sizeof(repo_path), "%s/CVS/Repository", dir);
                     96:        if (l == -1 || l >= (int)sizeof(repo_path)) {
                     97:                errno = ENAMETOOLONG;
                     98:                cvs_log(LP_ERRNO, "%s", repo_path);
                     99:                return (NULL);
                    100:         }
                    101:
1.1       jfb       102:        fp = fopen(repo_path, "r");
1.21      xsa       103:        if (fp == NULL)
1.1       jfb       104:                return (-1);
                    105:
                    106:        if (fgets(dst, (int)len, fp) == NULL) {
                    107:                if (ferror(fp)) {
                    108:                        cvs_log(LP_ERRNO, "failed to read from `%s'",
                    109:                            repo_path);
                    110:                }
                    111:                (void)fclose(fp);
                    112:                return (-1);
                    113:        }
                    114:        dlen = strlen(dst);
                    115:        if ((dlen > 0) && (dst[dlen - 1] == '\n'))
                    116:                dst[--dlen] = '\0';
                    117:
                    118:        (void)fclose(fp);
                    119:        return (0);
1.9       jfb       120: }
                    121:
                    122:
                    123: /*
1.1       jfb       124:  * cvs_strtomode()
                    125:  *
                    126:  * Read the contents of the string <str> and generate a permission mode from
                    127:  * the contents of <str>, which is assumed to have the mode format of CVS.
                    128:  * The CVS protocol specification states that any modes or mode types that are
                    129:  * not recognized should be silently ignored.  This function does not return
                    130:  * an error in such cases, but will issue warnings.
                    131:  * Returns 0 on success, or -1 on failure.
                    132:  */
                    133: int
                    134: cvs_strtomode(const char *str, mode_t *mode)
                    135: {
1.2       jfb       136:        char type;
1.1       jfb       137:        mode_t m;
                    138:        char buf[32], ms[4], *sp, *ep;
                    139:
                    140:        m = 0;
1.30      jfb       141:        if (strlcpy(buf, str, sizeof(buf)) >= sizeof(buf)) {
                    142:                return (-1);
                    143:        }
1.1       jfb       144:        sp = buf;
                    145:        ep = sp;
                    146:
                    147:        for (sp = buf; ep != NULL; sp = ep + 1) {
                    148:                ep = strchr(sp, ',');
                    149:                if (ep != NULL)
1.2       jfb       150:                        *ep = '\0';
1.1       jfb       151:
1.14      weingart  152:                memset(ms, 0, sizeof ms);
                    153:                if (sscanf(sp, "%c=%3s", &type, ms) != 2 &&
                    154:                        sscanf(sp, "%c=", &type) != 1) {
1.1       jfb       155:                        cvs_log(LP_WARN, "failed to scan mode string `%s'", sp);
                    156:                        continue;
                    157:                }
                    158:
                    159:                if ((type <= 'a') || (type >= 'z') ||
                    160:                    (cvs_modetypes[type - 'a'] == -1)) {
                    161:                        cvs_log(LP_WARN,
                    162:                            "invalid mode type `%c'"
                    163:                            " (`u', `g' or `o' expected), ignoring", type);
                    164:                        continue;
                    165:                }
                    166:
                    167:                /* make type contain the actual mode index */
                    168:                type = cvs_modetypes[type - 'a'];
                    169:
                    170:                for (sp = ms; *sp != '\0'; sp++) {
                    171:                        if ((*sp <= 'a') || (*sp >= 'z') ||
1.5       jfb       172:                            (cvs_modes[(int)type][*sp - 'a'] == 0)) {
1.1       jfb       173:                                cvs_log(LP_WARN,
                    174:                                    "invalid permission bit `%c'", *sp);
1.15      deraadt   175:                        } else
1.5       jfb       176:                                m |= cvs_modes[(int)type][*sp - 'a'];
1.1       jfb       177:                }
                    178:        }
                    179:
                    180:        *mode = m;
                    181:
                    182:        return (0);
                    183: }
                    184:
                    185:
                    186: /*
                    187:  * cvs_modetostr()
                    188:  *
1.30      jfb       189:  * Generate a CVS-format string to represent the permissions mask on a file
                    190:  * from the mode <mode> and store the result in <buf>, which can accept up to
                    191:  * <len> bytes (including the terminating NUL byte).  The result is guaranteed
                    192:  * to be NUL-terminated.
1.1       jfb       193:  * Returns 0 on success, or -1 on failure.
                    194:  */
                    195: int
                    196: cvs_modetostr(mode_t mode, char *buf, size_t len)
                    197: {
                    198:        size_t l;
                    199:        char tmp[16], *bp;
                    200:        mode_t um, gm, om;
                    201:
                    202:        um = (mode & S_IRWXU) >> 6;
                    203:        gm = (mode & S_IRWXG) >> 3;
                    204:        om = mode & S_IRWXO;
                    205:
                    206:        bp = buf;
                    207:        *bp = '\0';
                    208:        l = 0;
                    209:
                    210:        if (um) {
                    211:                snprintf(tmp, sizeof(tmp), "u=%s", cvs_modestr[um]);
1.9       jfb       212:                l = strlcat(buf, tmp, len);
1.1       jfb       213:        }
                    214:        if (gm) {
                    215:                if (um)
                    216:                        strlcat(buf, ",", len);
                    217:                snprintf(tmp, sizeof(tmp), "g=%s", cvs_modestr[gm]);
1.9       jfb       218:                strlcat(buf, tmp, len);
1.1       jfb       219:        }
                    220:        if (om) {
                    221:                if (um || gm)
                    222:                        strlcat(buf, ",", len);
                    223:                snprintf(tmp, sizeof(tmp), "o=%s", cvs_modestr[gm]);
1.9       jfb       224:                strlcat(buf, tmp, len);
1.1       jfb       225:        }
                    226:
                    227:        return (0);
                    228: }
                    229:
                    230: /*
                    231:  * cvs_cksum()
                    232:  *
                    233:  * Calculate the MD5 checksum of the file whose path is <file> and generate
                    234:  * a CVS-format 32 hex-digit string, which is stored in <dst>, whose size is
                    235:  * given in <len> and must be at least 33.
                    236:  * Returns 0 on success, or -1 on failure.
                    237:  */
                    238: int
                    239: cvs_cksum(const char *file, char *dst, size_t len)
                    240: {
                    241:        if (len < CVS_CKSUM_LEN) {
                    242:                cvs_log(LP_WARN, "buffer too small for checksum");
                    243:                return (-1);
                    244:        }
                    245:        if (MD5File(file, dst) == NULL) {
1.19      jfb       246:                cvs_log(LP_ERRNO, "failed to generate checksum for %s", file);
1.1       jfb       247:                return (-1);
                    248:        }
                    249:
                    250:        return (0);
                    251: }
                    252:
                    253: /*
                    254:  * cvs_splitpath()
                    255:  *
1.7       jfb       256:  * Split a path <path> into the base portion and the filename portion.
                    257:  * The path is copied in <base> and the last delimiter is replaced by a NUL
                    258:  * byte.  The <file> pointer is set to point to the first character after
                    259:  * that delimiter.
1.1       jfb       260:  * Returns 0 on success, or -1 on failure.
                    261:  */
                    262: int
1.7       jfb       263: cvs_splitpath(const char *path, char *base, size_t blen, char **file)
1.1       jfb       264: {
                    265:        size_t rlen;
1.7       jfb       266:        char *sp;
1.1       jfb       267:
1.7       jfb       268:        if ((rlen = strlcpy(base, path, blen)) >= blen)
                    269:                return (-1);
1.6       jfb       270:
1.7       jfb       271:        while ((rlen > 0) && (base[rlen - 1] == '/'))
                    272:                base[--rlen] = '\0';
                    273:
                    274:        sp = strrchr(base, '/');
1.1       jfb       275:        if (sp == NULL) {
1.7       jfb       276:                strlcpy(base, "./", blen);
                    277:                strlcat(base, path, blen);
                    278:                sp = base + 1;
1.1       jfb       279:        }
                    280:
1.7       jfb       281:        *sp = '\0';
                    282:        if (file != NULL)
                    283:                *file = sp + 1;
1.1       jfb       284:
                    285:        return (0);
                    286: }
                    287:
                    288:
                    289: /*
                    290:  * cvs_getargv()
                    291:  *
                    292:  * Parse a line contained in <line> and generate an argument vector by
                    293:  * splitting the line on spaces and tabs.  The resulting vector is stored in
                    294:  * <argv>, which can accept up to <argvlen> entries.
1.20      david     295:  * Returns the number of arguments in the vector, or -1 if an error occurred.
1.1       jfb       296:  */
                    297: int
                    298: cvs_getargv(const char *line, char **argv, int argvlen)
                    299: {
                    300:        u_int i;
                    301:        int argc, err;
                    302:        char linebuf[256], qbuf[128], *lp, *cp, *arg;
                    303:
                    304:        strlcpy(linebuf, line, sizeof(linebuf));
1.27      pat       305:        memset(argv, 0, argvlen * sizeof(char *));
1.1       jfb       306:        argc = 0;
                    307:
                    308:        /* build the argument vector */
                    309:        err = 0;
                    310:        for (lp = linebuf; lp != NULL;) {
                    311:                if (*lp == '"') {
                    312:                        /* double-quoted string */
                    313:                        lp++;
                    314:                        i = 0;
                    315:                        memset(qbuf, 0, sizeof(qbuf));
                    316:                        while (*lp != '"') {
1.16      jfb       317:                                if (*lp == '\\')
                    318:                                        lp++;
1.1       jfb       319:                                if (*lp == '\0') {
                    320:                                        cvs_log(LP_ERR, "no terminating quote");
                    321:                                        err++;
                    322:                                        break;
1.16      jfb       323:                                }
1.1       jfb       324:
1.9       jfb       325:                                qbuf[i++] = *lp++;
1.1       jfb       326:                                if (i == sizeof(qbuf)) {
                    327:                                        err++;
                    328:                                        break;
                    329:                                }
                    330:                        }
                    331:
                    332:                        arg = qbuf;
1.15      deraadt   333:                } else {
1.1       jfb       334:                        cp = strsep(&lp, " \t");
                    335:                        if (cp == NULL)
                    336:                                break;
                    337:                        else if (*cp == '\0')
                    338:                                continue;
                    339:
                    340:                        arg = cp;
                    341:                }
                    342:
1.16      jfb       343:                if (argc == argvlen) {
                    344:                        err++;
                    345:                        break;
                    346:                }
                    347:
1.1       jfb       348:                argv[argc] = strdup(arg);
                    349:                if (argv[argc] == NULL) {
                    350:                        cvs_log(LP_ERRNO, "failed to copy argument");
                    351:                        err++;
                    352:                        break;
                    353:                }
                    354:                argc++;
                    355:        }
                    356:
                    357:        if (err) {
                    358:                /* ditch the argument vector */
                    359:                for (i = 0; i < (u_int)argc; i++)
                    360:                        free(argv[i]);
                    361:                argc = -1;
                    362:        }
                    363:
                    364:        return (argc);
1.17      jfb       365: }
                    366:
                    367:
                    368: /*
                    369:  * cvs_makeargv()
                    370:  *
1.20      david     371:  * Allocate an argument vector large enough to accommodate for all the
1.17      jfb       372:  * arguments found in <line> and return it.
                    373:  */
                    374: char**
                    375: cvs_makeargv(const char *line, int *argc)
                    376: {
                    377:        int i, ret;
                    378:        char *argv[1024], **copy;
1.27      pat       379:        size_t size;
1.17      jfb       380:
                    381:        ret = cvs_getargv(line, argv, 1024);
                    382:        if (ret == -1)
                    383:                return (NULL);
                    384:
1.27      pat       385:        size = (ret + 1) * sizeof(char *);
                    386:        copy = (char **)malloc(size);
1.17      jfb       387:        if (copy == NULL) {
                    388:                cvs_log(LP_ERRNO, "failed to allocate argument vector");
1.27      pat       389:                cvs_freeargv(argv, ret);
1.17      jfb       390:                return (NULL);
                    391:        }
1.27      pat       392:        memset(copy, 0, size);
1.17      jfb       393:
                    394:        for (i = 0; i < ret; i++)
                    395:                copy[i] = argv[i];
                    396:        copy[ret] = NULL;
                    397:
                    398:        *argc = ret;
                    399:        return (copy);
1.1       jfb       400: }
                    401:
                    402:
                    403: /*
                    404:  * cvs_freeargv()
                    405:  *
                    406:  * Free an argument vector previously generated by cvs_getargv().
                    407:  */
                    408: void
                    409: cvs_freeargv(char **argv, int argc)
                    410: {
                    411:        int i;
                    412:
                    413:        for (i = 0; i < argc; i++)
1.16      jfb       414:                if (argv[i] != NULL)
                    415:                        free(argv[i]);
1.2       jfb       416: }
                    417:
                    418:
                    419: /*
                    420:  * cvs_mkadmin()
                    421:  *
1.5       jfb       422:  * Create the CVS administrative files within the directory <cdir>.  If the
                    423:  * files already exist, they are kept as is.
1.2       jfb       424:  * Returns 0 on success, or -1 on failure.
                    425:  */
                    426: int
1.28      joris     427: cvs_mkadmin(const char *dpath, const char *rootpath, const char *repopath)
1.2       jfb       428: {
1.21      xsa       429:        int l;
1.28      joris     430:        char path[MAXPATHLEN];
1.2       jfb       431:        FILE *fp;
                    432:        CVSENTRIES *ef;
1.5       jfb       433:        struct stat st;
1.13      jfb       434:
1.21      xsa       435:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_CVSDIR, dpath);
                    436:        if (l == -1 || l >= (int)sizeof(path)) {
                    437:                errno = ENAMETOOLONG;
                    438:                cvs_log(LP_ERRNO, "%s", path);
                    439:                return (-1);
                    440:        }
                    441:
1.28      joris     442:        if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
1.2       jfb       443:                cvs_log(LP_ERRNO, "failed to create directory %s", path);
                    444:                return (-1);
                    445:        }
                    446:
1.5       jfb       447:        /* just create an empty Entries file */
1.13      jfb       448:        ef = cvs_ent_open(dpath, O_WRONLY);
1.2       jfb       449:        (void)cvs_ent_close(ef);
                    450:
1.21      xsa       451:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_ROOTSPEC, dpath);
                    452:        if (l == -1 || l >= (int)sizeof(path)) {
                    453:                errno = ENAMETOOLONG;
                    454:                cvs_log(LP_ERRNO, "%s", path);
                    455:                return (-1);
                    456:        }
                    457:
1.28      joris     458:        if ((stat(path, &st) != 0) && (errno == ENOENT)) {
1.5       jfb       459:                fp = fopen(path, "w");
                    460:                if (fp == NULL) {
                    461:                        cvs_log(LP_ERRNO, "failed to open %s", path);
                    462:                        return (-1);
                    463:                }
1.28      joris     464:                if (rootpath != NULL)
                    465:                        fprintf(fp, "%s\n", rootpath);
1.5       jfb       466:                (void)fclose(fp);
1.2       jfb       467:        }
                    468:
1.22      xsa       469:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_REPOSITORY, dpath);
1.21      xsa       470:        if (l == -1 || l >= (int)sizeof(path)) {
                    471:                errno = ENAMETOOLONG;
                    472:                cvs_log(LP_ERRNO, "%s", path);
                    473:                return (-1);
                    474:        }
                    475:
1.28      joris     476:        if ((stat(path, &st) != 0) && (errno == ENOENT)) {
1.2       jfb       477:                fp = fopen(path, "w");
                    478:                if (fp == NULL) {
                    479:                        cvs_log(LP_ERRNO, "failed to open %s", path);
                    480:                        return (-1);
                    481:                }
1.28      joris     482:                if (repopath != NULL)
                    483:                        fprintf(fp, "%s\n", repopath);
1.2       jfb       484:                (void)fclose(fp);
                    485:        }
                    486:
                    487:        return (0);
1.11      krapht    488: }
                    489:
                    490:
                    491: /*
                    492:  * cvs_exec()
                    493:  */
                    494: int
                    495: cvs_exec(int argc, char **argv, int fds[3])
                    496: {
                    497:        int ret;
                    498:        pid_t pid;
                    499:
                    500:        if ((pid = fork()) == -1) {
                    501:                cvs_log(LP_ERRNO, "failed to fork");
                    502:                return (-1);
                    503:        } else if (pid == 0) {
                    504:                execvp(argv[0], argv);
1.13      jfb       505:                cvs_log(LP_ERRNO, "failed to exec %s", argv[0]);
                    506:                exit(1);
1.11      krapht    507:        }
                    508:
                    509:        if (waitpid(pid, &ret, 0) == -1)
1.13      jfb       510:                cvs_log(LP_ERRNO, "failed to waitpid");
1.11      krapht    511:
                    512:        return (ret);
1.1       jfb       513: }
1.24      joris     514:
                    515: /*
1.30      jfb       516:  * cvs_remove_dir()
                    517:  *
                    518:  * Remove a directory tree from disk.
                    519:  * Returns 0 on success, or -1 on failure.
1.24      joris     520:  */
                    521: int
                    522: cvs_remove_dir(const char *path)
                    523: {
1.33      pat       524:        int ret = -1;
1.30      jfb       525:        size_t len;
1.24      joris     526:        DIR *dirp;
                    527:        struct dirent *ent;
                    528:        char fpath[MAXPATHLEN];
                    529:
                    530:        if ((dirp = opendir(path)) == NULL) {
                    531:                cvs_log(LP_ERRNO, "failed to open '%s'", path);
1.30      jfb       532:                return (-1);
1.24      joris     533:        }
                    534:
                    535:        while ((ent = readdir(dirp)) != NULL) {
                    536:                if (!strcmp(ent->d_name, ".") ||
                    537:                    !strcmp(ent->d_name, ".."))
                    538:                        continue;
                    539:
1.30      jfb       540:                len = cvs_path_cat(path, ent->d_name, fpath, sizeof(fpath));
1.33      pat       541:                if (len >= sizeof(fpath))
                    542:                        goto done;
1.24      joris     543:
                    544:                if (ent->d_type == DT_DIR) {
1.33      pat       545:                        if (cvs_remove_dir(fpath) == -1)
                    546:                                goto done;
1.30      jfb       547:                } else if ((unlink(fpath) == -1) && (errno != ENOENT)) {
                    548:                        cvs_log(LP_ERRNO, "failed to remove '%s'", fpath);
1.33      pat       549:                        goto done;
1.24      joris     550:                }
                    551:        }
                    552:
                    553:
1.30      jfb       554:        if ((rmdir(path) == -1) && (errno != ENOENT)) {
1.24      joris     555:                cvs_log(LP_ERRNO, "failed to remove '%s'", path);
1.33      pat       556:                goto done;
1.30      jfb       557:        }
1.24      joris     558:
1.33      pat       559:        ret = 0;
                    560: done:
                    561:        closedir(dirp);
1.34    ! joris     562:        return (ret);
        !           563: }
        !           564:
        !           565: /*
        !           566:  * Create a directory, and the parent directories if needed.
        !           567:  * based upon mkpath() from mkdir.c
        !           568:  */
        !           569: int
        !           570: cvs_create_dir(const char *path, int create_adm, char *root, char *repo)
        !           571: {
        !           572:        size_t l;
        !           573:        int len, ret;
        !           574:        char *d, *s;
        !           575:        struct stat sb;
        !           576:        char rpath[MAXPATHLEN], entry[MAXPATHLEN];
        !           577:        CVSENTRIES *entf;
        !           578:        struct cvs_ent *ent;
        !           579:
        !           580:        if (create_adm == 1 && (root == NULL || repo == NULL)) {
        !           581:                cvs_log(LP_ERR, "missing stuff in cvs_create_dir");
        !           582:                return (-1);
        !           583:        }
        !           584:
        !           585:        if ((s = strdup(path)) == NULL)
        !           586:                return (-1);
        !           587:
        !           588:        if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath) ||
        !           589:            strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) {
        !           590:                errno = ENAMETOOLONG;
        !           591:                cvs_log(LP_ERRNO, "%s", rpath);
        !           592:                free(s);
        !           593:                return (-1);
        !           594:        }
        !           595:
        !           596:        ret = -1;
        !           597:        entf = NULL;
        !           598:        d = strtok(s, "/");
        !           599:        while (d != NULL) {
        !           600:                if (stat(d, &sb)) {
        !           601:                        /* try to create the directory */
        !           602:                        if ((errno != ENOENT) || (mkdir(d, 0755) &&
        !           603:                            errno != EEXIST)) {
        !           604:                                cvs_log(LP_ERRNO, "failed to create `%s'", d);
        !           605:                                goto done;
        !           606:                        }
        !           607:                } else if (!S_ISDIR(sb.st_mode)) {
        !           608:                        cvs_log(LP_ERR, "`%s' not a directory", d);
        !           609:                        goto done;
        !           610:                }
        !           611:
        !           612:                /*
        !           613:                 * Create administrative files if requested.
        !           614:                 */
        !           615:                if (create_adm) {
        !           616:                        l = strlcat(rpath, d, sizeof(rpath));
        !           617:                        if (l >= sizeof(rpath))
        !           618:                                goto done;
        !           619:
        !           620:                        l = strlcat(rpath, "/", sizeof(rpath));
        !           621:                        if (l >= sizeof(rpath))
        !           622:                                goto done;
        !           623:
        !           624:                        if (cvs_mkadmin(d, root, rpath) < 0) {
        !           625:                                cvs_log(LP_ERR, "failed to create adm files");
        !           626:                                goto done;
        !           627:                        }
        !           628:                }
        !           629:
        !           630:                /*
        !           631:                 * Add it to the parent directory entry file.
        !           632:                 * (if any).
        !           633:                 */
        !           634:                entf = cvs_ent_open(".", O_RDWR);
        !           635:                if (entf != NULL && strcmp(d, ".")) {
        !           636:                        len = snprintf(entry, sizeof(entry), "D/%s////", d);
        !           637:                        if (len == -1 || len >= (int)sizeof(entry)) {
        !           638:                                errno = ENAMETOOLONG;
        !           639:                                cvs_log(LP_ERRNO, "%s", entry);
        !           640:                                goto done;
        !           641:                        }
        !           642:
        !           643:                        if ((ent = cvs_ent_parse(entry)) == NULL) {
        !           644:                                cvs_log(LP_ERR, "failed to parse entry");
        !           645:                                goto done;
        !           646:                        }
        !           647:
        !           648:                        cvs_ent_remove(entf, d);
        !           649:
        !           650:                        if (cvs_ent_add(entf, ent) < 0) {
        !           651:                                cvs_log(LP_ERR, "failed to add entry");
        !           652:                                goto done;
        !           653:                        }
        !           654:                }
        !           655:
        !           656:                if (entf != NULL) {
        !           657:                        cvs_ent_close(entf);
        !           658:                        entf = NULL;
        !           659:                }
        !           660:
        !           661:                /*
        !           662:                 * All went ok, switch to the newly created directory.
        !           663:                 */
        !           664:                if (chdir(d) == -1) {
        !           665:                        cvs_log(LP_ERRNO, "failed to change dir to `%s'", d);
        !           666:                        goto done;
        !           667:                }
        !           668:
        !           669:                d = strtok(NULL, "/");
        !           670:        }
        !           671:
        !           672:        ret = 0;
        !           673: done:
        !           674:        if (entf != NULL)
        !           675:                cvs_ent_close(entf);
        !           676:        free(s);
1.33      pat       677:        return (ret);
1.24      joris     678: }
                    679:
1.30      jfb       680: /*
                    681:  * cvs_path_cat()
                    682:  *
                    683:  * Concatenate the two paths <base> and <end> and store the generated path
                    684:  * into the buffer <dst>, which can accept up to <dlen> bytes, including the
                    685:  * NUL byte.  The result is guaranteed to be NUL-terminated.
                    686:  * Returns the number of bytes necessary to store the full resulting path,
                    687:  * not including the NUL byte (a value equal to or larger than <dlen>
                    688:  * indicates truncation).
                    689:  */
1.29      jfb       690: size_t
                    691: cvs_path_cat(const char *base, const char *end, char *dst, size_t dlen)
                    692: {
                    693:        size_t len;
                    694:
                    695:        len = strlcpy(dst, base, dlen);
                    696:        if (len >= dlen - 1) {
                    697:                errno = ENAMETOOLONG;
                    698:                cvs_log(LP_ERRNO, "%s", dst);
                    699:        } else {
                    700:                dst[len] = '/';
                    701:                dst[len + 1] = '\0';
                    702:                len = strlcat(dst, end, dlen);
                    703:                if (len >= dlen) {
                    704:                        errno = ENAMETOOLONG;
                    705:                        cvs_log(LP_ERRNO, "%s", dst);
                    706:                }
                    707:        }
                    708:
                    709:        return (len);
                    710: }