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

Annotation of src/usr.bin/diff/diffdir.c, Revision 1.18

1.18    ! millert     1: /*     $OpenBSD: diffdir.c,v 1.17 2003/07/04 17:50:24 millert Exp $    */
1.2       deraadt     2:
                      3: /*
                      4:  * Copyright (C) Caldera International Inc.  2001-2002.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code and documentation must retain the above
                     11:  *    copyright notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed or owned by Caldera
                     18:  *     International, Inc.
                     19:  * 4. Neither the name of Caldera International, Inc. nor the names of other
                     20:  *    contributors may be used to endorse or promote products derived from
                     21:  *    this software without specific prior written permission.
                     22:  *
                     23:  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
                     24:  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
                     25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     27:  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
                     28:  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     29:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     30:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     32:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
                     33:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     34:  * POSSIBILITY OF SUCH DAMAGE.
                     35:  */
                     36:
1.3       tedu       37: #include <sys/types.h>
                     38: #include <sys/wait.h>
                     39:
1.12      millert    40: #include <dirent.h>
                     41: #include <errno.h>
                     42: #include <fcntl.h>
1.8       tedu       43: #include <stdio.h>
1.3       tedu       44: #include <stdlib.h>
1.12      millert    45: #include <string.h>
1.3       tedu       46: #include <unistd.h>
1.1       deraadt    47:
                     48: #include "diff.h"
1.16      millert    49: #include "pathnames.h"
1.3       tedu       50:
                     51: #if 0
                     52: static const char sccsid[] = "@(#)diffdir.c    4.12 (Berkeley) 4/30/89";
                     53: #endif
                     54:
1.1       deraadt    55: /*
                     56:  * diff - directory comparison
                     57:  */
                     58: #define        d_flags d_ino
                     59:
1.17      millert    60: #define        DIRECT  1               /* Directory */
1.1       deraadt    61:
                     62: struct dir {
1.3       tedu       63:        u_long d_ino;
                     64:        short d_reclen;
                     65:        short d_namlen;
                     66:        char *d_entry;
1.1       deraadt    67: };
                     68:
1.3       tedu       69: static int dirstatus;          /* exit status from diffdir */
1.17      millert    70: static char title[2 * BUFSIZ];
1.3       tedu       71:
                     72:
                     73: static struct dir *setupdir(char *);
                     74: static int ascii(int);
                     75: static void compare(struct dir *);
1.17      millert    76: static void calldiff(void);
1.3       tedu       77: static void setfile(char **fpp, char **epp, char *file);
                     78: static int useless(char *);
1.4       tedu       79: static void only(struct dir *dp, int which);
1.8       tedu       80: static int entcmp(const void *, const void *);
                     81:
1.3       tedu       82: void
                     83: diffdir(char **argv)
1.1       deraadt    84: {
1.9       deraadt    85:        struct dir *dir1, *dir2;
1.3       tedu       86:        struct dir *d1, *d2;
1.9       deraadt    87:        int i, cmp;
1.1       deraadt    88:
1.11      millert    89:        if (opt == D_IFDEF)
                     90:                warnx("can't specify -I with directories");
1.17      millert    91:        if (opt == D_EDIT && sflag)
                     92:                warnx("warning: shouldn't give -s with -e");
1.3       tedu       93:        strlcpy(title, "diff ", sizeof title);
                     94:        for (i = 1; diffargv[i + 2]; i++) {
1.1       deraadt    95:                if (!strcmp(diffargv[i], "-"))
                     96:                        continue;       /* was -S, dont look silly */
1.3       tedu       97:                strlcat(title, diffargv[i], sizeof title);
                     98:                strlcat(title, " ", sizeof title);
1.1       deraadt    99:        }
                    100:        setfile(&file1, &efile1, file1);
                    101:        setfile(&file2, &efile2, file2);
                    102:        argv[0] = file1;
                    103:        argv[1] = file2;
                    104:        dir1 = setupdir(file1);
                    105:        dir2 = setupdir(file2);
1.3       tedu      106:        d1 = dir1;
                    107:        d2 = dir2;
1.1       deraadt   108:        while (d1->d_entry != 0 || d2->d_entry != 0) {
                    109:                if (d1->d_entry && useless(d1->d_entry)) {
                    110:                        d1++;
                    111:                        continue;
                    112:                }
                    113:                if (d2->d_entry && useless(d2->d_entry)) {
                    114:                        d2++;
                    115:                        continue;
                    116:                }
                    117:                if (d1->d_entry == 0)
                    118:                        cmp = 1;
                    119:                else if (d2->d_entry == 0)
                    120:                        cmp = -1;
                    121:                else
                    122:                        cmp = strcmp(d1->d_entry, d2->d_entry);
                    123:                if (cmp < 0) {
1.18    ! millert   124:                        if (opt == D_NORMAL || opt == D_CONTEXT ||
        !           125:                            opt == D_UNIFIED)
1.1       deraadt   126:                                only(d1, 1);
                    127:                        d1++;
                    128:                        dirstatus |= 1;
                    129:                } else if (cmp == 0) {
                    130:                        compare(d1);
                    131:                        d1++;
                    132:                        d2++;
                    133:                } else {
1.18    ! millert   134:                        if (opt == D_NORMAL || opt == D_CONTEXT ||
        !           135:                            opt == D_UNIFIED)
1.1       deraadt   136:                                only(d2, 2);
                    137:                        d2++;
                    138:                        dirstatus |= 1;
                    139:                }
                    140:        }
                    141:        if (rflag) {
1.3       tedu      142:                for (d1 = dir1; d1->d_entry; d1++) {
1.1       deraadt   143:                        if ((d1->d_flags & DIRECT) == 0)
                    144:                                continue;
1.12      millert   145:                        strlcpy(efile1, d1->d_entry,
                    146:                            file1 + MAXPATHLEN - efile1);
                    147:                        strlcpy(efile2, d1->d_entry,
                    148:                            file2 + MAXPATHLEN - efile2);
1.17      millert   149:                        calldiff();
1.1       deraadt   150:                }
                    151:        }
                    152:        status = dirstatus;
                    153: }
                    154:
1.3       tedu      155: void
                    156: setfile(char **fpp, char **epp, char *file)
1.1       deraadt   157: {
1.3       tedu      158:        char *cp;
1.12      millert   159:        size_t len;
1.1       deraadt   160:
1.12      millert   161:        if (*file == '\0')
                    162:                file = ".";
                    163:        *fpp = emalloc(MAXPATHLEN);
                    164:        len = strlcpy(*fpp, file, MAXPATHLEN);
                    165:        if (len >= MAXPATHLEN - 1)
1.14      millert   166:                errorx("%s: %s", file, strerror(ENAMETOOLONG));
1.12      millert   167:        cp = *fpp + len - 1;
                    168:        if (*cp == '/')
                    169:                ++cp;
                    170:        else {
                    171:                *++cp = '/';
                    172:                *++cp = '\0';
                    173:        }
1.1       deraadt   174:        *epp = cp;
                    175: }
                    176:
1.3       tedu      177: void
1.4       tedu      178: only(struct dir *dp, int which)
1.1       deraadt   179: {
                    180:        char *file = which == 1 ? file1 : file2;
                    181:        char *efile = which == 1 ? efile1 : efile2;
                    182:
1.3       tedu      183:        printf("Only in %.*s: %s\n", (int)(efile - file - 1), file, dp->d_entry);
1.1       deraadt   184: }
                    185:
                    186: struct dir *
1.3       tedu      187: setupdir(char *cp)
1.1       deraadt   188: {
1.3       tedu      189:        struct dir *dp, *ep;
1.12      millert   190:        struct dirent *rp;
1.3       tedu      191:        int nitems;
1.1       deraadt   192:        DIR *dirp;
                    193:
                    194:        dirp = opendir(cp);
1.14      millert   195:        if (dirp == NULL)
                    196:                error("%s", cp);
1.1       deraadt   197:        nitems = 0;
1.12      millert   198:        dp = emalloc(sizeof(struct dir));
1.3       tedu      199:        while ((rp = readdir(dirp))) {
1.1       deraadt   200:                ep = &dp[nitems++];
                    201:                ep->d_reclen = rp->d_reclen;
                    202:                ep->d_namlen = rp->d_namlen;
                    203:                ep->d_entry = 0;
                    204:                ep->d_flags = 0;
                    205:                if (ep->d_namlen > 0) {
1.12      millert   206:                        ep->d_entry = emalloc(ep->d_namlen + 1);
                    207:                        strlcpy(ep->d_entry, rp->d_name, ep->d_namlen + 1);
1.1       deraadt   208:                }
1.12      millert   209:                dp = erealloc(dp, (nitems + 1) * sizeof(struct dir));
1.1       deraadt   210:        }
1.3       tedu      211:        dp[nitems].d_entry = 0; /* delimiter */
1.1       deraadt   212:        closedir(dirp);
1.3       tedu      213:        qsort(dp, nitems, sizeof(struct dir), entcmp);
1.1       deraadt   214:        return (dp);
                    215: }
                    216:
1.8       tedu      217: static int
                    218: entcmp(const void *v1, const void *v2)
1.1       deraadt   219: {
1.8       tedu      220:        const struct dir *d1, *d2;
                    221:
                    222:        d1 = v1;
                    223:        d2 = v2;
1.1       deraadt   224:        return (strcmp(d1->d_entry, d2->d_entry));
                    225: }
                    226:
1.3       tedu      227: static void
1.4       tedu      228: compare(struct dir *dp)
1.1       deraadt   229: {
1.9       deraadt   230:        char buf1[BUFSIZ], buf2[BUFSIZ];
                    231:        int i, j, f1, f2, fmt1, fmt2;
1.1       deraadt   232:        struct stat stb1, stb2;
                    233:
1.12      millert   234:        strlcpy(efile1, dp->d_entry, file1 + MAXPATHLEN - efile1);
                    235:        strlcpy(efile2, dp->d_entry, file2 + MAXPATHLEN - efile2);
1.1       deraadt   236:        f1 = open(file1, 0);
                    237:        if (f1 < 0) {
1.14      millert   238:                warn("%s", file1);
1.1       deraadt   239:                return;
                    240:        }
                    241:        f2 = open(file2, 0);
                    242:        if (f2 < 0) {
1.14      millert   243:                warn("%s", file2);
1.1       deraadt   244:                close(f1);
                    245:                return;
                    246:        }
1.3       tedu      247:        fstat(f1, &stb1);
                    248:        fstat(f2, &stb2);
1.1       deraadt   249:        fmt1 = stb1.st_mode & S_IFMT;
                    250:        fmt2 = stb2.st_mode & S_IFMT;
                    251:        if (fmt1 != S_IFREG || fmt2 != S_IFREG) {
                    252:                if (fmt1 == fmt2) {
                    253:                        if (fmt1 != S_IFDIR && stb1.st_rdev == stb2.st_rdev)
                    254:                                goto same;
                    255:                        if (fmt1 == S_IFDIR) {
                    256:                                dp->d_flags = DIRECT;
1.17      millert   257:                                if (opt == D_EDIT)
1.1       deraadt   258:                                        goto closem;
                    259:                                printf("Common subdirectories: %s and %s\n",
                    260:                                    file1, file2);
                    261:                                goto closem;
                    262:                        }
                    263:                }
                    264:                goto notsame;
                    265:        }
                    266:        if (stb1.st_size != stb2.st_size)
                    267:                goto notsame;
                    268:        for (;;) {
                    269:                i = read(f1, buf1, BUFSIZ);
                    270:                j = read(f2, buf2, BUFSIZ);
                    271:                if (i < 0 || j < 0 || i != j)
                    272:                        goto notsame;
                    273:                if (i == 0 && j == 0)
                    274:                        goto same;
                    275:                for (j = 0; j < i; j++)
                    276:                        if (buf1[j] != buf2[j])
                    277:                                goto notsame;
                    278:        }
                    279: same:
1.17      millert   280:        if (sflag != 0)
1.1       deraadt   281:                printf("Files %s and %s are identical\n", file1, file2);
                    282:        goto closem;
                    283: notsame:
                    284:        dirstatus |= 1;
                    285:        if (!ascii(f1) || !ascii(f2)) {
1.17      millert   286:                if (opt == D_NORMAL || opt == D_CONTEXT || opt == D_UNIFIED)
1.1       deraadt   287:                        printf("Binary files %s and %s differ\n",
                    288:                            file1, file2);
                    289:                goto closem;
                    290:        }
1.3       tedu      291:        close(f1);
                    292:        close(f2);
1.1       deraadt   293:        anychange = 1;
1.17      millert   294:        if (opt == D_EDIT) {
                    295:                printf("ed - %s << '-*-END-*-'\n", dp->d_entry);
                    296:                calldiff();
                    297:        } else {
                    298:                printf("%s%s %s\n", title, file1, file2);
                    299:                calldiff();
1.1       deraadt   300:        }
1.17      millert   301:        if (opt == D_EDIT)
                    302:                printf("w\nq\n-*-END-*-\n");
1.1       deraadt   303:        return;
                    304: closem:
1.3       tedu      305:        close(f1);
                    306:        close(f2);
1.1       deraadt   307: }
                    308:
1.3       tedu      309: static void
1.17      millert   310: calldiff(void)
1.1       deraadt   311: {
1.17      millert   312:        int lstatus;
1.9       deraadt   313:        pid_t pid;
1.1       deraadt   314:
                    315:        fflush(stdout);
                    316:        pid = fork();
1.14      millert   317:        if (pid == -1)
                    318:                errorx("No more processes");
1.1       deraadt   319:        if (pid == 0) {
1.16      millert   320:                execv(_PATH_DIFF, diffargv);
                    321:                error("%s", _PATH_DIFF);
1.1       deraadt   322:        }
                    323:        while (wait(&lstatus) != pid)
                    324:                continue;
1.3       tedu      325:        /*
                    326:                if ((lstatus >> 8) >= 2)
1.7       deraadt   327:                        done(0);
1.3       tedu      328:        */
1.1       deraadt   329:        dirstatus |= lstatus >> 8;
                    330: }
                    331:
1.3       tedu      332: int
                    333: ascii(int f)
1.1       deraadt   334: {
1.9       deraadt   335:        char buf[BUFSIZ], *cp;
1.3       tedu      336:        int cnt;
1.15      tedu      337:
                    338:        if (aflag)
                    339:                return (1);
1.1       deraadt   340:
1.6       deraadt   341:        lseek(f, (off_t)0, SEEK_SET);
1.1       deraadt   342:        cnt = read(f, buf, BUFSIZ);
                    343:        cp = buf;
                    344:        while (--cnt >= 0)
                    345:                if (*cp++ & 0200)
                    346:                        return (0);
                    347:        return (1);
                    348: }
                    349:
                    350: /*
                    351:  * THIS IS CRUDE.
                    352:  */
1.3       tedu      353: int
                    354: useless(char *cp)
1.1       deraadt   355: {
                    356:        if (cp[0] == '.') {
                    357:                if (cp[1] == '\0')
                    358:                        return (1);     /* directory "." */
                    359:                if (cp[1] == '.' && cp[2] == '\0')
                    360:                        return (1);     /* directory ".." */
                    361:        }
                    362:        if (start && strcmp(start, cp) > 0)
                    363:                return (1);
                    364:        return (0);
                    365: }