diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index cc6e32619751..382b22c36434 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -466,9 +466,7 @@ static int hash_compare(struct swupdate_digest *dgst, unsigned char *hash)
 	return 0;
 }
 
-static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nbytes, unsigned long *offs, unsigned long long seek,
-	int skip_file, int __attribute__ ((__unused__)) compressed,
-	uint32_t *checksum, unsigned char *hash, bool encrypted, const char *imgivt, writeimage callback)
+int copyfile(struct swupdate_copy *args)
 {
 	unsigned int percent, prevpercent = 0;
 	int ret = 0;
@@ -478,12 +476,12 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	unsigned char ivtbuf[AES_BLK_SIZE];
 
 	struct InputState input_state = {
-		.fdin = fdin,
+		.fdin = args->fdin,
 		.source = INPUT_FROM_FD,
 		.inbuf = NULL,
 		.pos = 0,
-		.nbytes = nbytes,
-		.offs = offs,
+		.nbytes = args->nbytes,
+		.offs = args->offs,
 		.dgst = NULL,
 		.checksum = 0
 	};
@@ -522,32 +520,33 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	/*
 	 * If inbuf is set, read from buffer instead of from file
 	 */
-	if (inbuf) {
-		input_state.inbuf = inbuf;
+	if (args->inbuf) {
+		input_state.inbuf = args->inbuf;
 		input_state.source = INPUT_FROM_MEMORY;
 	}
 
 	PipelineStep step = NULL;
 	void *state = NULL;
 	uint8_t buffer[BUFF_SIZE];
+	writeimage callback = args->callback;
 
 	if (!callback) {
 		callback = copy_write;
 	}
 
-	if (checksum)
-		*checksum = 0;
+	if (args->checksum)
+		*args->checksum = 0;
 
-	if (IsValidHash(hash)) {
+	if (IsValidHash(args->hash)) {
 		input_state.dgst = swupdate_HASH_init(SHA_DEFAULT);
 		if (!input_state.dgst)
 			return -EFAULT;
 	}
 
-	if (encrypted) {
+	if (args->encrypted) {
 		aes_key = get_aes_key();
-		if (imgivt && strlen(imgivt)) {
-			if (!is_hex_str(imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), imgivt)) {
+		if (args->imgivt && strlen(args->imgivt)) {
+			if (!is_hex_str(args->imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), args->imgivt)) {
 				ERROR("Invalid image ivt");
 				return -EINVAL;
 			}
@@ -562,12 +561,12 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 		}
 	}
 
-	if (compressed) {
-		if (compressed == COMPRESSED_TRUE) {
+	if (args->compressed) {
+		if (args->compressed == COMPRESSED_TRUE) {
 			WARN("compressed argument: boolean form is deprecated, use compressed = \"zlib\";");
 		}
 #ifdef CONFIG_GUNZIP
-		if (compressed == COMPRESSED_ZLIB || compressed == COMPRESSED_TRUE) {
+		if (args->compressed == COMPRESSED_ZLIB || args->compressed == COMPRESSED_TRUE) {
 			/*
 			 * 16 + MAX_WBITS means that Zlib should expect and decode a
 			 * gzip header.
@@ -583,7 +582,7 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 		} else
 #endif
 #ifdef CONFIG_ZSTD
-		if (compressed == COMPRESSED_ZSTD) {
+		if (args->compressed == COMPRESSED_ZSTD) {
 			if ((zstd_state.dctx = ZSTD_createDStream()) == NULL) {
 				ERROR("ZSTD_createDStream failed");
 				ret = -EFAULT;
@@ -595,22 +594,22 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 		} else
 #endif
 		{
-			TRACE("Requested decompression method (%d) is not configured!", compressed);
+			TRACE("Requested decompression method (%d) is not configured!", args->compressed);
 			ret = -EINVAL;
 			goto copyfile_exit;
 		}
 	}
 
-	if (seek) {
-		int fdout = (out != NULL) ? *(int *)out : -1;
+	if (args->seek) {
+		int fdout = (args->out != NULL) ? *(int *)args->out : -1;
 		if (fdout < 0) {
 			ERROR("out argument: invalid fd or pointer");
 			ret = -EFAULT;
 			goto copyfile_exit;
 		}
 
-		TRACE("offset has been defined: %llu bytes", seek);
-		if (lseek(fdout, seek, SEEK_SET) < 0) {
+		TRACE("offset has been defined: %llu bytes", args->seek);
+		if (lseek(fdout, args->seek, SEEK_SET) < 0) {
 			ERROR("offset argument: seek failed");
 			ret = -EFAULT;
 			goto copyfile_exit;
@@ -620,7 +619,7 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	step = &input_step;
 	state = &input_state;
 
-	if (encrypted) {
+	if (args->encrypted) {
 		decrypt_state.upstream_step = step;
 		decrypt_state.upstream_state = state;
 		step = &decrypt_step;
@@ -628,7 +627,7 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	}
 
 #if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD)
-	if (compressed) {
+	if (args->compressed) {
 		decompress_state.upstream_step = step;
 		decompress_state.upstream_state = state;
 		step = decompress_step;
@@ -644,7 +643,7 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 		if (ret == 0) {
 			break;
 		}
-		if (skip_file) {
+		if (args->skip_file) {
 			continue;
 		}
 		len = ret;
@@ -654,31 +653,32 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 		 * results corrupted. This lets the cleanup routine
 		 * to remove it
 		 */
-		if (callback(out, buffer, len) < 0) {
+		if (callback(args->out, buffer, len) < 0) {
 			ret = -ENOSPC;
 			goto copyfile_exit;
 		}
 
-		percent = (unsigned)(100ULL * (nbytes - input_state.nbytes) / nbytes);
+		percent = (unsigned)(100ULL * (args->nbytes - input_state.nbytes) / args->nbytes);
 		if (percent != prevpercent) {
 			prevpercent = percent;
 			swupdate_progress_update(percent);
 		}
 	}
 
-	if (IsValidHash(hash) && hash_compare(input_state.dgst, hash) < 0) {
+	if (IsValidHash(args->hash) && hash_compare(input_state.dgst, args->hash) < 0) {
 		ret = -EFAULT;
 		goto copyfile_exit;
 	}
 
-	if (!inbuf) {
-		ret = _fill_buffer(fdin, buffer, NPAD_BYTES(*offs), offs, checksum, NULL);
+	if (!args->inbuf) {
+		ret = _fill_buffer(args->fdin, buffer, NPAD_BYTES(*args->offs),
+				   args->offs, args->checksum, NULL);
 		if (ret < 0)
 			DEBUG("Padding bytes are not read, ignoring");
 	}
 
-	if (checksum != NULL) {
-		*checksum = input_state.checksum;
+	if (args->checksum != NULL) {
+		*args->checksum = input_state.checksum;
 	}
 
 	ret = 0;
@@ -704,57 +704,23 @@ copyfile_exit:
 	return ret;
 }
 
-int copyfile(int fdin, void *out, size_t nbytes, unsigned long *offs, unsigned long long seek,
-	int skip_file, int __attribute__ ((__unused__)) compressed,
-	uint32_t *checksum, unsigned char *hash, bool encrypted, const char *imgivt, writeimage callback)
-{
-	return __swupdate_copy(fdin,
-				NULL,
-				out,
-				nbytes,
-				offs,
-				seek,
-				skip_file,
-				compressed,
-				checksum,
-				hash,
-				encrypted,
-				imgivt,
-				callback);
-}
-
-int copybuffer(unsigned char *inbuf, void *out, size_t nbytes, int __attribute__ ((__unused__)) compressed,
-	unsigned char *hash, bool encrypted, const char *imgivt, writeimage callback)
-{
-	return __swupdate_copy(-1,
-				inbuf,
-				out,
-				nbytes,
-				NULL,
-				0,
-				0,
-				compressed,
-				NULL,
-				hash,
-				encrypted,
-				imgivt,
-				callback);
-}
-
 int copyimage(void *out, struct img_type *img, writeimage callback)
 {
-	return copyfile(img->fdin,
-			out,
-			img->size,
-			(unsigned long *)&img->offset,
-			img->seek,
-			0, /* no skip */
-			img->compressed,
-			&img->checksum,
-			img->sha256,
-			img->is_encrypted,
-			img->ivt_ascii,
-			callback);
+	struct swupdate_copy copy = {
+		.fdin = img->fdin,
+		.out = out,
+		.callback = callback,
+		.nbytes = img->size,
+		.offs = (unsigned long*)&img->offset,
+		.seek = img->seek,
+		.skip_file = 0,
+		.compressed = img->compressed,
+		.checksum = &img->checksum,
+		.hash = img->sha256,
+		.encrypted = img->is_encrypted,
+		.imgivt = img->ivt_ascii,
+	};
+	return copyfile(&copy);
 }
 
 int extract_cpio_header(int fd, struct filehdr *fhdr, unsigned long *offset)
@@ -837,8 +803,15 @@ int cpio_scan(int fd, struct swupdate_cfg *cfg, off_t start)
 		 * use copyfile for checksum and hash verification, as we skip file
 		 * we do not have to provide fdout
 		 */
-		if (copyfile(fd, NULL, fdh.size, &offset, 0, 1, 0, &checksum, img ? img->sha256 : NULL,
-				false, NULL, NULL) != 0) {
+		struct swupdate_copy copy = {
+			.fdin = fd,
+			.nbytes = fdh.size,
+			.offs = &offset,
+			.skip_file = 1,
+			.checksum = &checksum,
+			.hash = img ? img->sha256 : NULL,
+		};
+		if (copyfile(&copy) != 0) {
 			ERROR("invalid archive");
 			return -1;
 		}
diff --git a/core/installer.c b/core/installer.c
index cc5ca34b013d..0cb06b2ca419 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -141,13 +141,18 @@ static int extract_scripts(struct imglist *head)
 			return -ENOENT;
 		}
 
-		ret = copyfile(fdin, &fdout, script->size, &offset, 0, 0,
-				script->compressed,
-				&checksum,
-				script->sha256,
-				script->is_encrypted,
-				script->ivt_ascii,
-				NULL);
+		struct swupdate_copy copy = {
+			.fdin = fdin,
+			.out = &fdout,
+			.nbytes = script->size,
+			.offs = &offset,
+			.compressed = script->compressed,
+			.checksum = &checksum,
+			.hash = script->sha256,
+			.encrypted = script->is_encrypted,
+			.imgivt = script->ivt_ascii,
+		};
+		ret = copyfile(&copy);
 		close(fdin);
 		close(fdout);
 
diff --git a/core/stream_interface.c b/core/stream_interface.c
index 5f3ad2e3fd93..14a483b19648 100644
--- a/core/stream_interface.c
+++ b/core/stream_interface.c
@@ -103,8 +103,15 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,
 	if (fdout < 0)
 		return -1;
 
-	if (copyfile(fd, &fdout, fdh.size, poffs, 0, 0, 0, &checksum, NULL,
-		     encrypted, NULL, NULL) < 0) {
+	struct swupdate_copy copy = {
+		.fdin = fd,
+		.out = &fdout,
+		.nbytes = fdh.size,
+		.offs = poffs,
+		.checksum = &checksum,
+		.encrypted = encrypted,
+	};
+	if (copyfile(&copy) < 0) {
 		close(fdout);
 		return -1;
 	}
@@ -230,6 +237,13 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 			fdout = -1;
 			offset = 0;
 
+			struct swupdate_copy copy = {
+				.fdin = fd,
+				.out = &fdout,
+				.nbytes = fdh.size,
+				.offs = &offset,
+				.checksum = &checksum,
+			};
 			/*
 			 * If images are not streamed directly into the target
 			 * copy them into TMPDIR to check if it is all ok
@@ -243,7 +257,8 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 					close(fdout);
 					return -1;
 				}
-				if (copyfile(fd, &fdout, fdh.size, &offset, 0, 0, 0, &checksum, img->sha256, false, NULL, NULL) < 0) {
+				copy.hash = img->sha256;
+				if (copyfile(&copy) < 0) {
 					close(fdout);
 					return -1;
 				}
@@ -255,7 +270,8 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 				break;
 
 			case SKIP_FILE:
-				if (copyfile(fd, &fdout, fdh.size, &offset, 0, skip, 0, &checksum, NULL, false, NULL, NULL) < 0) {
+				copy.skip_file = 1;
+				if (copyfile(&copy) < 0) {
 					return -1;
 				}
 				if (!swupdate_verify_chksum(checksum, &fdh)) {
diff --git a/handlers/copy_handler.c b/handlers/copy_handler.c
index 3e2f1f40f9e5..0dcb540a119e 100644
--- a/handlers/copy_handler.c
+++ b/handlers/copy_handler.c
@@ -121,18 +121,14 @@ static int copy_single_file(const char *path, ssize_t size, struct img_type *img
 	 * Copying from device itself,
 	 * no encryption or compression
 	 */
-	ret = copyfile(fdin,
-			&fdout,
-			size,
-			&offset,
-			0,
-			0, /* no skip */
-			0, /* no compressed */
-			&checksum,
-			0, /* no sha256 */
-			false, /* no encrypted */
-			NULL, /* no IVT */
-			NULL);
+	struct swupdate_copy copy = {
+		.fdin = fdin,
+		.out = &fdout,
+		.nbytes = size,
+		.offs = &offset,
+		.checksum = &checksum,
+	};
+	ret = copyfile(&copy);
 
 	close(fdout);
 	void *status;
diff --git a/handlers/delta_handler.c b/handlers/delta_handler.c
index 5ec243ee01d9..a14181f11d49 100644
--- a/handlers/delta_handler.c
+++ b/handlers/delta_handler.c
@@ -161,14 +161,14 @@ static int network_process_data(multipart_parser* p, const char *at, size_t leng
 					zck_get_chunk_number(priv->chunk),
 					priv->current.chunksize);
 			if (priv->current.chunksize != 0) {
-				ret = copybuffer(priv->current.buf,
-						 &priv->fdout,
-						 priv->current.chunksize,
-						 COMPRESSED_ZSTD,
-						 hash,
-						 0,
-						 NULL,
-						 NULL);
+				struct swupdate_copy copy = {
+					.inbuf = priv->current.buf,
+					.out = &priv->fdout,
+					.nbytes = priv->current.chunksize,
+					.compressed = COMPRESSED_ZSTD,
+					.hash = hash,
+				};
+				ret = copyfile(&copy);
 			} else
 				ret = 0; /* skipping, nothing to be copied */
 			/* Buffer can be discarged */
@@ -178,7 +178,7 @@ static int network_process_data(multipart_parser* p, const char *at, size_t leng
 			 * if an error occurred, stops
 			 */
 			if (ret) {
-				ERROR("copybuffer failed !");
+				ERROR("copyfile failed !");
 				priv->error_in_parser = true;
 				return -EFAULT;
 			}
@@ -845,8 +845,15 @@ static bool copy_existing_chunks(zckChunk **dstChunk, struct hnd_priv *priv)
 				zck_get_chunk_number(chunk),
 				start,
 				len);
-		ret = copyfile(priv->fdsrc, &priv->fdout, len, &offset, 0, 0, COMPRESSED_FALSE,
-				&checksum, hash, false, NULL, NULL);
+		struct swupdate_copy copy = {
+			.fdin = priv->fdsrc,
+			.out = &priv->fdout,
+			.nbytes = len,
+			.offs = &offset,
+			.checksum = &checksum,
+			.hash = hash,
+		};
+		ret = copyfile(&copy);
 
 		free(sha);
 		if (ret)
diff --git a/handlers/readback_handler.c b/handlers/readback_handler.c
index 70a82c1a893c..9e462eabe8e5 100644
--- a/handlers/readback_handler.c
+++ b/handlers/readback_handler.c
@@ -102,18 +102,14 @@ static int readback_postinst(struct img_type *img)
 	 * the input device.
 	 */
 	unsigned long offset_out = 0;
-	int status = copyfile(fdin,
-			NULL,  /* no output */
-			size,
-			&offset_out,
-			0,     /* no output seek */
-			1,     /* skip file, do not write to the output */
-			0,     /* no compressed */
-			NULL,  /* no checksum */
-			hash,
-			false,     /* no encrypted */
-			NULL,     /* no IVT */
-			NULL); /* no callback */
+	struct swupdate_copy copy = {
+		.fdin = fdin,
+		.nbytes = size,
+		.offs = &offset_out,
+		.skip_file = 1,
+		.hash = hash,
+	};
+	int status = copyfile(&copy);
 	if (status == 0) {
 		INFO("Readback verification success");
 	} else {
diff --git a/include/util.h b/include/util.h
index 77da1b17ce15..1703514269f1 100644
--- a/include/util.h
+++ b/include/util.h
@@ -56,13 +56,42 @@ typedef enum {
 	SERVER_ID_REQUESTED,
 } server_op_res_t;
 
-enum {
+enum compression_type {
   COMPRESSED_FALSE,
   COMPRESSED_TRUE,
   COMPRESSED_ZLIB,
   COMPRESSED_ZSTD,
 };
 
+typedef int (*writeimage) (void *out, const void *buf, size_t len);
+
+struct swupdate_copy {
+	/* input: either fdin is set or fdin < 0 and inbuf */
+	int fdin;
+	unsigned char *inbuf;
+	/* data handler callback and output argument.
+	 * out must point to a fd if seeking */
+	writeimage callback;
+	void *out;
+	/* amount of data to copy */
+	size_t nbytes;
+	/* pointer to offset within source, must be set for fd */
+	unsigned long *offs;
+	/* absolute offset to seek in output (*out) if non-zero */
+	unsigned long long seek;
+	/* skip callback: only verify input */
+	int skip_file;
+	/* decompression to use */
+	enum compression_type compressed;
+	/* cpio crc checksum */
+	uint32_t *checksum;
+	/* sw-description sha256 checksum */
+	unsigned char *hash;
+	/* encryption */
+	bool encrypted;
+	const char *imgivt;
+};
+
 /*
  * loglevel is used into TRACE / ERROR
  * for values > LASTLOGLEVEL, it is an encoded field 
@@ -188,8 +217,6 @@ bool strtobool(const char *s);
 /*
  * Function to extract / copy images
  */
-typedef int (*writeimage) (void *out, const void *buf, size_t len);
-
 void *saferealloc(void *ptr, size_t size);
 int copy_write(void *out, const void *buf, size_t len);
 #if defined(__FreeBSD__)
@@ -200,13 +227,8 @@ int copy_write_padded(void *out, const void *buf, size_t len);
 size_t
 strlcpy(char *dst, const char * src, size_t size);
 #endif
-int copyfile(int fdin, void *out, size_t nbytes, unsigned long *offs,
-	unsigned long long seek,
-	int skip_file, int compressed, uint32_t *checksum,
-	unsigned char *hash, bool encrypted, const char *imgivt, writeimage callback);
+int copyfile(struct swupdate_copy *copy);
 int copyimage(void *out, struct img_type *img, writeimage callback);
-int copybuffer(unsigned char *inbuf, void *out, size_t nbytes, int compressed,
-	unsigned char *hash, bool encrypted, const char *imgivt, writeimage callback);
 int openfileoutput(const char *filename);
 int mkpath(char *dir, mode_t mode);
 int swupdate_file_setnonblock(int fd, bool block);
