From f4a7ce7c49ef3048865901ceb139af08d8a91ae1 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Tue, 11 Dec 2001 16:49:40 +0000 Subject: [PATCH] - Change label format to include a string disk_type and a version number. - The iterator can find labels by string and also appropriate version number (==, <= or any) if you want. - Add labels_match() call that compares the two labels and returns an error if they do not match. - Write labels in sector 1 & last rather than 2 & last as per Joe. --- lib/label/label.c | 214 ++++++++++++++++++++++++++++++++++++++++------ lib/label/label.h | 23 +++-- 2 files changed, 201 insertions(+), 36 deletions(-) diff --git a/lib/label/label.c b/lib/label/label.c index 45e2e3349..7c976830a 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "device.h" @@ -27,16 +28,19 @@ static void *label_pool = NULL; struct label_ondisk { uint32_t magic; - uint32_t format_type; uint32_t checksum; uint16_t datalen; - uint16_t pad; + + char disk_type[32]; + uint32_t version[3]; }; struct filter_private { void *mem; - uint32_t format_type; + char disk_type[32]; + uint32_t version[3]; + int version_match; }; @@ -47,7 +51,9 @@ static uint32_t calc_checksum(struct label *label) int i; csum += label->magic; - csum += label->format_type; + csum += label->version[0]; + csum += label->version[1]; + csum += label->version[2]; csum += label->datalen; for (i=0; idatalen; i++) @@ -55,6 +61,11 @@ static uint32_t calc_checksum(struct label *label) csum += label->data[i]; } + for (i=0; idisk_type); i++) + { + csum += label->disk_type[i]; + } + return csum; } @@ -76,7 +87,7 @@ int label_read(struct device *dev, struct label *label) if (!dev_get_sectsize(dev, §size)) return 0; - if (!dev_open(dev, O_RDWR)) + if (!dev_open(dev, O_RDONLY)) return 0; if (label_pool == NULL) @@ -86,38 +97,59 @@ int label_read(struct device *dev, struct label *label) if (!block) { stack; - return 1; + return 0; } ondisk = (struct label_ondisk *)block; - status = dev_read(dev, sectsize*2, sectsize, block); - /* If the first label is bad then use the second */ for (iter = 0; iter <= 1; iter++) { if (iter == 0) - status = dev_read(dev, sectsize*2, sectsize, block); + status = dev_read(dev, sectsize, sectsize, block); else - status = dev_read(dev, size*512 - sectsize, sizeof(struct label_ondisk) + label->datalen, block); + status = dev_read(dev, size*512 - sectsize, sectsize, block); if (status) { struct label incore; + int i; + int found_nul; - /* Copy and convert endianness */ + /* If the MAGIC doesn't match there's no point in + carrying on */ + if (xlate32(ondisk->magic) != LABEL_MAGIC) + continue; + + /* Look for a NUL in the disk_type string so we don't + SEGV is something has gone horribly wrong */ + found_nul = 0; + for (i=0; idisk_type); i++) + if (ondisk->disk_type[i] == '\0') + found_nul = 1; + + if (!found_nul) + continue; + + /* Copy and convert endianness */ incore.magic = xlate32(ondisk->magic); - incore.format_type = xlate32(ondisk->format_type); + incore.version[0] = xlate32(ondisk->version[0]); + incore.version[1] = xlate32(ondisk->version[1]); + incore.version[2] = xlate32(ondisk->version[2]); + for (i=0; idisk_type)+1; i++) + incore.disk_type[i] = ondisk->disk_type[i]; incore.checksum = xlate32(ondisk->checksum); incore.datalen = xlate16(ondisk->datalen); incore.data = block + sizeof(struct label_ondisk); - if (incore.magic != LABEL_MAGIC) + /* Make sure datalen is a sensible size too */ + if (incore.datalen > sectsize) continue; /* Check Checksum */ if (incore.checksum != calc_checksum(&incore)) { - log_error("Checksum %d on device %s does not match. got %x, need %x", iter, dev_name(dev), incore.checksum, calc_checksum(&incore)); + log_error("Checksum %d on device %s does not match. got %x, expected %x", + iter, dev_name(dev), incore.checksum, calc_checksum(&incore)); continue; } @@ -127,10 +159,9 @@ int label_read(struct device *dev, struct label *label) if (!label->data) { stack; - return 1; + return 0; } memcpy(label->data, incore.data, incore.datalen); - label->pool = label_pool; pool_free(label_pool, block); dev_close(dev); @@ -152,6 +183,7 @@ int label_write(struct device *dev, struct label *label) char *block; struct label_ondisk *ondisk; int status1, status2; + int i; if (!dev_get_size(dev, &size)) return 0; @@ -170,7 +202,7 @@ int label_write(struct device *dev, struct label *label) if (!block) { stack; - return 1; + return 0; } ondisk = (struct label_ondisk *)block; @@ -178,7 +210,12 @@ int label_write(struct device *dev, struct label *label) /* Make into ondisk format */ label->magic = LABEL_MAGIC; ondisk->magic = xlate32(LABEL_MAGIC); - ondisk->format_type = xlate32(label->format_type); + + ondisk->version[0] = xlate32(label->version[0]); + ondisk->version[1] = xlate32(label->version[1]); + ondisk->version[2] = xlate32(label->version[2]); + for (i=0; idisk_type)+1; i++) + ondisk->disk_type[i] = label->disk_type[i]; ondisk->datalen = xlate16(label->datalen); ondisk->checksum = xlate32(calc_checksum(label)); memcpy(block+sizeof(struct label_ondisk), label->data, label->datalen); @@ -190,7 +227,7 @@ int label_write(struct device *dev, struct label *label) return 0; } - status1 = dev_write(dev, sectsize*2, sizeof(struct label_ondisk) + label->datalen, block); + status1 = dev_write(dev, sectsize, sizeof(struct label_ondisk) + label->datalen, block); /* Write another at the end of the device */ status2 = dev_write(dev, size*512 - sectsize, sizeof(struct label_ondisk) + label->datalen, block); @@ -210,7 +247,7 @@ int is_labelled(struct device *dev) int status; status = label_read(dev, &l); - if (status) pool_free(l.pool, l.data); + if (status) label_free(&l); return status; } @@ -220,15 +257,42 @@ static int _accept_format(struct dev_filter *f, struct device *dev) { struct label l; int status; + struct filter_private *fp = (struct filter_private *) f->private; status = label_read(dev, &l); - if (status) pool_free(l.pool, l.data); + if (status) label_free(&l); - if (status && l.format_type == (uint32_t)f->private) - return 1; + if (status) + { + if (strcmp(l.disk_type, fp->disk_type) == 0) + { + switch (fp->version_match) + { + case VERSION_MATCH_EQUAL: + if (l.version[0] == fp->version[0] && + l.version[1] == fp->version[1] && + l.version[2] == fp->version[2]) + return 1; + break; - else - return 0; + case VERSION_MATCH_LESSTHAN: + if (l.version[0] == fp->version[0] && + l.version[1] < fp->version[1]) + return 1; + break; + + case VERSION_MATCH_LESSEQUAL: + if (l.version[0] == fp->version[0] && + l.version[1] <= fp->version[1]) + return 1; + break; + + case VERSION_MATCH_ANY: + return 1; + } + } + } + return 0; } /* We just want to know if it's labelled or not */ @@ -244,12 +308,20 @@ static void _destroy(struct dev_filter *f) } /* A filter to find devices with a particular label type on them */ -struct dev_filter *label_format_filter_create(uint32_t format_type) +struct dev_filter *label_format_filter_create(char *disk_type, uint32_t version[3], int match_type) { - struct pool *mem = pool_create(10 * 1024); + struct pool *mem; struct filter_private *fp; struct dev_filter *f; + /* Validate the match type */ + if (match_type != VERSION_MATCH_EQUAL && + match_type != VERSION_MATCH_LESSTHAN && + match_type != VERSION_MATCH_LESSEQUAL && + match_type != VERSION_MATCH_ANY) + return 0; + + mem = pool_create(10 * 1024); if (!mem) { stack; return NULL; @@ -266,7 +338,11 @@ struct dev_filter *label_format_filter_create(uint32_t format_type) } fp->mem = mem; - fp->format_type = format_type; + strcpy(fp->disk_type, disk_type); + fp->version[0] = version[0]; + fp->version[1] = version[1]; + fp->version[2] = version[2]; + fp->version_match = match_type; f->passes_filter = _accept_format; f->destroy = _destroy; f->private = fp; @@ -311,3 +387,85 @@ struct dev_filter *label_filter_create() pool_destroy(mem); return NULL; } + +/* Return 1 if both labels are identical, 0 if not or there was an error */ +int labels_match(struct device *dev) +{ + uint64_t size; + uint32_t sectsize; + char *block1; + char *block2; + struct label_ondisk *ondisk1; + struct label_ondisk *ondisk2; + int status = 0; + + if (!dev_get_size(dev, &size)) + return 0; + + if (!dev_get_sectsize(dev, §size)) + return 0; + + if (label_pool == NULL) + label_pool = pool_create(512); + + /* ALlocate some space for the blocks we are going to read in */ + block1 = pool_alloc(label_pool, sectsize); + if (!block1) + { + stack; + return 0; + } + + block2 = pool_alloc(label_pool, sectsize); + if (!block2) + { + stack; + pool_free(label_pool, block1); + return 0; + } + ondisk1 = (struct label_ondisk *)block1; + ondisk2 = (struct label_ondisk *)block2; + + /* Fetch em */ + if (!dev_open(dev, O_RDONLY)) + goto finish; + + if (!dev_read(dev, sectsize, sectsize, block1)) + goto finish; + + if (!dev_read(dev, size*512 - sectsize, sectsize, block2)) + goto finish; + + dev_close(dev); + + /* Is it labelled? */ + if (xlate32(ondisk1->magic) != LABEL_MAGIC) + goto finish; + + /* Compare the whole structs */ + if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0) + goto finish; + + /* OK, check the data area */ + if (memcmp(block1 + sizeof(struct label_ondisk), + block2 + sizeof(struct label_ondisk), + xlate16(ondisk1->datalen)) != 0) + goto finish; + + /* They match !! */ + status = 1; + + finish: + pool_free(label_pool, block2); + pool_free(label_pool, block1); + + return status; +} + +/* Free data area allocated by label_read() */ +void label_free(struct label *label) +{ + if (label->data) + pool_free(label_pool, label->data); +} + diff --git a/lib/label/label.h b/lib/label/label.h index c58f07c35..0177976de 100644 --- a/lib/label/label.h +++ b/lib/label/label.h @@ -7,18 +7,25 @@ struct label { uint32_t magic; - uint32_t format_type; uint32_t checksum; uint16_t datalen; - char *data; - void *pool; /* Pool that data is allocated from */ + + char disk_type[32]; + uint32_t version[3]; + + char *data; /* Should be freed with label_free() */ }; +#define VERSION_MATCH_EQUAL 1 +#define VERSION_MATCH_LESSTHAN 2 +#define VERSION_MATCH_LESSEQUAL 3 +#define VERSION_MATCH_ANY 4 - -extern int label_write(struct device *dev, struct label *label); -extern int label_read(struct device *dev, struct label *label); -extern int is_labelled(struct device *dev); +extern int label_write(struct device *dev, struct label *label); +extern int label_read(struct device *dev, struct label *label); +extern void label_free(struct label *label); +extern int is_labelled(struct device *dev); +extern int labels_match(struct device *dev); extern struct dev_filter *label_filter_create(); -extern struct dev_filter *label_format_filter_create(uint32_t format_type); +extern struct dev_filter *label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);