Annotation of src/usr.bin/diff/diffdir.c, Revision 1.39
1.39 ! millert 1: /* $OpenBSD: diffdir.c,v 1.38 2010/10/28 15:02:41 millert Exp $ */
1.2 deraadt 2:
3: /*
1.39 ! millert 4: * Copyright (c) 2003, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
1.2 deraadt 5: *
1.19 millert 6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.2 deraadt 9: *
1.19 millert 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: *
18: * Sponsored in part by the Defense Advanced Research Projects
19: * Agency (DARPA) and Air Force Research Laboratory, Air Force
20: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.2 deraadt 21: */
1.19 millert 22:
23: #include <sys/param.h>
24: #include <sys/stat.h>
1.3 tedu 25:
1.12 millert 26: #include <dirent.h>
1.19 millert 27: #include <err.h>
1.12 millert 28: #include <errno.h>
29: #include <fcntl.h>
1.19 millert 30: #include <fnmatch.h>
31: #include <paths.h>
1.8 tedu 32: #include <stdio.h>
1.3 tedu 33: #include <stdlib.h>
1.12 millert 34: #include <string.h>
1.3 tedu 35: #include <unistd.h>
1.1 deraadt 36:
37: #include "diff.h"
1.31 ray 38: #include "xmalloc.h"
1.3 tedu 39:
1.39 ! millert 40: static int selectfile(struct dirent *);
! 41: static struct dirent **slurpdir(char *, int);
1.33 ray 42: static void diffit(struct dirent *, char *, size_t, char *, size_t, int);
1.3 tedu 43:
1.22 millert 44: #define d_status d_type /* we need to store status for -l */
45:
1.1 deraadt 46: /*
1.26 otto 47: * Diff directory traversal. Will be called recursively if -r was specified.
1.1 deraadt 48: */
1.19 millert 49: void
1.33 ray 50: diffdir(char *p1, char *p2, int flags)
1.19 millert 51: {
1.39 ! millert 52: struct dirent *dent1, **dp1, **dirp1 = NULL;
! 53: struct dirent *dent2, **dp2, **dirp2 = NULL;
1.19 millert 54: size_t dirlen1, dirlen2;
55: char path1[MAXPATHLEN], path2[MAXPATHLEN];
56: int pos;
57:
58: dirlen1 = strlcpy(path1, *p1 ? p1 : ".", sizeof(path1));
59: if (dirlen1 >= sizeof(path1) - 1) {
60: warnx("%s: %s", p1, strerror(ENAMETOOLONG));
61: status = 2;
62: return;
63: }
64: if (path1[dirlen1 - 1] != '/') {
65: path1[dirlen1++] = '/';
66: path1[dirlen1] = '\0';
67: }
68: dirlen2 = strlcpy(path2, *p2 ? p2 : ".", sizeof(path2));
69: if (dirlen2 >= sizeof(path2) - 1) {
70: warnx("%s: %s", p2, strerror(ENAMETOOLONG));
71: status = 2;
72: return;
73: }
74: if (path2[dirlen2 - 1] != '/') {
75: path2[dirlen2++] = '/';
76: path2[dirlen2] = '\0';
77: }
1.1 deraadt 78:
1.19 millert 79: /* get a list of the entries in each directory */
1.39 ! millert 80: dp1 = dirp1 = slurpdir(path1, Nflag + Pflag);
! 81: dp2 = dirp2 = slurpdir(path2, Nflag);
! 82: if (dirp1 == NULL || dirp2 == NULL)
1.37 ray 83: goto closem;
1.1 deraadt 84:
1.19 millert 85: /*
86: * If we were given a starting point, find it.
87: */
88: if (start != NULL) {
89: while (*dp1 != NULL && strcmp((*dp1)->d_name, start) < 0)
90: dp1++;
91: while (*dp2 != NULL && strcmp((*dp2)->d_name, start) < 0)
92: dp2++;
93: }
1.8 tedu 94:
1.19 millert 95: /*
96: * Iterate through the two directory lists, diffing as we go.
97: */
98: while (*dp1 != NULL || *dp2 != NULL) {
99: dent1 = *dp1;
100: dent2 = *dp2;
101:
102: pos = dent1 == NULL ? 1 : dent2 == NULL ? -1 :
103: strcmp(dent1->d_name, dent2->d_name);
104: if (pos == 0) {
105: /* file exists in both dirs, diff it */
1.33 ray 106: diffit(dent1, path1, dirlen1, path2, dirlen2, flags);
1.19 millert 107: dp1++;
108: dp2++;
109: } else if (pos < 0) {
110: /* file only in first dir, only diff if -N */
111: if (Nflag)
1.33 ray 112: diffit(dent1, path1, dirlen1, path2, dirlen2,
113: flags);
1.22 millert 114: else if (lflag)
115: dent1->d_status |= D_ONLY;
1.24 millert 116: else
1.25 millert 117: print_only(path1, dirlen1, dent1->d_name);
1.19 millert 118: dp1++;
1.1 deraadt 119: } else {
1.20 millert 120: /* file only in second dir, only diff if -N or -P */
121: if (Nflag || Pflag)
1.33 ray 122: diffit(dent2, path1, dirlen1, path2, dirlen2,
123: flags);
1.22 millert 124: else if (lflag)
125: dent2->d_status |= D_ONLY;
1.24 millert 126: else
1.25 millert 127: print_only(path2, dirlen2, dent2->d_name);
1.19 millert 128: dp2++;
1.1 deraadt 129: }
130: }
1.22 millert 131: if (lflag) {
1.23 millert 132: path1[dirlen1] = '\0';
133: path2[dirlen2] = '\0';
1.22 millert 134: for (dp1 = dirp1; (dent1 = *dp1) != NULL; dp1++) {
135: print_status(dent1->d_status, path1, path2,
136: dent1->d_name);
137: }
138: for (dp2 = dirp2; (dent2 = *dp2) != NULL; dp2++) {
139: if (dent2->d_status == D_ONLY)
140: print_status(dent2->d_status, path2, NULL,
141: dent2->d_name);
142: }
143: }
1.19 millert 144:
1.37 ray 145: closem:
1.39 ! millert 146: if (dirp1 != NULL) {
! 147: for (dp1 = dirp1; (dent1 = *dp1) != NULL; dp1++)
! 148: xfree(dent1);
1.31 ray 149: xfree(dirp1);
1.19 millert 150: }
1.39 ! millert 151: if (dirp2 != NULL) {
! 152: for (dp2 = dirp2; (dent2 = *dp2) != NULL; dp2++)
! 153: xfree(dent2);
1.31 ray 154: xfree(dirp2);
1.1 deraadt 155: }
156: }
157:
1.19 millert 158: /*
1.39 ! millert 159: * Read in a whole directory, culling out the "excluded" files.
! 160: * Returns an array of struct dirent *'s in alphabetic order.
! 161: * Caller is responsible for free()ing each array element and the array itself.
1.19 millert 162: */
163: static struct dirent **
1.39 ! millert 164: slurpdir(char *dirname, int enoentok)
1.1 deraadt 165: {
1.39 ! millert 166: struct dirent **namelist = NULL;
! 167: int rval;
1.1 deraadt 168:
1.39 ! millert 169: rval = scandir(dirname, &namelist, selectfile, alphasort);
! 170: if (rval == -1) {
! 171: if (enoentok && errno == ENOENT) {
! 172: namelist = xmalloc(sizeof(struct dirent *));
! 173: namelist[0] = NULL;
! 174: } else {
! 175: warn("%s", dirname);
1.22 millert 176: }
1.19 millert 177: }
1.1 deraadt 178:
1.39 ! millert 179: return (namelist);
1.1 deraadt 180: }
181:
1.19 millert 182: /*
183: * Do the actual diff by calling either diffreg() or diffdir().
184: */
1.3 tedu 185: static void
1.33 ray 186: diffit(struct dirent *dp, char *path1, size_t plen1, char *path2, size_t plen2,
187: int flags)
1.1 deraadt 188: {
1.33 ray 189: flags |= D_HEADER;
1.19 millert 190: strlcpy(path1 + plen1, dp->d_name, MAXPATHLEN - plen1);
191: if (stat(path1, &stb1) != 0) {
1.20 millert 192: if (!(Nflag || Pflag) || errno != ENOENT) {
1.19 millert 193: warn("%s", path1);
194: return;
1.1 deraadt 195: }
1.19 millert 196: flags |= D_EMPTY1;
197: memset(&stb1, 0, sizeof(stb1));
1.1 deraadt 198: }
199:
1.19 millert 200: strlcpy(path2 + plen2, dp->d_name, MAXPATHLEN - plen2);
201: if (stat(path2, &stb2) != 0) {
202: if (!Nflag || errno != ENOENT) {
203: warn("%s", path2);
204: return;
205: }
206: flags |= D_EMPTY2;
207: memset(&stb2, 0, sizeof(stb2));
208: stb2.st_mode = stb1.st_mode;
209: }
210: if (stb1.st_mode == 0)
211: stb1.st_mode = stb2.st_mode;
212:
213: if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) {
1.20 millert 214: if (rflag)
1.33 ray 215: diffdir(path1, path2, flags);
1.22 millert 216: else if (lflag)
217: dp->d_status |= D_COMMON;
1.24 millert 218: else
1.19 millert 219: printf("Common subdirectories: %s and %s\n",
220: path1, path2);
221: return;
1.1 deraadt 222: }
1.27 millert 223: if (!S_ISREG(stb1.st_mode) && !S_ISDIR(stb1.st_mode))
224: dp->d_status = D_SKIPPED1;
225: else if (!S_ISREG(stb2.st_mode) && !S_ISDIR(stb2.st_mode))
226: dp->d_status = D_SKIPPED2;
227: else
228: dp->d_status = diffreg(path1, path2, flags);
1.23 millert 229: if (!lflag)
1.36 ray 230: print_status(dp->d_status, path1, path2, "");
1.1 deraadt 231: }
232:
1.19 millert 233: /*
1.39 ! millert 234: * Returns 1 if the directory entry should be included in the
! 235: * diff, else 0. Checks the excludes list.
1.19 millert 236: */
237: static int
1.39 ! millert 238: selectfile(struct dirent *dp)
1.1 deraadt 239: {
1.19 millert 240: struct excludes *excl;
1.15 tedu 241:
1.39 ! millert 242: if (dp->d_fileno == 0)
! 243: return (0);
! 244:
1.19 millert 245: /* always skip "." and ".." */
1.39 ! millert 246: if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
! 247: (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
! 248: return (0);
1.1 deraadt 249:
1.19 millert 250: /* check excludes list */
251: for (excl = excludes_list; excl != NULL; excl = excl->next)
1.39 ! millert 252: if (fnmatch(excl->pattern, dp->d_name, FNM_PATHNAME) == 0)
! 253: return (0);
1.1 deraadt 254:
1.39 ! millert 255: return (1);
1.1 deraadt 256: }