18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* 78c2ecf20Sopenharmony_ci * _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines 88c2ecf20Sopenharmony_ci * that. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci#include <errno.h> 128c2ecf20Sopenharmony_ci#include <string.h> 138c2ecf20Sopenharmony_ci#include <arpa/inet.h> 148c2ecf20Sopenharmony_ci#include <endian.h> 158c2ecf20Sopenharmony_ci#include "cow.h" 168c2ecf20Sopenharmony_ci#include "cow_sys.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define PATH_LEN_V1 256 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* unsigned time_t works until year 2106 */ 218c2ecf20Sopenharmony_citypedef __u32 time32_t; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct cow_header_v1 { 248c2ecf20Sopenharmony_ci __s32 magic; 258c2ecf20Sopenharmony_ci __s32 version; 268c2ecf20Sopenharmony_ci char backing_file[PATH_LEN_V1]; 278c2ecf20Sopenharmony_ci time32_t mtime; 288c2ecf20Sopenharmony_ci __u64 size; 298c2ecf20Sopenharmony_ci __s32 sectorsize; 308c2ecf20Sopenharmony_ci} __attribute__((packed)); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in 348c2ecf20Sopenharmony_ci * case other systems have different values for MAXPATHLEN. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * The same must hold for V2 - we want file format compatibility, not anything 378c2ecf20Sopenharmony_ci * else. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define PATH_LEN_V3 4096 408c2ecf20Sopenharmony_ci#define PATH_LEN_V2 PATH_LEN_V3 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct cow_header_v2 { 438c2ecf20Sopenharmony_ci __u32 magic; 448c2ecf20Sopenharmony_ci __u32 version; 458c2ecf20Sopenharmony_ci char backing_file[PATH_LEN_V2]; 468c2ecf20Sopenharmony_ci time32_t mtime; 478c2ecf20Sopenharmony_ci __u64 size; 488c2ecf20Sopenharmony_ci __s32 sectorsize; 498c2ecf20Sopenharmony_ci} __attribute__((packed)); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * Changes from V2 - 538c2ecf20Sopenharmony_ci * PATH_LEN_V3 as described above 548c2ecf20Sopenharmony_ci * Explicitly specify field bit lengths for systems with different 558c2ecf20Sopenharmony_ci * lengths for the usual C types. Not sure whether char or 568c2ecf20Sopenharmony_ci * time_t should be changed, this can be changed later without 578c2ecf20Sopenharmony_ci * breaking compatibility 588c2ecf20Sopenharmony_ci * Add alignment field so that different alignments can be used for the 598c2ecf20Sopenharmony_ci * bitmap and data 608c2ecf20Sopenharmony_ci * Add cow_format field to allow for the possibility of different ways 618c2ecf20Sopenharmony_ci * of specifying the COW blocks. For now, the only value is 0, 628c2ecf20Sopenharmony_ci * for the traditional COW bitmap. 638c2ecf20Sopenharmony_ci * Move the backing_file field to the end of the header. This allows 648c2ecf20Sopenharmony_ci * for the possibility of expanding it into the padding required 658c2ecf20Sopenharmony_ci * by the bitmap alignment. 668c2ecf20Sopenharmony_ci * The bitmap and data portions of the file will be aligned as specified 678c2ecf20Sopenharmony_ci * by the alignment field. This is to allow COW files to be 688c2ecf20Sopenharmony_ci * put on devices with restrictions on access alignments, such as 698c2ecf20Sopenharmony_ci * /dev/raw, with a 512 byte alignment restriction. This also 708c2ecf20Sopenharmony_ci * allows the data to be more aligned more strictly than on 718c2ecf20Sopenharmony_ci * sector boundaries. This is needed for ubd-mmap, which needs 728c2ecf20Sopenharmony_ci * the data to be page aligned. 738c2ecf20Sopenharmony_ci * Fixed (finally!) the rounding bug 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * Until Dec2005, __attribute__((packed)) was left out from the below 788c2ecf20Sopenharmony_ci * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to 798c2ecf20Sopenharmony_ci * align size to 8-byte alignment. This shifted all fields above (no padding 808c2ecf20Sopenharmony_ci * was present on 32-bit, no other padding was added). 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * However, this _can be detected_: it means that cow_format (always 0 until 838c2ecf20Sopenharmony_ci * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise 848c2ecf20Sopenharmony_ci * impossible to find 4 zeros. -bb */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct cow_header_v3 { 878c2ecf20Sopenharmony_ci __u32 magic; 888c2ecf20Sopenharmony_ci __u32 version; 898c2ecf20Sopenharmony_ci __u32 mtime; 908c2ecf20Sopenharmony_ci __u64 size; 918c2ecf20Sopenharmony_ci __u32 sectorsize; 928c2ecf20Sopenharmony_ci __u32 alignment; 938c2ecf20Sopenharmony_ci __u32 cow_format; 948c2ecf20Sopenharmony_ci char backing_file[PATH_LEN_V3]; 958c2ecf20Sopenharmony_ci} __attribute__((packed)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* This is the broken layout used by some 64-bit binaries. */ 988c2ecf20Sopenharmony_cistruct cow_header_v3_broken { 998c2ecf20Sopenharmony_ci __u32 magic; 1008c2ecf20Sopenharmony_ci __u32 version; 1018c2ecf20Sopenharmony_ci __s64 mtime; 1028c2ecf20Sopenharmony_ci __u64 size; 1038c2ecf20Sopenharmony_ci __u32 sectorsize; 1048c2ecf20Sopenharmony_ci __u32 alignment; 1058c2ecf20Sopenharmony_ci __u32 cow_format; 1068c2ecf20Sopenharmony_ci char backing_file[PATH_LEN_V3]; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* COW format definitions - for now, we have only the usual COW bitmap */ 1108c2ecf20Sopenharmony_ci#define COW_BITMAP 0 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciunion cow_header { 1138c2ecf20Sopenharmony_ci struct cow_header_v1 v1; 1148c2ecf20Sopenharmony_ci struct cow_header_v2 v2; 1158c2ecf20Sopenharmony_ci struct cow_header_v3 v3; 1168c2ecf20Sopenharmony_ci struct cow_header_v3_broken v3_b; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define COW_MAGIC 0x4f4f4f4d /* MOOO */ 1208c2ecf20Sopenharmony_ci#define COW_VERSION 3 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) 1238c2ecf20Sopenharmony_ci#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_civoid cow_sizes(int version, __u64 size, int sectorsize, int align, 1268c2ecf20Sopenharmony_ci int bitmap_offset, unsigned long *bitmap_len_out, 1278c2ecf20Sopenharmony_ci int *data_offset_out) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci if (version < 3) { 1308c2ecf20Sopenharmony_ci *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci *data_offset_out = bitmap_offset + *bitmap_len_out; 1338c2ecf20Sopenharmony_ci *data_offset_out = (*data_offset_out + sectorsize - 1) / 1348c2ecf20Sopenharmony_ci sectorsize; 1358c2ecf20Sopenharmony_ci *data_offset_out *= sectorsize; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci else { 1388c2ecf20Sopenharmony_ci *bitmap_len_out = DIV_ROUND(size, sectorsize); 1398c2ecf20Sopenharmony_ci *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci *data_offset_out = bitmap_offset + *bitmap_len_out; 1428c2ecf20Sopenharmony_ci *data_offset_out = ROUND_UP(*data_offset_out, align); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int absolutize(char *to, int size, char *from) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci char save_cwd[256], *slash; 1498c2ecf20Sopenharmony_ci int remaining; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (getcwd(save_cwd, sizeof(save_cwd)) == NULL) { 1528c2ecf20Sopenharmony_ci cow_printf("absolutize : unable to get cwd - errno = %d\n", 1538c2ecf20Sopenharmony_ci errno); 1548c2ecf20Sopenharmony_ci return -1; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci slash = strrchr(from, '/'); 1578c2ecf20Sopenharmony_ci if (slash != NULL) { 1588c2ecf20Sopenharmony_ci *slash = '\0'; 1598c2ecf20Sopenharmony_ci if (chdir(from)) { 1608c2ecf20Sopenharmony_ci *slash = '/'; 1618c2ecf20Sopenharmony_ci cow_printf("absolutize : Can't cd to '%s' - " 1628c2ecf20Sopenharmony_ci "errno = %d\n", from, errno); 1638c2ecf20Sopenharmony_ci return -1; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci *slash = '/'; 1668c2ecf20Sopenharmony_ci if (getcwd(to, size) == NULL) { 1678c2ecf20Sopenharmony_ci cow_printf("absolutize : unable to get cwd of '%s' - " 1688c2ecf20Sopenharmony_ci "errno = %d\n", from, errno); 1698c2ecf20Sopenharmony_ci return -1; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci remaining = size - strlen(to); 1728c2ecf20Sopenharmony_ci if (strlen(slash) + 1 > remaining) { 1738c2ecf20Sopenharmony_ci cow_printf("absolutize : unable to fit '%s' into %d " 1748c2ecf20Sopenharmony_ci "chars\n", from, size); 1758c2ecf20Sopenharmony_ci return -1; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci strcat(to, slash); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci else { 1808c2ecf20Sopenharmony_ci if (strlen(save_cwd) + 1 + strlen(from) + 1 > size) { 1818c2ecf20Sopenharmony_ci cow_printf("absolutize : unable to fit '%s' into %d " 1828c2ecf20Sopenharmony_ci "chars\n", from, size); 1838c2ecf20Sopenharmony_ci return -1; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci strcpy(to, save_cwd); 1868c2ecf20Sopenharmony_ci strcat(to, "/"); 1878c2ecf20Sopenharmony_ci strcat(to, from); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci if (chdir(save_cwd)) { 1908c2ecf20Sopenharmony_ci cow_printf("absolutize : Can't cd to '%s' - " 1918c2ecf20Sopenharmony_ci "errno = %d\n", save_cwd, errno); 1928c2ecf20Sopenharmony_ci return -1; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciint write_cow_header(char *cow_file, int fd, char *backing_file, 1988c2ecf20Sopenharmony_ci int sectorsize, int alignment, unsigned long long *size) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct cow_header_v3 *header; 2018c2ecf20Sopenharmony_ci long long modtime; 2028c2ecf20Sopenharmony_ci int err; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci err = cow_seek_file(fd, 0); 2058c2ecf20Sopenharmony_ci if (err < 0) { 2068c2ecf20Sopenharmony_ci cow_printf("write_cow_header - lseek failed, err = %d\n", -err); 2078c2ecf20Sopenharmony_ci goto out; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci err = -ENOMEM; 2118c2ecf20Sopenharmony_ci header = cow_malloc(sizeof(*header)); 2128c2ecf20Sopenharmony_ci if (header == NULL) { 2138c2ecf20Sopenharmony_ci cow_printf("write_cow_header - failed to allocate COW V3 " 2148c2ecf20Sopenharmony_ci "header\n"); 2158c2ecf20Sopenharmony_ci goto out; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci header->magic = htobe32(COW_MAGIC); 2188c2ecf20Sopenharmony_ci header->version = htobe32(COW_VERSION); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci err = -EINVAL; 2218c2ecf20Sopenharmony_ci if (strlen(backing_file) > sizeof(header->backing_file) - 1) { 2228c2ecf20Sopenharmony_ci /* Below, %zd is for a size_t value */ 2238c2ecf20Sopenharmony_ci cow_printf("Backing file name \"%s\" is too long - names are " 2248c2ecf20Sopenharmony_ci "limited to %zd characters\n", backing_file, 2258c2ecf20Sopenharmony_ci sizeof(header->backing_file) - 1); 2268c2ecf20Sopenharmony_ci goto out_free; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (absolutize(header->backing_file, sizeof(header->backing_file), 2308c2ecf20Sopenharmony_ci backing_file)) 2318c2ecf20Sopenharmony_ci goto out_free; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci err = os_file_modtime(header->backing_file, &modtime); 2348c2ecf20Sopenharmony_ci if (err < 0) { 2358c2ecf20Sopenharmony_ci cow_printf("write_cow_header - backing file '%s' mtime " 2368c2ecf20Sopenharmony_ci "request failed, err = %d\n", header->backing_file, 2378c2ecf20Sopenharmony_ci -err); 2388c2ecf20Sopenharmony_ci goto out_free; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci err = cow_file_size(header->backing_file, size); 2428c2ecf20Sopenharmony_ci if (err < 0) { 2438c2ecf20Sopenharmony_ci cow_printf("write_cow_header - couldn't get size of " 2448c2ecf20Sopenharmony_ci "backing file '%s', err = %d\n", 2458c2ecf20Sopenharmony_ci header->backing_file, -err); 2468c2ecf20Sopenharmony_ci goto out_free; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci header->mtime = htobe32(modtime); 2508c2ecf20Sopenharmony_ci header->size = htobe64(*size); 2518c2ecf20Sopenharmony_ci header->sectorsize = htobe32(sectorsize); 2528c2ecf20Sopenharmony_ci header->alignment = htobe32(alignment); 2538c2ecf20Sopenharmony_ci header->cow_format = COW_BITMAP; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci err = cow_write_file(fd, header, sizeof(*header)); 2568c2ecf20Sopenharmony_ci if (err != sizeof(*header)) { 2578c2ecf20Sopenharmony_ci cow_printf("write_cow_header - write of header to " 2588c2ecf20Sopenharmony_ci "new COW file '%s' failed, err = %d\n", cow_file, 2598c2ecf20Sopenharmony_ci -err); 2608c2ecf20Sopenharmony_ci goto out_free; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci err = 0; 2638c2ecf20Sopenharmony_ci out_free: 2648c2ecf20Sopenharmony_ci cow_free(header); 2658c2ecf20Sopenharmony_ci out: 2668c2ecf20Sopenharmony_ci return err; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciint file_reader(__u64 offset, char *buf, int len, void *arg) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int fd = *((int *) arg); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return pread(fd, buf, len, offset); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* XXX Need to sanity-check the values read from the header */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciint read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 2798c2ecf20Sopenharmony_ci __u32 *version_out, char **backing_file_out, 2808c2ecf20Sopenharmony_ci long long *mtime_out, unsigned long long *size_out, 2818c2ecf20Sopenharmony_ci int *sectorsize_out, __u32 *align_out, 2828c2ecf20Sopenharmony_ci int *bitmap_offset_out) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci union cow_header *header; 2858c2ecf20Sopenharmony_ci char *file; 2868c2ecf20Sopenharmony_ci int err, n; 2878c2ecf20Sopenharmony_ci unsigned long version, magic; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci header = cow_malloc(sizeof(*header)); 2908c2ecf20Sopenharmony_ci if (header == NULL) { 2918c2ecf20Sopenharmony_ci cow_printf("read_cow_header - Failed to allocate header\n"); 2928c2ecf20Sopenharmony_ci return -ENOMEM; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci err = -EINVAL; 2958c2ecf20Sopenharmony_ci n = (*reader)(0, (char *) header, sizeof(*header), arg); 2968c2ecf20Sopenharmony_ci if (n < offsetof(typeof(header->v1), backing_file)) { 2978c2ecf20Sopenharmony_ci cow_printf("read_cow_header - short header\n"); 2988c2ecf20Sopenharmony_ci goto out; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci magic = header->v1.magic; 3028c2ecf20Sopenharmony_ci if (magic == COW_MAGIC) 3038c2ecf20Sopenharmony_ci version = header->v1.version; 3048c2ecf20Sopenharmony_ci else if (magic == be32toh(COW_MAGIC)) 3058c2ecf20Sopenharmony_ci version = be32toh(header->v1.version); 3068c2ecf20Sopenharmony_ci /* No error printed because the non-COW case comes through here */ 3078c2ecf20Sopenharmony_ci else goto out; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci *version_out = version; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (version == 1) { 3128c2ecf20Sopenharmony_ci if (n < sizeof(header->v1)) { 3138c2ecf20Sopenharmony_ci cow_printf("read_cow_header - failed to read V1 " 3148c2ecf20Sopenharmony_ci "header\n"); 3158c2ecf20Sopenharmony_ci goto out; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci *mtime_out = header->v1.mtime; 3188c2ecf20Sopenharmony_ci *size_out = header->v1.size; 3198c2ecf20Sopenharmony_ci *sectorsize_out = header->v1.sectorsize; 3208c2ecf20Sopenharmony_ci *bitmap_offset_out = sizeof(header->v1); 3218c2ecf20Sopenharmony_ci *align_out = *sectorsize_out; 3228c2ecf20Sopenharmony_ci file = header->v1.backing_file; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci else if (version == 2) { 3258c2ecf20Sopenharmony_ci if (n < sizeof(header->v2)) { 3268c2ecf20Sopenharmony_ci cow_printf("read_cow_header - failed to read V2 " 3278c2ecf20Sopenharmony_ci "header\n"); 3288c2ecf20Sopenharmony_ci goto out; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci *mtime_out = be32toh(header->v2.mtime); 3318c2ecf20Sopenharmony_ci *size_out = be64toh(header->v2.size); 3328c2ecf20Sopenharmony_ci *sectorsize_out = be32toh(header->v2.sectorsize); 3338c2ecf20Sopenharmony_ci *bitmap_offset_out = sizeof(header->v2); 3348c2ecf20Sopenharmony_ci *align_out = *sectorsize_out; 3358c2ecf20Sopenharmony_ci file = header->v2.backing_file; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci /* This is very subtle - see above at union cow_header definition */ 3388c2ecf20Sopenharmony_ci else if (version == 3 && (*((int*)header->v3.backing_file) != 0)) { 3398c2ecf20Sopenharmony_ci if (n < sizeof(header->v3)) { 3408c2ecf20Sopenharmony_ci cow_printf("read_cow_header - failed to read V3 " 3418c2ecf20Sopenharmony_ci "header\n"); 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci *mtime_out = be32toh(header->v3.mtime); 3458c2ecf20Sopenharmony_ci *size_out = be64toh(header->v3.size); 3468c2ecf20Sopenharmony_ci *sectorsize_out = be32toh(header->v3.sectorsize); 3478c2ecf20Sopenharmony_ci *align_out = be32toh(header->v3.alignment); 3488c2ecf20Sopenharmony_ci if (*align_out == 0) { 3498c2ecf20Sopenharmony_ci cow_printf("read_cow_header - invalid COW header, " 3508c2ecf20Sopenharmony_ci "align == 0\n"); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); 3538c2ecf20Sopenharmony_ci file = header->v3.backing_file; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci else if (version == 3) { 3568c2ecf20Sopenharmony_ci cow_printf("read_cow_header - broken V3 file with" 3578c2ecf20Sopenharmony_ci " 64-bit layout - recovering content.\n"); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (n < sizeof(header->v3_b)) { 3608c2ecf20Sopenharmony_ci cow_printf("read_cow_header - failed to read V3 " 3618c2ecf20Sopenharmony_ci "header\n"); 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * this was used until Dec2005 - 64bits are needed to represent 3678c2ecf20Sopenharmony_ci * 2106+. I.e. we can safely do this truncating cast. 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * Additionally, we must use be32toh() instead of be64toh(), since 3708c2ecf20Sopenharmony_ci * the program used to use the former (tested - I got mtime 3718c2ecf20Sopenharmony_ci * mismatch "0 vs whatever"). 3728c2ecf20Sopenharmony_ci * 3738c2ecf20Sopenharmony_ci * Ever heard about bug-to-bug-compatibility ? ;-) */ 3748c2ecf20Sopenharmony_ci *mtime_out = (time32_t) be32toh(header->v3_b.mtime); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci *size_out = be64toh(header->v3_b.size); 3778c2ecf20Sopenharmony_ci *sectorsize_out = be32toh(header->v3_b.sectorsize); 3788c2ecf20Sopenharmony_ci *align_out = be32toh(header->v3_b.alignment); 3798c2ecf20Sopenharmony_ci if (*align_out == 0) { 3808c2ecf20Sopenharmony_ci cow_printf("read_cow_header - invalid COW header, " 3818c2ecf20Sopenharmony_ci "align == 0\n"); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); 3848c2ecf20Sopenharmony_ci file = header->v3_b.backing_file; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci else { 3878c2ecf20Sopenharmony_ci cow_printf("read_cow_header - invalid COW version\n"); 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci err = -ENOMEM; 3918c2ecf20Sopenharmony_ci *backing_file_out = cow_strdup(file); 3928c2ecf20Sopenharmony_ci if (*backing_file_out == NULL) { 3938c2ecf20Sopenharmony_ci cow_printf("read_cow_header - failed to allocate backing " 3948c2ecf20Sopenharmony_ci "file\n"); 3958c2ecf20Sopenharmony_ci goto out; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci err = 0; 3988c2ecf20Sopenharmony_ci out: 3998c2ecf20Sopenharmony_ci cow_free(header); 4008c2ecf20Sopenharmony_ci return err; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciint init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, 4048c2ecf20Sopenharmony_ci int alignment, int *bitmap_offset_out, 4058c2ecf20Sopenharmony_ci unsigned long *bitmap_len_out, int *data_offset_out) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci unsigned long long size, offset; 4088c2ecf20Sopenharmony_ci char zero = 0; 4098c2ecf20Sopenharmony_ci int err; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci err = write_cow_header(cow_file, fd, backing_file, sectorsize, 4128c2ecf20Sopenharmony_ci alignment, &size); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci goto out; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); 4178c2ecf20Sopenharmony_ci cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, 4188c2ecf20Sopenharmony_ci bitmap_len_out, data_offset_out); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci offset = *data_offset_out + size - sizeof(zero); 4218c2ecf20Sopenharmony_ci err = cow_seek_file(fd, offset); 4228c2ecf20Sopenharmony_ci if (err < 0) { 4238c2ecf20Sopenharmony_ci cow_printf("cow bitmap lseek failed : err = %d\n", -err); 4248c2ecf20Sopenharmony_ci goto out; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* 4288c2ecf20Sopenharmony_ci * does not really matter how much we write it is just to set EOF 4298c2ecf20Sopenharmony_ci * this also sets the entire COW bitmap 4308c2ecf20Sopenharmony_ci * to zero without having to allocate it 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci err = cow_write_file(fd, &zero, sizeof(zero)); 4338c2ecf20Sopenharmony_ci if (err != sizeof(zero)) { 4348c2ecf20Sopenharmony_ci cow_printf("Write of bitmap to new COW file '%s' failed, " 4358c2ecf20Sopenharmony_ci "err = %d\n", cow_file, -err); 4368c2ecf20Sopenharmony_ci if (err >= 0) 4378c2ecf20Sopenharmony_ci err = -EINVAL; 4388c2ecf20Sopenharmony_ci goto out; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci out: 4438c2ecf20Sopenharmony_ci return err; 4448c2ecf20Sopenharmony_ci} 445