]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/crc32: don't require to modify GPT header
authorKarel Zak <kzak@redhat.com>
Tue, 22 Sep 2015 13:26:36 +0000 (15:26 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 24 Sep 2015 07:26:42 +0000 (09:26 +0200)
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>
include/crc32.h
lib/crc32.c
libblkid/src/partitions/gpt.c
libfdisk/src/gpt.c

index 26169109ebdead56f1e455570035797bfe36f804..ff2dd99d874115acc000764bab2e7a14c54e334d 100644 (file)
@@ -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
 
index be98f1a8d12796c057a841aef7521ce27e45aca2..0c986288dfdf4208ea7822b062e0dc5924321cf5 100644 (file)
@@ -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;
+}
+
index 665577fa42a5c1aaaa418307681850b15bd3e0bf..26f0474426ca04ce5bf757b28e91f5aaf41dcc2a 100644 (file)
@@ -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;
index 81741679ace4cde90467a609c5afde4aebec75d5..607cb32cc61c619e0d560595aee35ac55c0faeeb 100644 (file)
@@ -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)