1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * copy_sparse.c -- copy a very large sparse files efficiently
3*6a54128fSAndroid Build Coastguard Worker * (requires root privileges)
4*6a54128fSAndroid Build Coastguard Worker *
5*6a54128fSAndroid Build Coastguard Worker * Copyright 2003, 2004 by Theodore Ts'o.
6*6a54128fSAndroid Build Coastguard Worker *
7*6a54128fSAndroid Build Coastguard Worker * %Begin-Header%
8*6a54128fSAndroid Build Coastguard Worker * This file may be redistributed under the terms of the GNU Public
9*6a54128fSAndroid Build Coastguard Worker * License.
10*6a54128fSAndroid Build Coastguard Worker * %End-Header%
11*6a54128fSAndroid Build Coastguard Worker */
12*6a54128fSAndroid Build Coastguard Worker
13*6a54128fSAndroid Build Coastguard Worker #ifndef __linux__
14*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
15*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
16*6a54128fSAndroid Build Coastguard Worker
main(void)17*6a54128fSAndroid Build Coastguard Worker int main(void) {
18*6a54128fSAndroid Build Coastguard Worker fputs("This program is only supported on Linux!\n", stderr);
19*6a54128fSAndroid Build Coastguard Worker exit(EXIT_FAILURE);
20*6a54128fSAndroid Build Coastguard Worker }
21*6a54128fSAndroid Build Coastguard Worker #else
22*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
23*6a54128fSAndroid Build Coastguard Worker
24*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
25*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
26*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
27*6a54128fSAndroid Build Coastguard Worker #include <string.h>
28*6a54128fSAndroid Build Coastguard Worker #include <time.h>
29*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
30*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
31*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
32*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
33*6a54128fSAndroid Build Coastguard Worker #else
34*6a54128fSAndroid Build Coastguard Worker extern char *optarg;
35*6a54128fSAndroid Build Coastguard Worker extern int optind;
36*6a54128fSAndroid Build Coastguard Worker #endif
37*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
38*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
39*6a54128fSAndroid Build Coastguard Worker #include <sys/vfs.h>
40*6a54128fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
41*6a54128fSAndroid Build Coastguard Worker #include <linux/fd.h>
42*6a54128fSAndroid Build Coastguard Worker
43*6a54128fSAndroid Build Coastguard Worker int verbose = 0;
44*6a54128fSAndroid Build Coastguard Worker
45*6a54128fSAndroid Build Coastguard Worker #define FIBMAP _IO(0x00,1) /* bmap access */
46*6a54128fSAndroid Build Coastguard Worker #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
47*6a54128fSAndroid Build Coastguard Worker
get_bmap(int fd,unsigned long block)48*6a54128fSAndroid Build Coastguard Worker static unsigned long get_bmap(int fd, unsigned long block)
49*6a54128fSAndroid Build Coastguard Worker {
50*6a54128fSAndroid Build Coastguard Worker int ret;
51*6a54128fSAndroid Build Coastguard Worker unsigned long b;
52*6a54128fSAndroid Build Coastguard Worker
53*6a54128fSAndroid Build Coastguard Worker b = block;
54*6a54128fSAndroid Build Coastguard Worker ret = ioctl(fd, FIBMAP, &b);
55*6a54128fSAndroid Build Coastguard Worker if (ret < 0) {
56*6a54128fSAndroid Build Coastguard Worker if (errno == EPERM) {
57*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "No permission to use FIBMAP ioctl; must have root privileges\n");
58*6a54128fSAndroid Build Coastguard Worker exit(1);
59*6a54128fSAndroid Build Coastguard Worker }
60*6a54128fSAndroid Build Coastguard Worker perror("FIBMAP");
61*6a54128fSAndroid Build Coastguard Worker }
62*6a54128fSAndroid Build Coastguard Worker return b;
63*6a54128fSAndroid Build Coastguard Worker }
64*6a54128fSAndroid Build Coastguard Worker
full_read(int fd,char * buf,size_t count)65*6a54128fSAndroid Build Coastguard Worker static int full_read(int fd, char *buf, size_t count)
66*6a54128fSAndroid Build Coastguard Worker {
67*6a54128fSAndroid Build Coastguard Worker int got, total = 0;
68*6a54128fSAndroid Build Coastguard Worker int pass = 0;
69*6a54128fSAndroid Build Coastguard Worker
70*6a54128fSAndroid Build Coastguard Worker while (count > 0) {
71*6a54128fSAndroid Build Coastguard Worker got = read(fd, buf, count);
72*6a54128fSAndroid Build Coastguard Worker if (got == -1) {
73*6a54128fSAndroid Build Coastguard Worker if ((errno == EINTR) || (errno == EAGAIN))
74*6a54128fSAndroid Build Coastguard Worker continue;
75*6a54128fSAndroid Build Coastguard Worker return total ? total : -1;
76*6a54128fSAndroid Build Coastguard Worker }
77*6a54128fSAndroid Build Coastguard Worker if (got == 0) {
78*6a54128fSAndroid Build Coastguard Worker if (pass++ >= 3)
79*6a54128fSAndroid Build Coastguard Worker return total;
80*6a54128fSAndroid Build Coastguard Worker continue;
81*6a54128fSAndroid Build Coastguard Worker }
82*6a54128fSAndroid Build Coastguard Worker pass = 0;
83*6a54128fSAndroid Build Coastguard Worker buf += got;
84*6a54128fSAndroid Build Coastguard Worker total += got;
85*6a54128fSAndroid Build Coastguard Worker count -= got;
86*6a54128fSAndroid Build Coastguard Worker }
87*6a54128fSAndroid Build Coastguard Worker return total;
88*6a54128fSAndroid Build Coastguard Worker }
89*6a54128fSAndroid Build Coastguard Worker
copy_sparse_file(const char * src,const char * dest)90*6a54128fSAndroid Build Coastguard Worker static void copy_sparse_file(const char *src, const char *dest)
91*6a54128fSAndroid Build Coastguard Worker {
92*6a54128fSAndroid Build Coastguard Worker struct stat64 fileinfo;
93*6a54128fSAndroid Build Coastguard Worker long lb, i, fd, ofd, bs, block, numblocks;
94*6a54128fSAndroid Build Coastguard Worker ssize_t got, got2;
95*6a54128fSAndroid Build Coastguard Worker off64_t offset = 0, should_be;
96*6a54128fSAndroid Build Coastguard Worker char *buf;
97*6a54128fSAndroid Build Coastguard Worker
98*6a54128fSAndroid Build Coastguard Worker if (verbose)
99*6a54128fSAndroid Build Coastguard Worker printf("Copying sparse file from %s to %s\n", src, dest);
100*6a54128fSAndroid Build Coastguard Worker
101*6a54128fSAndroid Build Coastguard Worker if (strcmp(src, "-")) {
102*6a54128fSAndroid Build Coastguard Worker if (stat64(src, &fileinfo) < 0) {
103*6a54128fSAndroid Build Coastguard Worker perror("stat");
104*6a54128fSAndroid Build Coastguard Worker exit(1);
105*6a54128fSAndroid Build Coastguard Worker }
106*6a54128fSAndroid Build Coastguard Worker if (!S_ISREG(fileinfo.st_mode)) {
107*6a54128fSAndroid Build Coastguard Worker printf("%s: Not a regular file\n", src);
108*6a54128fSAndroid Build Coastguard Worker exit(1);
109*6a54128fSAndroid Build Coastguard Worker }
110*6a54128fSAndroid Build Coastguard Worker fd = open(src, O_RDONLY | O_LARGEFILE);
111*6a54128fSAndroid Build Coastguard Worker if (fd < 0) {
112*6a54128fSAndroid Build Coastguard Worker perror("open");
113*6a54128fSAndroid Build Coastguard Worker exit(1);
114*6a54128fSAndroid Build Coastguard Worker }
115*6a54128fSAndroid Build Coastguard Worker if (ioctl(fd, FIGETBSZ, &bs) < 0) {
116*6a54128fSAndroid Build Coastguard Worker perror("FIGETBSZ");
117*6a54128fSAndroid Build Coastguard Worker close(fd);
118*6a54128fSAndroid Build Coastguard Worker exit(1);
119*6a54128fSAndroid Build Coastguard Worker }
120*6a54128fSAndroid Build Coastguard Worker if (bs < 0) {
121*6a54128fSAndroid Build Coastguard Worker printf("%s: Invalid block size: %ld\n", src, bs);
122*6a54128fSAndroid Build Coastguard Worker exit(1);
123*6a54128fSAndroid Build Coastguard Worker }
124*6a54128fSAndroid Build Coastguard Worker if (verbose)
125*6a54128fSAndroid Build Coastguard Worker printf("Blocksize of file %s is %ld\n", src, bs);
126*6a54128fSAndroid Build Coastguard Worker numblocks = (fileinfo.st_size + (bs-1)) / bs;
127*6a54128fSAndroid Build Coastguard Worker if (verbose)
128*6a54128fSAndroid Build Coastguard Worker printf("File size of %s is %lld (%ld blocks)\n", src,
129*6a54128fSAndroid Build Coastguard Worker (long long) fileinfo.st_size, numblocks);
130*6a54128fSAndroid Build Coastguard Worker } else {
131*6a54128fSAndroid Build Coastguard Worker fd = 0;
132*6a54128fSAndroid Build Coastguard Worker bs = 1024;
133*6a54128fSAndroid Build Coastguard Worker }
134*6a54128fSAndroid Build Coastguard Worker
135*6a54128fSAndroid Build Coastguard Worker ofd = open(dest, O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0777);
136*6a54128fSAndroid Build Coastguard Worker if (ofd < 0) {
137*6a54128fSAndroid Build Coastguard Worker perror(dest);
138*6a54128fSAndroid Build Coastguard Worker exit(1);
139*6a54128fSAndroid Build Coastguard Worker }
140*6a54128fSAndroid Build Coastguard Worker
141*6a54128fSAndroid Build Coastguard Worker buf = malloc(bs);
142*6a54128fSAndroid Build Coastguard Worker if (!buf) {
143*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "Couldn't allocate buffer");
144*6a54128fSAndroid Build Coastguard Worker exit(1);
145*6a54128fSAndroid Build Coastguard Worker }
146*6a54128fSAndroid Build Coastguard Worker
147*6a54128fSAndroid Build Coastguard Worker for (lb = 0; !fd || lb < numblocks; lb++) {
148*6a54128fSAndroid Build Coastguard Worker if (fd) {
149*6a54128fSAndroid Build Coastguard Worker block = get_bmap(fd, lb);
150*6a54128fSAndroid Build Coastguard Worker if (!block)
151*6a54128fSAndroid Build Coastguard Worker continue;
152*6a54128fSAndroid Build Coastguard Worker should_be = ((off64_t) lb) * bs;
153*6a54128fSAndroid Build Coastguard Worker if (offset != should_be) {
154*6a54128fSAndroid Build Coastguard Worker if (verbose)
155*6a54128fSAndroid Build Coastguard Worker printf("Seeking to %lld\n", should_be);
156*6a54128fSAndroid Build Coastguard Worker if (lseek64(fd, should_be, SEEK_SET) == (off_t) -1) {
157*6a54128fSAndroid Build Coastguard Worker perror("lseek src");
158*6a54128fSAndroid Build Coastguard Worker exit(1);
159*6a54128fSAndroid Build Coastguard Worker }
160*6a54128fSAndroid Build Coastguard Worker if (lseek64(ofd, should_be, SEEK_SET) == (off_t) -1) {
161*6a54128fSAndroid Build Coastguard Worker perror("lseek dest");
162*6a54128fSAndroid Build Coastguard Worker exit(1);
163*6a54128fSAndroid Build Coastguard Worker }
164*6a54128fSAndroid Build Coastguard Worker offset = should_be;
165*6a54128fSAndroid Build Coastguard Worker }
166*6a54128fSAndroid Build Coastguard Worker }
167*6a54128fSAndroid Build Coastguard Worker got = full_read(fd, buf, bs);
168*6a54128fSAndroid Build Coastguard Worker
169*6a54128fSAndroid Build Coastguard Worker if (fd == 0 && got == 0)
170*6a54128fSAndroid Build Coastguard Worker break;
171*6a54128fSAndroid Build Coastguard Worker
172*6a54128fSAndroid Build Coastguard Worker if (got == bs) {
173*6a54128fSAndroid Build Coastguard Worker for (i=0; i < bs; i++)
174*6a54128fSAndroid Build Coastguard Worker if (buf[i])
175*6a54128fSAndroid Build Coastguard Worker break;
176*6a54128fSAndroid Build Coastguard Worker if (i == bs) {
177*6a54128fSAndroid Build Coastguard Worker lseek(ofd, bs, SEEK_CUR);
178*6a54128fSAndroid Build Coastguard Worker offset += bs;
179*6a54128fSAndroid Build Coastguard Worker continue;
180*6a54128fSAndroid Build Coastguard Worker }
181*6a54128fSAndroid Build Coastguard Worker }
182*6a54128fSAndroid Build Coastguard Worker got2 = write(ofd, buf, got);
183*6a54128fSAndroid Build Coastguard Worker if (got != got2) {
184*6a54128fSAndroid Build Coastguard Worker printf("short write\n");
185*6a54128fSAndroid Build Coastguard Worker exit(1);
186*6a54128fSAndroid Build Coastguard Worker }
187*6a54128fSAndroid Build Coastguard Worker offset += got;
188*6a54128fSAndroid Build Coastguard Worker }
189*6a54128fSAndroid Build Coastguard Worker offset = fileinfo.st_size;
190*6a54128fSAndroid Build Coastguard Worker if (fstat64(ofd, &fileinfo) < 0) {
191*6a54128fSAndroid Build Coastguard Worker perror("fstat");
192*6a54128fSAndroid Build Coastguard Worker exit(1);
193*6a54128fSAndroid Build Coastguard Worker }
194*6a54128fSAndroid Build Coastguard Worker if (fileinfo.st_size != offset) {
195*6a54128fSAndroid Build Coastguard Worker lseek64(ofd, offset-1, SEEK_CUR);
196*6a54128fSAndroid Build Coastguard Worker buf[0] = 0;
197*6a54128fSAndroid Build Coastguard Worker write(ofd, buf, 1);
198*6a54128fSAndroid Build Coastguard Worker }
199*6a54128fSAndroid Build Coastguard Worker close(fd);
200*6a54128fSAndroid Build Coastguard Worker close(ofd);
201*6a54128fSAndroid Build Coastguard Worker }
202*6a54128fSAndroid Build Coastguard Worker
usage(const char * progname)203*6a54128fSAndroid Build Coastguard Worker static void usage(const char *progname)
204*6a54128fSAndroid Build Coastguard Worker {
205*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "Usage: %s [-v] source_file destination_file\n", progname);
206*6a54128fSAndroid Build Coastguard Worker exit(1);
207*6a54128fSAndroid Build Coastguard Worker }
208*6a54128fSAndroid Build Coastguard Worker
main(int argc,char ** argv)209*6a54128fSAndroid Build Coastguard Worker int main(int argc, char**argv)
210*6a54128fSAndroid Build Coastguard Worker {
211*6a54128fSAndroid Build Coastguard Worker int c;
212*6a54128fSAndroid Build Coastguard Worker
213*6a54128fSAndroid Build Coastguard Worker while ((c = getopt(argc, argv, "v")) != EOF)
214*6a54128fSAndroid Build Coastguard Worker switch (c) {
215*6a54128fSAndroid Build Coastguard Worker case 'v':
216*6a54128fSAndroid Build Coastguard Worker verbose++;
217*6a54128fSAndroid Build Coastguard Worker break;
218*6a54128fSAndroid Build Coastguard Worker default:
219*6a54128fSAndroid Build Coastguard Worker usage(argv[0]);
220*6a54128fSAndroid Build Coastguard Worker break;
221*6a54128fSAndroid Build Coastguard Worker }
222*6a54128fSAndroid Build Coastguard Worker if (optind+2 != argc)
223*6a54128fSAndroid Build Coastguard Worker usage(argv[0]);
224*6a54128fSAndroid Build Coastguard Worker copy_sparse_file(argv[optind], argv[optind+1]);
225*6a54128fSAndroid Build Coastguard Worker
226*6a54128fSAndroid Build Coastguard Worker return 0;
227*6a54128fSAndroid Build Coastguard Worker }
228*6a54128fSAndroid Build Coastguard Worker #endif
229