1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) |
4 | */ |
5 | |
6 | /* |
7 | * _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines |
8 | * that. |
9 | */ |
10 | #include <unistd.h> |
11 | #include <errno.h> |
12 | #include <string.h> |
13 | #include <arpa/inet.h> |
14 | #include <endian.h> |
15 | #include "cow.h" |
16 | #include "cow_sys.h" |
17 | |
18 | #define PATH_LEN_V1 256 |
19 | |
20 | /* unsigned time_t works until year 2106 */ |
21 | typedef __u32 time32_t; |
22 | |
23 | struct { |
24 | __s32 ; |
25 | __s32 ; |
26 | char [PATH_LEN_V1]; |
27 | time32_t ; |
28 | __u64 ; |
29 | __s32 ; |
30 | } __attribute__((packed)); |
31 | |
32 | /* |
33 | * Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in |
34 | * case other systems have different values for MAXPATHLEN. |
35 | * |
36 | * The same must hold for V2 - we want file format compatibility, not anything |
37 | * else. |
38 | */ |
39 | #define PATH_LEN_V3 4096 |
40 | #define PATH_LEN_V2 PATH_LEN_V3 |
41 | |
42 | struct { |
43 | __u32 ; |
44 | __u32 ; |
45 | char [PATH_LEN_V2]; |
46 | time32_t ; |
47 | __u64 ; |
48 | __s32 ; |
49 | } __attribute__((packed)); |
50 | |
51 | /* |
52 | * Changes from V2 - |
53 | * PATH_LEN_V3 as described above |
54 | * Explicitly specify field bit lengths for systems with different |
55 | * lengths for the usual C types. Not sure whether char or |
56 | * time_t should be changed, this can be changed later without |
57 | * breaking compatibility |
58 | * Add alignment field so that different alignments can be used for the |
59 | * bitmap and data |
60 | * Add cow_format field to allow for the possibility of different ways |
61 | * of specifying the COW blocks. For now, the only value is 0, |
62 | * for the traditional COW bitmap. |
63 | * Move the backing_file field to the end of the header. This allows |
64 | * for the possibility of expanding it into the padding required |
65 | * by the bitmap alignment. |
66 | * The bitmap and data portions of the file will be aligned as specified |
67 | * by the alignment field. This is to allow COW files to be |
68 | * put on devices with restrictions on access alignments, such as |
69 | * /dev/raw, with a 512 byte alignment restriction. This also |
70 | * allows the data to be more aligned more strictly than on |
71 | * sector boundaries. This is needed for ubd-mmap, which needs |
72 | * the data to be page aligned. |
73 | * Fixed (finally!) the rounding bug |
74 | */ |
75 | |
76 | /* |
77 | * Until Dec2005, __attribute__((packed)) was left out from the below |
78 | * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to |
79 | * align size to 8-byte alignment. This shifted all fields above (no padding |
80 | * was present on 32-bit, no other padding was added). |
81 | * |
82 | * However, this _can be detected_: it means that cow_format (always 0 until |
83 | * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise |
84 | * impossible to find 4 zeros. -bb */ |
85 | |
86 | struct { |
87 | __u32 ; |
88 | __u32 ; |
89 | __u32 ; |
90 | __u64 ; |
91 | __u32 ; |
92 | __u32 ; |
93 | __u32 ; |
94 | char [PATH_LEN_V3]; |
95 | } __attribute__((packed)); |
96 | |
97 | /* This is the broken layout used by some 64-bit binaries. */ |
98 | struct { |
99 | __u32 ; |
100 | __u32 ; |
101 | __s64 ; |
102 | __u64 ; |
103 | __u32 ; |
104 | __u32 ; |
105 | __u32 ; |
106 | char [PATH_LEN_V3]; |
107 | }; |
108 | |
109 | /* COW format definitions - for now, we have only the usual COW bitmap */ |
110 | #define COW_BITMAP 0 |
111 | |
112 | union { |
113 | struct cow_header_v1 ; |
114 | struct cow_header_v2 ; |
115 | struct cow_header_v3 ; |
116 | struct cow_header_v3_broken ; |
117 | }; |
118 | |
119 | #define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
120 | #define COW_VERSION 3 |
121 | |
122 | #define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) |
123 | #define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) |
124 | |
125 | void cow_sizes(int version, __u64 size, int sectorsize, int align, |
126 | int bitmap_offset, unsigned long *bitmap_len_out, |
127 | int *data_offset_out) |
128 | { |
129 | if (version < 3) { |
130 | *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); |
131 | |
132 | *data_offset_out = bitmap_offset + *bitmap_len_out; |
133 | *data_offset_out = (*data_offset_out + sectorsize - 1) / |
134 | sectorsize; |
135 | *data_offset_out *= sectorsize; |
136 | } |
137 | else { |
138 | *bitmap_len_out = DIV_ROUND(size, sectorsize); |
139 | *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); |
140 | |
141 | *data_offset_out = bitmap_offset + *bitmap_len_out; |
142 | *data_offset_out = ROUND_UP(*data_offset_out, align); |
143 | } |
144 | } |
145 | |
146 | static int absolutize(char *to, int size, char *from) |
147 | { |
148 | char save_cwd[256], *slash; |
149 | int remaining; |
150 | |
151 | if (getcwd(save_cwd, sizeof(save_cwd)) == NULL) { |
152 | cow_printf("absolutize : unable to get cwd - errno = %d\n" , |
153 | errno); |
154 | return -1; |
155 | } |
156 | slash = strrchr(from, '/'); |
157 | if (slash != NULL) { |
158 | *slash = '\0'; |
159 | if (chdir(from)) { |
160 | *slash = '/'; |
161 | cow_printf("absolutize : Can't cd to '%s' - " |
162 | "errno = %d\n" , from, errno); |
163 | return -1; |
164 | } |
165 | *slash = '/'; |
166 | if (getcwd(to, size) == NULL) { |
167 | cow_printf("absolutize : unable to get cwd of '%s' - " |
168 | "errno = %d\n" , from, errno); |
169 | return -1; |
170 | } |
171 | remaining = size - strlen(to); |
172 | if (strlen(slash) + 1 > remaining) { |
173 | cow_printf("absolutize : unable to fit '%s' into %d " |
174 | "chars\n" , from, size); |
175 | return -1; |
176 | } |
177 | strcat(to, slash); |
178 | } |
179 | else { |
180 | if (strlen(save_cwd) + 1 + strlen(from) + 1 > size) { |
181 | cow_printf("absolutize : unable to fit '%s' into %d " |
182 | "chars\n" , from, size); |
183 | return -1; |
184 | } |
185 | strcpy(to, save_cwd); |
186 | strcat(to, "/" ); |
187 | strcat(to, from); |
188 | } |
189 | if (chdir(save_cwd)) { |
190 | cow_printf("absolutize : Can't cd to '%s' - " |
191 | "errno = %d\n" , save_cwd, errno); |
192 | return -1; |
193 | } |
194 | return 0; |
195 | } |
196 | |
197 | int (char *cow_file, int fd, char *backing_file, |
198 | int sectorsize, int alignment, unsigned long long *size) |
199 | { |
200 | struct cow_header_v3 *; |
201 | long long modtime; |
202 | int err; |
203 | |
204 | err = cow_seek_file(fd, offset: 0); |
205 | if (err < 0) { |
206 | cow_printf("write_cow_header - lseek failed, err = %d\n" , -err); |
207 | goto out; |
208 | } |
209 | |
210 | err = -ENOMEM; |
211 | header = cow_malloc(size: sizeof(*header)); |
212 | if (header == NULL) { |
213 | cow_printf("write_cow_header - failed to allocate COW V3 " |
214 | "header\n" ); |
215 | goto out; |
216 | } |
217 | header->magic = htobe32(COW_MAGIC); |
218 | header->version = htobe32(COW_VERSION); |
219 | |
220 | err = -EINVAL; |
221 | if (strlen(backing_file) > sizeof(header->backing_file) - 1) { |
222 | /* Below, %zd is for a size_t value */ |
223 | cow_printf("Backing file name \"%s\" is too long - names are " |
224 | "limited to %zd characters\n" , backing_file, |
225 | sizeof(header->backing_file) - 1); |
226 | goto out_free; |
227 | } |
228 | |
229 | if (absolutize(to: header->backing_file, size: sizeof(header->backing_file), |
230 | from: backing_file)) |
231 | goto out_free; |
232 | |
233 | err = os_file_modtime(header->backing_file, &modtime); |
234 | if (err < 0) { |
235 | cow_printf("write_cow_header - backing file '%s' mtime " |
236 | "request failed, err = %d\n" , header->backing_file, |
237 | -err); |
238 | goto out_free; |
239 | } |
240 | |
241 | err = cow_file_size(file: header->backing_file, size_out: size); |
242 | if (err < 0) { |
243 | cow_printf("write_cow_header - couldn't get size of " |
244 | "backing file '%s', err = %d\n" , |
245 | header->backing_file, -err); |
246 | goto out_free; |
247 | } |
248 | |
249 | header->mtime = htobe32(modtime); |
250 | header->size = htobe64(*size); |
251 | header->sectorsize = htobe32(sectorsize); |
252 | header->alignment = htobe32(alignment); |
253 | header->cow_format = COW_BITMAP; |
254 | |
255 | err = cow_write_file(fd, buf: header, size: sizeof(*header)); |
256 | if (err != sizeof(*header)) { |
257 | cow_printf("write_cow_header - write of header to " |
258 | "new COW file '%s' failed, err = %d\n" , cow_file, |
259 | -err); |
260 | goto out_free; |
261 | } |
262 | err = 0; |
263 | out_free: |
264 | cow_free(ptr: header); |
265 | out: |
266 | return err; |
267 | } |
268 | |
269 | int file_reader(__u64 offset, char *buf, int len, void *arg) |
270 | { |
271 | int fd = *((int *) arg); |
272 | |
273 | return pread(fd, buf, len, offset); |
274 | } |
275 | |
276 | /* XXX Need to sanity-check the values read from the header */ |
277 | |
278 | int (int (*reader)(__u64, char *, int, void *), void *arg, |
279 | __u32 *version_out, char **backing_file_out, |
280 | long long *mtime_out, unsigned long long *size_out, |
281 | int *sectorsize_out, __u32 *align_out, |
282 | int *bitmap_offset_out) |
283 | { |
284 | union cow_header *; |
285 | char *file; |
286 | int err, n; |
287 | unsigned long version, magic; |
288 | |
289 | header = cow_malloc(size: sizeof(*header)); |
290 | if (header == NULL) { |
291 | cow_printf("read_cow_header - Failed to allocate header\n" ); |
292 | return -ENOMEM; |
293 | } |
294 | err = -EINVAL; |
295 | n = (*reader)(0, (char *) header, sizeof(*header), arg); |
296 | if (n < offsetof(typeof(header->v1), backing_file)) { |
297 | cow_printf("read_cow_header - short header\n" ); |
298 | goto out; |
299 | } |
300 | |
301 | magic = header->v1.magic; |
302 | if (magic == COW_MAGIC) |
303 | version = header->v1.version; |
304 | else if (magic == be32toh(COW_MAGIC)) |
305 | version = be32toh(header->v1.version); |
306 | /* No error printed because the non-COW case comes through here */ |
307 | else goto out; |
308 | |
309 | *version_out = version; |
310 | |
311 | if (version == 1) { |
312 | if (n < sizeof(header->v1)) { |
313 | cow_printf("read_cow_header - failed to read V1 " |
314 | "header\n" ); |
315 | goto out; |
316 | } |
317 | *mtime_out = header->v1.mtime; |
318 | *size_out = header->v1.size; |
319 | *sectorsize_out = header->v1.sectorsize; |
320 | *bitmap_offset_out = sizeof(header->v1); |
321 | *align_out = *sectorsize_out; |
322 | file = header->v1.backing_file; |
323 | } |
324 | else if (version == 2) { |
325 | if (n < sizeof(header->v2)) { |
326 | cow_printf("read_cow_header - failed to read V2 " |
327 | "header\n" ); |
328 | goto out; |
329 | } |
330 | *mtime_out = be32toh(header->v2.mtime); |
331 | *size_out = be64toh(header->v2.size); |
332 | *sectorsize_out = be32toh(header->v2.sectorsize); |
333 | *bitmap_offset_out = sizeof(header->v2); |
334 | *align_out = *sectorsize_out; |
335 | file = header->v2.backing_file; |
336 | } |
337 | /* This is very subtle - see above at union cow_header definition */ |
338 | else if (version == 3 && (*((int*)header->v3.backing_file) != 0)) { |
339 | if (n < sizeof(header->v3)) { |
340 | cow_printf("read_cow_header - failed to read V3 " |
341 | "header\n" ); |
342 | goto out; |
343 | } |
344 | *mtime_out = be32toh(header->v3.mtime); |
345 | *size_out = be64toh(header->v3.size); |
346 | *sectorsize_out = be32toh(header->v3.sectorsize); |
347 | *align_out = be32toh(header->v3.alignment); |
348 | if (*align_out == 0) { |
349 | cow_printf("read_cow_header - invalid COW header, " |
350 | "align == 0\n" ); |
351 | } |
352 | *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); |
353 | file = header->v3.backing_file; |
354 | } |
355 | else if (version == 3) { |
356 | cow_printf("read_cow_header - broken V3 file with" |
357 | " 64-bit layout - recovering content.\n" ); |
358 | |
359 | if (n < sizeof(header->v3_b)) { |
360 | cow_printf("read_cow_header - failed to read V3 " |
361 | "header\n" ); |
362 | goto out; |
363 | } |
364 | |
365 | /* |
366 | * this was used until Dec2005 - 64bits are needed to represent |
367 | * 2106+. I.e. we can safely do this truncating cast. |
368 | * |
369 | * Additionally, we must use be32toh() instead of be64toh(), since |
370 | * the program used to use the former (tested - I got mtime |
371 | * mismatch "0 vs whatever"). |
372 | * |
373 | * Ever heard about bug-to-bug-compatibility ? ;-) */ |
374 | *mtime_out = (time32_t) be32toh(header->v3_b.mtime); |
375 | |
376 | *size_out = be64toh(header->v3_b.size); |
377 | *sectorsize_out = be32toh(header->v3_b.sectorsize); |
378 | *align_out = be32toh(header->v3_b.alignment); |
379 | if (*align_out == 0) { |
380 | cow_printf("read_cow_header - invalid COW header, " |
381 | "align == 0\n" ); |
382 | } |
383 | *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); |
384 | file = header->v3_b.backing_file; |
385 | } |
386 | else { |
387 | cow_printf("read_cow_header - invalid COW version\n" ); |
388 | goto out; |
389 | } |
390 | err = -ENOMEM; |
391 | *backing_file_out = cow_strdup(str: file); |
392 | if (*backing_file_out == NULL) { |
393 | cow_printf("read_cow_header - failed to allocate backing " |
394 | "file\n" ); |
395 | goto out; |
396 | } |
397 | err = 0; |
398 | out: |
399 | cow_free(ptr: header); |
400 | return err; |
401 | } |
402 | |
403 | int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, |
404 | int alignment, int *bitmap_offset_out, |
405 | unsigned long *bitmap_len_out, int *data_offset_out) |
406 | { |
407 | unsigned long long size, offset; |
408 | char zero = 0; |
409 | int err; |
410 | |
411 | err = write_cow_header(cow_file, fd, backing_file, sectorsize, |
412 | alignment, size: &size); |
413 | if (err) |
414 | goto out; |
415 | |
416 | *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); |
417 | cow_sizes(COW_VERSION, size, sectorsize, align: alignment, bitmap_offset: *bitmap_offset_out, |
418 | bitmap_len_out, data_offset_out); |
419 | |
420 | offset = *data_offset_out + size - sizeof(zero); |
421 | err = cow_seek_file(fd, offset); |
422 | if (err < 0) { |
423 | cow_printf("cow bitmap lseek failed : err = %d\n" , -err); |
424 | goto out; |
425 | } |
426 | |
427 | /* |
428 | * does not really matter how much we write it is just to set EOF |
429 | * this also sets the entire COW bitmap |
430 | * to zero without having to allocate it |
431 | */ |
432 | err = cow_write_file(fd, buf: &zero, size: sizeof(zero)); |
433 | if (err != sizeof(zero)) { |
434 | cow_printf("Write of bitmap to new COW file '%s' failed, " |
435 | "err = %d\n" , cow_file, -err); |
436 | if (err >= 0) |
437 | err = -EINVAL; |
438 | goto out; |
439 | } |
440 | |
441 | return 0; |
442 | out: |
443 | return err; |
444 | } |
445 | |