+struct hardlink {
+ dev_t dev;
+ ino_t ino;
+ char path[1];
+};
+static void *hardlinks;
+
+static int hardlink_compar(const void *av, const void *bv) {
+ const struct hardlink *a=av, *b=bv;
+ if (a->ino != b->ino) return b->ino - a->ino;
+ return b->dev - a->dev;
+}
+
+static void recurse(const char *path, unsigned nodeflags, dev_t fs);
+
+static void node(const char *path, unsigned nodeflags, dev_t fs) {
+ char linktarg[MAXFN+1];
+ struct hardlink *foundhl;
+ const struct stat *stab;
+ struct stat stabuf;
+ int r, mountpoint=0;
+
+ r= lstat(path, &stabuf);
+ stab= r ? 0 : &stabuf;
+
+ foundhl= 0;
+ if (stab && stab->st_nlink>1) {
+ struct hardlink *newhl, **foundhl_node;
+ newhl= mmalloc(sizeof(*newhl) + strlen(path));
+ newhl->dev= stab->st_dev;
+ newhl->ino= stab->st_ino;
+ foundhl_node= tsearch(newhl, &hardlinks, hardlink_compar);
+ if (!foundhl_node) malloc_fail();
+ foundhl= *foundhl_node;
+ if (foundhl!=newhl) {
+ free(newhl); /* hardlink to an earlier object */
+ } else {
+ foundhl= 0; /* new object with link count>1 */
+ strcpy(newhl->path, path);
+ }
+ }
+
+ if (stab) {
+ if ((nodeflags & nodeflag_fsvalid) && stab->st_dev != fs)
+ mountpoint= 1;
+ fs= stab->st_dev;
+ nodeflags |= nodeflag_fsvalid;
+ }
+
+ if (!stab) problem_e(path,CSUMXL,"inaccessible");
+ else if (foundhl) csum_str("hardlink");
+ else if (S_ISREG(stab->st_mode)) csum_file(path);
+ else if (S_ISCHR(stab->st_mode)) csum_dev('c',stab);
+ else if (S_ISBLK(stab->st_mode)) csum_dev('b',stab);
+ else if (S_ISFIFO(stab->st_mode)) csum_str("pipe");
+ else if (S_ISLNK(stab->st_mode)) csum_str("symlink");
+ else if (S_ISSOCK(stab->st_mode)) csum_str("sock");
+ else if (S_ISDIR(stab->st_mode)) csum_str(mountpoint ? "mountpoint" : "dir");
+ else problem(path,CSUMXL,"badobj: 0x%lx", (unsigned long)stab->st_mode);
+
+ if (stab && S_ISLNK(stab->st_mode)) {