Move icon cache to a separate file; protect cache with file locks

This commit is contained in:
o9000
2016-03-01 20:59:13 +01:00
parent 4dfe411bf4
commit 50e6278327
7 changed files with 214 additions and 81 deletions

156
src/util/cache.c Normal file
View File

@@ -0,0 +1,156 @@
/**************************************************************************
*
* Tint2 : cache
*
* Copyright (C) 2016 @o9000
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**************************************************************************/
#include "cache.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "common.h"
void init_cache(Cache *cache)
{
if (cache->_table)
free_cache(cache);
cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
cache->dirty = FALSE;
cache->loaded = FALSE;
}
void free_cache(Cache *cache)
{
if (cache->_table)
g_hash_table_destroy(cache->_table);
cache->_table = NULL;
cache->dirty = FALSE;
cache->loaded = FALSE;
}
void load_cache(Cache *cache, const gchar *cache_path)
{
init_cache(cache);
int fd = open(cache_path, O_RDONLY);
if (fd == -1)
return;
flock(fd, LOCK_SH);
FILE *f = fopen(cache_path, "rt");
if (!f)
goto unlock;
char *line = NULL;
size_t line_size;
while (getline(&line, &line_size, f) >= 0) {
char *key, *value;
size_t line_len = strlen(line);
gboolean has_newline = FALSE;
if (line_len >= 1) {
if (line[line_len - 1] == '\n') {
line[line_len - 1] = '\0';
line_len--;
has_newline = TRUE;
}
}
if (!has_newline)
break;
if (line_len == 0)
continue;
if (parse_line(line, &key, &value)) {
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
}
}
free(line);
fclose(f);
cache->loaded = TRUE;
unlock:
flock(fd, LOCK_UN);
close(fd);
}
void write_cache_line(gpointer key, gpointer value, gpointer user_data)
{
gchar *k = key;
gchar *v = value;
FILE *f = user_data;
fprintf(f, "%s=%s\n", k, v);
}
void save_cache(Cache *cache, const gchar *cache_path)
{
int fd = open(cache_path, O_RDONLY | O_CREAT);
if (fd == -1)
return;
flock(fd, LOCK_EX);
FILE *f = fopen(cache_path, "w");
if (!f) {
gchar *dir_path = g_path_get_dirname(cache_path);
g_mkdir_with_parents(dir_path, 0700);
g_free(dir_path);
f = fopen(cache_path, "w");
if (!f) {
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
goto unlock;
}
}
g_hash_table_foreach(cache->_table, write_cache_line, f);
fclose(f);
cache->dirty = FALSE;
unlock:
flock(fd, LOCK_UN);
close(fd);
}
const gchar *get_from_cache(Cache *cache, const gchar *key)
{
if (!cache->_table)
return NULL;
return g_hash_table_lookup(cache->_table, key);
}
void add_to_cache(Cache *cache, const gchar *key, const gchar *value)
{
if (!cache->_table)
init_cache(cache);
if (!key || !value)
return;
gchar *old_value = g_hash_table_lookup(cache->_table, key);
if (old_value && g_str_equal(old_value, value))
return;
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
cache->dirty = TRUE;
}

39
src/util/cache.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef CACHE_H
#define CACHE_H
#include <glib.h>
// A cache with string keys and values, backed by a file.
// The strings must not be NULL and are stripped of any whitespace at start and end.
typedef struct Cache {
gboolean dirty;
gboolean loaded;
GHashTable *_table;
} Cache;
// Initializes the cache. You can also call load_cache directly if you set the memory contents to zero first.
void init_cache(Cache *cache);
// Clears the cache contents and releases all memory, but not the object.
// You can use init_cache or load_cache afterwards.
void free_cache(Cache *cache);
// Clears the cache contents and loads new contents from a file.
// Sets the loaded flag to TRUE.
void load_cache(Cache *cache, const gchar *cache_path);
// Saves the cache contents to a file.
// Clears the dirty flag.
void save_cache(Cache *cache, const gchar *cache_path);
// Returns a pointer to the value in the cache, or NULL if not found.
// Do not free the returned value!
const gchar *get_from_cache(Cache *cache, const gchar *key);
// Adds a key-value pair to the cache. NULL keys or values are not allowed.
// If the key already exists, the old value is and replaced with the new value.
// Does not take ownership of the pointers (neither key, nor value); instead it makes copies.
// Sets the dirty flag to TRUE.
void add_to_cache(Cache *cache, const gchar *key, const gchar *value);
#endif