]> git.saurik.com Git - apple/file_cmds.git/blame - mtree/compare.c
file_cmds-264.50.1.tar.gz
[apple/file_cmds.git] / mtree / compare.c
CommitLineData
44a7a5ab
A
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
864a4b6e 13 * 3. Neither the name of the University nor the names of its contributors
44a7a5ab
A
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
44a7a5ab 30#if 0
864a4b6e 31#ifndef lint
44a7a5ab 32static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
44a7a5ab 33#endif /* not lint */
864a4b6e
A
34#endif
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
44a7a5ab
A
37
38#include <sys/param.h>
39#include <sys/stat.h>
864a4b6e
A
40#include <sys/time.h>
41
440bd198
A
42#include <err.h>
43#include <errno.h>
44a7a5ab
A
44#include <fcntl.h>
45#include <fts.h>
4d0bb651 46#ifndef __APPLE__
864a4b6e 47#ifdef ENABLE_MD5
440bd198
A
48#include <md5.h>
49#endif
864a4b6e
A
50#ifdef ENABLE_RMD160
51#include <ripemd.h>
52#endif
53#ifdef ENABLE_SHA1
440bd198
A
54#include <sha.h>
55#endif
864a4b6e
A
56#ifdef ENABLE_SHA256
57#include <sha256.h>
440bd198 58#endif
4d0bb651 59#endif /* !__APPLE__ */
864a4b6e 60#include <stdint.h>
44a7a5ab
A
61#include <stdio.h>
62#include <time.h>
63#include <unistd.h>
864a4b6e
A
64#include <vis.h>
65
44a7a5ab
A
66#include "mtree.h"
67#include "extern.h"
68
4d0bb651
A
69#ifdef __APPLE__
70#include "commoncrypto.h"
71#endif /* __APPLE__ */
72
44a7a5ab
A
73#define INDENTNAMELEN 8
74#define LABEL \
75 if (!label++) { \
440bd198
A
76 len = printf("%s changed\n", RP(p)); \
77 tab = "\t"; \
44a7a5ab
A
78 }
79
80int
864a4b6e 81compare(char *name __unused, NODE *s, FTSENT *p)
44a7a5ab 82{
864a4b6e
A
83 struct timeval tv[2];
84 uint32_t val;
44a7a5ab 85 int fd, label;
864a4b6e
A
86 off_t len;
87 char *cp;
88 const char *tab = "";
e0055cbe
A
89 char *fflags, *badflags;
90 u_long flags;
44a7a5ab 91
44a7a5ab
A
92 label = 0;
93 switch(s->type) {
94 case F_BLOCK:
95 if (!S_ISBLK(p->fts_statp->st_mode))
96 goto typeerr;
97 break;
98 case F_CHAR:
99 if (!S_ISCHR(p->fts_statp->st_mode))
100 goto typeerr;
101 break;
102 case F_DIR:
103 if (!S_ISDIR(p->fts_statp->st_mode))
104 goto typeerr;
105 break;
106 case F_FIFO:
107 if (!S_ISFIFO(p->fts_statp->st_mode))
108 goto typeerr;
109 break;
110 case F_FILE:
111 if (!S_ISREG(p->fts_statp->st_mode))
112 goto typeerr;
113 break;
114 case F_LINK:
115 if (!S_ISLNK(p->fts_statp->st_mode))
116 goto typeerr;
117 break;
118 case F_SOCK:
119 if (!S_ISSOCK(p->fts_statp->st_mode)) {
120typeerr: LABEL;
440bd198 121 (void)printf("\ttype expected %s found %s\n",
44a7a5ab 122 ftype(s->type), inotype(p->fts_statp->st_mode));
440bd198 123 return (label);
44a7a5ab
A
124 }
125 break;
126 }
127 /* Set the uid/gid first, then set the mode. */
128 if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
129 LABEL;
440bd198
A
130 (void)printf("%suser expected %lu found %lu",
131 tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
44a7a5ab
A
132 if (uflag)
133 if (chown(p->fts_accpath, s->st_uid, -1))
440bd198 134 (void)printf(" not modified: %s\n",
44a7a5ab
A
135 strerror(errno));
136 else
440bd198 137 (void)printf(" modified\n");
44a7a5ab 138 else
440bd198 139 (void)printf("\n");
44a7a5ab
A
140 tab = "\t";
141 }
142 if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
143 LABEL;
440bd198
A
144 (void)printf("%sgid expected %lu found %lu",
145 tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
44a7a5ab
A
146 if (uflag)
147 if (chown(p->fts_accpath, -1, s->st_gid))
440bd198 148 (void)printf(" not modified: %s\n",
44a7a5ab
A
149 strerror(errno));
150 else
440bd198 151 (void)printf(" modified\n");
44a7a5ab 152 else
440bd198 153 (void)printf("\n");
44a7a5ab
A
154 tab = "\t";
155 }
156 if (s->flags & F_MODE &&
440bd198 157 !S_ISLNK(p->fts_statp->st_mode) &&
44a7a5ab
A
158 s->st_mode != (p->fts_statp->st_mode & MBITS)) {
159 LABEL;
440bd198 160 (void)printf("%spermissions expected %#o found %#o",
44a7a5ab
A
161 tab, s->st_mode, p->fts_statp->st_mode & MBITS);
162 if (uflag)
163 if (chmod(p->fts_accpath, s->st_mode))
440bd198 164 (void)printf(" not modified: %s\n",
44a7a5ab
A
165 strerror(errno));
166 else
440bd198 167 (void)printf(" modified\n");
44a7a5ab 168 else
440bd198 169 (void)printf("\n");
44a7a5ab
A
170 tab = "\t";
171 }
172 if (s->flags & F_NLINK && s->type != F_DIR &&
173 s->st_nlink != p->fts_statp->st_nlink) {
174 LABEL;
440bd198 175 (void)printf("%slink_count expected %u found %u\n",
44a7a5ab
A
176 tab, s->st_nlink, p->fts_statp->st_nlink);
177 tab = "\t";
178 }
440bd198
A
179 if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
180 !S_ISDIR(p->fts_statp->st_mode)) {
44a7a5ab 181 LABEL;
864a4b6e
A
182 (void)printf("%ssize expected %jd found %jd\n", tab,
183 (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
44a7a5ab
A
184 tab = "\t";
185 }
440bd198
A
186 if ((s->flags & F_TIME) &&
187 ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
188 (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
189 LABEL;
e0055cbe
A
190 (void)printf("%smodification time expected %.24s.%09ld ",
191 tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
192 (void)printf("found %.24s.%09ld",
193 ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
864a4b6e
A
194 if (uflag) {
195 tv[0].tv_sec = s->st_mtimespec.tv_sec;
196 tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
197 tv[1] = tv[0];
198 if (utimes(p->fts_accpath, tv))
199 (void)printf(" not modified: %s\n",
200 strerror(errno));
201 else
202 (void)printf(" modified\n");
203 } else
204 (void)printf("\n");
440bd198 205 tab = "\t";
44a7a5ab
A
206 }
207 if (s->flags & F_CKSUM) {
208 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
209 LABEL;
210 (void)printf("%scksum: %s: %s\n",
211 tab, p->fts_accpath, strerror(errno));
212 tab = "\t";
213 } else if (crc(fd, &val, &len)) {
214 (void)close(fd);
215 LABEL;
216 (void)printf("%scksum: %s: %s\n",
217 tab, p->fts_accpath, strerror(errno));
218 tab = "\t";
219 } else {
220 (void)close(fd);
221 if (s->cksum != val) {
222 LABEL;
440bd198 223 (void)printf("%scksum expected %lu found %lu\n",
864a4b6e
A
224 tab, s->cksum, (unsigned long)val);
225 tab = "\t";
44a7a5ab 226 }
44a7a5ab
A
227 }
228 }
e0055cbe
A
229 if (s->flags & F_FLAGS) {
230 // There are unpublished flags that should not fail comparison
231 // we convert to string and back to filter them out
232 fflags = badflags = flags_to_string(p->fts_statp->st_flags);
233 if (strcmp("none", fflags) == 0) {
234 flags = 0;
235 } else if (strtofflags(&badflags, &flags, NULL) != 0)
236 errx(1, "invalid flag %s", badflags);
440bd198 237 free(fflags);
e0055cbe
A
238 if (s->st_flags != flags) {
239 LABEL;
240 fflags = flags_to_string(s->st_flags);
241 (void)printf("%sflags expected \"%s\"", tab, fflags);
242 free(fflags);
243
244 fflags = flags_to_string(flags);
245 (void)printf(" found \"%s\"", fflags);
246 free(fflags);
247
248 if (uflag)
249 if (chflags(p->fts_accpath, (u_int)s->st_flags))
250 (void)printf(" not modified: %s\n",
251 strerror(errno));
252 else
253 (void)printf(" modified\n");
254 else
255 (void)printf("\n");
256 tab = "\t";
257 }
440bd198 258 }
864a4b6e 259#ifdef ENABLE_MD5
440bd198
A
260 if (s->flags & F_MD5) {
261 char *new_digest, buf[33];
262
263 new_digest = MD5File(p->fts_accpath, buf);
264 if (!new_digest) {
265 LABEL;
266 printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
267 strerror(errno));
268 tab = "\t";
269 } else if (strcmp(new_digest, s->md5digest)) {
270 LABEL;
271 printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
272 new_digest);
273 tab = "\t";
274 }
275 }
864a4b6e
A
276#endif /* ENABLE_MD5 */
277#ifdef ENABLE_SHA1
440bd198
A
278 if (s->flags & F_SHA1) {
279 char *new_digest, buf[41];
280
281 new_digest = SHA1_File(p->fts_accpath, buf);
282 if (!new_digest) {
283 LABEL;
284 printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
285 strerror(errno));
286 tab = "\t";
287 } else if (strcmp(new_digest, s->sha1digest)) {
288 LABEL;
864a4b6e 289 printf("%sSHA-1 expected %s found %s\n",
440bd198
A
290 tab, s->sha1digest, new_digest);
291 tab = "\t";
292 }
293 }
864a4b6e
A
294#endif /* ENABLE_SHA1 */
295#ifdef ENABLE_RMD160
440bd198
A
296 if (s->flags & F_RMD160) {
297 char *new_digest, buf[41];
298
299 new_digest = RIPEMD160_File(p->fts_accpath, buf);
300 if (!new_digest) {
301 LABEL;
302 printf("%sRIPEMD160: %s: %s\n", tab,
303 p->fts_accpath, strerror(errno));
304 tab = "\t";
305 } else if (strcmp(new_digest, s->rmd160digest)) {
306 LABEL;
307 printf("%sRIPEMD160 expected %s found %s\n",
308 tab, s->rmd160digest, new_digest);
309 tab = "\t";
310 }
311 }
864a4b6e
A
312#endif /* ENABLE_RMD160 */
313#ifdef ENABLE_SHA256
314 if (s->flags & F_SHA256) {
e0055cbe 315 char *new_digest, buf[kSHA256NullTerminatedBuffLen];
864a4b6e
A
316
317 new_digest = SHA256_File(p->fts_accpath, buf);
318 if (!new_digest) {
319 LABEL;
320 printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
321 strerror(errno));
322 tab = "\t";
323 } else if (strcmp(new_digest, s->sha256digest)) {
324 LABEL;
325 printf("%sSHA-256 expected %s found %s\n",
326 tab, s->sha256digest, new_digest);
327 tab = "\t";
328 }
329 }
330#endif /* ENABLE_SHA256 */
440bd198
A
331
332 if (s->flags & F_SLINK &&
333 strcmp(cp = rlink(p->fts_accpath), s->slink)) {
44a7a5ab 334 LABEL;
440bd198 335 (void)printf("%slink_ref expected %s found %s\n",
864a4b6e 336 tab, s->slink, cp);
44a7a5ab 337 }
e0055cbe
A
338 if ((s->flags & F_BTIME) &&
339 ((s->st_birthtimespec.tv_sec != p->fts_statp->st_birthtimespec.tv_sec) ||
340 (s->st_birthtimespec.tv_nsec != p->fts_statp->st_birthtimespec.tv_nsec))) {
341 LABEL;
342 (void)printf("%sbirth time expected %.24s.%09ld ",
343 tab, ctime(&s->st_birthtimespec.tv_sec), s->st_birthtimespec.tv_nsec);
344 (void)printf("found %.24s.%09ld\n",
345 ctime(&p->fts_statp->st_birthtimespec.tv_sec), p->fts_statp->st_birthtimespec.tv_nsec);
346 tab = "\t";
347 }
348 if ((s->flags & F_ATIME) &&
349 ((s->st_atimespec.tv_sec != p->fts_statp->st_atimespec.tv_sec) ||
350 (s->st_atimespec.tv_nsec != p->fts_statp->st_atimespec.tv_nsec))) {
351 LABEL;
352 (void)printf("%saccess time expected %.24s.%09ld ",
353 tab, ctime(&s->st_atimespec.tv_sec), s->st_atimespec.tv_nsec);
354 (void)printf("found %.24s.%09ld\n",
355 ctime(&p->fts_statp->st_atimespec.tv_sec), p->fts_statp->st_atimespec.tv_nsec);
356 tab = "\t";
357 }
358 if ((s->flags & F_CTIME) &&
359 ((s->st_ctimespec.tv_sec != p->fts_statp->st_ctimespec.tv_sec) ||
360 (s->st_ctimespec.tv_nsec != p->fts_statp->st_ctimespec.tv_nsec))) {
361 LABEL;
362 (void)printf("%smetadata modification time expected %.24s.%09ld ",
363 tab, ctime(&s->st_ctimespec.tv_sec), s->st_ctimespec.tv_nsec);
364 (void)printf("found %.24s.%09ld\n",
365 ctime(&p->fts_statp->st_ctimespec.tv_sec), p->fts_statp->st_ctimespec.tv_nsec);
366 tab = "\t";
367 }
368 if (s->flags & F_PTIME) {
369 int supported;
370 struct timespec ptimespec = ptime(p->fts_accpath, &supported);
371 if (!supported) {
372 LABEL;
373 (void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n",
374 tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
375 tab = "\t";
376 } else if ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
377 (s->st_ptimespec.tv_nsec != ptimespec.tv_nsec)) {
378 LABEL;
379 (void)printf("%stime added to parent folder expected %.24s.%09ld ",
380 tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
381 (void)printf("found %.24s.%09ld\n",
382 ctime(&ptimespec.tv_sec), ptimespec.tv_nsec);
383 tab = "\t";
384 }
385 }
386 if (s->flags & F_XATTRS) {
387 char *new_digest, buf[kSHA256NullTerminatedBuffLen];
388 new_digest = SHA256_Path_XATTRs(p->fts_accpath, buf);
389 if (!new_digest) {
390 LABEL;
391 printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
392 tab = "\t";
393 } else if (strcmp(new_digest, s->xattrsdigest)) {
394 LABEL;
395 printf("%sxattrsdigest expected %s found %s\n",
396 tab, s->xattrsdigest, new_digest);
397 tab = "\t";
398 }
399 }
400 if ((s->flags & F_INODE) &&
401 (p->fts_statp->st_ino != s->st_ino)) {
402 LABEL;
403 (void)printf("%sinode expected %llu found %llu\n",
404 tab, s->st_ino, p->fts_ino);
405 tab = "\t";
406 }
407 if (s->flags & F_ACL) {
408 char *new_digest, buf[kSHA256NullTerminatedBuffLen];
409 new_digest = SHA256_Path_ACL(p->fts_accpath, buf);
410 if (!new_digest) {
411 LABEL;
412 printf("%sacldigest missing, expected: %s\n", tab, s->acldigest);
413 tab = "\t";
414 } else if (strcmp(new_digest, s->acldigest)) {
415 LABEL;
416 printf("%sacldigest expected %s found %s\n",
417 tab, s->acldigest, new_digest);
418 tab = "\t";
419 }
420 }
421
44a7a5ab
A
422 return (label);
423}
424
864a4b6e
A
425const char *
426inotype(u_int type)
44a7a5ab
A
427{
428 switch(type & S_IFMT) {
429 case S_IFBLK:
430 return ("block");
431 case S_IFCHR:
432 return ("char");
433 case S_IFDIR:
434 return ("dir");
435 case S_IFIFO:
436 return ("fifo");
437 case S_IFREG:
438 return ("file");
439 case S_IFLNK:
440 return ("link");
441 case S_IFSOCK:
442 return ("socket");
443 default:
444 return ("unknown");
445 }
446 /* NOTREACHED */
447}
448
864a4b6e
A
449const char *
450ftype(u_int type)
44a7a5ab
A
451{
452 switch(type) {
453 case F_BLOCK:
454 return ("block");
455 case F_CHAR:
456 return ("char");
457 case F_DIR:
458 return ("dir");
459 case F_FIFO:
460 return ("fifo");
461 case F_FILE:
462 return ("file");
463 case F_LINK:
464 return ("link");
465 case F_SOCK:
466 return ("socket");
467 default:
468 return ("unknown");
469 }
470 /* NOTREACHED */
471}
472
473char *
864a4b6e 474rlink(char *name)
44a7a5ab 475{
00337e45 476 static char lbuf[MAXPATHLEN];
4d0bb651 477 ssize_t len;
44a7a5ab 478
00337e45 479 if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
440bd198 480 err(1, "line %d: %s", lineno, name);
00337e45 481 lbuf[len] = '\0';
44a7a5ab
A
482 return (lbuf);
483}