/* Jungle Monkey * Copyright (C) 1999-2001 The Regents of the University of Michigan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "sha_cache.h" #include "jmgnet.h" #include "util.h" typedef struct _Entry { GSHA* sha; time_t mtime; /* Last time modified */ } Entry; static void delete_hfunc (gpointer key, gpointer value, gpointer user_data); static void read_entry (ShaCache* sha_cache, gchar* buf); static void write_hfunc (gpointer key, gpointer value, gpointer user_data); ShaCache* sha_cache_new (void) { ShaCache* sha_cache; sha_cache = g_new0 (ShaCache, 1); sha_cache->path_to_sha = g_hash_table_new (g_str_hash, g_str_equal); return sha_cache; } void sha_cache_delete (ShaCache* sha_cache) { if (!sha_cache) return; g_hash_table_foreach (sha_cache->path_to_sha, delete_hfunc, NULL); g_hash_table_destroy (sha_cache->path_to_sha); g_free (sha_cache); } static void delete_hfunc (gpointer key, gpointer value, gpointer user_data) { Entry* entry = (Entry*) value; g_free ((gchar*) key); gnet_sha_delete (entry->sha); g_free (entry); } GSHA* sha_cache_get (ShaCache* sha_cache, const gchar* path) { Entry* entry; g_return_val_if_fail (sha_cache, NULL); g_return_val_if_fail (path, NULL); entry = g_hash_table_lookup (sha_cache->path_to_sha, path); if (!entry) return NULL; return gnet_sha_clone (entry->sha); } void sha_cache_add (ShaCache* sha_cache, const gchar* path, const GSHA* sha) { Entry* entry; g_return_if_fail (sha_cache); g_return_if_fail (path); entry = g_hash_table_lookup (sha_cache->path_to_sha, path); if (entry) { gnet_sha_delete (entry->sha); entry->sha = gnet_sha_clone (sha); return; } entry = g_new0 (Entry, 1); entry->sha = gnet_sha_clone (sha); entry->mtime = time(NULL); g_hash_table_insert (sha_cache->path_to_sha, g_strdup(path), entry); } guint sha_cache_size (ShaCache* sha_cache) { g_return_val_if_fail (sha_cache, 0); return g_hash_table_size (sha_cache->path_to_sha); } void sha_cache_read (ShaCache* sha_cache, FILE* file) { gchar buf[MAXPATHLEN + 2 * GNET_SHA_HASH_LENGTH + 10 + 64]; g_return_if_fail (sha_cache); g_return_if_fail (file); while (fgets (buf, sizeof(buf), file) != NULL) { read_entry (sha_cache, buf); } } static void read_entry (ShaCache* sha_cache, gchar* buf) { gchar** split; gchar* path; struct stat statbuf; time_t mtime; GSHA* sha; gchar* p; Entry* entry; split = g_strsplit (buf, "|", 3); if (!(split[0] && split[1] && split[2])) { g_strfreev (split); return; } /* Unescape path */ path = strunesc (split[0], ",\\", '\\'); /* Ignore if we have it - assume old copy is equivalent */ entry = g_hash_table_lookup (sha_cache->path_to_sha, path); if (entry) { g_strfreev (split); g_free (path); return; } /* Get the time */ mtime = 0; for (p = split[2]; *p && *p >= '0' && *p <= '9'; ++p) mtime = mtime * 10 + (*p - '0'); /* Check if file exists */ if (stat (path, &statbuf)) { if (errno != ENOENT) g_warning ("stat failed: %s\n", strerror(errno)); g_strfreev (split); g_free (path); return; } /* Check if file has been modified since last SHA */ if (statbuf.st_mtime > mtime) { g_strfreev (split); g_free (path); return; } /* Get the sha */ sha = gnet_sha_new_string (split[1]); g_return_if_fail (sha); /* Create an add a new entry */ entry = g_new0 (Entry, 1); entry->sha = sha; entry->mtime = mtime; g_hash_table_insert (sha_cache->path_to_sha, path, entry); g_strfreev (split); } void sha_cache_write (ShaCache* sha_cache, FILE* file) { g_return_if_fail (sha_cache); g_return_if_fail (file); if(sha_cache) g_hash_table_foreach (sha_cache->path_to_sha, write_hfunc, file); } static void write_hfunc (gpointer key, gpointer value, gpointer user_data) { gchar* path = (gchar*) key; Entry* entry = (Entry*) value; FILE* file = user_data; gchar* pathe; gchar shastr[2 * GNET_SHA_HASH_LENGTH + 1]; pathe = stresc (path, ",\\", ','); gnet_sha_copy_string (entry->sha, shastr); shastr[2 * GNET_SHA_HASH_LENGTH] = '\0'; fprintf (file, "%s|%s|%lu\n", pathe, shastr, entry->mtime); g_free (pathe); }