+ if (per_file_fn)
+ proceed = per_file_fn(datap,
+ hdir,
+ workdir->d_name,
+ hfile,
+ is_cruft);
+ if (!is_cruft && proceed && stop_at != STOP_AT_FILE)
+ holding_walk_file(hfile,
+ datap,
+ per_chunk_fn);
+ dumpfile_free_data(&dumpf);
+ }
+
+ closedir(dir);
+ amfree(hfile);
+}
+
+/* Recurse over all holding directories in a holding disk.
+ *
+ * Call per_dir_fn for each dir, and so on, stopping at the level given by
+ * stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hdisk: holding disk to examine (fully qualified path)
+ * @param datap: generic user-data pointer
+ * @param stop_at: do not proceed beyond this level of the hierarchy
+ * @param per_dir_fn: function to call for each holding dir
+ * @param per_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void
+holding_walk_disk(
+ char *hdisk,
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_dir_fn,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)
+{
+ DIR *dir;
+ struct dirent *workdir;
+ char *hdir = NULL;
+ int proceed = 1;
+
+ if ((dir = opendir(hdisk)) == NULL) {
+ if (errno != ENOENT)
+ dbprintf(_("Warning: could not open holding disk %s: %s\n"),
+ hdisk, strerror(errno));
+ return;
+ }
+
+ while ((workdir = readdir(dir)) != NULL) {
+ int is_cruft = 0;
+
+ if (is_dot_or_dotdot(workdir->d_name))
+ continue; /* expected cruft */
+
+ hdir = newvstralloc(hdir,
+ hdisk, "/", workdir->d_name,
+ NULL);
+
+ /* detect cruft */
+ if (!is_dir(hdir)) {
+ is_cruft = 1;
+ } else if (!is_datestr(workdir->d_name)) {
+ /* EXT2/3 leave these in the root of each volume */
+ if (strcmp(workdir->d_name, "lost+found") == 0)
+ continue; /* expected cruft */
+ else
+ is_cruft = 1; /* unexpected */
+ }
+
+ if (per_dir_fn)
+ proceed = per_dir_fn(datap,
+ hdisk,
+ workdir->d_name,
+ hdir,
+ is_cruft);
+ if (!is_cruft && proceed && stop_at != STOP_AT_DIR)
+ holding_walk_dir(hdir,
+ datap,
+ stop_at,
+ per_file_fn,
+ per_chunk_fn);
+ }
+
+ closedir(dir);
+ amfree(hdir);
+}
+
+/* Recurse over all holding disks.
+ *
+ * Call per_disk_fn for each disk, per_dir_fn for each dir, and so on, stopping
+ * at the level given by stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param datap: generic user-data pointer
+ * @param stop_at: do not proceed beyond this level of the hierarchy
+ * @param per_disk_fn: function to call for each holding disk
+ * @param per_dir_fn: function to call for each holding dir
+ * @param per_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void
+holding_walk(
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_disk_fn,
+ holding_walk_fn per_dir_fn,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)
+{
+ holdingdisk_t *hdisk_conf;
+ char *hdisk;
+ int proceed = 1;
+
+ for (hdisk_conf = getconf_holdingdisks();
+ hdisk_conf != NULL;
+ hdisk_conf = holdingdisk_next(hdisk_conf)) {
+ int is_cruft = 0;
+
+ hdisk = holdingdisk_get_diskdir(hdisk_conf);
+ if (!is_dir(hdisk))
+ is_cruft = 1;
+
+ if (per_disk_fn)
+ proceed = per_disk_fn(datap,
+ NULL,
+ hdisk,
+ hdisk,
+ 0);
+ if (proceed && stop_at != STOP_AT_DISK)
+ holding_walk_disk(hdisk,
+ datap,
+ stop_at,
+ per_dir_fn,
+ per_file_fn,
+ per_chunk_fn);