summaryrefslogtreecommitdiff
path: root/super-ddf.c
diff options
context:
space:
mode:
Diffstat (limited to 'super-ddf.c')
-rw-r--r--super-ddf.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/super-ddf.c b/super-ddf.c
index a78692c3..9192ccdc 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -1327,6 +1327,68 @@ static void export_examine_super_ddf(struct supertype *st)
printf("MD_UUID=%s\n", nbuf+5);
}
+static int copy_metadata_ddf(struct supertype *st, int from, int to)
+{
+ void *buf;
+ unsigned long long dsize, offset;
+ int bytes;
+ struct ddf_header *ddf;
+ int written = 0;
+
+ /* The meta consists of an anchor, a primary, and a secondary.
+ * This all lives at the end of the device.
+ * So it is easiest to find the earliest of primary and
+ * secondary, and copy everything from there.
+ *
+ * Anchor is 512 from end It contains primary_lba and secondary_lba
+ * we choose one of those
+ */
+
+ if (posix_memalign(&buf, 4096, 4096) != 0)
+ return 1;
+
+ if (!get_dev_size(from, NULL, &dsize))
+ goto err;
+
+ if (lseek64(from, dsize-512, 0) < 0)
+ goto err;
+ if (read(from, buf, 512) != 512)
+ goto err;
+ ddf = buf;
+ if (ddf->magic != DDF_HEADER_MAGIC ||
+ calc_crc(ddf, 512) != ddf->crc ||
+ (memcmp(ddf->revision, DDF_REVISION_0, 8) != 0 &&
+ memcmp(ddf->revision, DDF_REVISION_2, 8) != 0))
+ goto err;
+
+ offset = dsize - 512;
+ if ((__be64_to_cpu(ddf->primary_lba) << 9) < offset)
+ offset = __be64_to_cpu(ddf->primary_lba) << 9;
+ if ((__be64_to_cpu(ddf->secondary_lba) << 9) < offset)
+ offset = __be64_to_cpu(ddf->secondary_lba) << 9;
+
+ bytes = dsize - offset;
+
+ if (lseek64(from, offset, 0) < 0 ||
+ lseek64(to, offset, 0) < 0)
+ goto err;
+ while (written < bytes) {
+ int n = bytes - written;
+ if (n > 4096)
+ n = 4096;
+ if (read(from, buf, n) != n)
+ goto err;
+ if (write(to, buf, n) != n)
+ goto err;
+ written += n;
+ }
+ free(buf);
+ return 0;
+err:
+ free(buf);
+ return 1;
+}
+
static void detail_super_ddf(struct supertype *st, char *homehost)
{
/* FIXME later
@@ -4298,6 +4360,7 @@ struct superswitch super_ddf = {
.add_to_super = add_to_super_ddf,
.remove_from_super = remove_from_super_ddf,
.load_container = load_container_ddf,
+ .copy_metadata = copy_metadata_ddf,
#endif
.match_home = match_home_ddf,
.uuid_from_super= uuid_from_super_ddf,