Use the new DB cache
authorSteve McIntyre <steve@einval.com>
Sun, 13 Mar 2005 23:05:11 +0000 (23:05 +0000)
committerSteve McIntyre <steve@einval.com>
Sun, 13 Mar 2005 23:05:11 +0000 (23:05 +0000)
jigsum.c

index 422797c..763a804 100644 (file)
--- a/jigsum.c
+++ b/jigsum.c
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include "md5.h"
+#include "jigdb.h"
 
 #define BUF_SIZE 65536
 
 #define MIN(x,y)        ( ((x) < (y)) ? (x) : (y))
 #endif
 
-static int md5_file(char *filename)
-{
-    FILE *file = NULL;
-    char buf[BUF_SIZE];
-    unsigned char file_md5[16] = {0};
-    char *base64_md5 = NULL;
-    struct mk_MD5Context file_context;
-    int done = 0;
-    int bytes_read = 0;
-
-    mk_MD5Init(&file_context);
+JIGDB *database = NULL;
 
-    /* Check if we're reading from stdin */
-    if (!strcmp("-", filename))
-        file = stdin;
-    else
+static int check_cache(char *filename, struct stat *sb, char **base64_md5)
+{
+    int error = 0;
+    db_entry_t *entry;
+    
+    error = db_lookup_by_name(database, filename, &entry);
+    if (!error)
     {
-        fprintf(stderr, "\r %-75.75s", filename);
-        file = fopen(filename, "rb");
-        if (!file)
+        if ( (sb->st_mtime <= entry->mtime) &&
+             (sb->st_size == entry->file_size) )
+            /* We have a cache entry already; simply return
+             * the cached sum */
         {
-            switch (errno)
-            {
-                case EACCES:
-                case EISDIR:
-                    break;
-                default:
-                    fprintf(stderr, "Unable to open file %s; error %d\n", filename, errno);
-                    break;
-            }
-            return errno;
+            *base64_md5 = entry->md5;
+            return 1;
+        }
+        else
+        {
+            /* We have an entry for this file, but the mtime or size
+             * has changed. Delete the old entry and replace it later
+             * on */
+            error = db_delete(database, entry->md5);
+            if (error)
+                printf("check_cache: unable to delete old entry for file %s\n", filename);
         }
     }
+    return 0;
+}
+
+static unsigned long long calculate_md5(char *filename, FILE *file, char **base64_md5)
+{
+    char buf[BUF_SIZE];
+    unsigned char file_md5[16] = {0};
+    int done = 0;
+    struct mk_MD5Context file_context;
+    unsigned long long bytes_read = 0;
     
+    mk_MD5Init(&file_context);
     while (!done)
     {
         int used = 0;
@@ -75,31 +82,145 @@ static int md5_file(char *filename)
                         filename, errno);
             break;
         }
-    }
-    
+    }    
     mk_MD5Final(file_md5, &file_context);
-    base64_md5 = base64_dump(file_md5, 16);
-    if (file != stdin)
+    *base64_md5 = base64_dump(file_md5, 16);
+    return bytes_read;
+}
+
+static int md5_file(char *filename)
+{
+    FILE *file = NULL;
+    char *base64_md5 = NULL;
+    unsigned long long bytes_read = 0;
+    db_entry_t entry;
+    struct stat sb;
+    int found_in_db = 0;
+    int error = 0;
+    char buf[PATH_MAX];
+    char *fullpath = NULL;
+
+    /* Check if we're reading from stdin */
+    if (!strcmp("-", filename))
     {
-        fclose(file);
-        if (bytes_read)
-            printf("%s  %s\n", base64_md5, filename);
+        (void)calculate_md5("<STDIN>", stdin, &base64_md5);
+        printf("%s\n", base64_md5);
+        fflush(stdout);
+        return 0;
     }
+
+    /* Make an absolute pathname if necessary */
+    if (filename[0] == '/')
+        fullpath = filename;
     else
-        if (bytes_read)
-            printf("%s\n", base64_md5);
+    {
+        size_t wdlen = 0;
+        if (buf != getcwd(buf, sizeof(buf)))
+        {
+            fprintf(stderr, "md5_file: Unable to get CWD!; giving up on file %s, error %d\n",
+                    filename, errno);
+            return errno;
+        }
+        wdlen = strlen(buf);
+        strcpy(buf + wdlen, "/");
+        strcpy(buf + wdlen + 1, filename);
+        fullpath = buf;
+    }
+
+    /* Check the DB to see if we already have a checksum for this file */
+    error = stat(fullpath, &sb);
+    if (error)
+    {
+        fprintf(stderr, "md5_file: Unable to stat file %s, error %d\n", fullpath, errno);
+        return errno;
+    }
+    found_in_db = check_cache(fullpath, &sb, &base64_md5);
+    if (!found_in_db)
+    {
+        file = fopen(fullpath, "rb");
+        if (!file)
+        {
+            switch (errno)
+            {
+                case EACCES:
+                case EISDIR:
+                    break;
+                default:
+                    fprintf(stderr, "Unable to open file %s; error %d\n", fullpath, errno);
+                    break;
+            }
+            return errno;
+        }
+        bytes_read = calculate_md5(fullpath, file, &base64_md5);
+        fclose(file);
+        memset(&entry, 0, sizeof(entry));
+        strncpy(&entry.md5[0], base64_md5, sizeof(entry.md5));
+        entry.type = FT_LOCAL;
+        entry.mtime = sb.st_mtime;
+        entry.age = UINT_MAX - time(NULL);
+        entry.file_size = bytes_read;
+        strncpy(&entry.filename[0], fullpath, sizeof(entry.filename));
+        error = db_store(database, &entry);
+        if (error)
+            fprintf(stderr, "Unable to write database entry; error %d\n", error);
+    }
+
+    printf("%s  %s\n", base64_md5, fullpath);
     fflush(stdout);
-    
     return 0;
 }
 
+/* Walk through the database deleting entries more than <n> seconds old */
+static void jigsum_db_cleanup(int delay)
+{
+    time_t delete_time = UINT_MAX - time(NULL);
+    int error = 0;
+    db_entry_t *entry = NULL;
+
+    delete_time += delay;
+
+    printf("Time now %X; deleting records older than %X\n",
+           UINT_MAX - (unsigned int)time(NULL), (unsigned int)delete_time);
+    while (!error)
+    {
+        error = db_lookup_by_age(database, delete_time, &entry);
+        if (error)
+        {
+            printf("jigsum_db_cleanup: error %d from db_lookup_by_age call\n", error);
+            break;
+        }
+        printf("jigsum_db_cleanup: deleting entry %s (time %X)\n",
+               entry->filename, (unsigned int)entry->age);
+        error = db_delete(database, entry->md5);
+        if (error)
+        {
+            printf("jigsum_db_cleanup: error %d from delete call\n", error);
+            break;
+        }
+    }
+}
+
 int main(int argc, char **argv)
 {
     int i = 0;
+
+    database = db_open();
+    if (!database)
+    {
+        fprintf(stderr, "Unable to open database, error %d\n", errno);
+        return errno;
+    }                
+
+    /* Clear out old records */
+    jigsum_db_cleanup(20);
     
     for (i = 1; i < argc; i++)
         (void) md5_file(argv[i]);
 
+    db_dump(database);
+
+    db_close(database);
+
     return 0;
 }