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
24 #define OLD_FILE_RECORD_AGE 86400
25 #define DB_NAME "jigit_db.sql"
28 #define MIN(x,y) ( ((x) < (y)) ? (x) : (y))
31 JIGDB *database = NULL;
33 static int check_cache(char *filename, struct stat *sb, char *base64_md5)
36 db_file_entry_t *entry;
38 error = db_lookup_file_by_name(database, filename, &entry);
41 if ( (sb->st_mtime <= entry->mtime) &&
42 (sb->st_size == entry->file_size) )
43 /* We have a cache entry already; simply return
46 strcpy(base64_md5, entry->md5);
51 /* We have an entry for this file, but the mtime or size
52 * has changed. Delete the old entry and replace it later
54 error = db_delete_file_by_name(database, entry->md5, entry->type, entry->filename);
56 printf("check_cache: unable to delete old entry for file %s\n", filename);
62 static unsigned long long calculate_md5(char *filename, FILE *file, char *base64_md5)
65 unsigned char file_md5[16] = {0};
67 struct mk_MD5Context file_context;
68 unsigned long long bytes_read = 0;
71 mk_MD5Init(&file_context);
75 memset(buf, 0, BUF_SIZE);
77 used = fread(buf, 1, BUF_SIZE, file);
80 mk_MD5Update(&file_context, (unsigned char *)buf, used);
83 if (ferror(file) && (EISDIR != errno))
84 fprintf(stderr, "Unable to read from file %s; error %d\n",
89 mk_MD5Final(file_md5, &file_context);
90 tmp_md5 = base64_dump(file_md5, 16);
91 strcpy(base64_md5, tmp_md5);
96 static int md5_file(char *filename)
99 char base64_md5[33] = {0};
100 unsigned long long bytes_read = 0;
101 db_file_entry_t entry;
106 char *fullpath = NULL;
108 /* Check if we're reading from stdin */
109 if (!strcmp("-", filename))
111 (void)calculate_md5("<STDIN>", stdin, base64_md5);
112 printf("%s\n", base64_md5);
117 /* Make an absolute pathname if necessary */
118 if (filename[0] == '/')
123 if (buf != getcwd(buf, sizeof(buf)))
125 fprintf(stderr, "md5_file: Unable to get CWD!; giving up on file %s, error %d\n",
130 strcpy(buf + wdlen, "/");
131 strcpy(buf + wdlen + 1, filename);
135 /* Check the DB to see if we already have a checksum for this file */
136 error = stat(fullpath, &sb);
139 fprintf(stderr, "md5_file: Unable to stat file %s, error %d\n", fullpath, errno);
142 if (S_ISDIR(sb.st_mode))
144 found_in_db = check_cache(fullpath, &sb, base64_md5);
147 file = fopen(fullpath, "rb");
156 fprintf(stderr, "Unable to open file %s; error %d\n", fullpath, errno);
161 bytes_read = calculate_md5(fullpath, file, base64_md5);
163 memset(&entry, 0, sizeof(entry));
164 strncpy(&entry.md5[0], base64_md5, sizeof(entry.md5));
165 entry.type = FT_LOCAL;
166 entry.mtime = sb.st_mtime;
167 entry.time_added = time(NULL);
168 entry.file_size = bytes_read;
169 strncpy(&entry.filename[0], fullpath, sizeof(entry.filename));
170 /* "extra" blanked already */
171 error = db_store_file(database, &entry);
173 fprintf(stderr, "Unable to write database entry; error %d\n", error);
176 printf("%s %s\n", base64_md5, fullpath);
181 /* Walk through the database deleting entries more than <n> seconds old */
182 static void jigsum_db_cleanup(int delay)
184 (void)db_delete_files_by_age(database, time(NULL) - delay);
187 int main(int argc, char **argv)
191 database = db_open(DB_NAME);
194 fprintf(stderr, "Unable to open database, error %d\n", errno);
198 /* Clear out old records */
199 jigsum_db_cleanup(OLD_FILE_RECORD_AGE);
201 for (i = 1; i < argc; i++)
202 (void) md5_file(argv[i]);