+/* Perform a custom action for this holding element (disk, dir, file, chunk).
+ *
+ * If the element is not cruft, the next step into the tree will only take place
+ * if this function returns a nonzero value.
+ *
+ * The walk is depth-first, with the callback for an element invoked
+ * before entering that element. Callbacks may depend on this behavior.
+ *
+ * @param datap: generic user-data pointer
+ * @param base: the parent of the element being examined, or NULL for
+ * holding disks
+ * @param element: the name of the element being examined
+ * @param fqpath: fully qualified path to 'element'
+ * @param is_cruft: nonzero if this element doesn't belong here
+ * @returns: nonzero if the walk should descend into this element.
+ */
+typedef int (*holding_walk_fn)(
+ gpointer datap,
+ char *base,
+ char *element,
+ char *fqpath,
+ int is_cruft);
+
+typedef enum {
+ STOP_AT_DISK,
+ STOP_AT_DIR,
+ STOP_AT_FILE,
+ STOP_AT_CHUNK
+} stop_at_t;
+
+/* Recurse over all holding chunks in a holding file.
+ *
+ * Call per_chunk_fn for each chunk of the given file
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hfile: holding file to examine (fully qualified path)
+ * @param datap: generic user-data pointer
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void holding_walk_file(
+ char *hfile,
+ gpointer datap,
+ holding_walk_fn per_chunk_fn)
+{
+ dumpfile_t file;
+ char *filename = NULL;
+
+ /* Loop through all cont_filenames (subsequent chunks) */
+ filename = stralloc(hfile);
+ while (filename != NULL && filename[0] != '\0') {
+ int is_cruft = 0;
+
+ /* get the header to look for cont_filename */
+ if (!holding_file_get_dumpfile(filename, &file)) {
+ is_cruft = 1;
+ }
+
+ if (per_chunk_fn)
+ per_chunk_fn(datap,
+ hfile,
+ filename,
+ filename,
+ is_cruft);
+ amfree(filename);
+
+ /* and go on to the next chunk if this wasn't cruft */
+ if (!is_cruft)
+ filename = stralloc(file.cont_filename);
+ dumpfile_free_data(&file);
+ }
+
+ amfree(filename);
+}
+
+/* Recurse over all holding files in a holding directory.
+ *
+ * Call per_file_fn for each file, and so on, stopping at the level given by
+ * stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hdir: holding directory 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_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void holding_walk_dir(
+ char *hdir,
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)