Index: uspace/app/meson.build
===================================================================
--- uspace/app/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/meson.build	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -103,4 +103,5 @@
 	'usbinfo',
 	'viewer',
+	'verify',
 	'vol',
 	'vuhid',
Index: uspace/app/nav/dlg/progress.c
===================================================================
--- uspace/app/nav/dlg/progress.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/dlg/progress.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -134,8 +134,35 @@
 	/* FIXME: Auto layout */
 	if (ui_is_textmode(ui)) {
-		rect.p0.x = 3;
+		rect.p0.x = 1;
 		rect.p0.y = 2;
-		rect.p1.x = 47;
+		rect.p1.x = 49;
 		rect.p1.y = 3;
+	} else {
+		rect.p0.x = 10;
+		rect.p0.y = 35;
+		rect.p1.x = 390;
+		rect.p1.y = 50;
+	}
+
+	ui_label_set_rect(label, &rect);
+	ui_label_set_halign(label, gfx_halign_center);
+
+	rc = ui_fixed_add(fixed, ui_label_ctl(label));
+	if (rc != EOK)
+		goto error;
+
+	dialog->ltotal_prog = label;
+	label = NULL;
+
+	rc = ui_label_create(ui_res, "XXX of XXX (XXX%)", &label);
+	if (rc != EOK)
+		goto error;
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 1;
+		rect.p0.y = 4;
+		rect.p1.x = 49;
+		rect.p1.y = 5;
 	} else {
 		rect.p0.x = 10;
@@ -240,17 +267,38 @@
  *
  * @param dialog Progress dialog
- * @param text New text for current file progress
+ * @param progress Progress
  *
  * @return EOK on success or an error code
  */
-errno_t progress_dlg_set_curf_prog(progress_dlg_t *dialog, const char *text)
-{
+errno_t progress_dlg_set_progress(progress_dlg_t *dialog,
+    fmgt_progress_t *progress)
+{
+	char buf[128];
 	errno_t rc;
 
-	rc = ui_label_set_text(dialog->lcurf_prog, text);
+	snprintf(buf, sizeof(buf), "Total: %s files, %s.",
+	    progress->total_procf, progress->total_procb);
+
+	rc = ui_label_set_text(dialog->ltotal_prog, buf);
 	if (rc != EOK)
 		return rc;
 
-	return ui_label_paint(dialog->lcurf_prog);
+	rc = ui_label_paint(dialog->ltotal_prog);
+	if (rc != EOK)
+		return rc;
+
+	snprintf(buf, sizeof(buf), "Current file: %s of %s (%s done).",
+	    progress->curf_procb, progress->curf_totalb,
+	    progress->curf_percent);
+
+	rc = ui_label_set_text(dialog->lcurf_prog, buf);
+	if (rc != EOK)
+		return rc;
+
+	rc = ui_label_paint(dialog->lcurf_prog);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
 }
 
Index: uspace/app/nav/dlg/progress.h
===================================================================
--- uspace/app/nav/dlg/progress.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/dlg/progress.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -38,4 +38,5 @@
 
 #include <errno.h>
+#include <fmgt.h>
 #include <types/ui/ui.h>
 #include "../types/dlg/progress.h"
@@ -46,5 +47,5 @@
 extern void progress_dlg_set_cb(progress_dlg_t *, progress_dlg_cb_t *,
     void *);
-extern errno_t progress_dlg_set_curf_prog(progress_dlg_t *, const char *);
+extern errno_t progress_dlg_set_progress(progress_dlg_t *, fmgt_progress_t *);
 extern void progress_dlg_destroy(progress_dlg_t *);
 
Index: uspace/app/nav/dlg/verifydlg.c
===================================================================
--- uspace/app/nav/dlg/verifydlg.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/dlg/verifydlg.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Verify dialog
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <mem.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <ui/fixed.h>
+#include <ui/label.h>
+#include <ui/pbutton.h>
+#include <ui/resource.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+#include "verifydlg.h"
+
+static void verify_dlg_wnd_close(ui_window_t *, void *);
+static void verify_dlg_wnd_kbd(ui_window_t *, void *, kbd_event_t *);
+
+ui_window_cb_t verify_dlg_wnd_cb = {
+	.close = verify_dlg_wnd_close,
+	.kbd = verify_dlg_wnd_kbd
+};
+
+static void verify_dlg_bok_clicked(ui_pbutton_t *, void *);
+static void verify_dlg_bcancel_clicked(ui_pbutton_t *, void *);
+
+ui_pbutton_cb_t verify_dlg_bok_cb = {
+	.clicked = verify_dlg_bok_clicked
+};
+
+ui_pbutton_cb_t verify_dlg_bcancel_cb = {
+	.clicked = verify_dlg_bcancel_clicked
+};
+
+/** Create Verify dialog.
+ *
+ * @param ui User interface
+ * @param flist List of files to verify (ownership transferred)
+ * @param rdialog Place to store pointer to new dialog
+ * @return EOK on success or an error code
+ */
+errno_t verify_dlg_create(ui_t *ui, fmgt_flist_t *flist,
+    verify_dlg_t **rdialog)
+{
+	errno_t rc;
+	verify_dlg_t *dialog;
+	ui_window_t *window = NULL;
+	ui_wnd_params_t wparams;
+	ui_fixed_t *fixed = NULL;
+	ui_label_t *label = NULL;
+	ui_pbutton_t *bok = NULL;
+	ui_pbutton_t *bcancel = NULL;
+	gfx_rect_t rect;
+	ui_resource_t *ui_res;
+	fmgt_flist_entry_t *entry;
+	char *tverify = NULL;
+	unsigned count;
+
+	dialog = calloc(1, sizeof(verify_dlg_t));
+	if (dialog == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	ui_wnd_params_init(&wparams);
+	wparams.caption = "Verify";
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 40;
+		wparams.rect.p1.y = 9;
+	} else {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 300;
+		wparams.rect.p1.y = 155;
+	}
+
+	rc = ui_window_create(ui, &wparams, &window);
+	if (rc != EOK)
+		goto error;
+
+	ui_window_set_cb(window, &verify_dlg_wnd_cb, dialog);
+
+	ui_res = ui_window_get_res(window);
+
+	rc = ui_fixed_create(&fixed);
+	if (rc != EOK)
+		goto error;
+
+	count = fmgt_flist_count(flist);
+	if (count == 1) {
+		entry = fmgt_flist_first(flist);
+		rc = asprintf(&tverify, "Verify \"%s\":",
+		    entry->fname);
+	} else {
+		rc = asprintf(&tverify, "Verify %u files/directories:",
+		    count);
+	}
+
+	rc = ui_label_create(ui_res, tverify, &label);
+	if (rc != EOK)
+		goto error;
+
+	free(tverify);
+	tverify = NULL;
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 3;
+		rect.p0.y = 2;
+		rect.p1.x = 17;
+		rect.p1.y = 3;
+	} else {
+		rect.p0.x = 10;
+		rect.p0.y = 35;
+		rect.p1.x = 190;
+		rect.p1.y = 50;
+	}
+
+	ui_label_set_rect(label, &rect);
+
+	rc = ui_fixed_add(fixed, ui_label_ctl(label));
+	if (rc != EOK)
+		goto error;
+
+	label = NULL;
+
+	rc = ui_pbutton_create(ui_res, "OK", &bok);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(bok, &verify_dlg_bok_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 10;
+		rect.p0.y = 6;
+		rect.p1.x = 20;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 55;
+		rect.p0.y = 120;
+		rect.p1.x = 145;
+		rect.p1.y = 148;
+	}
+
+	ui_pbutton_set_rect(bok, &rect);
+
+	ui_pbutton_set_default(bok, true);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(bok));
+	if (rc != EOK)
+		goto error;
+
+	dialog->bok = bok;
+	bok = NULL;
+
+	rc = ui_pbutton_create(ui_res, "Cancel", &bcancel);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(bcancel, &verify_dlg_bcancel_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 22;
+		rect.p0.y = 6;
+		rect.p1.x = 32;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 155;
+		rect.p0.y = 120;
+		rect.p1.x = 245;
+		rect.p1.y = 148;
+	}
+
+	ui_pbutton_set_rect(bcancel, &rect);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(bcancel));
+	if (rc != EOK)
+		goto error;
+
+	dialog->bcancel = bcancel;
+	bcancel = NULL;
+
+	ui_window_add(window, ui_fixed_ctl(fixed));
+	fixed = NULL;
+
+	rc = ui_window_paint(window);
+	if (rc != EOK)
+		goto error;
+
+	dialog->window = window;
+	dialog->flist = flist;
+	*rdialog = dialog;
+	return EOK;
+error:
+	if (tverify != NULL)
+		free(tverify);
+	if (bok != NULL)
+		ui_pbutton_destroy(bok);
+	if (bcancel != NULL)
+		ui_pbutton_destroy(bcancel);
+	if (label != NULL)
+		ui_label_destroy(label);
+	if (fixed != NULL)
+		ui_fixed_destroy(fixed);
+	if (window != NULL)
+		ui_window_destroy(window);
+	if (dialog != NULL)
+		free(dialog);
+	return rc;
+}
+
+/** Destroy new file dialog.
+ *
+ * @param dialog New file dialog or @c NULL
+ */
+void verify_dlg_destroy(verify_dlg_t *dialog)
+{
+	if (dialog == NULL)
+		return;
+
+	ui_window_destroy(dialog->window);
+	free(dialog);
+}
+
+/** Set new file dialog callback.
+ *
+ * @param dialog new file dialog
+ * @param cb New file dialog callbacks
+ * @param arg Callback argument
+ */
+void verify_dlg_set_cb(verify_dlg_t *dialog, verify_dlg_cb_t *cb,
+    void *arg)
+{
+	dialog->cb = cb;
+	dialog->arg = arg;
+}
+
+/** New file dialog window close handler.
+ *
+ * @param window Window
+ * @param arg Argument (verify_dlg_t *)
+ */
+static void verify_dlg_wnd_close(ui_window_t *window, void *arg)
+{
+	verify_dlg_t *dialog = (verify_dlg_t *) arg;
+
+	(void)window;
+	if (dialog->cb != NULL && dialog->cb->close != NULL) {
+		dialog->cb->close(dialog, dialog->arg);
+	}
+}
+
+/** New file dialog window keyboard event handler.
+ *
+ * @param window Window
+ * @param arg Argument (verify_dlg_t *)
+ * @param event Keyboard event
+ */
+static void verify_dlg_wnd_kbd(ui_window_t *window, void *arg,
+    kbd_event_t *event)
+{
+	verify_dlg_t *dialog = (verify_dlg_t *) arg;
+
+	if (event->type == KEY_PRESS &&
+	    (event->mods & (KM_CTRL | KM_SHIFT | KM_ALT)) == 0) {
+		if (event->key == KC_ENTER) {
+			/* Confirm */
+			if (dialog->cb != NULL && dialog->cb->bok != NULL) {
+				dialog->cb->bok(dialog, dialog->arg);
+				return;
+			}
+		} else if (event->key == KC_ESCAPE) {
+			/* Cancel */
+			if (dialog->cb != NULL && dialog->cb->bcancel != NULL) {
+				dialog->cb->bcancel(dialog, dialog->arg);
+				return;
+			}
+		}
+	}
+
+	ui_window_def_kbd(window, event);
+}
+
+/** New file dialog OK button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (verify_dlg_t *)
+ */
+static void verify_dlg_bok_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	verify_dlg_t *dialog = (verify_dlg_t *) arg;
+
+	if (dialog->cb != NULL && dialog->cb->bok != NULL) {
+		dialog->cb->bok(dialog, dialog->arg);
+	}
+}
+
+/** New file dialog cancel button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (verify_dlg_t *)
+ */
+static void verify_dlg_bcancel_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	verify_dlg_t *dialog = (verify_dlg_t *) arg;
+
+	(void)pbutton;
+	if (dialog->cb != NULL && dialog->cb->bcancel != NULL) {
+		dialog->cb->bcancel(dialog, dialog->arg);
+	}
+}
+
+/** @}
+ */
Index: uspace/app/nav/dlg/verifydlg.h
===================================================================
--- uspace/app/nav/dlg/verifydlg.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/dlg/verifydlg.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Verify dialog
+ */
+
+#ifndef DLG_VERIFYDLG_H
+#define DLG_VERIFYDLG_H
+
+#include <errno.h>
+#include <fmgt.h>
+#include <types/ui/ui.h>
+#include "../types/dlg/verifydlg.h"
+
+extern errno_t verify_dlg_create(ui_t *, fmgt_flist_t *, verify_dlg_t **);
+extern void verify_dlg_set_cb(verify_dlg_t *, verify_dlg_cb_t *,
+    void *);
+extern void verify_dlg_destroy(verify_dlg_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/menu.c
===================================================================
--- uspace/app/nav/menu.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/menu.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -57,4 +57,5 @@
 	ui_menu_entry_t *mopen;
 	ui_menu_entry_t *medit;
+	ui_menu_entry_t *mverify;
 	ui_menu_entry_t *mfsep;
 	ui_menu_entry_t *mexit;
@@ -97,4 +98,10 @@
 	ui_menu_entry_set_cb(medit, nav_menu_file_edit, (void *) menu);
 
+	rc = ui_menu_entry_create(mfile, "~V~erify", "Ctrl-V", &mverify);
+	if (rc != EOK)
+		goto error;
+
+	ui_menu_entry_set_cb(mverify, nav_menu_file_verify, (void *) menu);
+
 	rc = ui_menu_entry_sep_create(mfile, &mfsep);
 	if (rc != EOK)
@@ -194,4 +201,17 @@
 }
 
+/** File / Verify menu entry selected.
+ *
+ * @param mentry Menu entry
+ * @param arg Argument (navigator_t *)
+ */
+void nav_menu_file_verify(ui_menu_entry_t *mentry, void *arg)
+{
+	nav_menu_t *menu = (nav_menu_t *)arg;
+
+	if (menu->cb != NULL && menu->cb->file_verify != NULL)
+		menu->cb->file_verify(menu->cb_arg);
+}
+
 /** File / Exit menu entry selected.
  *
Index: uspace/app/nav/menu.h
===================================================================
--- uspace/app/nav/menu.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/menu.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -49,4 +49,5 @@
 extern void nav_menu_file_open(ui_menu_entry_t *, void *);
 extern void nav_menu_file_edit(ui_menu_entry_t *, void *);
+extern void nav_menu_file_verify(ui_menu_entry_t *, void *);
 extern void nav_menu_file_exit(ui_menu_entry_t *, void *);
 
Index: uspace/app/nav/meson.build
===================================================================
--- uspace/app/nav/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/meson.build	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -32,4 +32,5 @@
 	'dlg/newfiledlg.c',
 	'dlg/progress.c',
+	'dlg/verifydlg.c',
 	'main.c',
 	'menu.c',
@@ -37,4 +38,5 @@
 	'newfile.c',
 	'panel.c',
+	'verify.c',
 )
 
@@ -43,8 +45,10 @@
 	'dlg/newfiledlg.c',
 	'dlg/progress.c',
+	'dlg/verifydlg.c',
 	'menu.c',
 	'nav.c',
 	'newfile.c',
 	'panel.c',
+	'verify.c',
 	'test/main.c',
 	'test/menu.c',
Index: uspace/app/nav/nav.c
===================================================================
--- uspace/app/nav/nav.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/nav.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -53,4 +53,5 @@
 #include "nav.h"
 #include "panel.h"
+#include "verify.h"
 
 #define EDITOR_CMD "/app/edit"
@@ -67,4 +68,5 @@
 static void navigator_file_open(void *);
 static void navigator_file_edit(void *);
+static void navigator_file_verify(void *);
 static void navigator_file_exit(void *);
 
@@ -73,4 +75,5 @@
 	.file_open = navigator_file_open,
 	.file_edit = navigator_file_edit,
+	.file_verify = navigator_file_verify,
 	.file_exit = navigator_file_exit
 };
@@ -135,4 +138,7 @@
 			navigator_file_edit((void *)navigator);
 			break;
+		case KC_V:
+			navigator_file_verify((void *)navigator);
+			break;
 		case KC_Q:
 			ui_quit(navigator->ui);
@@ -526,4 +532,33 @@
 }
 
+/** File / Verify menu entry selected */
+static void navigator_file_verify(void *arg)
+{
+	navigator_t *navigator = (navigator_t *)arg;
+
+	ui_file_list_entry_t *entry;
+	ui_file_list_entry_attr_t attr;
+	fmgt_flist_t *flist;
+	panel_t *panel;
+	errno_t rc;
+
+	panel = navigator_get_active_panel(navigator);
+	entry = ui_file_list_get_cursor(panel->flist);
+	ui_file_list_entry_get_attr(entry, &attr);
+
+	rc = fmgt_flist_create(&flist);
+	if (rc != EOK)
+		return;
+
+	rc = fmgt_flist_append(flist, attr.name);
+	if (rc != EOK) {
+		fmgt_flist_destroy(flist);
+		return;
+	}
+
+	/* flist ownership transferred */
+	navigator_verify_dlg(navigator, flist);
+}
+
 /** File / Exit menu entry selected */
 static void navigator_file_exit(void *arg)
Index: uspace/app/nav/newfile.c
===================================================================
--- uspace/app/nav/newfile.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/newfile.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -259,10 +259,6 @@
 {
 	navigator_t *nav = (navigator_t *)arg;
-	char buf[128];
-
-	snprintf(buf, sizeof(buf), "Written %s of %s (%s done).",
-	    progress->curf_procb, progress->curf_totalb,
-	    progress->curf_percent);
-	progress_dlg_set_curf_prog(nav->progress_dlg, buf);
+
+	progress_dlg_set_progress(nav->progress_dlg, progress);
 }
 
Index: uspace/app/nav/types/dlg/progress.h
===================================================================
--- uspace/app/nav/types/dlg/progress.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/types/dlg/progress.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -46,4 +46,6 @@
 	/** Dialog window */
 	ui_window_t *window;
+	/** Label with total progress */
+	ui_label_t *ltotal_prog;
 	/** Label with current file progress */
 	ui_label_t *lcurf_prog;
Index: uspace/app/nav/types/dlg/verifydlg.h
===================================================================
--- uspace/app/nav/types/dlg/verifydlg.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/types/dlg/verifydlg.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Verify dialog
+ */
+
+#ifndef TYPES_DLG_VERIFYDLG_H
+#define TYPES_DLG_VERIFYDLG_H
+
+#include <errno.h>
+#include <fmgt.h>
+#include <ui/label.h>
+#include <ui/pbutton.h>
+#include <ui/window.h>
+#include <stdbool.h>
+
+/** Verify dialog */
+typedef struct verify_dlg {
+	/** Dialog window */
+	ui_window_t *window;
+	/** "Verify 'xxx'" */
+	ui_label_t *lverify;
+	/** OK button */
+	ui_pbutton_t *bok;
+	/** Cancel button */
+	ui_pbutton_t *bcancel;
+	/** Verify dialog callbacks */
+	struct verify_dlg_cb *cb;
+	/** Callback argument */
+	void *arg;
+	/** File list */
+	fmgt_flist_t *flist;
+} verify_dlg_t;
+
+/** Verify dialog callbacks */
+typedef struct verify_dlg_cb {
+	/** OK button was pressed */
+	void (*bok)(verify_dlg_t *, void *);
+	/** Cancel button was pressed */
+	void (*bcancel)(verify_dlg_t *, void *);
+	/** Window closure requested (e.g. via close button) */
+	void (*close)(verify_dlg_t *, void *);
+} verify_dlg_cb_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/types/menu.h
===================================================================
--- uspace/app/nav/types/menu.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/nav/types/menu.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -49,4 +49,6 @@
 	/** File / Edit */
 	void (*file_edit)(void *);
+	/** File / Verify */
+	void (*file_verify)(void *);
 	/** File / Exit */
 	void (*file_exit)(void *);
Index: uspace/app/nav/types/verify.h
===================================================================
--- uspace/app/nav/types/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/types/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Verify types
+ */
+
+#ifndef TYPES_VERIFY_H
+#define TYPES_VERIFY_H
+
+#include <fmgt.h>
+
+/** Navigator Verify job */
+typedef struct {
+	/** Navigator */
+	struct navigator *navigator;
+	/** File list */
+	fmgt_flist_t *flist;
+} navigator_verify_job_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/verify.c
===================================================================
--- uspace/app/nav/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Verify File.
+ */
+
+#include <fmgt.h>
+#include <stdlib.h>
+#include <str_error.h>
+#include <ui/fixed.h>
+#include <ui/filelist.h>
+#include <ui/msgdialog.h>
+#include <ui/resource.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+#include <stdbool.h>
+#include <str.h>
+#include "dlg/progress.h"
+#include "dlg/verifydlg.h"
+#include "menu.h"
+#include "nav.h"
+#include "types/verify.h"
+#include "verify.h"
+
+static void verify_bok(verify_dlg_t *, void *);
+static void verify_bcancel(verify_dlg_t *, void *);
+static void verify_close(verify_dlg_t *, void *);
+
+static verify_dlg_cb_t verify_cb = {
+	.bok = verify_bok,
+	.bcancel = verify_bcancel,
+	.close = verify_close
+};
+
+static bool verify_abort_query(void *);
+static void verify_progress(void *, fmgt_progress_t *);
+
+static fmgt_cb_t verify_fmgt_cb = {
+	.abort_query = verify_abort_query,
+	.io_error_query = navigator_io_error_query,
+	.progress = verify_progress,
+};
+
+/** Open Verify dialog.
+ *
+ * @param navigator Navigator
+ * @param flist File list
+ */
+void navigator_verify_dlg(navigator_t *navigator, fmgt_flist_t *flist)
+{
+	verify_dlg_t *dlg;
+	errno_t rc;
+
+	rc = verify_dlg_create(navigator->ui, flist, &dlg);
+	if (rc != EOK)
+		return;
+
+	verify_dlg_set_cb(dlg, &verify_cb, (void *)navigator);
+}
+
+/** Verify worker function.
+ *
+ * @param arg Argument (navigator_verify_job_t)
+ */
+static void verify_wfunc(void *arg)
+{
+	fmgt_t *fmgt = NULL;
+	navigator_verify_job_t *job = (navigator_verify_job_t *)arg;
+	char *msg = NULL;
+	navigator_t *nav = job->navigator;
+	ui_msg_dialog_t *dialog = NULL;
+	ui_msg_dialog_params_t params;
+	errno_t rc;
+	int rv;
+
+	rc = fmgt_create(&fmgt);
+	if (rc != EOK) {
+		/* out of memory */
+		return;
+	}
+
+	fmgt_set_cb(fmgt, &verify_fmgt_cb, (void *)nav);
+	fmgt_set_init_update(fmgt, true);
+
+	rc = fmgt_verify(fmgt, job->flist);
+	if (rc != EOK) {
+		rv = asprintf(&msg, "Error verifying file(s) (%s).",
+		    str_error(rc));
+		if (rv < 0)
+			return;
+		goto error;
+	}
+
+	fmgt_destroy(fmgt);
+	ui_lock(nav->ui);
+	progress_dlg_destroy(nav->progress_dlg);
+	navigator_refresh_panels(nav);
+	ui_unlock(nav->ui);
+	fmgt_flist_destroy(job->flist);
+	free(job);
+	return;
+error:
+	fmgt_destroy(fmgt);
+	ui_lock(nav->ui);
+	progress_dlg_destroy(nav->progress_dlg);
+	navigator_refresh_panels(nav);
+	ui_msg_dialog_params_init(&params);
+	params.caption = "Error";
+	params.text = msg;
+	(void) ui_msg_dialog_create(nav->ui, &params, &dialog);
+	ui_unlock(nav->ui);
+	free(msg);
+}
+
+/** Verify dialog confirmed.
+ *
+ * @param dlg Verify dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void verify_bok(verify_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+	ui_msg_dialog_t *dialog = NULL;
+	navigator_verify_job_t *job;
+	ui_msg_dialog_params_t params;
+	progress_dlg_params_t pd_params;
+	char *msg = NULL;
+	errno_t rc;
+
+	verify_dlg_destroy(dlg);
+
+	job = calloc(1, sizeof(navigator_verify_job_t));
+	if (job == NULL)
+		return;
+
+	job->navigator = nav;
+	job->flist = dlg->flist;
+	dlg->flist = NULL;
+
+	progress_dlg_params_init(&pd_params);
+	pd_params.caption = "Verifying";
+
+	rc = progress_dlg_create(nav->ui, &pd_params, &nav->progress_dlg);
+	if (rc != EOK) {
+		msg = str_dup("Out of memory.");
+		if (msg == NULL)
+			return;
+		goto error;
+	}
+
+	progress_dlg_set_cb(nav->progress_dlg, &navigator_progress_cb,
+	    (void *)nav);
+
+	rc = navigator_worker_start(nav, verify_wfunc, (void *)job);
+	if (rc != EOK) {
+		msg = str_dup("Out of memory.");
+		if (msg == NULL)
+			return;
+		goto error;
+	}
+
+	return;
+error:
+	ui_msg_dialog_params_init(&params);
+	params.caption = "Error";
+	params.text = msg;
+	(void) ui_msg_dialog_create(nav->ui, &params, &dialog);
+	free(msg);
+}
+
+/** New file dialog cancelled.
+ *
+ * @param dlg New file dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void verify_bcancel(verify_dlg_t *dlg, void *arg)
+{
+	(void)arg;
+	verify_dlg_destroy(dlg);
+}
+
+/** New file dialog closed.
+ *
+ * @param dlg New file dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void verify_close(verify_dlg_t *dlg, void *arg)
+{
+	(void)arg;
+	verify_dlg_destroy(dlg);
+}
+
+/** New file abort query.
+ *
+ * @param arg Argument (navigator_t *)
+ * @return @c true iff abort is requested
+ */
+static bool verify_abort_query(void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	return nav->abort_op;
+}
+
+/** New file progress update.
+ *
+ * @param arg Argument (navigator_t *)
+ * @param progress Progress update
+ */
+static void verify_progress(void *arg, fmgt_progress_t *progress)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	progress_dlg_set_progress(nav->progress_dlg, progress);
+}
+
+/** @}
+ */
Index: uspace/app/nav/verify.h
===================================================================
--- uspace/app/nav/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/nav/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Verify File
+ */
+
+#ifndef VERIFY_H
+#define VERIFY_H
+
+#include <fmgt.h>
+#include "types/nav.h"
+
+extern void navigator_verify_dlg(navigator_t *, fmgt_flist_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/newfile/newfile.c
===================================================================
--- uspace/app/newfile/newfile.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/app/newfile/newfile.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -241,8 +241,4 @@
 	}
 
-	(void)nonint;
-	(void)quiet;
-	(void)sparse;
-
 	if (fsize != NULL) {
 		rc = capa_parse(fsize, &fcap);
Index: uspace/app/verify/doc/doxygroups.h
===================================================================
--- uspace/app/verify/doc/doxygroups.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/verify/doc/doxygroups.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,4 @@
+/** @addtogroup verify verify
+ * @brief Verify that file can be read.
+ * @ingroup apps
+ */
Index: uspace/app/verify/meson.build
===================================================================
--- uspace/app/verify/meson.build	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/verify/meson.build	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2025 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+deps = [ 'console', 'fmgt', 'input' ]
+src = files('verify.c')
Index: uspace/app/verify/verify.c
===================================================================
--- uspace/app/verify/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/app/verify/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup verify
+ * @{
+ */
+/** @file Verify that file can be read.
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <io/console.h>
+#include <io/cons_event.h>
+#include <io/kbd_event.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
+
+#define NAME  "verify"
+
+static bool verify_abort_query(void *);
+static void verify_progress(void *, fmgt_progress_t *);
+static fmgt_error_action_t verify_io_error_query(void *, fmgt_io_error_t *);
+
+static bool prog_upd = false;
+static bool nonint = false;
+static bool quiet = false;
+
+static console_ctrl_t *con;
+
+static fmgt_cb_t verify_fmgt_cb = {
+	.abort_query = verify_abort_query,
+	.io_error_query = verify_io_error_query,
+	.progress = verify_progress,
+};
+
+static void print_syntax(void)
+{
+	printf("Verify that file can be read.\n");
+	printf("Syntax: %s [<options] <file-name>...\n", NAME);
+	printf("\t-h           help\n");
+	printf("\t-n           non-interactive\n");
+	printf("\t-q           quiet\n");
+}
+
+/** Called by fmgt to query for user abort.
+ *
+ * @param arg Argument (not used)
+ * @return @c true iff user requested abort
+ */
+static bool verify_abort_query(void *arg)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	errno_t rc;
+	usec_t timeout;
+
+	if (con == NULL)
+		return false;
+
+	timeout = 0;
+	rc = console_get_event_timeout(con, &event, &timeout);
+	if (rc != EOK)
+		return false;
+
+	if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+		ev = &event.ev.key;
+		if ((ev->mods & KM_ALT) == 0 &&
+		    (ev->mods & KM_SHIFT) == 0 &&
+		    (ev->mods & KM_CTRL) != 0) {
+			if (ev->key == KC_C)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/** Called by fmgt to give the user progress update.
+ *
+ * @param arg Argument (not used)
+ * @param progress Progress report
+ */
+static void verify_progress(void *arg, fmgt_progress_t *progress)
+{
+	(void)arg;
+
+	if (!quiet) {
+		printf("\rVerified %s files, %s; current file: %s done.  "
+		    "\b\b", progress->total_procf, progress->total_procb,
+		    progress->curf_percent);
+		fflush(stdout);
+		prog_upd = true;
+	}
+}
+
+/** Called by fmgt to let user choose I/O error recovery action.
+ *
+ * @param arg Argument (not used)
+ * @param err I/O error report
+ * @return Error recovery action.
+ */
+static fmgt_error_action_t verify_io_error_query(void *arg,
+    fmgt_io_error_t *err)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	errno_t rc;
+
+	(void)arg;
+
+	if (nonint)
+		return fmgt_er_abort;
+
+	if (prog_upd)
+		putchar('\n');
+
+	fprintf(stderr, "I/O error %s file '%s' (%s).\n",
+	    err->optype == fmgt_io_write ? "writing" : "reading",
+	    err->fname, str_error(err->rc));
+	fprintf(stderr, "[A]bort or [R]etry?\n");
+
+	if (con == NULL)
+		return fmgt_er_abort;
+
+	while (true) {
+		rc = console_get_event(con, &event);
+		if (rc != EOK)
+			return fmgt_er_abort;
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_CTRL) == 0) {
+				if (ev->c == 'r' || ev->c == 'R')
+					return fmgt_er_retry;
+				if (ev->c == 'a' || ev->c == 'A')
+					return fmgt_er_abort;
+			}
+		}
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_SHIFT) == 0 &&
+			    (ev->mods & KM_CTRL) != 0) {
+				if (ev->key == KC_C)
+					return fmgt_er_abort;
+			}
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	fmgt_t *fmgt = NULL;
+	errno_t rc;
+	int i;
+	fmgt_flist_t *flist = NULL;
+
+	rc = fmgt_flist_create(&flist);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		goto error;
+	}
+
+	con = console_init(stdin, stdout);
+
+	i = 1;
+	while (i < argc && argv[i][0] == '-') {
+		if (str_cmp(argv[i], "-h") == 0) {
+			print_syntax();
+			return 0;
+		} else if (str_cmp(argv[i], "-n") == 0) {
+			++i;
+			nonint = true;
+		} else if (str_cmp(argv[i], "-q") == 0) {
+			++i;
+			quiet = true;
+		} else {
+			printf("Invalid option '%s'.\n", argv[i]);
+			print_syntax();
+			goto error;
+		}
+	}
+
+	if (i >= argc) {
+		print_syntax();
+		goto error;
+	}
+
+	do {
+		rc = fmgt_flist_append(flist, argv[i++]);
+		if (rc != EOK) {
+			printf("Out of memory.\n");
+			goto error;
+		}
+	} while (i < argc);
+
+	rc = fmgt_create(&fmgt);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		goto error;
+	}
+
+	fmgt_set_cb(fmgt, &verify_fmgt_cb, NULL);
+
+	rc = fmgt_verify(fmgt, flist);
+	if (prog_upd)
+		putchar('\n');
+	if (rc != EOK) {
+		printf("Error creating file: %s.\n", str_error(rc));
+		goto error;
+	}
+
+	fmgt_flist_destroy(flist);
+	fmgt_destroy(fmgt);
+	return 0;
+error:
+	if (flist != NULL)
+		fmgt_flist_destroy(flist);
+	if (fmgt != NULL)
+		fmgt_destroy(fmgt);
+	return 1;
+}
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/fmgt.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/include/fmgt.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -42,5 +42,7 @@
 #include <stddef.h>
 #include <stdint.h>
+#include "fmgt/flist.h"
 #include "fmgt/newfile.h"
+#include "fmgt/verify.h"
 #include "types/fmgt.h"
 
Index: uspace/lib/fmgt/include/fmgt/flist.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/flist.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/include/fmgt/flist.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/**
+ * @file
+ * @brief File list.
+ */
+
+#ifndef FMGT_FLIST_H
+#define FMGT_FLIST_H
+
+#include <errno.h>
+#include "types/fmgt.h"
+
+extern errno_t fmgt_flist_create(fmgt_flist_t **);
+extern errno_t fmgt_flist_append(fmgt_flist_t *, const char *);
+extern void fmgt_flist_destroy(fmgt_flist_t *);
+extern fmgt_flist_entry_t *fmgt_flist_first(fmgt_flist_t *);
+extern fmgt_flist_entry_t *fmgt_flist_next(fmgt_flist_entry_t *);
+extern unsigned fmgt_flist_count(fmgt_flist_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/fmgt/newfile.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/newfile.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/include/fmgt/newfile.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -32,5 +32,5 @@
 /**
  * @file
- * @brief File management library - creating new files.
+ * @brief Create new files.
  */
 
Index: uspace/lib/fmgt/include/fmgt/verify.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/include/fmgt/verify.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/**
+ * @file
+ * @brief Verify files.
+ */
+
+#ifndef FMGT_VERIFY_H
+#define FMGT_VERIFY_H
+
+#include <errno.h>
+#include "types/fmgt.h"
+
+extern errno_t fmgt_verify(fmgt_t *, fmgt_flist_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/fmgt/walk.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/walk.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/include/fmgt/walk.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/**
+ * @file
+ * @brief File system tree walker.
+ */
+
+#ifndef FMGT_WALK_H
+#define FMGT_WALK_H
+
+#include <errno.h>
+#include "types/fmgt.h"
+
+extern void fmgt_walk_params_init(fmgt_walk_params_t *);
+extern errno_t fmgt_walk(fmgt_walk_params_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/types/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/types/fmgt.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/include/types/fmgt.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -38,8 +38,11 @@
 #define TYPES_FMGT_H
 
+#include <adt/list.h>
 #include <capa.h>
 #include <errno.h>
 #include <fibril_synch.h>
 #include <stdbool.h>
+
+#define FMGT_FILE_COUNT_BUFSIZE 16
 
 /** File management progress update */
@@ -51,4 +54,8 @@
 	/** Percent of current file processed */
 	char curf_percent[5];
+	/** Total number of bytes processed */
+	char total_procb[CAPA_BLOCKS_BUFSIZE];
+	/** Number of files processed */
+	char total_procf[FMGT_FILE_COUNT_BUFSIZE];
 } fmgt_progress_t;
 
@@ -101,9 +108,13 @@
 	/** Progress was displayed for current file */
 	bool curf_progr;
+	/** Total number of processed bytes */
+	uint64_t total_procb;
+	/** Total number of processed files */
+	unsigned total_procf;
 	/** Post an immediate initial progress update */
 	bool do_init_update;
 } fmgt_t;
 
-/** New file flags. */
+/** New file flags */
 typedef enum {
 	nf_none = 0x0,
@@ -111,4 +122,37 @@
 } fmgt_nf_flags_t;
 
+/** File list */
+typedef struct {
+	/** List of fmgt_flist_entry_t */
+	list_t files;
+} fmgt_flist_t;
+
+/** File list entry */
+typedef struct {
+	/** Containing file list */
+	fmgt_flist_t *flist;
+	/** Link to flist->files */
+	link_t lfiles;
+	/** File name */
+	char *fname;
+} fmgt_flist_entry_t;
+
+/** File system tree walk callbacks */
+typedef struct {
+	errno_t (*dir_enter)(void *, const char *);
+	errno_t (*dir_leave)(void *, const char *);
+	errno_t (*file)(void *, const char *);
+} fmgt_walk_cb_t;
+
+/** File system tree walk parameters */
+typedef struct {
+	/** List of files or directories (walk roots) */
+	fmgt_flist_t *flist;
+	/** Callbacks */
+	fmgt_walk_cb_t *cb;
+	/** Callback argument */
+	void *arg;
+} fmgt_walk_params_t;
+
 #endif
 
Index: uspace/lib/fmgt/meson.build
===================================================================
--- uspace/lib/fmgt/meson.build	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/meson.build	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -28,6 +28,9 @@
 
 src = files(
+	'src/flist.c',
 	'src/fmgt.c',
-	'src/newfile.c'
+	'src/newfile.c',
+	'src/verify.c',
+	'src/walk.c'
 )
 
Index: uspace/lib/fmgt/private/fmgt.h
===================================================================
--- uspace/lib/fmgt/private/fmgt.h	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/private/fmgt.h	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -47,4 +47,8 @@
 extern bool fmgt_abort_query(fmgt_t *);
 extern fmgt_error_action_t fmgt_io_error_query(fmgt_t *, fmgt_io_error_t *);
+extern void fmgt_progress_init(fmgt_t *);
+extern void fmgt_progress_init_file(fmgt_t *, const char *);
+extern void fmgt_progress_incr_bytes(fmgt_t *, uint64_t);
+extern void fmgt_progress_incr_files(fmgt_t *);
 extern void fmgt_initial_progress_update(fmgt_t *);
 extern void fmgt_final_progress_update(fmgt_t *);
Index: uspace/lib/fmgt/src/flist.c
===================================================================
--- uspace/lib/fmgt/src/flist.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/src/flist.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/** @file File list.
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <str.h>
+
+#include "fmgt.h"
+
+/** Create file list.
+ *
+ * @param rflist Place to store pointer to new file list.
+ * @return EOK on success, ENOMEM if out of memory.
+ */
+errno_t fmgt_flist_create(fmgt_flist_t **rflist)
+{
+	fmgt_flist_t *flist;
+
+	flist = calloc(1, sizeof(fmgt_flist_t));
+	if (flist == NULL)
+		return ENOMEM;
+
+	list_initialize(&flist->files);
+	*rflist = flist;
+	return EOK;
+}
+
+/** Append file name to file list.
+ *
+ * @param flist File list
+ * @param fname File name to append
+ * @return EOK on success, ENOMEM if out of memory
+ */
+errno_t fmgt_flist_append(fmgt_flist_t *flist, const char *fname)
+{
+	fmgt_flist_entry_t *entry;
+
+	entry = calloc(1, sizeof(fmgt_flist_entry_t));
+	if (entry == NULL)
+		return ENOMEM;
+
+	entry->fname = str_dup(fname);
+	if (entry->fname == NULL) {
+		free(entry);
+		return ENOMEM;
+	}
+
+	entry->flist = flist;
+	list_append(&entry->lfiles, &flist->files);
+
+	return EOK;
+}
+
+/** Destroy file list.
+ *
+ * @param flist File list
+ */
+void fmgt_flist_destroy(fmgt_flist_t *flist)
+{
+	fmgt_flist_entry_t *entry;
+
+	entry = fmgt_flist_first(flist);
+	while (entry != NULL) {
+		list_remove(&entry->lfiles);
+		free(entry->fname);
+		free(entry);
+		entry = fmgt_flist_first(flist);
+	}
+
+	free(flist);
+}
+
+/** Get first file list entry.
+ *
+ * @param flist File list
+ * @return First file list entry or @c NULL iff list list empty
+ */
+fmgt_flist_entry_t *fmgt_flist_first(fmgt_flist_t *flist)
+{
+	link_t *link;
+
+	link = list_first(&flist->files);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, fmgt_flist_entry_t, lfiles);
+}
+
+/** Get first new list entry.
+ *
+ * @param entry Current file list entry
+ * @return Next file list entry or @c NULL iff @a entry is last
+ */
+fmgt_flist_entry_t *fmgt_flist_next(fmgt_flist_entry_t *entry)
+{
+	link_t *link;
+
+	link = list_next(&entry->lfiles, &entry->flist->files);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, fmgt_flist_entry_t, lfiles);
+}
+
+/** Return number of entries in file list.
+ *
+ * @param flist File list
+ * @return Number of entries in @a flist.
+ */
+unsigned fmgt_flist_count(fmgt_flist_t *flist)
+{
+	unsigned count;
+	fmgt_flist_entry_t *entry;
+
+	count = 0;
+	entry = fmgt_flist_first(flist);
+	while (entry != NULL) {
+		++count;
+		entry = fmgt_flist_next(entry);
+	}
+
+	return count;
+}
+
+/** @}
+ */
Index: uspace/lib/fmgt/src/fmgt.c
===================================================================
--- uspace/lib/fmgt/src/fmgt.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/src/fmgt.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -104,4 +104,56 @@
 }
 
+/** Initialize progress counters at beginning of operation.
+ *
+ * @param fmgt File management object
+ */
+void fmgt_progress_init(fmgt_t *fmgt)
+{
+	fmgt->total_procf = 0;
+	fmgt->total_procb = 0;
+
+	fmgt->curf_procb = 0;
+	fmgt->curf_totalb = 0;
+	fmgt->curf_progr = false;
+}
+
+/** Initialize progress counters at beginning of processing a file.
+ *
+ * @param fmgt File management object
+ * @param fname File name
+ */
+void fmgt_progress_init_file(fmgt_t *fmgt, const char *fname)
+{
+	vfs_stat_t stat;
+	errno_t rc;
+
+	fmgt->curf_procb = 0;
+	fmgt->curf_totalb = 0;
+
+	rc = vfs_stat_path(fname, &stat);
+	if (rc == EOK)
+		fmgt->curf_totalb = stat.size;
+}
+
+/** Increase count of processed bytes.
+ *
+ * @param fmgt File management object
+ * @param nbytes Number of newly processed bytes
+ */
+void fmgt_progress_incr_bytes(fmgt_t *fmgt, uint64_t nbytes)
+{
+	fmgt->curf_procb += nbytes;
+	fmgt->total_procb += nbytes;
+}
+
+/** Increase count of processed files.
+ *
+ * @parma fmgt File management object
+ */
+void fmgt_progress_incr_files(fmgt_t *fmgt)
+{
+	++fmgt->total_procf;
+}
+
 /** Get progress update report.
  *
@@ -124,4 +176,8 @@
 	snprintf(progress->curf_percent, sizeof(progress->curf_percent), "%u%%",
 	    percent);
+	snprintf(progress->total_procf, sizeof(progress->total_procf), "%u",
+	    fmgt->total_procf);
+	capa_blocks_format_buf(fmgt->total_procb, 1, progress->total_procb,
+	    sizeof(progress->total_procb));
 }
 
Index: uspace/lib/fmgt/src/newfile.c
===================================================================
--- uspace/lib/fmgt/src/newfile.c	(revision 3a4c6d93a7348ed56f730d1686fe37062c67f586)
+++ uspace/lib/fmgt/src/newfile.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file File management library - creating new files.
+/** @file Create new files.
  */
 
@@ -109,9 +109,6 @@
 	}
 
-	fmgt->curf_procb = 0;
-	fmgt->curf_totalb = fsize;
-	fmgt->curf_progr = false;
-	fmgt_timer_start(fmgt);
-
+	/* Clear statistics. */
+	fmgt_progress_init(fmgt);
 	fmgt_initial_progress_update(fmgt);
 
@@ -149,5 +146,5 @@
 		}
 
-		fmgt->curf_procb += nw;
+		fmgt_progress_incr_bytes(fmgt, nw);
 
 		/* User requested abort? */
Index: uspace/lib/fmgt/src/verify.c
===================================================================
--- uspace/lib/fmgt/src/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/src/verify.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/** @file Verify files.
+ */
+
+//#include <dirent.h>
+#include <errno.h>
+#include <stdbool.h>
+//#include <stdio.h>
+#include <stdlib.h>
+//#include <stddef.h>
+//#include <str.h>
+#include <vfs/vfs.h>
+//#include <dirent.h>
+
+#include "fmgt.h"
+#include "fmgt/walk.h"
+#include "../private/fmgt.h"
+
+static errno_t fmgt_verify_file(void *, const char *);
+
+static fmgt_walk_cb_t fmgt_verify_cb = {
+	.file = fmgt_verify_file
+};
+
+static errno_t fmgt_verify_file(void *arg, const char *fname)
+{
+	fmgt_t *fmgt = (fmgt_t *)arg;
+	int fd;
+	size_t nr;
+	aoff64_t pos = 0;
+	char *buffer;
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	errno_t rc;
+
+	buffer = calloc(BUFFER_SIZE, 1);
+	if (buffer == NULL)
+		return ENOMEM;
+
+	rc = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ, &fd);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+
+	fmgt_progress_init_file(fmgt, fname);
+
+	do {
+		do {
+			rc = vfs_read(fd, &pos, buffer, BUFFER_SIZE, &nr);
+			if (rc == EOK)
+				break;
+
+			/* I/O error */
+			err.fname = fname;
+			err.optype = fmgt_io_read;
+			err.rc = rc;
+			fmgt_timer_stop(fmgt);
+			action = fmgt_io_error_query(fmgt, &err);
+			fmgt_timer_start(fmgt);
+		} while (action == fmgt_er_retry);
+
+		/* Not recovered? */
+		if (rc != EOK) {
+			free(buffer);
+			vfs_put(fd);
+			return rc;
+		}
+
+		fmgt_progress_incr_bytes(fmgt, nr);
+
+		/* User requested abort? */
+		if (fmgt_abort_query(fmgt)) {
+			free(buffer);
+			vfs_put(fd);
+			return EINTR;
+		}
+	} while (nr > 0);
+
+	free(buffer);
+	vfs_put(fd);
+	fmgt_progress_incr_files(fmgt);
+	return EOK;
+}
+
+/** Verify files.
+ *
+ * @param fmgt File management object
+ * @param flist File list
+ * @return EOK on success or an error code
+ */
+errno_t fmgt_verify(fmgt_t *fmgt, fmgt_flist_t *flist)
+{
+	fmgt_walk_params_t params;
+	errno_t rc;
+
+	fmgt_walk_params_init(&params);
+
+	params.flist = flist;
+	params.cb = &fmgt_verify_cb;
+	params.arg = (void *)fmgt;
+
+	fmgt_progress_init(fmgt);
+
+	fmgt_timer_start(fmgt);
+	fmgt_initial_progress_update(fmgt);
+	rc = fmgt_walk(&params);
+	fmgt_final_progress_update(fmgt);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/fmgt/src/walk.c
===================================================================
--- uspace/lib/fmgt/src/walk.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
+++ uspace/lib/fmgt/src/walk.c	(revision 1ec732aab0ba8690739aa05157e7fe75269a7829)
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/** @file File system tree walker.
+ */
+
+#include <adt/list.h>
+#include <dirent.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <vfs/vfs.h>
+
+#include "fmgt.h"
+#include "fmgt/walk.h"
+
+static errno_t fmgt_walk_subtree(fmgt_walk_params_t *, const char *);
+
+/** Initialize walk parameters.
+ *
+ * Every walk parameters structure must be initialized first using this
+ * function.
+ *
+ * @param params Pointer to walk parameters structure.
+ */
+void fmgt_walk_params_init(fmgt_walk_params_t *params)
+{
+	memset(params, 0, sizeof(fmgt_walk_params_t));
+}
+
+/** Walk file (invoke file callback).
+ *
+ * @param params Walk parameters
+ * @param fname File path
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_walk_file(fmgt_walk_params_t *params, const char *fname)
+{
+	if (params->cb->file != NULL)
+		return params->cb->file(params->arg, fname);
+	else
+		return EOK;
+}
+
+/** Enter directory (invoke directory entry callback).
+ *
+ * @param params Walk parameters
+ * @param dname Directory path
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_walk_dir_enter(fmgt_walk_params_t *params,
+    const char *dname)
+{
+	if (params->cb->dir_enter != NULL)
+		return params->cb->dir_enter(params->arg, dname);
+	else
+		return EOK;
+}
+
+/** Leave directory (invoke directory exit callback).
+ *
+ * @param params Walk parameters
+ * @param dname Directory path
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_walk_dir_leave(fmgt_walk_params_t *params,
+    const char *dname)
+{
+	if (params->cb->dir_enter != NULL)
+		return params->cb->dir_leave(params->arg, dname);
+	else
+		return EOK;
+}
+
+/** Walk directory.
+ *
+ * @param params Walk parameters
+ * @param dname Directory name
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_walk_dir(fmgt_walk_params_t *params, const char *dname)
+{
+	DIR *dir = NULL;
+	struct dirent *de;
+	errno_t rc;
+	char *pathname = NULL;
+	int rv;
+
+	rc = fmgt_walk_dir_enter(params, dname);
+	if (rc != EOK)
+		goto error;
+
+	dir = opendir(dname);
+	if (dir == NULL) {
+		rc = EIO;
+		goto error;
+	}
+
+	de = readdir(dir);
+	while (de != NULL) {
+		rv = asprintf(&pathname, "%s/%s", dname, de->d_name);
+		if (rv < 0) {
+			rc = ENOMEM;
+			goto error;
+		}
+
+		rc = fmgt_walk_subtree(params, pathname);
+		if (rc != EOK) {
+			free(pathname);
+			goto error;
+		}
+
+		free(pathname);
+		de = readdir(dir);
+	}
+
+	rc = fmgt_walk_dir_leave(params, dname);
+	if (rc != EOK)
+		return rc;
+
+	closedir(dir);
+	return EOK;
+error:
+	if (dir != NULL)
+		closedir(dir);
+	return rc;
+}
+
+/** Walk subtree.
+ *
+ * @params params Walk parameters.
+ * @params fname Subtree path.
+ *
+ * @return EOK on success or an error code.
+ */
+static errno_t fmgt_walk_subtree(fmgt_walk_params_t *params, const char *fname)
+{
+	vfs_stat_t stat;
+	errno_t rc;
+
+	rc = vfs_stat_path(fname, &stat);
+	if (rc != EOK)
+		return rc;
+
+	if (stat.is_directory) {
+		/* Directory */
+		rc = fmgt_walk_dir(params, fname);
+		if (rc != EOK)
+			return rc;
+	} else {
+		/* Not a directory */
+		rc = fmgt_walk_file(params, fname);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
+/** Perform a file system walk.
+ *
+ * Walks the list of files/directories in @a params->flist. Directories
+ * are walked recursively. Callbacks are involved for each file, directory,
+ * if defined.in @a params->cb, the callback argument is @a params->arg.
+ *
+ * @param params Walk parameters
+ * @return EOK on success or an error code.
+ */
+errno_t fmgt_walk(fmgt_walk_params_t *params)
+{
+	fmgt_flist_entry_t *entry;
+	errno_t rc;
+
+	entry = fmgt_flist_first(params->flist);
+	while (entry != NULL) {
+		rc = fmgt_walk_subtree(params, entry->fname);
+		if (rc != EOK)
+			return rc;
+
+		entry = fmgt_flist_next(entry);
+	}
+
+	return EOK;
+}
+
+/** @}
+ */
