paulo@0: /* paulo@0: * $Id: file_cache.c,v 1.15 2004/03/24 06:28:16 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: paulo@0: #include "file_cache.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: FileCache *file_cache_new (const char *file) paulo@0: { paulo@0: FileCache *file_cache; paulo@0: paulo@0: if (!(file_cache = malloc (sizeof (FileCache)))) paulo@0: return NULL; paulo@0: paulo@0: memset (file_cache, 0, sizeof (FileCache)); paulo@0: paulo@0: file_cache->file = STRDUP (file); paulo@0: paulo@0: if (!file_cache_load (file_cache)) paulo@0: GT->DBGFN (GT, "failed loading %s", file); paulo@0: paulo@0: return file_cache; paulo@0: } paulo@0: paulo@0: void file_cache_free (FileCache *cache) paulo@0: { paulo@0: if (!cache) paulo@0: return; paulo@0: paulo@0: dataset_clear (cache->d); paulo@0: paulo@0: free (cache->file); paulo@0: free (cache); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: int file_cache_load (FileCache *cache) paulo@0: { paulo@0: struct stat st; paulo@0: time_t mtime; paulo@0: char *line = NULL; paulo@0: FILE *f; paulo@0: int nlines; paulo@0: paulo@0: if (!cache) paulo@0: return FALSE; paulo@0: paulo@0: if (!(f = fopen (cache->file, "r"))) paulo@0: { paulo@0: GT->DBGFN (GT, "couldnt open %s for reading: %s", cache->file, paulo@0: GIFT_STRERROR ()); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: mtime = 0; paulo@0: paulo@0: if (file_stat (cache->file, &st)) paulo@0: mtime = st.st_mtime; paulo@0: paulo@0: dataset_clear (cache->d); paulo@0: paulo@0: cache->d = dataset_new (DATASET_HASH); paulo@0: cache->mtime = mtime; paulo@0: paulo@0: nlines = 0; paulo@0: paulo@0: while (file_read_line (f, &line)) paulo@0: { paulo@0: char *key; paulo@0: char *value = line; paulo@0: paulo@0: key = string_sep (&value, " "); paulo@0: paulo@0: string_trim (key); paulo@0: string_trim (value); paulo@0: paulo@0: if (!key) paulo@0: continue; paulo@0: paulo@0: if (!value) paulo@0: value = ""; paulo@0: paulo@0: dataset_insertstr (&cache->d, key, value); paulo@0: paulo@0: nlines++; paulo@0: } paulo@0: paulo@0: if (fclose (f) != 0) paulo@0: return FALSE; paulo@0: paulo@0: GT->DBGFN (GT, "loaded filecache for %s. nlines = %i", cache->file, nlines); paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: static void sync_one (ds_data_t *key, ds_data_t *value, String *s) paulo@0: { paulo@0: char *keystr = key->data; paulo@0: char *valuestr = value->data; paulo@0: paulo@0: string_appendf (s, "%s %s\n", keystr, valuestr); paulo@0: } paulo@0: paulo@0: BOOL file_cache_sync (FileCache *cache) paulo@0: { paulo@0: FILE *f; paulo@0: String *s; paulo@0: char tmp_path[PATH_MAX]; paulo@0: paulo@0: if (!cache) paulo@0: return FALSE; paulo@0: paulo@0: snprintf (tmp_path, sizeof (tmp_path), "%s.tmp", cache->file); paulo@0: paulo@0: if (!(s = string_new (NULL, 0, 0, TRUE))) paulo@0: return FALSE; paulo@0: paulo@0: if (!(f = fopen (tmp_path, "w"))) paulo@0: { paulo@0: GT->DBGFN (GT, "couldnt write to %s: %s", tmp_path, GIFT_STRERROR ()); paulo@0: string_free (s); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: GT->DBGFN (GT, "syncing %s to disk", tmp_path); paulo@0: paulo@0: dataset_foreach (cache->d, DS_FOREACH(sync_one), s); paulo@0: paulo@0: if (fwrite (s->str, 1, s->len, f) != s->len) paulo@0: { paulo@0: GT->DBGFN (GT, "failed writing %s: %s", tmp_path, GIFT_STRERROR()); paulo@0: string_free (s); paulo@0: fclose (f); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: string_free (s); paulo@0: paulo@0: if (fclose (f) != 0) paulo@0: { paulo@0: GT->DBGFN (GT, "failed closing %s: %s", tmp_path, GIFT_STRERROR()); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: if (!file_mv (tmp_path, cache->file)) paulo@0: { paulo@0: GT->DBGFN (GT, "file move %s -> %s failed", tmp_path, cache->file); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: void file_cache_flush (FileCache *cache) paulo@0: { paulo@0: if (!cache) paulo@0: return; paulo@0: paulo@0: dataset_clear (cache->d); paulo@0: cache->d = NULL; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: char *file_cache_lookup (FileCache *cache, const char *key) paulo@0: { paulo@0: if (!cache) paulo@0: return NULL; paulo@0: paulo@0: return dataset_lookupstr (cache->d, key); paulo@0: } paulo@0: paulo@0: void file_cache_insert (FileCache *cache, const char *key, const char *value) paulo@0: { paulo@0: if (!cache) paulo@0: return; paulo@0: paulo@0: dataset_insertstr (&cache->d, key, value); paulo@0: } paulo@0: paulo@0: void file_cache_remove (FileCache *cache, const char *key) paulo@0: { paulo@0: if (!cache) paulo@0: return; paulo@0: paulo@0: dataset_removestr (cache->d, key); paulo@0: }