Index: uspace/lib/fmgt/include/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/fmgt.h	(revision a4301f153aa21cf694bedbfa9397d114925bc506)
+++ uspace/lib/fmgt/include/fmgt.h	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -42,4 +42,5 @@
 #include <stddef.h>
 #include <stdint.h>
+#include "fmgt/newfile.h"
 #include "types/fmgt.h"
 
@@ -48,6 +49,4 @@
 extern void fmgt_destroy(fmgt_t *);
 extern void fmgt_set_init_update(fmgt_t *, bool);
-extern errno_t fmgt_new_file_suggest(char **);
-extern errno_t fmgt_new_file(fmgt_t *, const char *, uint64_t, fmgt_nf_flags_t);
 
 #endif
Index: uspace/lib/fmgt/include/fmgt/newfile.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/newfile.h	(revision d101368843a610fee26218d73d35748078bdb56d)
+++ uspace/lib/fmgt/include/fmgt/newfile.h	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -0,0 +1,50 @@
+/*
+ * 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 management library - creating new files.
+ */
+
+#ifndef FMGT_NEWFILE_H
+#define FMGT_NEWFILE_H
+
+#include <errno.h>
+#include <stdint.h>
+#include "types/fmgt.h"
+
+extern errno_t fmgt_new_file_suggest(char **);
+extern errno_t fmgt_new_file(fmgt_t *, const char *, uint64_t, fmgt_nf_flags_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/meson.build
===================================================================
--- uspace/lib/fmgt/meson.build	(revision a4301f153aa21cf694bedbfa9397d114925bc506)
+++ uspace/lib/fmgt/meson.build	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -29,4 +29,5 @@
 src = files(
 	'src/fmgt.c',
+	'src/newfile.c'
 )
 
@@ -34,3 +35,4 @@
 	'test/fmgt.c',
 	'test/main.c',
+	'test/newfile.c'
 )
Index: uspace/lib/fmgt/private/fmgt.h
===================================================================
--- uspace/lib/fmgt/private/fmgt.h	(revision d101368843a610fee26218d73d35748078bdb56d)
+++ uspace/lib/fmgt/private/fmgt.h	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -0,0 +1,55 @@
+/*
+ * 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 management library - private definitions.
+ */
+
+#ifndef PRIVATE_FMGT_H
+#define PRIVATE_FMGT_H
+
+#include <stdbool.h>
+#include "../include/types/fmgt.h"
+
+#define BUFFER_SIZE 16384
+
+extern void fmgt_timer_start(fmgt_t *);
+extern void fmgt_timer_stop(fmgt_t *);
+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_initial_progress_update(fmgt_t *);
+extern void fmgt_final_progress_update(fmgt_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/src/fmgt.c
===================================================================
--- uspace/lib/fmgt/src/fmgt.c	(revision a4301f153aa21cf694bedbfa9397d114925bc506)
+++ uspace/lib/fmgt/src/fmgt.c	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -44,7 +44,5 @@
 
 #include "fmgt.h"
-
-#define NEWNAME_LEN 64
-#define BUFFER_SIZE 16384
+#include "../private/fmgt.h"
 
 /** Create file management library instance.
@@ -106,34 +104,4 @@
 }
 
-/** Suggest file name for new file.
- *
- * @param fmgt File management object
- * @param rstr Place to store pointer to newly allocated string
- * @return EOK on success or an error code
- */
-errno_t fmgt_new_file_suggest(char **rstr)
-{
-	errno_t rc;
-	vfs_stat_t stat;
-	unsigned u;
-	char name[NEWNAME_LEN];
-
-	u = 0;
-	while (true) {
-		snprintf(name, sizeof(name), "noname%02u.txt", u);
-		rc = vfs_stat_path(name, &stat);
-		if (rc != EOK)
-			break;
-
-		++u;
-	}
-
-	*rstr = str_dup(name);
-	if (*rstr == NULL)
-		return ENOMEM;
-
-	return EOK;
-}
-
 /** Get progress update report.
  *
@@ -180,5 +148,5 @@
  * @param fmgt File management object
  */
-static void fmgt_initial_progress_update(fmgt_t *fmgt)
+void fmgt_initial_progress_update(fmgt_t *fmgt)
 {
 	if (fmgt->do_init_update)
@@ -192,5 +160,5 @@
  * @param fmgt File management object
  */
-static void fmgt_final_progress_update(fmgt_t *fmgt)
+void fmgt_final_progress_update(fmgt_t *fmgt)
 {
 	if (fmgt->curf_progr)
@@ -216,5 +184,5 @@
  * @param fmgt File management object
  */
-static void fmgt_timer_start(fmgt_t *fmgt)
+void fmgt_timer_start(fmgt_t *fmgt)
 {
 	fibril_timer_set(fmgt->timer, 500000, fmgt_timer_fun, (void *)fmgt);
@@ -225,5 +193,5 @@
  * @param fmgt File management object
  */
-static void fmgt_timer_stop(fmgt_t *fmgt)
+void fmgt_timer_stop(fmgt_t *fmgt)
 {
 	(void)fibril_timer_clear(fmgt->timer);
@@ -235,5 +203,5 @@
  * @return @c true iff operation should be aborted
  */
-static bool fmgt_abort_query(fmgt_t *fmgt)
+bool fmgt_abort_query(fmgt_t *fmgt)
 {
 	if (fmgt->cb != NULL && fmgt->cb->abort_query != NULL)
@@ -249,5 +217,5 @@
  * @return What error recovery action should be taken.
  */
-static fmgt_error_action_t fmgt_io_error_query(fmgt_t *fmgt,
+fmgt_error_action_t fmgt_io_error_query(fmgt_t *fmgt,
     fmgt_io_error_t *err)
 {
@@ -258,92 +226,4 @@
 }
 
-/** Create new file.
- *
- * @param fmgt File management object
- * @param fname File name
- * @param fsize Size of new file (number of zero bytes to fill in)
- * @param flags New file flags
- * @return EOK on success or an error code
- */
-errno_t fmgt_new_file(fmgt_t *fmgt, const char *fname, uint64_t fsize,
-    fmgt_nf_flags_t flags)
-{
-	int fd;
-	size_t nw;
-	aoff64_t pos = 0;
-	uint64_t now;
-	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 | WALK_MUST_CREATE,
-	    MODE_WRITE, &fd);
-	if (rc != EOK) {
-		free(buffer);
-		return rc;
-	}
-
-	fmgt->curf_procb = 0;
-	fmgt->curf_totalb = fsize;
-	fmgt->curf_progr = false;
-	fmgt_timer_start(fmgt);
-
-	fmgt_initial_progress_update(fmgt);
-
-	/* Create sparse file? */
-	if ((flags & nf_sparse) != 0) {
-		fmgt->curf_procb = fsize - 1;
-		pos = fsize - 1;
-	}
-
-	while (fmgt->curf_procb < fsize) {
-		now = fsize - fmgt->curf_procb;
-		if (now > BUFFER_SIZE)
-			now = BUFFER_SIZE;
-
-		do {
-			rc = vfs_write(fd, &pos, buffer, now, &nw);
-			if (rc == EOK)
-				break;
-
-			/* I/O error */
-			err.fname = fname;
-			err.optype = fmgt_io_write;
-			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);
-			fmgt_final_progress_update(fmgt);
-			return rc;
-		}
-
-		fmgt->curf_procb += nw;
-
-		/* User requested abort? */
-		if (fmgt_abort_query(fmgt)) {
-			free(buffer);
-			vfs_put(fd);
-			fmgt_final_progress_update(fmgt);
-			return EINTR;
-		}
-	}
-
-	free(buffer);
-	vfs_put(fd);
-	fmgt_final_progress_update(fmgt);
-	return EOK;
-}
-
 /** @}
  */
Index: uspace/lib/fmgt/src/newfile.c
===================================================================
--- uspace/lib/fmgt/src/newfile.c	(revision d101368843a610fee26218d73d35748078bdb56d)
+++ uspace/lib/fmgt/src/newfile.c	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -0,0 +1,169 @@
+/*
+ * 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 management library - creating new 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 "../private/fmgt.h"
+
+#define NEWNAME_LEN 64
+
+/** Suggest file name for new file.
+ *
+ * @param fmgt File management object
+ * @param rstr Place to store pointer to newly allocated string
+ * @return EOK on success or an error code
+ */
+errno_t fmgt_new_file_suggest(char **rstr)
+{
+	errno_t rc;
+	vfs_stat_t stat;
+	unsigned u;
+	char name[NEWNAME_LEN];
+
+	u = 0;
+	while (true) {
+		snprintf(name, sizeof(name), "noname%02u.txt", u);
+		rc = vfs_stat_path(name, &stat);
+		if (rc != EOK)
+			break;
+
+		++u;
+	}
+
+	*rstr = str_dup(name);
+	if (*rstr == NULL)
+		return ENOMEM;
+
+	return EOK;
+}
+
+/** Create new file.
+ *
+ * @param fmgt File management object
+ * @param fname File name
+ * @param fsize Size of new file (number of zero bytes to fill in)
+ * @param flags New file flags
+ * @return EOK on success or an error code
+ */
+errno_t fmgt_new_file(fmgt_t *fmgt, const char *fname, uint64_t fsize,
+    fmgt_nf_flags_t flags)
+{
+	int fd;
+	size_t nw;
+	aoff64_t pos = 0;
+	uint64_t now;
+	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 | WALK_MUST_CREATE,
+	    MODE_WRITE, &fd);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+
+	fmgt->curf_procb = 0;
+	fmgt->curf_totalb = fsize;
+	fmgt->curf_progr = false;
+	fmgt_timer_start(fmgt);
+
+	fmgt_initial_progress_update(fmgt);
+
+	/* Create sparse file? */
+	if ((flags & nf_sparse) != 0) {
+		fmgt->curf_procb = fsize - 1;
+		pos = fsize - 1;
+	}
+
+	while (fmgt->curf_procb < fsize) {
+		now = fsize - fmgt->curf_procb;
+		if (now > BUFFER_SIZE)
+			now = BUFFER_SIZE;
+
+		do {
+			rc = vfs_write(fd, &pos, buffer, now, &nw);
+			if (rc == EOK)
+				break;
+
+			/* I/O error */
+			err.fname = fname;
+			err.optype = fmgt_io_write;
+			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);
+			fmgt_final_progress_update(fmgt);
+			return rc;
+		}
+
+		fmgt->curf_procb += nw;
+
+		/* User requested abort? */
+		if (fmgt_abort_query(fmgt)) {
+			free(buffer);
+			vfs_put(fd);
+			fmgt_final_progress_update(fmgt);
+			return EINTR;
+		}
+	}
+
+	free(buffer);
+	vfs_put(fd);
+	fmgt_final_progress_update(fmgt);
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/fmgt/test/fmgt.c
===================================================================
--- uspace/lib/fmgt/test/fmgt.c	(revision a4301f153aa21cf694bedbfa9397d114925bc506)
+++ uspace/lib/fmgt/test/fmgt.c	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -37,16 +37,4 @@
 PCUT_TEST_SUITE(fmgt);
 
-#define TEMP_DIR "/tmp"
-
-static void test_fmgt_progress(void *, fmgt_progress_t *);
-
-static fmgt_cb_t test_fmgt_cb = {
-	.progress = test_fmgt_progress
-};
-
-typedef struct {
-	unsigned nupdates;
-} test_resp_t;
-
 /** Create and destroy file management object succeeds. */
 PCUT_TEST(create_destroy)
@@ -62,234 +50,3 @@
 }
 
-/** Suggesting new file name succeeds and returns unique name. */
-PCUT_TEST(new_file_suggest)
-{
-	FILE *f = NULL;
-	char *fname1 = NULL;
-	char *fname2 = NULL;
-	errno_t rc;
-	int rv;
-
-	rc = vfs_cwd_set(TEMP_DIR);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Suggest unique file name. */
-	rc = fmgt_new_file_suggest(&fname1);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* See if we can actually create the file. */
-	f = fopen(fname1, "wx");
-	PCUT_ASSERT_NOT_NULL(f);
-	(void) fclose(f);
-
-	/* Now suggest another unique file name. */
-	rc = fmgt_new_file_suggest(&fname2);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* They should be different. */
-	PCUT_ASSERT_FALSE(str_cmp(fname1, fname2) == 0);
-
-	/* Remove the file. */
-	rv = remove(fname1);
-	PCUT_ASSERT_INT_EQUALS(0, rv);
-
-	free(fname1);
-	free(fname2);
-}
-
-/** New empty file can be created. */
-PCUT_TEST(new_file_empty)
-{
-	fmgt_t *fmgt = NULL;
-	char *fname = NULL;
-	errno_t rc;
-	int rv;
-
-	rc = vfs_cwd_set(TEMP_DIR);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_create(&fmgt);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Suggest unique file name. */
-	rc = fmgt_new_file_suggest(&fname);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_new_file(fmgt, fname, 0, nf_none);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Remove the file [this also verifies the file exists]. */
-	rv = remove(fname);
-	PCUT_ASSERT_INT_EQUALS(0, rv);
-
-	free(fname);
-	fmgt_destroy(fmgt);
-}
-
-/** New zero-filled file can be created. */
-PCUT_TEST(new_file_zerofill)
-{
-	FILE *f = NULL;
-	fmgt_t *fmgt = NULL;
-	char *fname = NULL;
-	char buf[128];
-	errno_t rc;
-	size_t nr;
-	size_t total_rd;
-	size_t i;
-	int rv;
-
-	rc = vfs_cwd_set(TEMP_DIR);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_create(&fmgt);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Suggest unique file name. */
-	rc = fmgt_new_file_suggest(&fname);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Verify the file. */
-	f = fopen(fname, "rb");
-	PCUT_ASSERT_NOT_NULL(f);
-	total_rd = 0;
-	do {
-		nr = fread(buf, 1, sizeof(buf), f);
-		for (i = 0; i < nr; i++)
-			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
-
-		total_rd += nr;
-	} while (nr > 0);
-
-	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
-
-	(void)fclose(f);
-
-	/* Remove the file. */
-	rv = remove(fname);
-	PCUT_ASSERT_INT_EQUALS(0, rv);
-
-	free(fname);
-	fmgt_destroy(fmgt);
-}
-
-/** New sparse file can be created. */
-PCUT_TEST(new_file_sparse)
-{
-	FILE *f = NULL;
-	fmgt_t *fmgt = NULL;
-	char *fname = NULL;
-	char buf[128];
-	errno_t rc;
-	size_t nr;
-	size_t total_rd;
-	size_t i;
-	int rv;
-
-	rc = vfs_cwd_set(TEMP_DIR);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_create(&fmgt);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Suggest unique file name. */
-	rc = fmgt_new_file_suggest(&fname);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_new_file(fmgt, fname, 20000, nf_sparse);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Verify the file. */
-	f = fopen(fname, "rb");
-	PCUT_ASSERT_NOT_NULL(f);
-	total_rd = 0;
-	do {
-		nr = fread(buf, 1, sizeof(buf), f);
-		for (i = 0; i < nr; i++)
-			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
-
-		total_rd += nr;
-	} while (nr > 0);
-
-	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
-
-	(void)fclose(f);
-
-	/* Remove the file. */
-	rv = remove(fname);
-	PCUT_ASSERT_INT_EQUALS(0, rv);
-
-	free(fname);
-	fmgt_destroy(fmgt);
-}
-
-/** Initial update provided when requested while creating new file. */
-PCUT_TEST(new_file_init_upd)
-{
-	FILE *f = NULL;
-	fmgt_t *fmgt = NULL;
-	char *fname = NULL;
-	char buf[128];
-	errno_t rc;
-	size_t nr;
-	size_t total_rd;
-	size_t i;
-	test_resp_t resp;
-	int rv;
-
-	rc = vfs_cwd_set(TEMP_DIR);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_create(&fmgt);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	fmgt_set_cb(fmgt, &test_fmgt_cb, (void *)&resp);
-	resp.nupdates = 0;
-
-	fmgt_set_init_update(fmgt, true);
-
-	/* Suggest unique file name. */
-	rc = fmgt_new_file_suggest(&fname);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
-	/* Verify the file. */
-	f = fopen(fname, "rb");
-	PCUT_ASSERT_NOT_NULL(f);
-	total_rd = 0;
-	do {
-		nr = fread(buf, 1, sizeof(buf), f);
-		for (i = 0; i < nr; i++)
-			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
-
-		total_rd += nr;
-	} while (nr > 0);
-
-	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
-
-	(void)fclose(f);
-
-	PCUT_ASSERT_TRUE(resp.nupdates > 0);
-
-	/* Remove the file. */
-	rv = remove(fname);
-	PCUT_ASSERT_INT_EQUALS(0, rv);
-
-	free(fname);
-	fmgt_destroy(fmgt);
-}
-
-static void test_fmgt_progress(void *arg, fmgt_progress_t *progress)
-{
-	test_resp_t *resp = (test_resp_t *)arg;
-
-	(void)progress;
-	++resp->nupdates;
-}
-
 PCUT_EXPORT(fmgt);
Index: uspace/lib/fmgt/test/main.c
===================================================================
--- uspace/lib/fmgt/test/main.c	(revision a4301f153aa21cf694bedbfa9397d114925bc506)
+++ uspace/lib/fmgt/test/main.c	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -32,4 +32,5 @@
 
 PCUT_IMPORT(fmgt);
+PCUT_IMPORT(newfile);
 
 PCUT_MAIN();
Index: uspace/lib/fmgt/test/newfile.c
===================================================================
--- uspace/lib/fmgt/test/newfile.c	(revision d101368843a610fee26218d73d35748078bdb56d)
+++ uspace/lib/fmgt/test/newfile.c	(revision d101368843a610fee26218d73d35748078bdb56d)
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#include <fmgt.h>
+#include <pcut/pcut.h>
+#include <stdio.h>
+#include <str.h>
+#include <vfs/vfs.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(newfile);
+
+#define TEMP_DIR "/tmp"
+
+static void test_fmgt_progress(void *, fmgt_progress_t *);
+
+static fmgt_cb_t test_fmgt_cb = {
+	.progress = test_fmgt_progress
+};
+
+typedef struct {
+	unsigned nupdates;
+} test_resp_t;
+
+/** Suggesting new file name succeeds and returns unique name. */
+PCUT_TEST(new_file_suggest)
+{
+	FILE *f = NULL;
+	char *fname1 = NULL;
+	char *fname2 = NULL;
+	errno_t rc;
+	int rv;
+
+	rc = vfs_cwd_set(TEMP_DIR);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Suggest unique file name. */
+	rc = fmgt_new_file_suggest(&fname1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* See if we can actually create the file. */
+	f = fopen(fname1, "wx");
+	PCUT_ASSERT_NOT_NULL(f);
+	(void) fclose(f);
+
+	/* Now suggest another unique file name. */
+	rc = fmgt_new_file_suggest(&fname2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* They should be different. */
+	PCUT_ASSERT_FALSE(str_cmp(fname1, fname2) == 0);
+
+	/* Remove the file. */
+	rv = remove(fname1);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname1);
+	free(fname2);
+}
+
+/** New empty file can be created. */
+PCUT_TEST(new_file_empty)
+{
+	fmgt_t *fmgt = NULL;
+	char *fname = NULL;
+	errno_t rc;
+	int rv;
+
+	rc = vfs_cwd_set(TEMP_DIR);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Suggest unique file name. */
+	rc = fmgt_new_file_suggest(&fname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_new_file(fmgt, fname, 0, nf_none);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Remove the file [this also verifies the file exists]. */
+	rv = remove(fname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname);
+	fmgt_destroy(fmgt);
+}
+
+/** New zero-filled file can be created. */
+PCUT_TEST(new_file_zerofill)
+{
+	FILE *f = NULL;
+	fmgt_t *fmgt = NULL;
+	char *fname = NULL;
+	char buf[128];
+	errno_t rc;
+	size_t nr;
+	size_t total_rd;
+	size_t i;
+	int rv;
+
+	rc = vfs_cwd_set(TEMP_DIR);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Suggest unique file name. */
+	rc = fmgt_new_file_suggest(&fname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Verify the file. */
+	f = fopen(fname, "rb");
+	PCUT_ASSERT_NOT_NULL(f);
+	total_rd = 0;
+	do {
+		nr = fread(buf, 1, sizeof(buf), f);
+		for (i = 0; i < nr; i++)
+			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
+
+		total_rd += nr;
+	} while (nr > 0);
+
+	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
+
+	(void)fclose(f);
+
+	/* Remove the file. */
+	rv = remove(fname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname);
+	fmgt_destroy(fmgt);
+}
+
+/** New sparse file can be created. */
+PCUT_TEST(new_file_sparse)
+{
+	FILE *f = NULL;
+	fmgt_t *fmgt = NULL;
+	char *fname = NULL;
+	char buf[128];
+	errno_t rc;
+	size_t nr;
+	size_t total_rd;
+	size_t i;
+	int rv;
+
+	rc = vfs_cwd_set(TEMP_DIR);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Suggest unique file name. */
+	rc = fmgt_new_file_suggest(&fname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_new_file(fmgt, fname, 20000, nf_sparse);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Verify the file. */
+	f = fopen(fname, "rb");
+	PCUT_ASSERT_NOT_NULL(f);
+	total_rd = 0;
+	do {
+		nr = fread(buf, 1, sizeof(buf), f);
+		for (i = 0; i < nr; i++)
+			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
+
+		total_rd += nr;
+	} while (nr > 0);
+
+	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
+
+	(void)fclose(f);
+
+	/* Remove the file. */
+	rv = remove(fname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname);
+	fmgt_destroy(fmgt);
+}
+
+/** Initial update provided when requested while creating new file. */
+PCUT_TEST(new_file_init_upd)
+{
+	FILE *f = NULL;
+	fmgt_t *fmgt = NULL;
+	char *fname = NULL;
+	char buf[128];
+	errno_t rc;
+	size_t nr;
+	size_t total_rd;
+	size_t i;
+	test_resp_t resp;
+	int rv;
+
+	rc = vfs_cwd_set(TEMP_DIR);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	fmgt_set_cb(fmgt, &test_fmgt_cb, (void *)&resp);
+	resp.nupdates = 0;
+
+	fmgt_set_init_update(fmgt, true);
+
+	/* Suggest unique file name. */
+	rc = fmgt_new_file_suggest(&fname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_new_file(fmgt, fname, 20000, nf_none);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Verify the file. */
+	f = fopen(fname, "rb");
+	PCUT_ASSERT_NOT_NULL(f);
+	total_rd = 0;
+	do {
+		nr = fread(buf, 1, sizeof(buf), f);
+		for (i = 0; i < nr; i++)
+			PCUT_ASSERT_INT_EQUALS(0, buf[i]);
+
+		total_rd += nr;
+	} while (nr > 0);
+
+	PCUT_ASSERT_INT_EQUALS(20000, total_rd);
+
+	(void)fclose(f);
+
+	PCUT_ASSERT_TRUE(resp.nupdates > 0);
+
+	/* Remove the file. */
+	rv = remove(fname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname);
+	fmgt_destroy(fmgt);
+}
+
+static void test_fmgt_progress(void *arg, fmgt_progress_t *progress)
+{
+	test_resp_t *resp = (test_resp_t *)arg;
+
+	(void)progress;
+	++resp->nupdates;
+}
+
+PCUT_EXPORT(newfile);
