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

Annotation of src/usr.bin/cvs/file.c, Revision 1.1

1.1     ! jfb         1: /*     $OpenBSD$       */
        !             2: /*
        !             3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  *
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. The name of the author may not be used to endorse or promote products
        !            13:  *    derived from this software without specific prior written permission.
        !            14:  *
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
        !            16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
        !            17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
        !            18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
        !            21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
        !            22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
        !            23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
        !            24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            25:  */
        !            26:
        !            27: #include <sys/types.h>
        !            28: #include <sys/queue.h>
        !            29: #include <sys/stat.h>
        !            30:
        !            31: #include <pwd.h>
        !            32: #include <errno.h>
        !            33: #include <stdio.h>
        !            34: #include <fcntl.h>
        !            35: #include <dirent.h>
        !            36: #include <stdlib.h>
        !            37: #include <unistd.h>
        !            38: #include <string.h>
        !            39: #include <fnmatch.h>
        !            40:
        !            41: #include "cvs.h"
        !            42: #include "log.h"
        !            43:
        !            44:
        !            45: #define CVS_IGN_STATIC    0x01     /* pattern is static, no need to glob */
        !            46:
        !            47:
        !            48:
        !            49: #define CVS_CHAR_ISMETA(c)  ((c == '*') || (c == '?') || (c == '['))
        !            50:
        !            51:
        !            52:
        !            53: /* ignore pattern */
        !            54: struct cvs_ignpat {
        !            55:        char  ip_pat[MAXNAMLEN];
        !            56:        int   ip_flags;
        !            57:        TAILQ_ENTRY (cvs_ignpat) ip_list;
        !            58: };
        !            59:
        !            60:
        !            61: /*
        !            62:  * Standard patterns to ignore.
        !            63:  */
        !            64:
        !            65: static const char *cvs_ign_std[] = {
        !            66:        ".",
        !            67:        "..",
        !            68:        "*.o",
        !            69:        "*.so",
        !            70:        "*.bak",
        !            71:        "*.orig",
        !            72:        "*.rej",
        !            73:        "*.exe",
        !            74:        "*.depend",
        !            75:        "CVS",
        !            76:        "core",
        !            77: #ifdef OLD_SMELLY_CRUFT
        !            78:        "RCSLOG",
        !            79:        "tags",
        !            80:        "TAGS",
        !            81:        "RCS",
        !            82:        "SCCS",
        !            83:        "#*",
        !            84:        ".#*",
        !            85:        ",*",
        !            86: #endif
        !            87: };
        !            88:
        !            89:
        !            90: TAILQ_HEAD(, cvs_ignpat)  cvs_ign_pats;
        !            91:
        !            92:
        !            93: /*
        !            94:  * cvs_file_init()
        !            95:  *
        !            96:  */
        !            97:
        !            98: int
        !            99: cvs_file_init(void)
        !           100: {
        !           101:        int i;
        !           102:        size_t len;
        !           103:        char path[MAXPATHLEN], buf[MAXNAMLEN];
        !           104:        FILE *ifp;
        !           105:        struct passwd *pwd;
        !           106:
        !           107:        TAILQ_INIT(&cvs_ign_pats);
        !           108:
        !           109:        /* standard patterns to ignore */
        !           110:        for (i = 0; i < sizeof(cvs_ign_std)/sizeof(char *); i++)
        !           111:                cvs_file_ignore(cvs_ign_std[i]);
        !           112:
        !           113:        /* read the cvsignore file in the user's home directory, if any */
        !           114:        pwd = getpwuid(getuid());
        !           115:        if (pwd != NULL) {
        !           116:                snprintf(path, sizeof(path), "%s/.cvsignore", pwd->pw_dir);
        !           117:                ifp = fopen(path, "r");
        !           118:                if (ifp == NULL) {
        !           119:                        if (errno != ENOENT)
        !           120:                                cvs_log(LP_ERRNO, "failed to open `%s'", path);
        !           121:                }
        !           122:                else {
        !           123:                        while (fgets(buf, sizeof(buf), ifp) != NULL) {
        !           124:                                len = strlen(buf);
        !           125:                                if (len == 0)
        !           126:                                        continue;
        !           127:                                if (buf[len - 1] != '\n') {
        !           128:                                        cvs_log(LP_ERR, "line too long in `%s'",
        !           129:                                            path);
        !           130:                                }
        !           131:                                buf[--len] = '\0';
        !           132:                                cvs_file_ignore(buf);
        !           133:                        }
        !           134:                        (void)fclose(ifp);
        !           135:                }
        !           136:        }
        !           137:
        !           138:        return (0);
        !           139: }
        !           140:
        !           141:
        !           142: /*
        !           143:  * cvs_file_ignore()
        !           144:  *
        !           145:  * Add the pattern <pat> to the list of patterns for files to ignore.
        !           146:  * Returns 0 on success, or -1 on failure.
        !           147:  */
        !           148:
        !           149: int
        !           150: cvs_file_ignore(const char *pat)
        !           151: {
        !           152:        char *cp;
        !           153:        struct cvs_ignpat *ip;
        !           154:
        !           155:        ip = (struct cvs_ignpat *)malloc(sizeof(*ip));
        !           156:        if (ip == NULL) {
        !           157:                cvs_log(LP_ERR, "failed to allocate space for ignore pattern");
        !           158:                return (-1);
        !           159:        }
        !           160:
        !           161:        strlcpy(ip->ip_pat, pat, sizeof(ip->ip_pat));
        !           162:
        !           163:        /* check if we will need globbing for that pattern */
        !           164:        ip->ip_flags = CVS_IGN_STATIC;
        !           165:        for (cp = ip->ip_pat; *cp != '\0'; cp++) {
        !           166:                if (CVS_CHAR_ISMETA(*cp)) {
        !           167:                        ip->ip_flags &= ~CVS_IGN_STATIC;
        !           168:                        break;
        !           169:                }
        !           170:        }
        !           171:
        !           172:        TAILQ_INSERT_TAIL(&cvs_ign_pats, ip, ip_list);
        !           173:
        !           174:        return (0);
        !           175: }
        !           176:
        !           177:
        !           178: /*
        !           179:  * cvs_file_isignored()
        !           180:  *
        !           181:  * Returns 1 if the filename <file> is matched by one of the ignore
        !           182:  * patterns, or 0 otherwise.
        !           183:  */
        !           184:
        !           185: int
        !           186: cvs_file_isignored(const char *file)
        !           187: {
        !           188:        struct cvs_ignpat *ip;
        !           189:
        !           190:        TAILQ_FOREACH(ip, &cvs_ign_pats, ip_list) {
        !           191:                if (ip->ip_flags & CVS_IGN_STATIC) {
        !           192:                        if (strcmp(file, ip->ip_pat) == 0)
        !           193:                                return (1);
        !           194:                }
        !           195:                else if (fnmatch(ip->ip_pat, file, FNM_PERIOD) == 0)
        !           196:                        return (1);
        !           197:        }
        !           198:
        !           199:        return (0);
        !           200: }
        !           201:
        !           202:
        !           203: /*
        !           204:  * cvs_file_getv()
        !           205:  *
        !           206:  * Get a vector of all the files found in the directory <dir> and not
        !           207:  * matching any of the ignore patterns.  The number of files found is
        !           208:  * returned in <nfiles>.
        !           209:  * Returns a pointer to a dynamically-allocated string vector on success,
        !           210:  * or NULL on failure.
        !           211:  */
        !           212:
        !           213: char**
        !           214: cvs_file_getv(const char *dir, int *nfiles)
        !           215: {
        !           216:        int nf, ret, fd;
        !           217:        long base;
        !           218:        void *dp, *ep, *tmp;
        !           219:        char fbuf[1024], **fvec;
        !           220:        struct dirent *ent;
        !           221:
        !           222:        *nfiles = 0;
        !           223:        fvec = NULL;
        !           224:
        !           225:        fd = open(dir, O_RDONLY);
        !           226:        if (fd == -1) {
        !           227:                cvs_log(LP_ERRNO, "failed to open `%s'", dir);
        !           228:                return (NULL);
        !           229:        }
        !           230:        ret = getdirentries(fd, fbuf, sizeof(fbuf), &base);
        !           231:        if (ret == -1) {
        !           232:                cvs_log(LP_ERRNO, "failed to get directory entries");
        !           233:                (void)close(fd);
        !           234:                return (NULL);
        !           235:        }
        !           236:
        !           237:        dp = fbuf;
        !           238:        ep = fbuf + (size_t)ret;
        !           239:        while (dp < ep) {
        !           240:                ent = (struct dirent *)dp;
        !           241:                dp += ent->d_reclen;
        !           242:
        !           243:                if (cvs_file_isignored(ent->d_name))
        !           244:                        continue;
        !           245:
        !           246:                tmp = realloc(fvec, (*nfiles + 1) * sizeof(char *));
        !           247:                if (tmp == NULL) {
        !           248:                        cvs_log(LP_ERRNO, "failed to reallocate file vector");
        !           249:                        (void)close(fd);
        !           250:                        free(fvec);
        !           251:                        return (NULL);
        !           252:                }
        !           253:                fvec[++(*nfiles)] = strdup(ent->d_name);
        !           254:
        !           255:                *nfiles++;
        !           256:        }
        !           257:
        !           258:        (void)close(fd);
        !           259:
        !           260:        return (fvec);
        !           261: }
        !           262:
        !           263:
        !           264: /*
        !           265:  * cvs_file_freev()
        !           266:  *
        !           267:  * Free a file vector obtained with cvs_file_getv().
        !           268:  */
        !           269:
        !           270: void
        !           271: cvs_file_freev(char **fvec, int nfiles)
        !           272: {
        !           273:        int i;
        !           274:
        !           275:        for (i = 0; i < nfiles; i++)
        !           276:                free(fvec[i]);
        !           277:        free(fvec);
        !           278: }