Add compute_file_checksum and get_header_byte_range functions.
authorTomas Mlcoch <tmlcoch@redhat.com>
Wed, 11 Jan 2012 14:15:51 +0000 (15:15 +0100)
committerTomas Mlcoch <tmlcoch@redhat.com>
Wed, 11 Jan 2012 14:15:51 +0000 (15:15 +0100)
misc.c
misc.h

diff --git a/misc.c b/misc.c
index cd09a9d..732f388 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1,8 +1,13 @@
 #include <glib.h>
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <arpa/inet.h>
+#include "constants.h"
 #include "misc.h"
 
+#define BUFFER_SIZE     4096
+
 
 const char *flag_to_string(gint64 flags)
 {
@@ -141,3 +146,111 @@ int is_primary(const char *filename)
     return 0;
 }
 
+
+
+char *compute_file_checksum(const char *filename, ChecksumType type)
+{
+    GChecksumType gchecksumtype;
+
+    // Check if file exists and if it is a regular file (not a directory)
+
+    if (!g_file_test(filename, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
+        return NULL;
+    }
+
+    // Convert our checksum type into glib type
+
+    switch (type) {
+        case PKG_CHECKSUM_MD5:
+            gchecksumtype = G_CHECKSUM_MD5;
+            break;
+        case PKG_CHECKSUM_SHA1:
+            gchecksumtype = G_CHECKSUM_SHA1;
+            break;
+        case PKG_CHECKSUM_SHA256:
+            gchecksumtype = G_CHECKSUM_SHA256;
+            break;
+    };
+
+    // Open file and initialize checksum structure
+
+    FILE *fp = fopen(filename, "rb");
+    if (!fp) {
+        return NULL;
+    }
+
+    // Calculate checksum
+
+    GChecksum *checksum = g_checksum_new(gchecksumtype);
+    unsigned char buffer[BUFFER_SIZE];
+
+    while (1) {
+        size_t input_len;
+        input_len = fread((void *) buffer, sizeof(unsigned char), BUFFER_SIZE, fp);
+        g_checksum_update(checksum, (const guchar *) buffer, input_len);
+        if (input_len < BUFFER_SIZE) {
+            break;
+        }
+    }
+
+    fclose(fp);
+
+    // Malloc space and get checksum
+
+    const char *checksum_tmp_str = g_checksum_get_string(checksum);
+    size_t checksum_len = strlen(checksum_tmp_str);
+    char *checksum_str = (char *) malloc(sizeof(char) * (checksum_len + 1));
+    if (!checksum_str) {
+        g_checksum_free(checksum);
+        return NULL;
+    }
+    strcpy(checksum_str, checksum_tmp_str);
+
+    // Clean up
+
+    g_checksum_free(checksum);
+
+    return checksum_str;
+}
+
+
+#define VAL_LEN         4       // Len of numeric values in rpm
+
+struct HeaderRangeStruct get_header_byte_range(const char *filename)
+{
+    /* Values readed by fread are 4 bytes long and stored as big-endian.
+     * So there is htonl function to convert this big-endian number into host byte order.
+     */
+    FILE *fp = fopen(filename, "rb");
+    fseek(fp, 104, SEEK_SET);
+    unsigned int sigindex = 0;
+    unsigned int sigdata  = 0;
+    fread(&sigindex, VAL_LEN, 1, fp);
+    sigindex = htonl(sigindex);
+    fread(&sigdata, VAL_LEN, 1, fp);
+    sigdata = htonl(sigdata);
+    unsigned int sigindexsize = sigindex * 16;
+    unsigned int sigsize = sigdata + sigindexsize;
+    unsigned int disttoboundary = sigsize % 8;
+    if (disttoboundary) {
+        disttoboundary = 8 - disttoboundary;
+    }
+    unsigned int hdrstart = 112 + sigsize + disttoboundary;
+
+    fseek(fp, hdrstart, SEEK_SET);
+    fseek(fp, 8, SEEK_CUR);
+
+    unsigned int hdrindex = 0;
+    unsigned int hdrdata  = 0;
+    fread(&hdrindex, VAL_LEN, 1, fp);
+    hdrindex = htonl(hdrindex);
+    fread(&hdrdata, VAL_LEN, 1, fp);
+    hdrdata = htonl(hdrdata);
+    unsigned int hdrindexsize = hdrindex * 16;
+    unsigned int hdrsize = hdrdata + hdrindexsize + 16;
+    unsigned int hdrend = hdrstart + hdrsize;
+
+    fclose(fp);
+
+    return (struct HeaderRangeStruct) {hdrstart, hdrend};
+}
diff --git a/misc.h b/misc.h
index 9f3254e..92aee65 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -2,10 +2,10 @@
 #define __MISC__
 
 #include <glib.h>
+#include "constants.h"
 
 const char *flag_to_string(gint64 flags);
 
-
 struct VersionStruct {
     char *epoch;
     char *version;
@@ -18,5 +18,13 @@ struct VersionStruct {
  */
 struct VersionStruct string_to_version(const char *string, GStringChunk *chunk);
 int is_primary(const char *filename);
+char *compute_file_checksum(const char *filename, ChecksumType type);
+
+struct HeaderRangeStruct {
+    unsigned int start;
+    unsigned int end;
+};
+struct HeaderRangeStruct get_header_byte_range(const char *filename);
+
 
 #endif /* __MISC__ */