Revision a3fb0cf9
/dev/null | ||
---|---|---|
1 |
/* user mode linux compatible COW file */ |
|
2 |
#define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
|
3 |
#define COW_VERSION 2 |
|
4 |
|
|
5 |
struct cow_header_v2 { |
|
6 |
uint32_t magic; |
|
7 |
uint32_t version; |
|
8 |
char backing_file[1024]; |
|
9 |
int32_t mtime; |
|
10 |
uint64_t size; |
|
11 |
uint32_t sectorsize; |
|
12 |
}; |
|
13 |
|
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* create a COW disk image |
|
3 |
* |
|
4 |
* Copyright (c) 2003 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <fcntl.h> |
|
32 |
#include <signal.h> |
|
33 |
#include <time.h> |
|
34 |
#include <sys/time.h> |
|
35 |
#include <errno.h> |
|
36 |
#include <sys/stat.h> |
|
37 |
#include <netinet/in.h> |
|
38 |
|
|
39 |
#include "cow.h" |
|
40 |
|
|
41 |
#include "bswap.h" |
|
42 |
|
|
43 |
int cow_create(int cow_fd, const char *image_filename, |
|
44 |
int64_t image_sectors) |
|
45 |
{ |
|
46 |
struct cow_header_v2 cow_header; |
|
47 |
int fd; |
|
48 |
struct stat st; |
|
49 |
|
|
50 |
memset(&cow_header, 0, sizeof(cow_header)); |
|
51 |
cow_header.magic = htonl(COW_MAGIC); |
|
52 |
cow_header.version = htonl(COW_VERSION); |
|
53 |
if (image_filename) { |
|
54 |
fd = open(image_filename, O_RDONLY); |
|
55 |
if (fd < 0) { |
|
56 |
perror(image_filename); |
|
57 |
exit(1); |
|
58 |
} |
|
59 |
image_sectors = lseek64(fd, 0, SEEK_END); |
|
60 |
if (fstat(fd, &st) != 0) { |
|
61 |
close(fd); |
|
62 |
return -1; |
|
63 |
} |
|
64 |
close(fd); |
|
65 |
image_sectors /= 512; |
|
66 |
cow_header.mtime = htonl(st.st_mtime); |
|
67 |
realpath(image_filename, cow_header.backing_file); |
|
68 |
} |
|
69 |
cow_header.sectorsize = htonl(512); |
|
70 |
cow_header.size = image_sectors * 512; |
|
71 |
#ifndef WORDS_BIGENDIAN |
|
72 |
cow_header.size = bswap64(cow_header.size); |
|
73 |
#endif |
|
74 |
write(cow_fd, &cow_header, sizeof(cow_header)); |
|
75 |
/* resize to include at least all the bitmap */ |
|
76 |
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); |
|
77 |
lseek(cow_fd, 0, SEEK_SET); |
|
78 |
return 0; |
|
79 |
} |
|
80 |
|
|
81 |
void help(void) |
|
82 |
{ |
|
83 |
printf("qemu-mkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" |
|
84 |
"usage: qemu-mkcow [-h] [-f disk_image] cow_image [cow_size]\n" |
|
85 |
"Create a Copy On Write disk image from an optional raw disk image\n" |
|
86 |
"\n" |
|
87 |
"-f disk_image set the raw disk image name\n" |
|
88 |
"cow_image the created cow_image\n" |
|
89 |
"cow_size the create cow_image size in MB if no raw disk image is used\n" |
|
90 |
"\n" |
|
91 |
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" |
|
92 |
); |
|
93 |
exit(1); |
|
94 |
} |
|
95 |
|
|
96 |
int main(int argc, char **argv) |
|
97 |
{ |
|
98 |
const char *image_filename, *cow_filename; |
|
99 |
int cow_fd, c, nb_args, simple_image; |
|
100 |
int64_t image_size; |
|
101 |
|
|
102 |
image_filename = NULL; |
|
103 |
image_size = 0; |
|
104 |
simple_image = 0; |
|
105 |
for(;;) { |
|
106 |
c = getopt(argc, argv, "hf:s"); |
|
107 |
if (c == -1) |
|
108 |
break; |
|
109 |
switch(c) { |
|
110 |
case 'h': |
|
111 |
help(); |
|
112 |
break; |
|
113 |
case 'f': |
|
114 |
image_filename = optarg; |
|
115 |
break; |
|
116 |
case 's': |
|
117 |
simple_image = 1; |
|
118 |
break; |
|
119 |
} |
|
120 |
} |
|
121 |
if (!image_filename) |
|
122 |
nb_args = 2; |
|
123 |
else |
|
124 |
nb_args = 1; |
|
125 |
if (optind + nb_args != argc) |
|
126 |
help(); |
|
127 |
|
|
128 |
cow_filename = argv[optind]; |
|
129 |
if (nb_args == 2) { |
|
130 |
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; |
|
131 |
} |
|
132 |
|
|
133 |
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); |
|
134 |
if (!cow_fd < 0) |
|
135 |
return -1; |
|
136 |
if (simple_image) { |
|
137 |
ftruncate64(cow_fd, image_size * 512); |
|
138 |
} else { |
|
139 |
if (cow_create(cow_fd, image_filename, image_size) < 0) { |
|
140 |
fprintf(stderr, "%s: error while formating\n", cow_filename); |
|
141 |
exit(1); |
|
142 |
} |
|
143 |
} |
|
144 |
close(cow_fd); |
|
145 |
return 0; |
|
146 |
} |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
Copyright (C) Matthew Chapman 2003 |
|
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
|
5 |
it under the terms of the GNU General Public License as published by |
|
6 |
the Free Software Foundation; either version 2 of the License, or |
|
7 |
(at your option) any later version. |
|
8 |
|
|
9 |
This program is distributed in the hope that it will be useful, |
|
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
GNU General Public License for more details. |
|
13 |
|
|
14 |
You should have received a copy of the GNU General Public License |
|
15 |
along with this program; if not, write to the Free Software |
|
16 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
17 |
*/ |
|
18 |
|
|
19 |
#define SECTOR_BITS 9 |
|
20 |
#define SECTOR_SIZE (1 << SECTOR_BITS) |
|
21 |
#define SECTOR_MASK (SECTOR_SIZE - 1) |
|
22 |
|
|
23 |
#define L1_BITS (SECTOR_BITS - 3) |
|
24 |
#define L1_SIZE (1 << L1_BITS) |
|
25 |
#define L1_MASK (L1_SIZE - 1) |
|
26 |
|
|
27 |
#define L2_BITS SECTOR_BITS |
|
28 |
#define L2_SIZE (1 << L2_BITS) |
|
29 |
#define L2_MASK (L2_SIZE - 1) |
|
30 |
|
|
31 |
#define MIN(x,y) (((x) < (y)) ? (x) : (y)) |
|
32 |
|
|
33 |
struct cowdisk_header |
|
34 |
{ |
|
35 |
uint32_t version; |
|
36 |
uint32_t flags; |
|
37 |
uint32_t disk_sectors; |
|
38 |
uint32_t granularity; |
|
39 |
uint32_t l1dir_offset; |
|
40 |
uint32_t l1dir_size; |
|
41 |
uint32_t file_sectors; |
|
42 |
uint32_t cylinders; |
|
43 |
uint32_t heads; |
|
44 |
uint32_t sectors_per_track; |
|
45 |
}; |
|
46 |
|
|
47 |
struct cowdisk_header2 |
|
48 |
{ |
|
49 |
uint32_t parent_ts; |
|
50 |
uint32_t timestamp; |
|
51 |
}; |
|
52 |
|
|
53 |
/* based on vdk 3.1 10-11-2003 by Ken Kato */ |
|
54 |
|
|
55 |
struct vmdisk_header |
|
56 |
{ |
|
57 |
uint32_t version; |
|
58 |
uint32_t flags; |
|
59 |
|
|
60 |
int64_t capacity; |
|
61 |
int64_t granularity; |
|
62 |
int64_t desc_offset; |
|
63 |
int64_t desc_size; |
|
64 |
int32_t num_gtes_per_gte; |
|
65 |
int64_t rgd_offset; |
|
66 |
int64_t gd_offset; |
|
67 |
int64_t grain_offset; |
|
68 |
|
|
69 |
char filler[1]; |
|
70 |
|
|
71 |
char check_bytes[4]; |
|
72 |
}; |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
vmdk2raw: convert vmware images to raw disk images |
|
3 |
Copyright (C) Net Integration Technologies 2004 |
|
4 |
Copyright (C) Matthew Chapman 2003 |
|
5 |
|
|
6 |
This program is free software; you can redistribute it and/or modify |
|
7 |
it under the terms of the GNU General Public License as published by |
|
8 |
the Free Software Foundation; either version 2 of the License, or |
|
9 |
(at your option) any later version. |
|
10 |
|
|
11 |
This program is distributed in the hope that it will be useful, |
|
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
GNU General Public License for more details. |
|
15 |
|
|
16 |
You should have received a copy of the GNU General Public License |
|
17 |
along with this program; if not, write to the Free Software |
|
18 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 |
*/ |
|
20 |
|
|
21 |
#include <stdlib.h> |
|
22 |
#include <stdio.h> |
|
23 |
#include <unistd.h> |
|
24 |
#include <fcntl.h> |
|
25 |
#include <inttypes.h> |
|
26 |
#include <sys/types.h> |
|
27 |
#include <string.h> |
|
28 |
#include <sys/stat.h> |
|
29 |
#include <errno.h> |
|
30 |
#include "vmdk.h" |
|
31 |
#include "config-host.h" |
|
32 |
|
|
33 |
static struct cowdisk_header header; |
|
34 |
static struct vmdisk_header header4; |
|
35 |
static off64_t disk_limit; |
|
36 |
static unsigned int granule_size; |
|
37 |
static uint32_t *l1dir; |
|
38 |
|
|
39 |
static unsigned int cached_l2dir; |
|
40 |
static uint32_t l2dir[L2_SIZE]; |
|
41 |
|
|
42 |
static struct vmdk_prm { |
|
43 |
uint32_t grain_table_size; |
|
44 |
uint32_t sectors_per_grain; |
|
45 |
uint32_t sectors_per_table; |
|
46 |
uint32_t directory_size; |
|
47 |
} vdsk; |
|
48 |
|
|
49 |
static size_t read_physical(int fd, off64_t offset, size_t length, void *buffer) |
|
50 |
{ |
|
51 |
size_t n; |
|
52 |
|
|
53 |
if (lseek64(fd, offset, SEEK_SET) == -1) { |
|
54 |
printf(" error trying to seek lseek to %lld", offset); |
|
55 |
return -1; |
|
56 |
} |
|
57 |
|
|
58 |
n = read(fd, buffer, length); |
|
59 |
|
|
60 |
if (n == -1) { |
|
61 |
printf("read from disk %lld", offset); |
|
62 |
return -1; |
|
63 |
} |
|
64 |
|
|
65 |
return n; |
|
66 |
} |
|
67 |
|
|
68 |
static int read_l1dir(int fd, size_t offset, int num) |
|
69 |
{ |
|
70 |
l1dir = malloc(sizeof(*l1dir) * num); |
|
71 |
if (!l1dir) |
|
72 |
return -1; |
|
73 |
return read_physical(fd, offset << SECTOR_BITS, sizeof(*l1dir) * num, (char *)l1dir) != (sizeof(*l1dir) * num); |
|
74 |
} |
|
75 |
|
|
76 |
static int read_l2dir(int fd, size_t offset, int num) |
|
77 |
{ |
|
78 |
return read_physical(fd, offset << SECTOR_BITS, sizeof(l2dir[0]) * num, (char *)l2dir) != sizeof(l2dir); |
|
79 |
} |
|
80 |
|
|
81 |
static size_t copy_virtual(struct vmdk_prm *dsk, int in_fd, int out_fd, off64_t offset, void *buffer, size_t length) |
|
82 |
{ |
|
83 |
|
|
84 |
unsigned int granule_offset; |
|
85 |
unsigned int grain_index; |
|
86 |
unsigned int sector_map_idx; |
|
87 |
|
|
88 |
granule_offset = offset % granule_size; |
|
89 |
length = MIN(length, granule_size - granule_offset); |
|
90 |
length = MIN(length, disk_limit - offset); |
|
91 |
|
|
92 |
sector_map_idx = (offset >> SECTOR_BITS) / dsk->sectors_per_table; |
|
93 |
|
|
94 |
if (sector_map_idx >= dsk->directory_size) { |
|
95 |
fprintf(stderr, "cannot locate grain table for %d in %d\n", sector_map_idx, dsk->directory_size); |
|
96 |
return -1; |
|
97 |
} |
|
98 |
|
|
99 |
if (l1dir[sector_map_idx] == 0) |
|
100 |
goto zero_fill; |
|
101 |
|
|
102 |
if (sector_map_idx != cached_l2dir) { |
|
103 |
if (read_l2dir(in_fd, l1dir[sector_map_idx], dsk->grain_table_size)) { |
|
104 |
fprintf(stderr, "read failed\n"); |
|
105 |
return -1; |
|
106 |
} |
|
107 |
cached_l2dir = sector_map_idx; |
|
108 |
} |
|
109 |
|
|
110 |
grain_index = ((offset >> SECTOR_BITS) % dsk->sectors_per_table) / dsk->sectors_per_grain; |
|
111 |
|
|
112 |
if (grain_index >= dsk->grain_table_size) { |
|
113 |
fprintf(stderr, "grain to large"); |
|
114 |
return -1; |
|
115 |
} |
|
116 |
|
|
117 |
if (l2dir[grain_index] == 0) |
|
118 |
goto zero_fill; |
|
119 |
|
|
120 |
if (read_physical(in_fd, (l2dir[grain_index] << SECTOR_BITS) + granule_offset, length, buffer) != length) { |
|
121 |
fprintf(stderr, "read error 2\n"); |
|
122 |
return -1; |
|
123 |
} |
|
124 |
|
|
125 |
write(out_fd, buffer, length); |
|
126 |
return length; |
|
127 |
|
|
128 |
zero_fill: |
|
129 |
/* the last chunk of the file can not be sparse |
|
130 |
* or the file will be truncated */ |
|
131 |
if (offset + length >= disk_limit) { |
|
132 |
if (lseek64(out_fd, length-1, SEEK_CUR) == (off_t)-1) |
|
133 |
perror("lseek"); |
|
134 |
/* write the last NULL byte instead of seeking */ |
|
135 |
const char nil = 0; |
|
136 |
write(out_fd, &nil, 1); |
|
137 |
} else { |
|
138 |
if (lseek64(out_fd, length, SEEK_CUR) == (off_t)-1) |
|
139 |
perror("lseek"); |
|
140 |
} |
|
141 |
return length; |
|
142 |
} |
|
143 |
|
|
144 |
static int open_vmdk4(int fd) |
|
145 |
{ |
|
146 |
if (read(fd, &header4, sizeof(header4)) != sizeof(header4)) { |
|
147 |
perror("read from disk"); |
|
148 |
return -1; |
|
149 |
} |
|
150 |
|
|
151 |
granule_size = header4.granularity << SECTOR_BITS; |
|
152 |
disk_limit = header4.capacity << SECTOR_BITS; |
|
153 |
|
|
154 |
cached_l2dir = -1; |
|
155 |
vdsk.grain_table_size = header4.num_gtes_per_gte; |
|
156 |
vdsk.sectors_per_grain = header4.granularity; |
|
157 |
vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; |
|
158 |
vdsk.directory_size = (header4.capacity + vdsk.sectors_per_table - 1) / vdsk.sectors_per_table + 1; |
|
159 |
|
|
160 |
if (read_l1dir(fd, header4.rgd_offset, vdsk.directory_size)) |
|
161 |
return -1; |
|
162 |
|
|
163 |
return 0; |
|
164 |
|
|
165 |
} |
|
166 |
|
|
167 |
static int open_vmdk3(int fd) |
|
168 |
{ |
|
169 |
if (read(fd, &header, sizeof(header)) != sizeof(header)) { |
|
170 |
perror("read from disk\n"); |
|
171 |
return -1; |
|
172 |
} |
|
173 |
granule_size = header.granularity << SECTOR_BITS; |
|
174 |
vdsk.sectors_per_grain = header.granularity; |
|
175 |
vdsk.grain_table_size = L2_SIZE; |
|
176 |
vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; |
|
177 |
vdsk.directory_size = L1_SIZE; |
|
178 |
if (read_l1dir(fd, header.l1dir_offset, L1_SIZE)) |
|
179 |
return -1; |
|
180 |
|
|
181 |
disk_limit = header.disk_sectors << SECTOR_BITS; |
|
182 |
|
|
183 |
return fd; |
|
184 |
} |
|
185 |
|
|
186 |
static int open_vmdk(const char *filename) |
|
187 |
{ |
|
188 |
int fd = open(filename, O_RDONLY | O_LARGEFILE); |
|
189 |
if (fd == -1) { |
|
190 |
perror(filename); |
|
191 |
return -1; |
|
192 |
} |
|
193 |
|
|
194 |
char magic[4]; |
|
195 |
if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) { |
|
196 |
perror("read from disk"); |
|
197 |
return -1; |
|
198 |
} |
|
199 |
|
|
200 |
if (!memcmp(magic, "KDMV", sizeof(magic))) { |
|
201 |
open_vmdk4(fd); |
|
202 |
} else if (!memcmp(magic, "COWD", sizeof(magic))) { |
|
203 |
open_vmdk3(fd); |
|
204 |
} else { |
|
205 |
fprintf(stderr, "%s is not a VMware virtual disk image\n", filename); |
|
206 |
return -1; |
|
207 |
} |
|
208 |
|
|
209 |
cached_l2dir = -1; |
|
210 |
return fd; |
|
211 |
} |
|
212 |
|
|
213 |
static void help(void) |
|
214 |
{ |
|
215 |
printf("vmdk2raw\n" |
|
216 |
"usage: vmdk2raw vmware_image output_image\n" |
|
217 |
"\n" |
|
218 |
"vmware_image a vmware cow image\n" |
|
219 |
"output_image the created disk image\n" |
|
220 |
); |
|
221 |
exit(1); |
|
222 |
} |
|
223 |
|
|
224 |
#define BUF_SIZE 0x10000 |
|
225 |
static void copy_disk(in_fd, out_fd) |
|
226 |
{ |
|
227 |
char buf[BUF_SIZE]; |
|
228 |
off64_t i = 0; |
|
229 |
int ret; |
|
230 |
while (i < disk_limit) { |
|
231 |
ret = copy_virtual(&vdsk, in_fd, out_fd, i, buf, sizeof(buf)); |
|
232 |
if (ret < 0) { |
|
233 |
fprintf(stderr, "copying failed\n"); |
|
234 |
exit(-1); |
|
235 |
} |
|
236 |
i += ret; |
|
237 |
} |
|
238 |
} |
|
239 |
|
|
240 |
int main(int argc, char **argv) |
|
241 |
{ |
|
242 |
int out_fd, in_fd; |
|
243 |
|
|
244 |
if (argc < 3) |
|
245 |
help(); |
|
246 |
|
|
247 |
in_fd = open_vmdk(argv[1]); |
|
248 |
if (in_fd < 0) { |
|
249 |
return -1; |
|
250 |
} |
|
251 |
|
|
252 |
out_fd = open(argv[2], O_WRONLY | O_LARGEFILE | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
|
253 |
if (out_fd < 0) { |
|
254 |
perror(argv[2]); |
|
255 |
return -1; |
|
256 |
} |
|
257 |
|
|
258 |
copy_disk(in_fd, out_fd); |
|
259 |
close(out_fd); |
|
260 |
return 0; |
|
261 |
} |
Also available in: Unified diff