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