4 * Tool to calculate and print MD5 checksums in jigdo's awkward
7 * Copyright (c) 2004 Steve McIntyre <steve@einval.com>
15 #include <sys/types.h>
23 #define BUF_SIZE 65536
26 #define MIN(x,y) ( ((x) < (y)) ? (x) : (y))
29 JIGDB *database = NULL;
31 static int check_cache(char *filename, struct stat *sb, char **base64_md5)
36 error = db_lookup_by_name(database, filename, &entry);
39 if ( (sb->st_mtime <= entry->mtime) &&
40 (sb->st_size == entry->file_size) )
41 /* We have a cache entry already; simply return
44 *base64_md5 = entry->md5;
49 /* We have an entry for this file, but the mtime or size
50 * has changed. Delete the old entry and replace it later
52 error = db_delete(database, entry->md5, entry->type, entry->filename);
54 printf("check_cache: unable to delete old entry for file %s\n", filename);
60 static unsigned long long calculate_md5(char *filename, FILE *file, char **base64_md5)
63 unsigned char file_md5[16] = {0};
65 struct mk_MD5Context file_context;
66 unsigned long long bytes_read = 0;
68 mk_MD5Init(&file_context);
72 memset(buf, 0, BUF_SIZE);
74 used = fread(buf, 1, BUF_SIZE, file);
77 mk_MD5Update(&file_context, (unsigned char *)buf, used);
80 if (ferror(file) && (EISDIR != errno))
81 fprintf(stderr, "Unable to read from file %s; error %d\n",
86 mk_MD5Final(file_md5, &file_context);
87 *base64_md5 = base64_dump(file_md5, 16);
91 static int md5_file(char *filename)
94 char *base64_md5 = NULL;
95 unsigned long long bytes_read = 0;
101 char *fullpath = NULL;
103 /* Check if we're reading from stdin */
104 if (!strcmp("-", filename))
106 (void)calculate_md5("<STDIN>", stdin, &base64_md5);
107 printf("%s\n", base64_md5);
112 /* Make an absolute pathname if necessary */
113 if (filename[0] == '/')
118 if (buf != getcwd(buf, sizeof(buf)))
120 fprintf(stderr, "md5_file: Unable to get CWD!; giving up on file %s, error %d\n",
125 strcpy(buf + wdlen, "/");
126 strcpy(buf + wdlen + 1, filename);
130 /* Check the DB to see if we already have a checksum for this file */
131 error = stat(fullpath, &sb);
134 fprintf(stderr, "md5_file: Unable to stat file %s, error %d\n", fullpath, errno);
137 if (S_ISDIR(sb.st_mode))
139 found_in_db = check_cache(fullpath, &sb, &base64_md5);
142 file = fopen(fullpath, "rb");
151 fprintf(stderr, "Unable to open file %s; error %d\n", fullpath, errno);
156 bytes_read = calculate_md5(fullpath, file, &base64_md5);
158 memset(&entry, 0, sizeof(entry));
159 strncpy(&entry.md5[0], base64_md5, sizeof(entry.md5));
160 entry.type = FT_LOCAL;
161 entry.mtime = sb.st_mtime;
162 entry.age = UINT_MAX - time(NULL);
163 entry.file_size = bytes_read;
164 strncpy(&entry.filename[0], fullpath, sizeof(entry.filename));
165 /* "extra" blanked already */
166 error = db_store(database, &entry);
168 fprintf(stderr, "Unable to write database entry; error %d\n", error);
171 printf("%s %s\n", base64_md5, fullpath);
176 /* Walk through the database deleting entries more than <n> seconds old */
177 static void jigsum_db_cleanup(int delay)
179 time_t delete_time = UINT_MAX - time(NULL);
181 db_entry_t *entry = NULL;
183 delete_time += delay;
187 error = db_lookup_by_age(database, delete_time, &entry);
190 error = db_delete(database, entry->md5, entry->type, entry->filename);
193 printf("jigsum_db_cleanup: error %d from delete call\n", error);
199 int main(int argc, char **argv)
203 #define DB_NAME "jigit_db.sql"
205 database = db_open(DB_NAME);
208 fprintf(stderr, "Unable to open database, error %d\n", errno);
212 /* Clear out old records */
213 jigsum_db_cleanup(86400);
215 for (i = 1; i < argc; i++)
216 (void) md5_file(argv[i]);