--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fs.h>
+
+// XXX: Assuming block size == 512
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <from> <to>\n", argv[0]);
+ return 1;
+ }
+
+ int fi = open(argv[1], O_RDONLY);
+ if (fi < 0) {
+ fprintf(stderr, "Cannot open source %s: %m\n", argv[1]);
+ return 1;
+ }
+
+ int fo = open(argv[2], O_WRONLY);
+ if (fo < 0) {
+ fprintf(stderr, "Cannot open destination %s: %m\n", argv[1]);
+ return 1;
+ }
+
+ struct stat sti, sto;
+ if (fstat(fi, &sti) < 0 || fstat(fo, &sto) < 0) {
+ fprintf(stderr, "Stat failed: %m\n");
+ return 1;
+ }
+ if (!S_ISBLK(sti.st_mode)) {
+ fprintf(stderr, "Input is not a block device\n");
+ return 1;
+ }
+ if (!S_ISBLK(sto.st_mode)) {
+ fprintf(stderr, "Output is not a block device\n");
+ return 1;
+ }
+
+ unsigned long leni, leno;
+ if (ioctl(fi, BLKGETSIZE, &leni) < 0 ||
+ ioctl(fo, BLKGETSIZE, &leno) < 0) {
+ fprintf(stderr, "Cannot get device size: %m\n");
+ return 1;
+ }
+ if (leni > leno) {
+ fprintf(stderr, "Will not fit: %ld > %ld\n", leni, leno);
+ return 1;
+ }
+
+#define BUFSIZE 65536
+ char *buf = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (buf == MAP_FAILED) {
+ fprintf(stderr, "Cannot mmap buffer: %m\n");
+ return 1;
+ }
+
+ unsigned int remi = leni;
+ int verb = 1;
+ while (remi) {
+ int s = (remi < BUFSIZE/512) ? remi : BUFSIZE/512;
+ int l = read(fi, buf, s*512);
+ if (l < 0) {
+ fprintf(stderr, "Read error: %m\n");
+ return 1;
+ }
+ if (l != s*512) {
+ fprintf(stderr, "Short read: %d of %d. Recovering.\n", l, s*512);
+ }
+ int w = write(fo, buf, l);
+ if (w < 0) {
+ fprintf(stderr, "Write error: %m\n");
+ return 1;
+ }
+ if (w != l) {
+ fprintf(stderr, "Short write: %d of %d\n", w, l);
+ return 1;
+ }
+ remi -= s;
+ if (!--verb) {
+ printf("\rCopied %d of %d MB (%d%%)...", (int)((leni-remi)/2048), (int)((leni+2047)/2048),
+ (int)((double)(leni-remi) / leni * 100));
+ verb = 64;
+ }
+ }
+
+ printf("Copied %d MB \n", (int)((leni+2047)/2048));
+ close(fo);
+ close(fi);
+ return 0;
+}