cow_user.c (12341B)
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 */ 21typedef __u32 time32_t; 22 23struct cow_header_v1 { 24 __s32 magic; 25 __s32 version; 26 char backing_file[PATH_LEN_V1]; 27 time32_t mtime; 28 __u64 size; 29 __s32 sectorsize; 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 42struct cow_header_v2 { 43 __u32 magic; 44 __u32 version; 45 char backing_file[PATH_LEN_V2]; 46 time32_t mtime; 47 __u64 size; 48 __s32 sectorsize; 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 86struct cow_header_v3 { 87 __u32 magic; 88 __u32 version; 89 __u32 mtime; 90 __u64 size; 91 __u32 sectorsize; 92 __u32 alignment; 93 __u32 cow_format; 94 char backing_file[PATH_LEN_V3]; 95} __attribute__((packed)); 96 97/* This is the broken layout used by some 64-bit binaries. */ 98struct cow_header_v3_broken { 99 __u32 magic; 100 __u32 version; 101 __s64 mtime; 102 __u64 size; 103 __u32 sectorsize; 104 __u32 alignment; 105 __u32 cow_format; 106 char backing_file[PATH_LEN_V3]; 107}; 108 109/* COW format definitions - for now, we have only the usual COW bitmap */ 110#define COW_BITMAP 0 111 112union cow_header { 113 struct cow_header_v1 v1; 114 struct cow_header_v2 v2; 115 struct cow_header_v3 v3; 116 struct cow_header_v3_broken v3_b; 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 125void 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 146static 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 197int write_cow_header(char *cow_file, int fd, char *backing_file, 198 int sectorsize, int alignment, unsigned long long *size) 199{ 200 struct cow_header_v3 *header; 201 long long modtime; 202 int err; 203 204 err = cow_seek_file(fd, 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(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(header->backing_file, sizeof(header->backing_file), 230 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(header->backing_file, 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, header, 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(header); 265 out: 266 return err; 267} 268 269int 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 278int read_cow_header(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 *header; 285 char *file; 286 int err, n; 287 unsigned long version, magic; 288 289 header = cow_malloc(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(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(header); 400 return err; 401} 402 403int 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); 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, alignment, *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, &zero, 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}