/* 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 <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1