Index: uspace/app/copy/copy.c
===================================================================
--- uspace/app/copy/copy.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/copy/copy.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,4 +49,5 @@
 static void copy_progress(void *, fmgt_progress_t *);
 static fmgt_error_action_t copy_io_error_query(void *, fmgt_io_error_t *);
+static fmgt_exists_action_t copy_exists_query(void *, fmgt_exists_t *);
 
 static bool prog_upd = false;
@@ -59,4 +60,5 @@
 	.abort_query = copy_abort_query,
 	.io_error_query = copy_io_error_query,
+	.exists_query = copy_exists_query,
 	.progress = copy_progress,
 };
@@ -188,4 +190,60 @@
 				if (ev->key == KC_C)
 					return fmgt_er_abort;
+			}
+		}
+	}
+}
+
+/** Called by fmgt to let user choose destination exists recovery action.
+ *
+ * @param arg Argument (not used)
+ * @param err I/O error report
+ * @return Error recovery action.
+ */
+static fmgt_exists_action_t copy_exists_query(void *arg, fmgt_exists_t *exists)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	errno_t rc;
+
+	(void)arg;
+
+	if (nonint)
+		return fmgt_exr_abort;
+
+	if (prog_upd)
+		putchar('\n');
+
+	fprintf(stderr, "File %s exists.\n", exists->fname);
+	fprintf(stderr, "[O]verwrite, [S]kip or [A]bort?\n");
+
+	if (con == NULL)
+		return fmgt_exr_abort;
+
+	while (true) {
+		rc = console_get_event(con, &event);
+		if (rc != EOK)
+			return fmgt_exr_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 == 'o' || ev->c == 'O')
+					return fmgt_exr_overwrite;
+				if (ev->c == 's' || ev->c == 'S')
+					return fmgt_exr_skip;
+				if (ev->c == 'a' || ev->c == 'A')
+					return fmgt_exr_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_exr_abort;
 			}
 		}
@@ -256,5 +314,5 @@
 		putchar('\n');
 	if (rc != EOK) {
-		printf("Error creating file: %s.\n", str_error(rc));
+		printf("Error copying file(s): %s.\n", str_error(rc));
 		goto error;
 	}
Index: uspace/app/nav/copy.c
===================================================================
--- uspace/app/nav/copy.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/copy.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -69,4 +69,5 @@
 	.abort_query = copy_abort_query,
 	.io_error_query = navigator_io_error_query,
+	.exists_query = navigator_exists_query,
 	.progress = copy_progress,
 };
Index: uspace/app/nav/dlg/existsdlg.c
===================================================================
--- uspace/app/nav/dlg/existsdlg.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
+++ uspace/app/nav/dlg/existsdlg.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2026 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 File/directory Exists 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 "existsdlg.h"
+
+static void exists_dlg_wnd_close(ui_window_t *, void *);
+static void exists_dlg_wnd_kbd(ui_window_t *, void *, kbd_event_t *);
+
+ui_window_cb_t exists_dlg_wnd_cb = {
+	.close = exists_dlg_wnd_close,
+	.kbd = exists_dlg_wnd_kbd
+};
+
+static void exists_dlg_boverwrite_clicked(ui_pbutton_t *, void *);
+static void exists_dlg_bskip_clicked(ui_pbutton_t *, void *);
+static void exists_dlg_babort_clicked(ui_pbutton_t *, void *);
+
+ui_pbutton_cb_t exists_dlg_boverwrite_cb = {
+	.clicked = exists_dlg_boverwrite_clicked
+};
+
+ui_pbutton_cb_t exists_dlg_bskip_cb = {
+	.clicked = exists_dlg_bskip_clicked
+};
+
+ui_pbutton_cb_t exists_dlg_babort_cb = {
+	.clicked = exists_dlg_babort_clicked
+};
+
+/** Initialize File/directory exists dialog parameters structure.
+ *
+ * File/directory exists parameters structure must always be initialized using
+ * this function first.
+ *
+ * @param params File/directory exists dialog parameters structure
+ */
+void exists_dlg_params_init(exists_dlg_params_t *params)
+{
+	memset(params, 0, sizeof(exists_dlg_params_t));
+	params->text1 = "";
+}
+
+/** Create File/directory exists dialog.
+ *
+ * @param ui User interface
+ * @param params Dialog parameters
+ * @param rdialog Place to store pointer to new dialog
+ * @return EOK on success or an error code
+ */
+errno_t exists_dlg_create(ui_t *ui, exists_dlg_params_t *params,
+    exists_dlg_t **rdialog)
+{
+	errno_t rc;
+	exists_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 *boverwrite = NULL;
+	ui_pbutton_t *bskip = NULL;
+	ui_pbutton_t *babort = NULL;
+	gfx_rect_t rect;
+	ui_resource_t *ui_res;
+	char *name = NULL;
+
+	dialog = calloc(1, sizeof(exists_dlg_t));
+	if (dialog == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	ui_wnd_params_init(&wparams);
+	wparams.caption = "File/directory exists";
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 60;
+		wparams.rect.p1.y = 9;
+	} else {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 440;
+		wparams.rect.p1.y = 155;
+	}
+
+	rc = ui_window_create(ui, &wparams, &window);
+	if (rc != EOK)
+		goto error;
+
+	ui_window_set_cb(window, &exists_dlg_wnd_cb, dialog);
+
+	ui_res = ui_window_get_res(window);
+
+	rc = ui_fixed_create(&fixed);
+	if (rc != EOK)
+		goto error;
+
+	rc = ui_label_create(ui_res, params->text1, &label);
+	if (rc != EOK)
+		goto error;
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 3;
+		rect.p0.y = 2;
+		rect.p1.x = 57;
+		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);
+	ui_label_set_halign(label, gfx_halign_center);
+
+	rc = ui_fixed_add(fixed, ui_label_ctl(label));
+	if (rc != EOK)
+		goto error;
+
+	label = NULL;
+
+	rc = ui_pbutton_create(ui_res, "Overwrite", &boverwrite);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(boverwrite, &exists_dlg_boverwrite_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 10;
+		rect.p0.y = 6;
+		rect.p1.x = 24;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 100;
+		rect.p0.y = 120;
+		rect.p1.x = 200;
+		rect.p1.y = 148;
+	}
+
+	ui_pbutton_set_rect(boverwrite, &rect);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(boverwrite));
+	if (rc != EOK)
+		goto error;
+
+	dialog->boverwrite = boverwrite;
+	boverwrite = NULL;
+
+	rc = ui_pbutton_create(ui_res, "Skip", &bskip);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(bskip, &exists_dlg_bskip_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 26;
+		rect.p0.y = 6;
+		rect.p1.x = 36;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 55;
+		rect.p0.y = 320;
+		rect.p1.x = 145;
+		rect.p1.y = 420;
+	}
+
+	ui_pbutton_set_rect(bskip, &rect);
+
+	ui_pbutton_set_default(bskip, true);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(bskip));
+	if (rc != EOK)
+		goto error;
+
+	dialog->bskip = bskip;
+	bskip = NULL;
+
+	rc = ui_pbutton_create(ui_res, "Abort", &babort);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(babort, &exists_dlg_babort_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 38;
+		rect.p0.y = 6;
+		rect.p1.x = 48;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 55;
+		rect.p0.y = 210;
+		rect.p1.x = 145;
+		rect.p1.y = 310;
+	}
+
+	ui_pbutton_set_rect(babort, &rect);
+
+	ui_pbutton_set_default(babort, true);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(babort));
+	if (rc != EOK)
+		goto error;
+
+	dialog->babort = babort;
+	babort = NULL;
+
+	ui_window_add(window, ui_fixed_ctl(fixed));
+	fixed = NULL;
+
+	rc = ui_window_paint(window);
+	if (rc != EOK)
+		goto error;
+
+	dialog->window = window;
+	*rdialog = dialog;
+	return EOK;
+error:
+	if (name != NULL)
+		free(name);
+	if (boverwrite != NULL)
+		ui_pbutton_destroy(boverwrite);
+	if (bskip != NULL)
+		ui_pbutton_destroy(bskip);
+	if (babort != NULL)
+		ui_pbutton_destroy(babort);
+	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 file/directory exists dialog.
+ *
+ * @param dialog File/directory exists dialog or @c NULL
+ */
+void exists_dlg_destroy(exists_dlg_t *dialog)
+{
+	if (dialog == NULL)
+		return;
+
+	ui_window_destroy(dialog->window);
+	free(dialog);
+}
+
+/** Set file/directory exists dialog callback.
+ *
+ * @param dialog File/directory exists dialog
+ * @param cb File/directory exists dialog callbacks
+ * @param arg Callback argument
+ */
+void exists_dlg_set_cb(exists_dlg_t *dialog, exists_dlg_cb_t *cb,
+    void *arg)
+{
+	dialog->cb = cb;
+	dialog->arg = arg;
+}
+
+/** File/directory exists dialog window close handler.
+ *
+ * @param window Window
+ * @param arg Argument (exists_dlg_t *)
+ */
+static void exists_dlg_wnd_close(ui_window_t *window, void *arg)
+{
+	exists_dlg_t *dialog = (exists_dlg_t *) arg;
+
+	(void)window;
+	if (dialog->cb != NULL && dialog->cb->close != NULL) {
+		dialog->cb->close(dialog, dialog->arg);
+	}
+}
+
+/** File/directory exists dialog window keyboard event handler.
+ *
+ * @param window Window
+ * @param arg Argument (exists_dlg_t *)
+ * @param event Keyboard event
+ */
+static void exists_dlg_wnd_kbd(ui_window_t *window, void *arg,
+    kbd_event_t *event)
+{
+	exists_dlg_t *dialog = (exists_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->babort != NULL) {
+				dialog->cb->babort(dialog, dialog->arg);
+				return;
+			}
+		} else if (event->key == KC_ESCAPE) {
+			/* Cancel */
+			if (dialog->cb != NULL && dialog->cb->boverwrite != NULL) {
+				dialog->cb->boverwrite(dialog, dialog->arg);
+				return;
+			}
+		}
+	}
+
+	ui_window_def_kbd(window, event);
+}
+
+/** File/directory exists dialog overwrite button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (exists_dlg_t *)
+ */
+static void exists_dlg_boverwrite_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	exists_dlg_t *dialog = (exists_dlg_t *) arg;
+
+	(void)pbutton;
+	if (dialog->cb != NULL && dialog->cb->boverwrite != NULL) {
+		dialog->cb->boverwrite(dialog, dialog->arg);
+	}
+}
+
+/** File/directory eists dialog skip button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (exists_dlg_t *)
+ */
+static void exists_dlg_bskip_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	exists_dlg_t *dialog = (exists_dlg_t *) arg;
+
+	if (dialog->cb != NULL && dialog->cb->bskip != NULL) {
+		dialog->cb->bskip(dialog, dialog->arg);
+	}
+}
+
+/** File/directory eists dialog abort button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (exists_dlg_t *)
+ */
+static void exists_dlg_babort_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	exists_dlg_t *dialog = (exists_dlg_t *) arg;
+
+	if (dialog->cb != NULL && dialog->cb->babort != NULL) {
+		dialog->cb->babort(dialog, dialog->arg);
+	}
+}
+
+/** @}
+ */
Index: uspace/app/nav/dlg/existsdlg.h
===================================================================
--- uspace/app/nav/dlg/existsdlg.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
+++ uspace/app/nav/dlg/existsdlg.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2026 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 File/directory Exists Dialog
+ */
+
+#ifndef DLG_EXISTSDLG_H
+#define DLG_EXISTSDLG_H
+
+#include <errno.h>
+#include <types/ui/ui.h>
+#include "../types/dlg/existsdlg.h"
+
+extern void exists_dlg_params_init(exists_dlg_params_t *);
+extern errno_t exists_dlg_create(ui_t *, exists_dlg_params_t *,
+    exists_dlg_t **);
+extern void exists_dlg_set_cb(exists_dlg_t *, exists_dlg_cb_t *,
+    void *);
+extern void exists_dlg_destroy(exists_dlg_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/dlg/ioerrdlg.c
===================================================================
--- uspace/app/nav/dlg/ioerrdlg.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/dlg/ioerrdlg.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -272,7 +272,7 @@
 }
 
-/** Destroy prompt dialog.
- *
- * @param dialog Prompt dialog or @c NULL
+/** Destroy I/O error dialog.
+ *
+ * @param dialog I/O error dialog or @c NULL
  */
 void io_err_dlg_destroy(io_err_dlg_t *dialog)
@@ -285,8 +285,8 @@
 }
 
-/** Set mesage dialog callback.
- *
- * @param dialog Prompt dialog
- * @param cb Prompt dialog callbacks
+/** Set I/O error dialog callback.
+ *
+ * @param dialog I/O error dialog
+ * @param cb I/O error dialog callbacks
  * @param arg Callback argument
  */
@@ -298,5 +298,5 @@
 }
 
-/** Prompt dialog window close handler.
+/** I/O error dialog window close handler.
  *
  * @param window Window
@@ -313,5 +313,5 @@
 }
 
-/** Prompt dialog window keyboard event handler.
+/** I/O error dialog window keyboard event handler.
  *
  * @param window Window
@@ -344,5 +344,5 @@
 }
 
-/** Prompt dialog OK button click handler.
+/** I/O error dialog abort button click handler.
  *
  * @param pbutton Push button
@@ -358,5 +358,5 @@
 }
 
-/** Prompt dialog cancel button click handler.
+/** I/O error dialog retry button click handler.
  *
  * @param pbutton Push button
Index: uspace/app/nav/meson.build
===================================================================
--- uspace/app/nav/meson.build	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/meson.build	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 #
-# Copyright (c) 2025 Jiri Svoboda
+# Copyright (c) 2026 Jiri Svoboda
 # All rights reserved.
 #
@@ -30,4 +30,5 @@
 src = files(
 	'dlg/copydlg.c',
+	'dlg/existsdlg.c',
 	'dlg/ioerrdlg.c',
 	'dlg/newfiledlg.c',
@@ -45,4 +46,5 @@
 test_src = files(
 	'dlg/copydlg.c',
+	'dlg/existsdlg.c',
 	'dlg/ioerrdlg.c',
 	'dlg/newfiledlg.c',
@@ -56,4 +58,5 @@
 	'verify.c',
 	'test/dlg/copydlg.c',
+	'test/dlg/existsdlg.c',
 	'test/dlg/ioerrdlg.c',
 	'test/dlg/newfiledlg.c',
Index: uspace/app/nav/nav.c
===================================================================
--- uspace/app/nav/nav.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/nav.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,4 +49,5 @@
 #include <ui/window.h>
 #include "copy.h"
+#include "dlg/existsdlg.h"
 #include "dlg/ioerrdlg.h"
 #include "menu.h"
@@ -106,4 +107,16 @@
 	.bretry = navigator_io_err_retry,
 	.close = navigator_io_err_close
+};
+
+static void navigator_exists_overwrite(exists_dlg_t *, void *);
+static void navigator_exists_skip(exists_dlg_t *, void *);
+static void navigator_exists_abort(exists_dlg_t *, void *);
+static void navigator_exists_close(exists_dlg_t *, void *);
+
+static exists_dlg_cb_t navigator_exists_dlg_cb = {
+	.boverwrite = navigator_exists_overwrite,
+	.bskip = navigator_exists_skip,
+	.babort = navigator_exists_abort,
+	.close = navigator_exists_close
 };
 
@@ -273,4 +286,8 @@
 	navigator->io_err_act_sel = false;
 
+	fibril_mutex_initialize(&navigator->exists_act_lock);
+	fibril_condvar_initialize(&navigator->exists_act_cv);
+	navigator->exists_act_sel = false;
+
 	*rnavigator = navigator;
 	return EOK;
@@ -857,4 +874,126 @@
 }
 
+/** Called by fmgt to query for file/directory exists recovery action.
+ *
+ * @param arg Argument (navigator_t *)
+ * @param exists File/directory exists report
+ * @return Recovery action to take.
+ */
+fmgt_exists_action_t navigator_exists_query(void *arg, fmgt_exists_t *exists)
+{
+	navigator_t *nav = (navigator_t *)arg;
+	exists_dlg_t *dlg;
+	exists_dlg_params_t params;
+	fmgt_exists_action_t exists_act;
+	char *text1;
+	errno_t rc;
+	int rv;
+
+	exists_dlg_params_init(&params);
+	rv = asprintf(&text1, "File %s exists.", exists->fname);
+	if (rv < 0)
+		return fmgt_exr_abort;
+
+	params.text1 = text1;
+
+	ui_lock(nav->ui);
+	rc = exists_dlg_create(nav->ui, &params, &dlg);
+	if (rc != EOK) {
+		ui_unlock(nav->ui);
+		free(text1);
+		return fmgt_exr_abort;
+	}
+
+	exists_dlg_set_cb(dlg, &navigator_exists_dlg_cb, (void *)nav);
+
+	ui_unlock(nav->ui);
+	free(text1);
+
+	fibril_mutex_lock(&nav->exists_act_lock);
+
+	while (!nav->exists_act_sel) {
+		fibril_condvar_wait(&nav->exists_act_cv,
+		    &nav->exists_act_lock);
+	}
+
+	exists_act = nav->exists_act;
+	nav->exists_act_sel = false;
+	fibril_mutex_unlock(&nav->exists_act_lock);
+
+	return exists_act;
+}
+
+/** File/directory exists dialog overwrite button was pressed.
+ *
+ * @param dlg File/directory exists dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void navigator_exists_overwrite(exists_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	exists_dlg_destroy(dlg);
+
+	fibril_mutex_lock(&nav->exists_act_lock);
+	nav->exists_act = fmgt_exr_overwrite;
+	nav->exists_act_sel = true;
+	fibril_condvar_signal(&nav->exists_act_cv);
+	fibril_mutex_unlock(&nav->exists_act_lock);
+}
+
+/** File/directory exists dialog skip button was pressed.
+ *
+ * @param dlg File/directory exists dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void navigator_exists_skip(exists_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	exists_dlg_destroy(dlg);
+
+	fibril_mutex_lock(&nav->exists_act_lock);
+	nav->exists_act = fmgt_exr_skip;
+	nav->exists_act_sel = true;
+	fibril_condvar_signal(&nav->exists_act_cv);
+	fibril_mutex_unlock(&nav->exists_act_lock);
+}
+
+/** File/directory exists dialog abort button was pressed.
+ *
+ * @param dlg File/directory exists dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void navigator_exists_abort(exists_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	exists_dlg_destroy(dlg);
+
+	fibril_mutex_lock(&nav->exists_act_lock);
+	nav->exists_act = fmgt_exr_abort;
+	nav->exists_act_sel = true;
+	fibril_condvar_signal(&nav->exists_act_cv);
+	fibril_mutex_unlock(&nav->exists_act_lock);
+}
+
+/** File/directory exists dialog closure requested.
+ *
+ * @param dlg File/directory exists dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void navigator_exists_close(exists_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	exists_dlg_destroy(dlg);
+
+	fibril_mutex_lock(&nav->exists_act_lock);
+	nav->exists_act = fmgt_exr_abort;
+	nav->exists_act_sel = true;
+	fibril_condvar_signal(&nav->exists_act_cv);
+	fibril_mutex_unlock(&nav->exists_act_lock);
+}
+
 /** @}
  */
Index: uspace/app/nav/nav.h
===================================================================
--- uspace/app/nav/nav.h	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/nav.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -55,4 +55,5 @@
     void *);
 extern fmgt_error_action_t navigator_io_error_query(void *, fmgt_io_error_t *);
+extern fmgt_exists_action_t navigator_exists_query(void *, fmgt_exists_t *);
 
 #endif
Index: uspace/app/nav/test/dlg/existsdlg.c
===================================================================
--- uspace/app/nav/test/dlg/existsdlg.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
+++ uspace/app/nav/test/dlg/existsdlg.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2026 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.
+ */
+
+#include <errno.h>
+#include <pcut/pcut.h>
+#include <ui/ui.h>
+#include "../../dlg/existsdlg.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(existsdlg);
+
+/** Create and destroy file/directory exists dialog. */
+PCUT_TEST(create_destroy)
+{
+	ui_t *ui;
+	exists_dlg_params_t params;
+	exists_dlg_t *dlg = NULL;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	exists_dlg_params_init(&params);
+	rc = exists_dlg_create(ui, &params, &dlg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(dlg);
+
+	exists_dlg_destroy(dlg);
+
+	ui_destroy(ui);
+}
+
+PCUT_EXPORT(existsdlg);
Index: uspace/app/nav/test/main.c
===================================================================
--- uspace/app/nav/test/main.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/test/main.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -32,4 +32,5 @@
 
 PCUT_IMPORT(copydlg);
+PCUT_IMPORT(existsdlg);
 PCUT_IMPORT(ioerrdlg);
 PCUT_IMPORT(newfiledlg);
Index: uspace/app/nav/types/dlg/existsdlg.h
===================================================================
--- uspace/app/nav/types/dlg/existsdlg.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
+++ uspace/app/nav/types/dlg/existsdlg.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2026 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 File/directory exists Dialog
+ */
+
+#ifndef TYPES_DLG_EXISTSDLG_H
+#define TYPES_DLG_EXISTSDLG_H
+
+#include <errno.h>
+#include <io/kbd_event.h>
+#include <io/pos_event.h>
+#include <ui/entry.h>
+#include <ui/pbutton.h>
+#include <ui/window.h>
+
+struct exists_dlg;
+typedef struct exists_dlg exists_dlg_t;
+
+enum {
+	/** Maximum number of buttons in file/directory exists dialog. */
+	exists_dlg_maxbtn = 2
+};
+
+/** File/directory exists dialog parameters */
+typedef struct {
+	/** First line of text */
+	const char *text1;
+} exists_dlg_params_t;
+
+/** File/directory exists dialog callback */
+typedef struct exists_dlg_cb {
+	/** Overwrite button was pressed */
+	void (*boverwrite)(exists_dlg_t *, void *);
+	/** Skip button was pressed */
+	void (*bskip)(exists_dlg_t *, void *);
+	/** Abort button was pressed */
+	void (*babort)(exists_dlg_t *, void *);
+	/** Window closure requested (e.g. via close button) */
+	void (*close)(exists_dlg_t *, void *);
+} exists_dlg_cb_t;
+
+/** File/directory exists dialog */
+typedef struct exists_dlg {
+	/** Dialog window */
+	ui_window_t *window;
+	/** Overwrite button */
+	ui_pbutton_t *boverwrite;
+	/** Skip button */
+	ui_pbutton_t *bskip;
+	/** Abort button */
+	ui_pbutton_t *babort;
+	/** New file dialog callbacks */
+	exists_dlg_cb_t *cb;
+	/** Callback argument */
+	void *arg;
+} exists_dlg_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/types/nav.h
===================================================================
--- uspace/app/nav/types/nav.h	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/app/nav/types/nav.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -75,4 +75,13 @@
 	/** Synchronizes access to I/O error recovery action */
 	fibril_mutex_t io_err_act_lock;
+
+	/** @c true if user selected file/dir exists recovery action */
+	bool exists_act_sel;
+	/** Selected file/directory exists recovery action */
+	fmgt_exists_action_t exists_act;
+	/** Signalled when user selects file/directory exists recovery action */
+	fibril_condvar_t exists_act_cv;
+	/** Synchronizes access to file/directory exists recovery action */
+	fibril_mutex_t exists_act_lock;
 } navigator_t;
 
Index: uspace/lib/fmgt/include/types/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/types/fmgt.h	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/lib/fmgt/include/types/fmgt.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -90,8 +90,25 @@
 } fmgt_error_action_t;
 
+/** File management file/directory exists report */
+typedef struct {
+	/** File name */
+	const char *fname;
+} fmgt_exists_t;
+
+/** File management file/directory exists recovery action */
+typedef enum {
+	/** Overwrite */
+	fmgt_exr_overwrite,
+	/** Skip */
+	fmgt_exr_skip,
+	/** Abort */
+	fmgt_exr_abort
+} fmgt_exists_action_t;
+
 /** File management callbacks */
 typedef struct {
 	bool (*abort_query)(void *);
 	fmgt_error_action_t (*io_error_query)(void *, fmgt_io_error_t *);
+	fmgt_exists_action_t (*exists_query)(void *, fmgt_exists_t *);
 	void (*progress)(void *, fmgt_progress_t *);
 } fmgt_cb_t;
Index: uspace/lib/fmgt/private/fmgt.h
===================================================================
--- uspace/lib/fmgt/private/fmgt.h	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/lib/fmgt/private/fmgt.h	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -47,4 +47,5 @@
 extern bool fmgt_abort_query(fmgt_t *);
 extern fmgt_error_action_t fmgt_io_error_query(fmgt_t *, fmgt_io_error_t *);
+extern fmgt_exists_action_t fmgt_exists_query(fmgt_t *, fmgt_exists_t *);
 extern void fmgt_progress_init(fmgt_t *);
 extern void fmgt_progress_init_file(fmgt_t *, const char *);
Index: uspace/lib/fmgt/src/copy.c
===================================================================
--- uspace/lib/fmgt/src/copy.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/lib/fmgt/src/copy.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -50,4 +50,177 @@
 };
 
+/** Open file.
+ *
+ * @param fmgt File management object
+ * @param fname File name
+ * @param rfd Place to store file descriptor
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_open(fmgt_t *fmgt, const char *fname, int *rfd)
+{
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	errno_t rc;
+
+	do {
+		rc = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ, rfd);
+		if (rc == EOK)
+			break;
+
+		/* I/O error */
+		err.fname = fname;
+		err.optype = fmgt_io_open;
+		err.rc = rc;
+		fmgt_timer_stop(fmgt);
+		action = fmgt_io_error_query(fmgt, &err);
+		fmgt_timer_start(fmgt);
+	} while (action == fmgt_er_retry);
+
+	return rc;
+}
+
+/** Create file.
+ *
+ * @param fmgt File management object
+ * @param fname Destination file name
+ * @param rfd Place to store file descriptor
+ * @param rskip If @c true, skip existing file and continue
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_create_file(fmgt_t *fmgt, const char *fname, int *rfd,
+    bool *rskip)
+{
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	fmgt_exists_t exists;
+	fmgt_exists_action_t exaction;
+	bool may_overwrite = false;
+	unsigned flags;
+	errno_t rc;
+
+	*rskip = false;
+
+	do {
+		flags = WALK_REGULAR | (may_overwrite ? WALK_MAY_CREATE :
+		    WALK_MUST_CREATE);
+		rc = vfs_lookup_open(fname, flags, MODE_WRITE, rfd);
+		if (rc == EOK)
+			break;
+
+		if (rc == EEXIST) {
+			/* File exists */
+			exists.fname = fname;
+			fmgt_timer_stop(fmgt);
+			exaction = fmgt_exists_query(fmgt, &exists);
+			fmgt_timer_start(fmgt);
+
+			if (exaction == fmgt_exr_skip)
+				*rskip = true;
+			if (exaction != fmgt_exr_overwrite)
+				break;
+
+			may_overwrite = true;
+		} else {
+			/* I/O error */
+			err.fname = fname;
+			err.optype = fmgt_io_create;
+			err.rc = rc;
+			fmgt_timer_stop(fmgt);
+			action = fmgt_io_error_query(fmgt, &err);
+			fmgt_timer_start(fmgt);
+
+			if (action != fmgt_er_retry)
+				break;
+		}
+	} while (true);
+
+	return rc;
+}
+
+/** Create directory.
+ *
+ * @param fmgt File management object
+ * @param dname Directory name
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_create_dir(fmgt_t *fmgt, const char *dname)
+{
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	errno_t rc;
+
+	do {
+		rc = vfs_link_path(dname, KIND_DIRECTORY, NULL);
+
+		/* It is okay if the directory exists. */
+		if (rc == EOK || rc == EEXIST)
+			break;
+
+		/* I/O error */
+		err.fname = dname;
+		err.optype = fmgt_io_create;
+		err.rc = rc;
+
+		fmgt_timer_stop(fmgt);
+		action = fmgt_io_error_query(fmgt, &err);
+		fmgt_timer_start(fmgt);
+	} while (action == fmgt_er_retry);
+
+	if (rc == EEXIST)
+		return EOK;
+
+	return rc;
+}
+
+/** Read data from file.
+ *
+ * @param fmgt File management object
+ * @param fd File descriptor
+ * @param fname File name (for printing diagnostics)
+ * @param pos Pointer to current position (will be updated)
+ * @param buffer Data buffer
+ * @param nbytes Number of bytes to read
+ * @param nr Place to store number of bytes read
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_read(fmgt_t *fmgt, int fd, const char *fname,
+    aoff64_t *pos, void *buffer, size_t nbytes, size_t *nr)
+{
+	char *bp = (char *)buffer;
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	errno_t rc;
+
+	do {
+		rc = vfs_read(fd, pos, bp, nbytes, 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)
+		return rc;
+
+	return EOK;
+}
+
+/** Write data to file.
+ *
+ * @param fmgt File management object
+ * @param fd File descriptor
+ * @param fname File name (for printing diagnostics)
+ * @param pos Pointer to current position (will be updated)
+ * @param buffer Pointer to data
+ * @param nbytes Number of bytes to write
+ * @return EOK on success or an error code
+ */
 static errno_t fmgt_write(fmgt_t *fmgt, int fd, const char *fname,
     aoff64_t *pos, void *buffer, size_t nbytes)
@@ -97,26 +270,7 @@
 {
 	fmgt_t *fmgt = (fmgt_t *)arg;
-	fmgt_io_error_t err;
-	fmgt_error_action_t action;
-	errno_t rc;
-
-	do {
-		rc = vfs_link_path(dest, KIND_DIRECTORY, NULL);
-
-		/* It is okay if the directory exists. */
-		if (rc == EOK || rc == EEXIST)
-			break;
-
-		/* I/O error */
-		err.fname = dest;
-		err.optype = fmgt_io_create;
-		err.rc = rc;
-
-		fmgt_timer_stop(fmgt);
-		action = fmgt_io_error_query(fmgt, &err);
-		fmgt_timer_start(fmgt);
-	} while (action == fmgt_er_retry);
-
-	return rc;
+
+	(void)dest;
+	return fmgt_create_dir(fmgt, dest);
 }
 
@@ -137,6 +291,5 @@
 	aoff64_t wpos = 0;
 	char *buffer;
-	fmgt_io_error_t err;
-	fmgt_error_action_t action;
+	bool skip;
 	errno_t rc;
 
@@ -145,19 +298,5 @@
 		return ENOMEM;
 
-	do {
-		rc = vfs_lookup_open(src, WALK_REGULAR, MODE_READ, &rfd);
-		if (rc == EOK)
-			break;
-
-		/* I/O error */
-		err.fname = src;
-		err.optype = fmgt_io_open;
-		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? */
+	rc = fmgt_open(fmgt, src, &rfd);
 	if (rc != EOK) {
 		free(buffer);
@@ -165,22 +304,12 @@
 	}
 
-	do {
-		rc = vfs_lookup_open(dest, WALK_REGULAR | WALK_MAY_CREATE,
-		    MODE_WRITE, &wfd);
-		if (rc == EOK)
-			break;
-
-		/* I/O error */
-		err.fname = dest;
-		err.optype = fmgt_io_create;
-		err.rc = rc;
-		fmgt_timer_stop(fmgt);
-		action = fmgt_io_error_query(fmgt, &err);
-		fmgt_timer_start(fmgt);
-	} while (action == fmgt_er_retry);
-
+	rc = fmgt_create_file(fmgt, dest, &wfd, &skip);
 	if (rc != EOK) {
 		free(buffer);
 		vfs_put(rfd);
+
+		/* User decided to skip and continue. */
+		if (rc == EEXIST && skip)
+			return EOK;
 		return rc;
 	}
@@ -189,19 +318,6 @@
 
 	do {
-		do {
-			rc = vfs_read(rfd, &rpos, buffer, BUFFER_SIZE, &nr);
-			if (rc == EOK)
-				break;
-
-			/* I/O error */
-			err.fname = src;
-			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? */
+		rc = fmgt_read(fmgt, rfd, src, &rpos, buffer, BUFFER_SIZE,
+		    &nr);
 		if (rc != EOK)
 			goto error;
@@ -233,5 +349,5 @@
 }
 
-/** copy files.
+/** Copy files.
  *
  * @param fmgt File management object
Index: uspace/lib/fmgt/src/fmgt.c
===================================================================
--- uspace/lib/fmgt/src/fmgt.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/lib/fmgt/src/fmgt.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -283,4 +283,18 @@
 }
 
+/** Query caller how to recover from existing destination file/directory.
+ *
+ * @param fmgt File management object
+ * @param exists File/directory exists report
+ * @return What recovery action should be taken.
+ */
+fmgt_exists_action_t fmgt_exists_query(fmgt_t *fmgt, fmgt_exists_t *exists)
+{
+	if (fmgt->cb != NULL && fmgt->cb->exists_query != NULL)
+		return fmgt->cb->exists_query(fmgt->cb_arg, exists);
+	else
+		return fmgt_exr_abort;
+}
+
 /** Return base name (without path component).
  *
Index: uspace/lib/ui/src/promptdialog.c
===================================================================
--- uspace/lib/ui/src/promptdialog.c	(revision 81805e06a9f080e240dbc7463874411778910389)
+++ uspace/lib/ui/src/promptdialog.c	(revision 0ce9eb8edda098a24cfad673ae33689661db3889)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2021 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -291,5 +291,5 @@
 }
 
-/** Set mesage dialog callback.
+/** Set prompt dialog callback.
  *
  * @param dialog Prompt dialog
