diff --git a/libtap/tap/files.c b/libtap/tap/files.c
index 90f087f3724cfb206f4866b6ce195f73cf65549e..2e67e9e57975b8ca8a33272f4bb5281a9f600baa 100644
--- a/libtap/tap/files.c
+++ b/libtap/tap/files.c
@@ -16,6 +16,7 @@
 
 #include "files.h"
 
+#include "../../src/contrib/string.c"
 #include "../../src/contrib/files.c"
 
 #include <stdlib.h>
diff --git a/src/contrib/files.c b/src/contrib/files.c
index cb55dcac3bbccbfe49e74417dbef7d337c8930a9..e654ea79a8393488733fe693389131eed4a7005a 100644
--- a/src/contrib/files.c
+++ b/src/contrib/files.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include "contrib/string.h"
 #include "libknot/errcode.h"
 
 static bool special_name(const char *name)
@@ -140,3 +141,44 @@ int make_path(const char *path, mode_t mode)
 
 	return KNOT_EOK;
 }
+
+int open_tmp_file(const char *path, char **tmp_name, FILE **file, mode_t mode)
+{
+	int ret;
+
+	*tmp_name = sprintf_alloc("%s.XXXXXX", path);
+	if (*tmp_name == NULL) {
+		ret = KNOT_ENOMEM;
+		goto open_tmp_failed;
+	}
+
+	int fd = mkstemp(*tmp_name);
+	if (fd < 0) {
+		ret = knot_map_errno();
+		goto open_tmp_failed;
+	}
+
+	if (fchmod(fd, mode) != 0) {
+		ret = knot_map_errno();
+		close(fd);
+		unlink(*tmp_name);
+		goto open_tmp_failed;
+	}
+
+	*file = fdopen(fd, "w");
+	if (*file == NULL) {
+		ret = knot_map_errno();
+		close(fd);
+		unlink(*tmp_name);
+		goto open_tmp_failed;
+	}
+
+	return KNOT_EOK;
+open_tmp_failed:
+	free(*tmp_name);
+	*tmp_name = NULL;
+	*file = NULL;
+
+	assert(ret != KNOT_EOK);
+	return ret;
+}
diff --git a/src/contrib/files.h b/src/contrib/files.h
index 2d83dbf48b3686885f7b5542027f0dfbbb6afc07..c4c681f866699efcf5ed7c4e7ea2aea5cfde6bca 100644
--- a/src/contrib/files.h
+++ b/src/contrib/files.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <stdbool.h>
+#include <stdio.h>
 #include <sys/types.h>
 
 /*!
@@ -35,3 +36,8 @@ int make_dir(const char *path, mode_t mode, bool ignore_existing);
  * Makes a directory part of the path with all parent directories if not exist.
  */
 int make_path(const char *path, mode_t mode);
+
+/*!
+ * Creates and opens for writing a temporary file based on given path.
+ */
+int open_tmp_file(const char *path, char **tmp_name, FILE **file, mode_t mode);
diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c
index 58b5c7b941a4cfe37d06cc22d0ae6c7c30346a91..ce8502f60b0ba92400de1f4d6b0d39d6eeea65ad 100644
--- a/src/knot/zone/zonefile.c
+++ b/src/knot/zone/zonefile.c
@@ -28,7 +28,6 @@
 #include "libknot/libknot.h"
 #include "contrib/files.h"
 #include "contrib/macros.h"
-#include "contrib/string.h"
 #include "knot/common/log.h"
 #include "knot/dnssec/zone-nsec.h"
 #include "knot/zone/semantic-check.h"
@@ -299,47 +298,6 @@ int zonefile_exists(const char *path, time_t *mtime)
 	return KNOT_EOK;
 }
 
-/*! \brief Open a temporary zonefile. */
-static int open_tmp_filename(const char *name, char **tmp_name, FILE **file)
-{
-	int ret;
-
-	*tmp_name = sprintf_alloc("%s.XXXXXX", name);
-	if (*tmp_name == NULL) {
-		ret = KNOT_ENOMEM;
-		goto open_tmp_failed;
-	}
-
-	int fd = mkstemp(*tmp_name);
-	if (fd < 0) {
-		ret = knot_map_errno();
-		goto open_tmp_failed;
-	}
-
-	if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0) {
-		ret = knot_map_errno();
-		close(fd);
-		unlink(*tmp_name);
-		goto open_tmp_failed;
-	}
-
-	*file = fdopen(fd, "w");
-	if (*file == NULL) {
-		ret = knot_map_errno();
-		close(fd);
-		unlink(*tmp_name);
-		goto open_tmp_failed;
-	}
-
-	return KNOT_EOK;
-open_tmp_failed:
-	free(*tmp_name);
-	*tmp_name = NULL;
-
-	assert(ret != KNOT_EOK);
-	return ret;
-}
-
 int zonefile_write(const char *path, zone_contents_t *zone)
 {
 	if (!zone || !path) {
@@ -353,7 +311,7 @@ int zonefile_write(const char *path, zone_contents_t *zone)
 
 	FILE *file = NULL;
 	char *tmp_name = NULL;
-	ret = open_tmp_filename(path, &tmp_name, &file);
+	ret = open_tmp_file(path, &tmp_name, &file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}