162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci * _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines
862306a36Sopenharmony_ci * that.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <arpa/inet.h>
1462306a36Sopenharmony_ci#include <endian.h>
1562306a36Sopenharmony_ci#include "cow.h"
1662306a36Sopenharmony_ci#include "cow_sys.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define PATH_LEN_V1 256
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* unsigned time_t works until year 2106 */
2162306a36Sopenharmony_citypedef __u32 time32_t;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct cow_header_v1 {
2462306a36Sopenharmony_ci	__s32 magic;
2562306a36Sopenharmony_ci	__s32 version;
2662306a36Sopenharmony_ci	char backing_file[PATH_LEN_V1];
2762306a36Sopenharmony_ci	time32_t mtime;
2862306a36Sopenharmony_ci	__u64 size;
2962306a36Sopenharmony_ci	__s32 sectorsize;
3062306a36Sopenharmony_ci} __attribute__((packed));
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
3462306a36Sopenharmony_ci * case other systems have different values for MAXPATHLEN.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * The same must hold for V2 - we want file format compatibility, not anything
3762306a36Sopenharmony_ci * else.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci#define PATH_LEN_V3 4096
4062306a36Sopenharmony_ci#define PATH_LEN_V2 PATH_LEN_V3
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct cow_header_v2 {
4362306a36Sopenharmony_ci	__u32 magic;
4462306a36Sopenharmony_ci	__u32 version;
4562306a36Sopenharmony_ci	char backing_file[PATH_LEN_V2];
4662306a36Sopenharmony_ci	time32_t mtime;
4762306a36Sopenharmony_ci	__u64 size;
4862306a36Sopenharmony_ci	__s32 sectorsize;
4962306a36Sopenharmony_ci} __attribute__((packed));
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Changes from V2 -
5362306a36Sopenharmony_ci *	PATH_LEN_V3 as described above
5462306a36Sopenharmony_ci *	Explicitly specify field bit lengths for systems with different
5562306a36Sopenharmony_ci *		lengths for the usual C types.  Not sure whether char or
5662306a36Sopenharmony_ci *		time_t should be changed, this can be changed later without
5762306a36Sopenharmony_ci *		breaking compatibility
5862306a36Sopenharmony_ci *	Add alignment field so that different alignments can be used for the
5962306a36Sopenharmony_ci *		bitmap and data
6062306a36Sopenharmony_ci * 	Add cow_format field to allow for the possibility of different ways
6162306a36Sopenharmony_ci *		of specifying the COW blocks.  For now, the only value is 0,
6262306a36Sopenharmony_ci * 		for the traditional COW bitmap.
6362306a36Sopenharmony_ci *	Move the backing_file field to the end of the header.  This allows
6462306a36Sopenharmony_ci *		for the possibility of expanding it into the padding required
6562306a36Sopenharmony_ci *		by the bitmap alignment.
6662306a36Sopenharmony_ci * 	The bitmap and data portions of the file will be aligned as specified
6762306a36Sopenharmony_ci * 		by the alignment field.  This is to allow COW files to be
6862306a36Sopenharmony_ci *		put on devices with restrictions on access alignments, such as
6962306a36Sopenharmony_ci *		/dev/raw, with a 512 byte alignment restriction.  This also
7062306a36Sopenharmony_ci *		allows the data to be more aligned more strictly than on
7162306a36Sopenharmony_ci *		sector boundaries.  This is needed for ubd-mmap, which needs
7262306a36Sopenharmony_ci *		the data to be page aligned.
7362306a36Sopenharmony_ci *	Fixed (finally!) the rounding bug
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/*
7762306a36Sopenharmony_ci * Until Dec2005, __attribute__((packed)) was left out from the below
7862306a36Sopenharmony_ci * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to
7962306a36Sopenharmony_ci * align size to 8-byte alignment.  This shifted all fields above (no padding
8062306a36Sopenharmony_ci * was present on 32-bit, no other padding was added).
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * However, this _can be detected_: it means that cow_format (always 0 until
8362306a36Sopenharmony_ci * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise
8462306a36Sopenharmony_ci * impossible to find 4 zeros. -bb */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct cow_header_v3 {
8762306a36Sopenharmony_ci	__u32 magic;
8862306a36Sopenharmony_ci	__u32 version;
8962306a36Sopenharmony_ci	__u32 mtime;
9062306a36Sopenharmony_ci	__u64 size;
9162306a36Sopenharmony_ci	__u32 sectorsize;
9262306a36Sopenharmony_ci	__u32 alignment;
9362306a36Sopenharmony_ci	__u32 cow_format;
9462306a36Sopenharmony_ci	char backing_file[PATH_LEN_V3];
9562306a36Sopenharmony_ci} __attribute__((packed));
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* This is the broken layout used by some 64-bit binaries. */
9862306a36Sopenharmony_cistruct cow_header_v3_broken {
9962306a36Sopenharmony_ci	__u32 magic;
10062306a36Sopenharmony_ci	__u32 version;
10162306a36Sopenharmony_ci	__s64 mtime;
10262306a36Sopenharmony_ci	__u64 size;
10362306a36Sopenharmony_ci	__u32 sectorsize;
10462306a36Sopenharmony_ci	__u32 alignment;
10562306a36Sopenharmony_ci	__u32 cow_format;
10662306a36Sopenharmony_ci	char backing_file[PATH_LEN_V3];
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* COW format definitions - for now, we have only the usual COW bitmap */
11062306a36Sopenharmony_ci#define COW_BITMAP 0
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciunion cow_header {
11362306a36Sopenharmony_ci	struct cow_header_v1 v1;
11462306a36Sopenharmony_ci	struct cow_header_v2 v2;
11562306a36Sopenharmony_ci	struct cow_header_v3 v3;
11662306a36Sopenharmony_ci	struct cow_header_v3_broken v3_b;
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
12062306a36Sopenharmony_ci#define COW_VERSION 3
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
12362306a36Sopenharmony_ci#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_civoid cow_sizes(int version, __u64 size, int sectorsize, int align,
12662306a36Sopenharmony_ci	       int bitmap_offset, unsigned long *bitmap_len_out,
12762306a36Sopenharmony_ci	       int *data_offset_out)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	if (version < 3) {
13062306a36Sopenharmony_ci		*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		*data_offset_out = bitmap_offset + *bitmap_len_out;
13362306a36Sopenharmony_ci		*data_offset_out = (*data_offset_out + sectorsize - 1) /
13462306a36Sopenharmony_ci			sectorsize;
13562306a36Sopenharmony_ci		*data_offset_out *= sectorsize;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	else {
13862306a36Sopenharmony_ci		*bitmap_len_out = DIV_ROUND(size, sectorsize);
13962306a36Sopenharmony_ci		*bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		*data_offset_out = bitmap_offset + *bitmap_len_out;
14262306a36Sopenharmony_ci		*data_offset_out = ROUND_UP(*data_offset_out, align);
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int absolutize(char *to, int size, char *from)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	char save_cwd[256], *slash;
14962306a36Sopenharmony_ci	int remaining;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
15262306a36Sopenharmony_ci		cow_printf("absolutize : unable to get cwd - errno = %d\n",
15362306a36Sopenharmony_ci			   errno);
15462306a36Sopenharmony_ci		return -1;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	slash = strrchr(from, '/');
15762306a36Sopenharmony_ci	if (slash != NULL) {
15862306a36Sopenharmony_ci		*slash = '\0';
15962306a36Sopenharmony_ci		if (chdir(from)) {
16062306a36Sopenharmony_ci			*slash = '/';
16162306a36Sopenharmony_ci			cow_printf("absolutize : Can't cd to '%s' - "
16262306a36Sopenharmony_ci				   "errno = %d\n", from, errno);
16362306a36Sopenharmony_ci			return -1;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci		*slash = '/';
16662306a36Sopenharmony_ci		if (getcwd(to, size) == NULL) {
16762306a36Sopenharmony_ci			cow_printf("absolutize : unable to get cwd of '%s' - "
16862306a36Sopenharmony_ci			       "errno = %d\n", from, errno);
16962306a36Sopenharmony_ci			return -1;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci		remaining = size - strlen(to);
17262306a36Sopenharmony_ci		if (strlen(slash) + 1 > remaining) {
17362306a36Sopenharmony_ci			cow_printf("absolutize : unable to fit '%s' into %d "
17462306a36Sopenharmony_ci			       "chars\n", from, size);
17562306a36Sopenharmony_ci			return -1;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci		strcat(to, slash);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	else {
18062306a36Sopenharmony_ci		if (strlen(save_cwd) + 1 + strlen(from) + 1 > size) {
18162306a36Sopenharmony_ci			cow_printf("absolutize : unable to fit '%s' into %d "
18262306a36Sopenharmony_ci			       "chars\n", from, size);
18362306a36Sopenharmony_ci			return -1;
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci		strcpy(to, save_cwd);
18662306a36Sopenharmony_ci		strcat(to, "/");
18762306a36Sopenharmony_ci		strcat(to, from);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci	if (chdir(save_cwd)) {
19062306a36Sopenharmony_ci		cow_printf("absolutize : Can't cd to '%s' - "
19162306a36Sopenharmony_ci			   "errno = %d\n", save_cwd, errno);
19262306a36Sopenharmony_ci		return -1;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciint write_cow_header(char *cow_file, int fd, char *backing_file,
19862306a36Sopenharmony_ci		     int sectorsize, int alignment, unsigned long long *size)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct cow_header_v3 *header;
20162306a36Sopenharmony_ci	long long modtime;
20262306a36Sopenharmony_ci	int err;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	err = cow_seek_file(fd, 0);
20562306a36Sopenharmony_ci	if (err < 0) {
20662306a36Sopenharmony_ci		cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
20762306a36Sopenharmony_ci		goto out;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	err = -ENOMEM;
21162306a36Sopenharmony_ci	header = cow_malloc(sizeof(*header));
21262306a36Sopenharmony_ci	if (header == NULL) {
21362306a36Sopenharmony_ci		cow_printf("write_cow_header - failed to allocate COW V3 "
21462306a36Sopenharmony_ci			   "header\n");
21562306a36Sopenharmony_ci		goto out;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci	header->magic = htobe32(COW_MAGIC);
21862306a36Sopenharmony_ci	header->version = htobe32(COW_VERSION);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	err = -EINVAL;
22162306a36Sopenharmony_ci	if (strlen(backing_file) > sizeof(header->backing_file) - 1) {
22262306a36Sopenharmony_ci		/* Below, %zd is for a size_t value */
22362306a36Sopenharmony_ci		cow_printf("Backing file name \"%s\" is too long - names are "
22462306a36Sopenharmony_ci			   "limited to %zd characters\n", backing_file,
22562306a36Sopenharmony_ci			   sizeof(header->backing_file) - 1);
22662306a36Sopenharmony_ci		goto out_free;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (absolutize(header->backing_file, sizeof(header->backing_file),
23062306a36Sopenharmony_ci		      backing_file))
23162306a36Sopenharmony_ci		goto out_free;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	err = os_file_modtime(header->backing_file, &modtime);
23462306a36Sopenharmony_ci	if (err < 0) {
23562306a36Sopenharmony_ci		cow_printf("write_cow_header - backing file '%s' mtime "
23662306a36Sopenharmony_ci			   "request failed, err = %d\n", header->backing_file,
23762306a36Sopenharmony_ci			   -err);
23862306a36Sopenharmony_ci		goto out_free;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	err = cow_file_size(header->backing_file, size);
24262306a36Sopenharmony_ci	if (err < 0) {
24362306a36Sopenharmony_ci		cow_printf("write_cow_header - couldn't get size of "
24462306a36Sopenharmony_ci			   "backing file '%s', err = %d\n",
24562306a36Sopenharmony_ci			   header->backing_file, -err);
24662306a36Sopenharmony_ci		goto out_free;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	header->mtime = htobe32(modtime);
25062306a36Sopenharmony_ci	header->size = htobe64(*size);
25162306a36Sopenharmony_ci	header->sectorsize = htobe32(sectorsize);
25262306a36Sopenharmony_ci	header->alignment = htobe32(alignment);
25362306a36Sopenharmony_ci	header->cow_format = COW_BITMAP;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	err = cow_write_file(fd, header, sizeof(*header));
25662306a36Sopenharmony_ci	if (err != sizeof(*header)) {
25762306a36Sopenharmony_ci		cow_printf("write_cow_header - write of header to "
25862306a36Sopenharmony_ci			   "new COW file '%s' failed, err = %d\n", cow_file,
25962306a36Sopenharmony_ci			   -err);
26062306a36Sopenharmony_ci		goto out_free;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	err = 0;
26362306a36Sopenharmony_ci out_free:
26462306a36Sopenharmony_ci	cow_free(header);
26562306a36Sopenharmony_ci out:
26662306a36Sopenharmony_ci	return err;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ciint file_reader(__u64 offset, char *buf, int len, void *arg)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	int fd = *((int *) arg);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return pread(fd, buf, len, offset);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/* XXX Need to sanity-check the values read from the header */
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciint read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
27962306a36Sopenharmony_ci		    __u32 *version_out, char **backing_file_out,
28062306a36Sopenharmony_ci		    long long *mtime_out, unsigned long long *size_out,
28162306a36Sopenharmony_ci		    int *sectorsize_out, __u32 *align_out,
28262306a36Sopenharmony_ci		    int *bitmap_offset_out)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	union cow_header *header;
28562306a36Sopenharmony_ci	char *file;
28662306a36Sopenharmony_ci	int err, n;
28762306a36Sopenharmony_ci	unsigned long version, magic;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	header = cow_malloc(sizeof(*header));
29062306a36Sopenharmony_ci	if (header == NULL) {
29162306a36Sopenharmony_ci	        cow_printf("read_cow_header - Failed to allocate header\n");
29262306a36Sopenharmony_ci		return -ENOMEM;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	err = -EINVAL;
29562306a36Sopenharmony_ci	n = (*reader)(0, (char *) header, sizeof(*header), arg);
29662306a36Sopenharmony_ci	if (n < offsetof(typeof(header->v1), backing_file)) {
29762306a36Sopenharmony_ci		cow_printf("read_cow_header - short header\n");
29862306a36Sopenharmony_ci		goto out;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	magic = header->v1.magic;
30262306a36Sopenharmony_ci	if (magic == COW_MAGIC)
30362306a36Sopenharmony_ci		version = header->v1.version;
30462306a36Sopenharmony_ci	else if (magic == be32toh(COW_MAGIC))
30562306a36Sopenharmony_ci		version = be32toh(header->v1.version);
30662306a36Sopenharmony_ci	/* No error printed because the non-COW case comes through here */
30762306a36Sopenharmony_ci	else goto out;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	*version_out = version;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (version == 1) {
31262306a36Sopenharmony_ci		if (n < sizeof(header->v1)) {
31362306a36Sopenharmony_ci			cow_printf("read_cow_header - failed to read V1 "
31462306a36Sopenharmony_ci				   "header\n");
31562306a36Sopenharmony_ci			goto out;
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci		*mtime_out = header->v1.mtime;
31862306a36Sopenharmony_ci		*size_out = header->v1.size;
31962306a36Sopenharmony_ci		*sectorsize_out = header->v1.sectorsize;
32062306a36Sopenharmony_ci		*bitmap_offset_out = sizeof(header->v1);
32162306a36Sopenharmony_ci		*align_out = *sectorsize_out;
32262306a36Sopenharmony_ci		file = header->v1.backing_file;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	else if (version == 2) {
32562306a36Sopenharmony_ci		if (n < sizeof(header->v2)) {
32662306a36Sopenharmony_ci			cow_printf("read_cow_header - failed to read V2 "
32762306a36Sopenharmony_ci				   "header\n");
32862306a36Sopenharmony_ci			goto out;
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci		*mtime_out = be32toh(header->v2.mtime);
33162306a36Sopenharmony_ci		*size_out = be64toh(header->v2.size);
33262306a36Sopenharmony_ci		*sectorsize_out = be32toh(header->v2.sectorsize);
33362306a36Sopenharmony_ci		*bitmap_offset_out = sizeof(header->v2);
33462306a36Sopenharmony_ci		*align_out = *sectorsize_out;
33562306a36Sopenharmony_ci		file = header->v2.backing_file;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	/* This is very subtle - see above at union cow_header definition */
33862306a36Sopenharmony_ci	else if (version == 3 && (*((int*)header->v3.backing_file) != 0)) {
33962306a36Sopenharmony_ci		if (n < sizeof(header->v3)) {
34062306a36Sopenharmony_ci			cow_printf("read_cow_header - failed to read V3 "
34162306a36Sopenharmony_ci				   "header\n");
34262306a36Sopenharmony_ci			goto out;
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci		*mtime_out = be32toh(header->v3.mtime);
34562306a36Sopenharmony_ci		*size_out = be64toh(header->v3.size);
34662306a36Sopenharmony_ci		*sectorsize_out = be32toh(header->v3.sectorsize);
34762306a36Sopenharmony_ci		*align_out = be32toh(header->v3.alignment);
34862306a36Sopenharmony_ci		if (*align_out == 0) {
34962306a36Sopenharmony_ci			cow_printf("read_cow_header - invalid COW header, "
35062306a36Sopenharmony_ci				   "align == 0\n");
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		*bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
35362306a36Sopenharmony_ci		file = header->v3.backing_file;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	else if (version == 3) {
35662306a36Sopenharmony_ci		cow_printf("read_cow_header - broken V3 file with"
35762306a36Sopenharmony_ci			   " 64-bit layout - recovering content.\n");
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (n < sizeof(header->v3_b)) {
36062306a36Sopenharmony_ci			cow_printf("read_cow_header - failed to read V3 "
36162306a36Sopenharmony_ci				   "header\n");
36262306a36Sopenharmony_ci			goto out;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		/*
36662306a36Sopenharmony_ci		 * this was used until Dec2005 - 64bits are needed to represent
36762306a36Sopenharmony_ci		 * 2106+. I.e. we can safely do this truncating cast.
36862306a36Sopenharmony_ci		 *
36962306a36Sopenharmony_ci		 * Additionally, we must use be32toh() instead of be64toh(), since
37062306a36Sopenharmony_ci		 * the program used to use the former (tested - I got mtime
37162306a36Sopenharmony_ci		 * mismatch "0 vs whatever").
37262306a36Sopenharmony_ci		 *
37362306a36Sopenharmony_ci		 * Ever heard about bug-to-bug-compatibility ? ;-) */
37462306a36Sopenharmony_ci		*mtime_out = (time32_t) be32toh(header->v3_b.mtime);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		*size_out = be64toh(header->v3_b.size);
37762306a36Sopenharmony_ci		*sectorsize_out = be32toh(header->v3_b.sectorsize);
37862306a36Sopenharmony_ci		*align_out = be32toh(header->v3_b.alignment);
37962306a36Sopenharmony_ci		if (*align_out == 0) {
38062306a36Sopenharmony_ci			cow_printf("read_cow_header - invalid COW header, "
38162306a36Sopenharmony_ci				   "align == 0\n");
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci		*bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out);
38462306a36Sopenharmony_ci		file = header->v3_b.backing_file;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci	else {
38762306a36Sopenharmony_ci		cow_printf("read_cow_header - invalid COW version\n");
38862306a36Sopenharmony_ci		goto out;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	err = -ENOMEM;
39162306a36Sopenharmony_ci	*backing_file_out = cow_strdup(file);
39262306a36Sopenharmony_ci	if (*backing_file_out == NULL) {
39362306a36Sopenharmony_ci		cow_printf("read_cow_header - failed to allocate backing "
39462306a36Sopenharmony_ci			   "file\n");
39562306a36Sopenharmony_ci		goto out;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci	err = 0;
39862306a36Sopenharmony_ci out:
39962306a36Sopenharmony_ci	cow_free(header);
40062306a36Sopenharmony_ci	return err;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciint init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
40462306a36Sopenharmony_ci		  int alignment, int *bitmap_offset_out,
40562306a36Sopenharmony_ci		  unsigned long *bitmap_len_out, int *data_offset_out)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	unsigned long long size, offset;
40862306a36Sopenharmony_ci	char zero = 0;
40962306a36Sopenharmony_ci	int err;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	err = write_cow_header(cow_file, fd, backing_file, sectorsize,
41262306a36Sopenharmony_ci			       alignment, &size);
41362306a36Sopenharmony_ci	if (err)
41462306a36Sopenharmony_ci		goto out;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	*bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
41762306a36Sopenharmony_ci	cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
41862306a36Sopenharmony_ci		  bitmap_len_out, data_offset_out);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	offset = *data_offset_out + size - sizeof(zero);
42162306a36Sopenharmony_ci	err = cow_seek_file(fd, offset);
42262306a36Sopenharmony_ci	if (err < 0) {
42362306a36Sopenharmony_ci		cow_printf("cow bitmap lseek failed : err = %d\n", -err);
42462306a36Sopenharmony_ci		goto out;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/*
42862306a36Sopenharmony_ci	 * does not really matter how much we write it is just to set EOF
42962306a36Sopenharmony_ci	 * this also sets the entire COW bitmap
43062306a36Sopenharmony_ci	 * to zero without having to allocate it
43162306a36Sopenharmony_ci	 */
43262306a36Sopenharmony_ci	err = cow_write_file(fd, &zero, sizeof(zero));
43362306a36Sopenharmony_ci	if (err != sizeof(zero)) {
43462306a36Sopenharmony_ci		cow_printf("Write of bitmap to new COW file '%s' failed, "
43562306a36Sopenharmony_ci			   "err = %d\n", cow_file, -err);
43662306a36Sopenharmony_ci		if (err >= 0)
43762306a36Sopenharmony_ci			err = -EINVAL;
43862306a36Sopenharmony_ci		goto out;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci out:
44362306a36Sopenharmony_ci	return err;
44462306a36Sopenharmony_ci}
445