1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32
33 #include "libvhd.h"
34
35 static int
__raw_io_write(int fd,char * buf,uint64_t sec,uint32_t secs)36 __raw_io_write(int fd, char* buf, uint64_t sec, uint32_t secs)
37 {
38 off_t off;
39 size_t ret;
40
41 errno = 0;
42 off = lseek(fd, vhd_sectors_to_bytes(sec), SEEK_SET);
43 if (off == (off_t)-1) {
44 printf("raw parent: seek(0x%08"PRIx64") failed: %d\n",
45 vhd_sectors_to_bytes(sec), -errno);
46 return -errno;
47 }
48
49 ret = write(fd, buf, vhd_sectors_to_bytes(secs));
50 if (ret == vhd_sectors_to_bytes(secs))
51 return 0;
52
53 printf("raw parent: write of 0x%"PRIx64" returned %zd, errno: %d\n",
54 vhd_sectors_to_bytes(secs), ret, -errno);
55 return (errno ? -errno : -EIO);
56 }
57
58 /*
59 * Use 'parent' if the parent is VHD, and 'parent_fd' if the parent is raw
60 */
61 static int
vhd_util_coalesce_block(vhd_context_t * vhd,vhd_context_t * parent,int parent_fd,uint64_t block)62 vhd_util_coalesce_block(vhd_context_t *vhd, vhd_context_t *parent,
63 int parent_fd, uint64_t block)
64 {
65 int i, err;
66 char *buf, *map;
67 uint64_t sec, secs;
68
69 buf = NULL;
70 map = NULL;
71 sec = block * vhd->spb;
72
73 if (vhd->bat.bat[block] == DD_BLK_UNUSED)
74 return 0;
75
76 err = posix_memalign((void **)&buf, 4096, vhd->header.block_size);
77 if (err)
78 return -err;
79
80 err = vhd_io_read(vhd, buf, sec, vhd->spb);
81 if (err)
82 goto done;
83
84 if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, block)) {
85 if (parent->file)
86 err = vhd_io_write(parent, buf, sec, vhd->spb);
87 else
88 err = __raw_io_write(parent_fd, buf, sec, vhd->spb);
89 goto done;
90 }
91
92 err = vhd_read_bitmap(vhd, block, &map);
93 if (err)
94 goto done;
95
96 for (i = 0; i < vhd->spb; i++) {
97 if (!vhd_bitmap_test(vhd, map, i))
98 continue;
99
100 for (secs = 0; i + secs < vhd->spb; secs++)
101 if (!vhd_bitmap_test(vhd, map, i + secs))
102 break;
103
104 if (parent->file)
105 err = vhd_io_write(parent,
106 buf + vhd_sectors_to_bytes(i),
107 sec + i, secs);
108 else
109 err = __raw_io_write(parent_fd,
110 buf + vhd_sectors_to_bytes(i),
111 sec + i, secs);
112 if (err)
113 goto done;
114
115 i += secs;
116 }
117
118 err = 0;
119
120 done:
121 free(buf);
122 free(map);
123 return err;
124 }
125
126 int
vhd_util_coalesce(int argc,char ** argv)127 vhd_util_coalesce(int argc, char **argv)
128 {
129 int err, c;
130 uint64_t i;
131 char *name, *pname;
132 vhd_context_t vhd, parent;
133 int parent_fd = -1;
134
135 name = NULL;
136 pname = NULL;
137 parent.file = NULL;
138
139 if (!argc || !argv)
140 goto usage;
141
142 optind = 0;
143 while ((c = getopt(argc, argv, "n:h")) != -1) {
144 switch (c) {
145 case 'n':
146 name = optarg;
147 break;
148 case 'h':
149 default:
150 goto usage;
151 }
152 }
153
154 if (!name || optind != argc)
155 goto usage;
156
157 err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
158 if (err) {
159 printf("error opening %s: %d\n", name, err);
160 return err;
161 }
162
163 err = vhd_parent_locator_get(&vhd, &pname);
164 if (err) {
165 printf("error finding %s parent: %d\n", name, err);
166 vhd_close(&vhd);
167 return err;
168 }
169
170 if (vhd_parent_raw(&vhd)) {
171 parent_fd = open(pname, O_RDWR | O_DIRECT | O_LARGEFILE, 0644);
172 if (parent_fd == -1) {
173 err = -errno;
174 printf("failed to open parent %s: %d\n", pname, err);
175 vhd_close(&vhd);
176 return err;
177 }
178 } else {
179 err = vhd_open(&parent, pname, VHD_OPEN_RDWR);
180 if (err) {
181 printf("error opening %s: %d\n", pname, err);
182 free(pname);
183 vhd_close(&vhd);
184 return err;
185 }
186 }
187
188 err = vhd_get_bat(&vhd);
189 if (err)
190 goto done;
191
192 if (vhd_has_batmap(&vhd)) {
193 err = vhd_get_batmap(&vhd);
194 if (err)
195 goto done;
196 }
197
198 for (i = 0; i < vhd.bat.entries; i++) {
199 err = vhd_util_coalesce_block(&vhd, &parent, parent_fd, i);
200 if (err)
201 goto done;
202 }
203
204 err = 0;
205
206 done:
207 free(pname);
208 vhd_close(&vhd);
209 if (parent.file)
210 vhd_close(&parent);
211 else
212 close(parent_fd);
213 return err;
214
215 usage:
216 printf("options: <-n name> [-h help]\n");
217 return -EINVAL;
218 }
219