]> mj.ucw.cz Git - misc.git/blob - verbose-copy.c
Merge branch 'master' of git+ssh://git.ucw.cz/home/mj/GIT/misc
[misc.git] / verbose-copy.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <sys/stat.h>
6 #include <sys/ioctl.h>
7 #include <sys/mman.h>
8 #include <linux/fs.h>
9
10 // XXX: Assuming block size == 512
11
12 int main(int argc, char **argv)
13 {
14         if (argc != 3) {
15                 fprintf(stderr, "Usage: %s <from> <to>\n", argv[0]);
16                 return 1;
17         }
18
19         int fi = open(argv[1], O_RDONLY);
20         if (fi < 0) {
21                 fprintf(stderr, "Cannot open source %s: %m\n", argv[1]);
22                 return 1;
23         }
24
25         int fo = open(argv[2], O_WRONLY);
26         if (fo < 0) {
27                 fprintf(stderr, "Cannot open destination %s: %m\n", argv[1]);
28                 return 1;
29         }
30
31         struct stat sti, sto;
32         if (fstat(fi, &sti) < 0 || fstat(fo, &sto) < 0) {
33                 fprintf(stderr, "Stat failed: %m\n");
34                 return 1;
35         }
36         if (!S_ISBLK(sti.st_mode)) {
37                 fprintf(stderr, "Input is not a block device\n");
38                 return 1;
39         }
40         if (!S_ISBLK(sto.st_mode)) {
41                 fprintf(stderr, "Output is not a block device\n");
42                 return 1;
43         }
44
45         unsigned long leni, leno;
46         if (ioctl(fi, BLKGETSIZE, &leni) < 0 ||
47             ioctl(fo, BLKGETSIZE, &leno) < 0) {
48                 fprintf(stderr, "Cannot get device size: %m\n");
49                 return 1;
50         }
51         if (leni > leno) {
52                 fprintf(stderr, "Will not fit: %ld > %ld\n", leni, leno);
53                 return 1;
54         }
55
56 #define BUFSIZE 65536
57         char *buf = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
58         if (buf == MAP_FAILED) {
59                 fprintf(stderr, "Cannot mmap buffer: %m\n");
60                 return 1;
61         }
62
63         unsigned int remi = leni;
64         int verb = 1;
65         while (remi) {
66                 int s = (remi < BUFSIZE/512) ? remi : BUFSIZE/512;
67                 int l = read(fi, buf, s*512);
68                 if (l < 0) {
69                         fprintf(stderr, "Read error: %m\n");
70                         return 1;
71                 }
72                 if (l != s*512) {
73                         fprintf(stderr, "Short read: %d of %d. Recovering.\n", l, s*512);
74                 }
75                 int w = write(fo, buf, l);
76                 if (w < 0) {
77                         fprintf(stderr, "Write error: %m\n");
78                         return 1;
79                 }
80                 if (w != l) {
81                         fprintf(stderr, "Short write: %d of %d\n", w, l);
82                         return 1;
83                 }
84                 remi -= s;
85                 if (!--verb) {
86                         printf("\rCopied %d of %d MB (%d%%)...", (int)((leni-remi)/2048), (int)((leni+2047)/2048),
87                                 (int)((double)(leni-remi) / leni * 100));
88                         verb = 64;
89                 }
90         }
91
92         printf("Copied %d MB                                       \n", (int)((leni+2047)/2048));
93         close(fo);
94         close(fi);
95         return 0;
96 }