+/* --- @fhash_junk@ --- *
+ *
+ * Arguments: @fhashstate *fh@ = pointer to fhash state
+ * @void (*func)(const char *, const struct stat *, void *)@
+ * @void *p@ = pointer to pass to function
+ *
+ * Returns: Positive if any junk was found, negative on error, zero if
+ * everything was fine.
+ *
+ * Use: Reports junk files in any directories covered by the hash
+ * state.
+ */
+
+struct fhjunk {
+ int (*func)(const char *, const struct stat *, void *);
+ void *p;
+ dstr *d;
+};
+
+static int fhjunk(struct fhjunk *fhj, struct fhent *ents)
+{
+ DIR *dp;
+ int rc = 0, rrc;
+ struct stat st;
+ struct dirent *d;
+ const char *dname;
+ size_t n = fhj->d->len;
+ struct fhent *fhe;
+
+ dname = n ? fhj->d->buf : ".";
+ if ((dp = opendir(dname)) == 0) {
+ moan("failed to open directory `%s': %s", dname, strerror(errno));
+ rc = -1;
+ goto subs;
+ }
+ if (n) {
+ dstr_putc(fhj->d, '/');
+ n++;
+ }
+ while (errno = 0, (d = readdir(dp)) != 0) {
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
+ continue;
+ for (fhe = ents; fhe; fhe = fhe->next) {
+ if (strcmp(d->d_name, fhe->name) == 0) goto found;
+ }
+ fhj->d->len = n;
+ dstr_puts(fhj->d, d->d_name);
+ if (!lstat(fhj->d->buf, &st)) {
+ if (!rc) rc = 1;
+ rrc = fhj->func(fhj->d->buf, &st, fhj->p);
+ } else {
+ rc = -1;
+ rrc = fhj->func(fhj->d->buf, 0, fhj->p);
+ }
+ if (rrc < 0) rc = -1;
+ found:;
+ }
+ closedir(dp);
+ if (errno) {
+ moan("failed to read directory `%s': %s", dname, strerror(errno));
+ rc = -1;
+ }
+
+subs:
+ for (fhe = ents; fhe; fhe = fhe->next) {
+ if (fhe->ty == FHETY_DIR) {
+ fhj->d->len = n;
+ dstr_puts(fhj->d, fhe->name);
+ rrc = fhjunk(fhj, fhe->sub);
+ if (rrc < 0) rc = -1;
+ else if (!rc) rc = rrc;
+ }
+ }
+
+ return (rc);
+}
+
+int fhash_junk(fhashstate *fh,
+ int (*func)(const char *, const struct stat *, void *),
+ void *p)
+{
+ dstr d = DSTR_INIT;
+ struct fhjunk fhj;
+ int rc;
+
+ fhj.func = func;
+ fhj.p = p;
+ fhj.d = &d;
+ rc = fhjunk(&fhj, fh->ents);
+ dstr_destroy(&d);
+ return (rc);
+}
+