summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2015-09-22 15:26:36 +0200
committerKarel Zak2015-09-24 09:26:42 +0200
commit7020de0be8b5fa0cdb6a8feee3f64f5384b18f06 (patch)
tree9dd9ef9c801e55c6b99cde0a3cbace73d6cbda8e
parentsfdisk: add --delete (diff)
downloadkernel-qcow2-util-linux-7020de0be8b5fa0cdb6a8feee3f64f5384b18f06.tar.gz
kernel-qcow2-util-linux-7020de0be8b5fa0cdb6a8feee3f64f5384b18f06.tar.xz
kernel-qcow2-util-linux-7020de0be8b5fa0cdb6a8feee3f64f5384b18f06.zip
lib/crc32: don't require to modify GPT header
This patch introduces smart crc32 function that is able to exclude specified. The advantage is that we does not have to modify GPT header (set the current in-header crc field to zero) when we count crc32. This allows to keep GPT header in read-only buffers and simplify code. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--include/crc32.h2
-rw-r--r--lib/crc32.c26
-rw-r--r--libblkid/src/partitions/gpt.c18
-rw-r--r--libfdisk/src/gpt.c81
4 files changed, 71 insertions, 56 deletions
diff --git a/include/crc32.h b/include/crc32.h
index 26169109e..ff2dd99d8 100644
--- a/include/crc32.h
+++ b/include/crc32.h
@@ -5,6 +5,8 @@
#include <stdint.h>
extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len);
+extern uint32_t crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len);
#endif
diff --git a/lib/crc32.c b/lib/crc32.c
index be98f1a8d..0c986288d 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -98,6 +98,11 @@ static const uint32_t crc32_tab[] = {
0x2d02ef8dL
};
+static inline uint32_t crc32_add_char(uint32_t crc, unsigned char c)
+{
+ return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8);
+}
+
/*
* This a generic crc32() function, it takes seed as an argument,
* and does __not__ xor at the end. Then individual users can do
@@ -109,10 +114,29 @@ uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len)
const unsigned char *p = buf;
while (len) {
- crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+ crc = crc32_add_char(crc, *p++);
len--;
}
return crc;
}
+uint32_t crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len)
+{
+ uint32_t crc = seed;
+ const unsigned char *p = buf;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ unsigned char x = *p++;
+
+ if (i >= exclude_off && i < exclude_off + exclude_len)
+ x = 0;
+
+ crc = crc32_add_char(crc, x);
+ }
+
+ return crc;
+}
+
diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c
index 665577fa4..26f047442 100644
--- a/libblkid/src/partitions/gpt.c
+++ b/libblkid/src/partitions/gpt.c
@@ -102,9 +102,10 @@ struct gpt_entry {
/*
* EFI uses crc32 with ~0 seed and xor's with ~0 at the end.
*/
-static inline uint32_t count_crc32(const unsigned char *buf, size_t len)
+static inline uint32_t count_crc32(const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len)
{
- return (crc32(~0L, buf, len) ^ ~0L);
+ return (crc32_exclude_offset(~0L, buf, len, exclude_off, exclude_len) ^ ~0L);
}
static inline unsigned char *get_lba_buffer(blkid_probe pr,
@@ -207,7 +208,7 @@ static struct gpt_header *get_gpt_header(
uint64_t lastlba)
{
struct gpt_header *h;
- uint32_t crc, orgcrc;
+ uint32_t crc;
uint64_t lu, fu;
size_t esz;
uint32_t hsz, ssz;
@@ -231,12 +232,11 @@ static struct gpt_header *get_gpt_header(
return NULL;
/* Header has to be verified when header_crc32 is zero */
- orgcrc = h->header_crc32;
- h->header_crc32 = 0;
- crc = count_crc32((unsigned char *) h, hsz);
- h->header_crc32 = orgcrc;
+ crc = count_crc32((unsigned char *) h, hsz,
+ offsetof(struct gpt_header, header_crc32),
+ sizeof(h->header_crc32));
- if (crc != le32_to_cpu(orgcrc)) {
+ if (crc != le32_to_cpu(h->header_crc32)) {
DBG(LOWPROBE, ul_debug("GPT header corrupted"));
return NULL;
}
@@ -289,7 +289,7 @@ static struct gpt_header *get_gpt_header(
}
/* Validate entries */
- crc = count_crc32((unsigned char *) *ents, esz);
+ crc = count_crc32((unsigned char *) *ents, esz, 0, 0);
if (crc != le32_to_cpu(h->partition_entry_array_crc32)) {
DBG(LOWPROBE, ul_debug("GPT entries corrupted"));
return NULL;
diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
index 81741679a..607cb32cc 100644
--- a/libfdisk/src/gpt.c
+++ b/libfdisk/src/gpt.c
@@ -845,11 +845,31 @@ fail:
return NULL;
}
-static inline uint32_t count_crc32(const unsigned char *buf, size_t len)
+static inline uint32_t count_crc32(const unsigned char *buf, size_t len,
+ size_t ex_off, size_t ex_len)
{
- return (crc32(~0L, buf, len) ^ ~0L);
+ return (crc32_exclude_offset(~0L, buf, len, ex_off, ex_len) ^ ~0L);
}
+static inline uint32_t gpt_header_count_crc32(struct gpt_header *header)
+{
+ return count_crc32((unsigned char *) header, /* buffer */
+ le32_to_cpu(header->size), /* size of buffer */
+ offsetof(struct gpt_header, crc32), /* exclude */
+ sizeof(header->crc32)); /* size of excluded area */
+}
+
+static inline uint32_t gpt_entryarr_count_crc32(struct gpt_header *header, struct gpt_entry *ents)
+{
+ size_t arysz = 0;
+
+ arysz = le32_to_cpu(header->npartition_entries) *
+ le32_to_cpu(header->sizeof_partition_entry);
+
+ return count_crc32((unsigned char *) ents, arysz, 0, 0);
+}
+
+
/*
* Recompute header and partition array 32bit CRC checksums.
* This function does not fail - if there's corruption, then it
@@ -857,24 +877,13 @@ static inline uint32_t count_crc32(const unsigned char *buf, size_t len)
*/
static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents)
{
- uint32_t crc = 0;
- size_t entry_sz = 0;
-
if (!header)
return;
- /* header CRC */
- header->crc32 = 0;
- crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
- header->crc32 = cpu_to_le32(crc);
-
- /* partition entry array CRC */
- header->partition_entry_array_crc32 = 0;
- entry_sz = le32_to_cpu(header->npartition_entries) *
- le32_to_cpu(header->sizeof_partition_entry);
+ header->partition_entry_array_crc32 =
+ cpu_to_le32( gpt_entryarr_count_crc32(header, ents) );
- crc = count_crc32((unsigned char *) ents, entry_sz);
- header->partition_entry_array_crc32 = cpu_to_le32(crc);
+ header->crc32 = cpu_to_le32( gpt_header_count_crc32(header) );
}
/*
@@ -883,28 +892,20 @@ static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents)
*/
static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ents)
{
- uint32_t crc, orgcrc = le32_to_cpu(header->crc32);
-
- header->crc32 = 0;
- crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
- header->crc32 = cpu_to_le32(orgcrc);
+ uint32_t orgcrc = le32_to_cpu(header->crc32),
+ crc = gpt_header_count_crc32(header);
- if (crc == le32_to_cpu(header->crc32))
+ if (crc == orgcrc)
return 1;
/*
- * If we have checksum mismatch it may be due to stale data,
- * like a partition being added or deleted. Recompute the CRC again
- * and make sure this is not the case.
+ * If we have checksum mismatch it may be due to stale data, like a
+ * partition being added or deleted. Recompute the CRC again and make
+ * sure this is not the case.
*/
if (ents) {
gpt_recompute_crc(header, ents);
- orgcrc = le32_to_cpu(header->crc32);
- header->crc32 = 0;
- crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
- header->crc32 = cpu_to_le32(orgcrc);
-
- return crc == le32_to_cpu(header->crc32);
+ return gpt_header_count_crc32(header) == orgcrc;
}
return 0;
@@ -917,23 +918,11 @@ static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ent
static int gpt_check_entryarr_crc(struct gpt_header *header,
struct gpt_entry *ents)
{
- int ret = 0;
- ssize_t entry_sz;
- uint32_t crc;
-
if (!header || !ents)
- goto done;
-
- entry_sz = le32_to_cpu(header->npartition_entries) *
- le32_to_cpu(header->sizeof_partition_entry);
-
- if (!entry_sz)
- goto done;
+ return 0;
- crc = count_crc32((unsigned char *) ents, entry_sz);
- ret = (crc == le32_to_cpu(header->partition_entry_array_crc32));
-done:
- return ret;
+ return gpt_entryarr_count_crc32(header, ents) ==
+ le32_to_cpu(header->partition_entry_array_crc32);
}
static int gpt_check_lba_sanity(struct fdisk_context *cxt, struct gpt_header *header)