1 /* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $FreeBSD$ 10 */ 11 #include <stdio.h> 12 #include <stdint.h> 13 #include <stdlib.h> 14 #include <err.h> 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <time.h> 18 #include <unistd.h> 19 #include <sys/queue.h> 20 #include <sys/disk.h> 21 #include <sys/stat.h> 22 23 #define BIGSIZE (1024 * 1024) 24 #define MEDIUMSIZE (64 * 1024) 25 #define MINSIZE (512) 26 27 struct lump { 28 off_t start; 29 off_t len; 30 int state; 31 TAILQ_ENTRY(lump) list; 32 }; 33 34 static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps); 35 36 37 static void 38 new_lump(off_t start, off_t len, int state) 39 { 40 struct lump *lp; 41 42 lp = malloc(sizeof *lp); 43 if (lp == NULL) 44 err(1, "Malloc failed"); 45 lp->start = start; 46 lp->len = len; 47 lp->state = state; 48 TAILQ_INSERT_TAIL(&lumps, lp, list); 49 } 50 51 int 52 main(int argc, const char **argv) 53 { 54 int fdr, fdw; 55 struct lump *lp; 56 off_t t, d; 57 size_t i, j; 58 int error, flags; 59 u_char *buf; 60 u_int sectorsize, minsize; 61 time_t t1, t2; 62 struct stat sb; 63 64 65 if (argc < 2) 66 errx(1, "Usage: %s source-drive [destination]", argv[0]); 67 68 buf = malloc(BIGSIZE); 69 if (buf == NULL) 70 err(1, "Cannot allocate %d bytes buffer", BIGSIZE); 71 fdr = open(argv[1], O_RDONLY); 72 if (fdr < 0) 73 err(1, "Cannot open read descriptor %s", argv[1]); 74 75 error = fstat(fdr, &sb); 76 if (error < 0) 77 err(1, "fstat failed"); 78 flags = O_WRONLY; 79 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { 80 error = ioctl(fdr, DIOCGSECTORSIZE, §orsize); 81 if (error < 0) 82 err(1, "DIOCGSECTORSIZE failed"); 83 minsize = sectorsize; 84 85 error = ioctl(fdr, DIOCGMEDIASIZE, &t); 86 if (error < 0) 87 err(1, "DIOCGMEDIASIZE failed"); 88 } else { 89 sectorsize = 1; 90 t = sb.st_size; 91 minsize = MINSIZE; 92 flags |= O_CREAT | O_TRUNC; 93 } 94 95 if (argc > 2) { 96 fdw = open(argv[2], flags, DEFFILEMODE); 97 if (fdw < 0) 98 err(1, "Cannot open write descriptor %s", argv[2]); 99 } else { 100 fdw = -1; 101 } 102 103 new_lump(0, t, 0); 104 d = 0; 105 106 t1 = 0; 107 for (;;) { 108 lp = TAILQ_FIRST(&lumps); 109 if (lp == NULL) 110 break; 111 TAILQ_REMOVE(&lumps, lp, list); 112 while (lp->len > 0) { 113 i = BIGSIZE; 114 if (lp->len < BIGSIZE) 115 i = lp->len; 116 if (lp->state == 1) 117 i = MEDIUMSIZE; 118 if (lp->state > 1) 119 i = minsize; 120 time(&t2); 121 if (t1 != t2 || lp->len < BIGSIZE) { 122 printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f", 123 (intmax_t)lp->start, 124 i, 125 (intmax_t)lp->len, 126 lp->state, 127 (intmax_t)d, 128 (intmax_t)(t - d), 129 (double)d/(double)t); 130 t1 = t2; 131 } 132 if (i == 0) { 133 errx(1, "BOGUS i %10jd", (intmax_t)i); 134 } 135 fflush(stdout); 136 j = pread(fdr, buf, i, lp->start); 137 if (j == i) { 138 d += i; 139 if (fdw >= 0) 140 j = pwrite(fdw, buf, i, lp->start); 141 else 142 j = i; 143 if (j != i) 144 printf("\nWrite error at %jd/%zu\n", 145 lp->start, i); 146 lp->start += i; 147 lp->len -= i; 148 continue; 149 } 150 printf("\n%jd %zu failed %d\n", lp->start, i, errno); 151 new_lump(lp->start, i, lp->state + 1); 152 lp->start += i; 153 lp->len -= i; 154 } 155 free(lp); 156 } 157 printf("\nCompleted\n"); 158 exit (0); 159 } 160 161