+static char file_type (TSK_FS_FILE *fsfile);
+static int send_dirent_info (guestfs_int_tsk_dirent *dirent);
+static void reply_with_tsk_error (const char *funcname);
+
+int
+do_internal_filesystem_walk (const mountable_t *mountable)
+{
+ int ret = -1;
+ TSK_FS_INFO *fs = NULL;
+ TSK_IMG_INFO *img = NULL; /* Used internally by tsk_fs_dir_walk */
+ int flags = TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC
|
+ TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN;
+
+ ret = open_filesystem (mountable->device, &img, &fs);
+ if (ret < 0)
+ return ret;
+
+ reply (NULL, NULL); /* Reply message. */
+
+ ret = tsk_fs_dir_walk (fs, fs->root_inum, flags, fswalk_callback,
NULL);
+ if (ret == 0)
+ ret = send_file_end (0); /* File transfer end. */
+ else
+ send_file_end (1); /* Cancel file transfer. */
+
+ fs->close (fs);
+ img->close (img);
+
+ return ret;
+}
+
+/* Inspect the device and initialises the img and fs structures.
+ * Return 0 on success, -1 on error.
+ */
+static int
+open_filesystem (const char *device, TSK_IMG_INFO **img, TSK_FS_INFO
**fs)
+{
+ const char *images[] = { device };
+
+ *img = tsk_img_open (1, images, TSK_IMG_TYPE_DETECT , 0);
+ if (*img == NULL) {
+ reply_with_tsk_error ("tsk_image_open");
+ return -1;
+ }
+
+ *fs = tsk_fs_open_img (*img, 0, TSK_FS_TYPE_DETECT);
+ if (*fs == NULL) {
+ reply_with_tsk_error ("tsk_fs_open_img");
+ (*img)->close (*img);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Filesystem walk callback, it gets called on every FS node.
+ * Parse the node, encode it into an XDR structure and send it to the
appliance.
+ * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error.
+ */
+static TSK_WALK_RET_ENUM
+fswalk_callback (TSK_FS_FILE *fsfile, const char *path, void *data)
+{
+ int ret = 0;
+ CLEANUP_FREE char *fname = NULL;
+ struct guestfs_int_tsk_dirent dirent;
+
+ /* Ignore ./ and ../ */
+ ret = TSK_FS_ISDOT (fsfile->name->name);
+ if (ret != 0)
+ return TSK_WALK_CONT;
+
+ /* Build the full relative path of the entry */
+ ret = asprintf_nowarn (&fname, "%Q%Q", path, fsfile->name->name);
Why the quoting? We don't quote results in similar APIs (e.g. readdir).