diff --git a/fdtextract.c b/fdtextract.c
index 24cd700892355d20fce604abedffa8935e1a7c8f..5a2a686782d262386c506e1a2b827dda0a5689d8 100644
--- a/fdtextract.c
+++ b/fdtextract.c
@@ -28,6 +28,7 @@
 #include <stdbool.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sendfile.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -37,8 +38,6 @@
 
 #include "util.h"
 
-#define FDT_MAGIC_SIZE  4
-#define MAX_VERSION 17
 #define MAX_PATH_LEN 100
 #define SHA_256_LEN 32
 
@@ -92,21 +91,56 @@ static int list_images(char *buf)
 	return 0;
 }
 
+static ssize_t copy_data(int out_fd, int in_fd, ssize_t size)
+{
+	ssize_t left = size;
+
+	if (left < 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	while (left > 0) {
+		ssize_t written = sendfile(out_fd, in_fd, NULL, left);
+		if (written < 0 && errno == EINVAL)
+			break;
+		if (written < 0)
+			return -1;
+		if (written == 0)
+			return size - left;
+		left -= written;
+	}
+
+	while (left > 0) {
+		char buf[4096];
+		ssize_t count = sizeof(buf) < left ? sizeof(buf) : left;
+		ssize_t written;
+
+		count = read(in_fd, buf, count);
+		if (count < 0)
+			return -1;
+		if (count == 0)
+			break;
+
+		written = write(out_fd, buf, count);
+		if (written < 0)
+			return -1;
+		left -= written;
+		if (written < count)
+			break;
+	}
+
+	return size - left;
+}
+
 /* Extract an image embedded in the FIT. */
-static int extract_image(const char *file, char *name, char *out)
+static int extract_image(char *buf, char *name, int in_fd, int out_fd)
 {
 	char path[MAX_PATH_LEN] = {0};
-	int noffset, fd, count, data_size;
+	int noffset, count, data_size;
 	unsigned int data_offset;
 	const fdt32_t *val;
-	char *buf;
-	char *data;
-	size_t len;
-
-	buf = utilfdt_read(file, &len);
-	if (!buf) {
-		die("could not read: %s\n", file);
-	}
+	bool is_external = false;
 
 	snprintf(path, MAX_PATH_LEN, "/images/%s", name);
 	noffset = fdt_path_offset(buf, path);
@@ -115,9 +149,7 @@ static int extract_image(const char *file, char *name, char *out)
 		return -1;
 	}
 
-	bool is_external = false;
 	/* Get offset of image. Try both relative and absolute offset. */
-
 	if ((val = fdt_getprop(buf, noffset, "data-offset", NULL))) {
 		/* Relative offset */
 		data_offset = fdt32_to_cpu(*val);
@@ -136,32 +168,29 @@ static int extract_image(const char *file, char *name, char *out)
 			fprintf(stderr, "Error: Could not get image size: %s.\n", name);
 			return -1;
 		}
-		data = buf + data_offset;
 		data_size = fdt32_to_cpu(*val);
+		if (lseek(in_fd, data_offset, SEEK_SET) < 0) {
+			fprintf(stderr, "Error: Could not lseek to: %u\n", data_offset);
+			return errno;
+		}
+		count = copy_data(out_fd, in_fd, data_size);
 	} else {
-		data = fdt_getprop(buf, noffset, "data", &data_size);
+		const char *data = fdt_getprop(buf, noffset, "data", &data_size);
 		if (data_size < 0) {
 			fprintf(stderr, "Error: Could not get image data: %s.\n", name);
 			return -1;
 		}
+		count = write(out_fd, data, data_size);
 	}
 
-	/* If output file is provided, write to that file. If not, write
-	   to stdout. */
-	if (out) {
-		fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-		if (fd < 0) {
-			fprintf(stderr, "Error opening output file %s.\n", out);
-			return errno;
-		}
-	} else {
-		fd = STDOUT_FILENO;
+	if (count < 0) {
+		fprintf(stderr, "Error: I/O error while copying image data.\n");
+		return errno;
 	}
 
-	count = write(fd, data, data_size);
 	if (count < data_size) {
-		fprintf(stderr, "Error writing output file %s.\n", out);
-		return errno;
+		fprintf(stderr, "Error: Image data was truncated.\n");
+		return -1;
 	}
 
 	return 0;
@@ -215,18 +244,14 @@ static int get_attribute(char *buf, char *name, char *imagename)
 {
 	int noffset;
 	const char *val = NULL;
-	char path[MAX_PATH_LEN] = {0};
+	char path[MAX_PATH_LEN] = "/";
 
-	if (imagename == NULL) {
-		/* Get path of root node. */
-		noffset = fdt_path_offset(buf, "/");
-	} else {
-		/* Get path of image node. */
+	if (imagename)
 		snprintf(path, MAX_PATH_LEN, "/images/%s", imagename);
-		noffset = fdt_path_offset(buf, path);
-	}
+
+	noffset = fdt_path_offset(buf, path);
 	if (noffset < 0) {
-		fprintf(stderr, "Error: could not find image hash: %s.\n", name);
+		fprintf(stderr, "Error: invalid FDT path: %s\n", path);
 		return -1;
 	}
 
@@ -241,15 +266,10 @@ static int get_attribute(char *buf, char *name, char *imagename)
 	return 0;
 }
 
-char *read_header(const char *file)
+char *read_header(int fd)
 {
 	char *buf;
-	int fd, total_size;
-	size_t len;
-
-	fd = open(file, O_RDONLY);
-	if (fd < 0)
-		return NULL;
+	ssize_t len, total_size;
 
 	/* Read minimal static struct */
 	buf = malloc(FDT_V1_SIZE);
@@ -257,18 +277,27 @@ char *read_header(const char *file)
 		return NULL;
 
 	len = read(fd, buf, FDT_V1_SIZE);
-	if (len < FDT_V1_SIZE)
+	if (len < FDT_V1_SIZE) {
+		free(buf);
 		return NULL;
+	}
 
 	/* Read rest of header */
 	total_size = fdt_totalsize(buf);
+	if (total_size < FDT_V1_SIZE) {
+		free(buf);
+		return NULL;
+	}
+
 	buf = realloc(buf, total_size);
 	if (!buf)
 		return NULL;
 
 	len = read(fd, buf + FDT_V1_SIZE, total_size - FDT_V1_SIZE);
-	if (len < total_size - FDT_V1_SIZE)
+	if (len < total_size - FDT_V1_SIZE) {
+		free(buf);
 		return NULL;
+	}
 
 	return buf;
 }
@@ -280,8 +309,13 @@ int main(int argc, char *argv[])
 	char *buf, *name = NULL, *out = NULL, *imagename = NULL;
 	bool list = false, extract = false,
 		hash = false, attribute = false;
+	int in_fd, out_fd = STDOUT_FILENO;
 
 	while ((opt = util_getopt_long()) != EOF) {
+		if ((opt == 'l' || opt == 'e' || opt == 's' || opt == 'a') &&
+		    (list || extract || hash || attribute))
+			usage("only one of --list/--extract/--hash/--attribute allowed");
+
 		switch (opt) {
 		case_USAGE_COMMON_FLAGS
 
@@ -290,21 +324,21 @@ int main(int argc, char *argv[])
 			break;
 		case 'e':
 			extract = true;
-			name = strdup(optarg);
+			name = optarg;
 			break;
 		case 'o':
-			out = strdup(optarg);
+			out = optarg;
 			break;
 		case 's':
 			hash = true;
-			name = strdup(optarg);
+			name = optarg;
 			break;
 		case 'a':
 			attribute = true;
-			name = strdup(optarg);
+			name = optarg;
 			break;
 		case 'i':
-			imagename = strdup(optarg);
+			imagename = optarg;
 			break;
 		}
 	}
@@ -312,7 +346,12 @@ int main(int argc, char *argv[])
 		usage("missing input filename");
 	file = argv[optind];
 
-	buf = read_header(file);
+	in_fd = open(file, O_RDONLY);
+	if (in_fd < 0) {
+		die("could not open: %s\n", file);
+	}
+
+	buf = read_header(in_fd);
 	if (!buf) {
 		die("could not read header from: %s\n", file);
 	}
@@ -325,6 +364,14 @@ int main(int argc, char *argv[])
 		die("--image should be used with --attribute\n");
 	}
 
+	if (out != NULL && extract == false) {
+		die("--out should be used with --extract\n");
+	}
+
+	if (out && (out_fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+		die("could not open output file: %s\n", out);
+	}
+
 	/* Pass the pointer to the header to read attributes. */
 	if (list)
 		ret = list_images(buf);
@@ -337,17 +384,13 @@ int main(int argc, char *argv[])
 
 	/* Let extract image read the entire file. */
 	if (extract)
-		ret = extract_image(file, name, out);
+		ret = extract_image(buf, name, in_fd, out_fd);
 
-	/* Free up memory */
-	if(buf != NULL)
-		free(buf);
-	if(name != NULL)
-		free(name);
-	if(out != NULL)
-		free(out);
-	if(imagename != NULL)
-		free(imagename);
+	if (out_fd != STDOUT_FILENO)
+		close(out_fd);
+
+	free(buf);
+	close(in_fd);
 
 	return ret;
 }