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 20 typedef __u32 time32_t; 21 22 struct 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 40 struct 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 82 struct 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. */ 94 struct 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 108 union 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 121 void 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 142 static 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 189 int 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 260 int 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 /* XXX Need to sanity-check the values read from the header */ 268 269 int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 270 __u32 *version_out, char **backing_file_out, 271 time_t *mtime_out, unsigned long long *size_out, 272 int *sectorsize_out, __u32 *align_out, 273 int *bitmap_offset_out) 274 { 275 union cow_header *header; 276 char *file; 277 int err, n; 278 unsigned long version, magic; 279 280 header = cow_malloc(sizeof(*header)); 281 if(header == NULL){ 282 cow_printf("read_cow_header - Failed to allocate header\n"); 283 return(-ENOMEM); 284 } 285 err = -EINVAL; 286 n = (*reader)(0, (char *) header, sizeof(*header), arg); 287 if(n < offsetof(typeof(header->v1), backing_file)){ 288 cow_printf("read_cow_header - short header\n"); 289 goto out; 290 } 291 292 magic = header->v1.magic; 293 if(magic == COW_MAGIC) { 294 version = header->v1.version; 295 } 296 else if(magic == ntohl(COW_MAGIC)){ 297 version = ntohl(header->v1.version); 298 } 299 /* No error printed because the non-COW case comes through here */ 300 else goto out; 301 302 *version_out = version; 303 304 if(version == 1){ 305 if(n < sizeof(header->v1)){ 306 cow_printf("read_cow_header - failed to read V1 " 307 "header\n"); 308 goto out; 309 } 310 *mtime_out = header->v1.mtime; 311 *size_out = header->v1.size; 312 *sectorsize_out = header->v1.sectorsize; 313 *bitmap_offset_out = sizeof(header->v1); 314 *align_out = *sectorsize_out; 315 file = header->v1.backing_file; 316 } 317 else if(version == 2){ 318 if(n < sizeof(header->v2)){ 319 cow_printf("read_cow_header - failed to read V2 " 320 "header\n"); 321 goto out; 322 } 323 *mtime_out = ntohl(header->v2.mtime); 324 *size_out = ntohll(header->v2.size); 325 *sectorsize_out = ntohl(header->v2.sectorsize); 326 *bitmap_offset_out = sizeof(header->v2); 327 *align_out = *sectorsize_out; 328 file = header->v2.backing_file; 329 } 330 /* This is very subtle - see above at union cow_header definition */ 331 else if(version == 3 && (*((int*)header->v3.backing_file) != 0)){ 332 if(n < sizeof(header->v3)){ 333 cow_printf("read_cow_header - failed to read V3 " 334 "header\n"); 335 goto out; 336 } 337 *mtime_out = ntohl(header->v3.mtime); 338 *size_out = ntohll(header->v3.size); 339 *sectorsize_out = ntohl(header->v3.sectorsize); 340 *align_out = ntohl(header->v3.alignment); 341 if (*align_out == 0) { 342 cow_printf("read_cow_header - invalid COW header, " 343 "align == 0\n"); 344 } 345 *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); 346 file = header->v3.backing_file; 347 } 348 else if(version == 3){ 349 cow_printf("read_cow_header - broken V3 file with" 350 " 64-bit layout - recovering content.\n"); 351 352 if(n < sizeof(header->v3_b)){ 353 cow_printf("read_cow_header - failed to read V3 " 354 "header\n"); 355 goto out; 356 } 357 358 /* this was used until Dec2005 - 64bits are needed to represent 359 * 2038+. I.e. we can safely do this truncating cast. 360 * 361 * Additionally, we must use ntohl() instead of ntohll(), since 362 * the program used to use the former (tested - I got mtime 363 * mismatch "0 vs whatever"). 364 * 365 * Ever heard about bug-to-bug-compatibility ? ;-) */ 366 *mtime_out = (time32_t) ntohl(header->v3_b.mtime); 367 368 *size_out = ntohll(header->v3_b.size); 369 *sectorsize_out = ntohl(header->v3_b.sectorsize); 370 *align_out = ntohl(header->v3_b.alignment); 371 if (*align_out == 0) { 372 cow_printf("read_cow_header - invalid COW header, " 373 "align == 0\n"); 374 } 375 *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); 376 file = header->v3_b.backing_file; 377 } 378 else { 379 cow_printf("read_cow_header - invalid COW version\n"); 380 goto out; 381 } 382 err = -ENOMEM; 383 *backing_file_out = cow_strdup(file); 384 if(*backing_file_out == NULL){ 385 cow_printf("read_cow_header - failed to allocate backing " 386 "file\n"); 387 goto out; 388 } 389 err = 0; 390 out: 391 cow_free(header); 392 return(err); 393 } 394 395 int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, 396 int alignment, int *bitmap_offset_out, 397 unsigned long *bitmap_len_out, int *data_offset_out) 398 { 399 unsigned long long size, offset; 400 char zero = 0; 401 int err; 402 403 err = write_cow_header(cow_file, fd, backing_file, sectorsize, 404 alignment, &size); 405 if(err) 406 goto out; 407 408 *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); 409 cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, 410 bitmap_len_out, data_offset_out); 411 412 offset = *data_offset_out + size - sizeof(zero); 413 err = cow_seek_file(fd, offset); 414 if(err < 0){ 415 cow_printf("cow bitmap lseek failed : err = %d\n", -err); 416 goto out; 417 } 418 419 /* does not really matter how much we write it is just to set EOF 420 * this also sets the entire COW bitmap 421 * to zero without having to allocate it 422 */ 423 err = cow_write_file(fd, &zero, sizeof(zero)); 424 if(err != sizeof(zero)){ 425 cow_printf("Write of bitmap to new COW file '%s' failed, " 426 "err = %d\n", cow_file, -err); 427 if (err >= 0) 428 err = -EINVAL; 429 goto out; 430 } 431 432 return(0); 433 434 out: 435 return(err); 436 } 437 438 /* 439 * --------------------------------------------------------------------------- 440 * Local variables: 441 * c-file-style: "linux" 442 * End: 443 */ 444