Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
imagecache: implement sha1 contents hashing, fixes #2996
  • Loading branch information
perexg committed Sep 10, 2015
1 parent 875ebe5 commit 4528915
Showing 1 changed file with 82 additions and 29 deletions.
111 changes: 82 additions & 29 deletions src/imagecache.c
Expand Up @@ -46,6 +46,7 @@ typedef struct imagecache_image
const char *url; ///< Upstream URL
int failed; ///< Last update failed
time_t updated; ///< Last time the file was checked
uint8_t sha1[20]; ///< Contents hash
enum {
IDLE,
QUEUED,
Expand Down Expand Up @@ -110,6 +111,16 @@ static TAILQ_HEAD(, imagecache_image) imagecache_queue;
static gtimer_t imagecache_timer;
#endif

static int
sha1_empty( const uint8_t *sha1 )
{
int i;
for (i = 0; i < 20; i++)
if (sha1[i])
return 0;
return 1;
}

static int
url_cmp ( imagecache_image_t *a, imagecache_image_t *b )
{
Expand All @@ -125,15 +136,32 @@ id_cmp ( imagecache_image_t *a, imagecache_image_t *b )
static void
imagecache_image_save ( imagecache_image_t *img )
{
char hex[41];
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "url", img->url);
if (img->updated)
htsmsg_add_s64(m, "updated", img->updated);
if (!sha1_empty(img->sha1)) {
bin2hex(hex, sizeof(hex), img->sha1, 20);
htsmsg_add_str(m, "sha1", hex);
}
hts_settings_save(m, "imagecache/meta/%d", img->id);
htsmsg_destroy(m);
}

#if ENABLE_IMAGECACHE
static void
imagecache_new_id ( imagecache_image_t *i )
{
imagecache_image_t *j;

do {
i->id = ++imagecache_id % INT_MAX;
if (!i->id) i->id = ++imagecache_id % INT_MAX;
j = RB_INSERT_SORTED(&imagecache_by_id, i, id_link, id_cmp);
} while (j);
}

static void
imagecache_image_add ( imagecache_image_t *img )
{
Expand All @@ -146,13 +174,50 @@ imagecache_image_add ( imagecache_image_t *img )
}
}

static int
imagecache_new_contents ( imagecache_image_t *img,
const char *tpath, char *path,
const uint8_t *data, size_t dsize )
{
int empty, r = 0;
uint8_t sha1[20];
FILE *fp;

sha1_calc(sha1, data, dsize, NULL, 0);
empty = sha1_empty(img->sha1);
if (!empty && memcmp(sha1, img->sha1, 20) == 0)
return 0; /* identical */

if (!(fp = tvh_fopen(tpath, "wb")))
return 1;

fwrite(data, dsize, 1, fp);
fclose(fp);
unlink(path);
pthread_mutex_lock(&global_lock);
memcpy(img->sha1, sha1, 20);
if (!empty) {
/* change id - contents changed */
hts_settings_remove("imagecache/meta/%d", img->id);
RB_REMOVE(&imagecache_by_id, img, id_link);
imagecache_new_id(img);
r = hts_settings_buildpath(path, PATH_MAX, "imagecache/data/%d", img->id);
}
if (!r) {
if (rename(tpath, path))
tvherror("imagecache", "unable to rename file '%s' to '%s'", tpath, path);
}
imagecache_image_save(img);
pthread_mutex_unlock(&global_lock);
return r;
}

static int
imagecache_image_fetch ( imagecache_image_t *img )
{
int res = 1, r;
FILE *fp = NULL;
url_t url;
char tmp[256] = "", path[256];
char tpath[PATH_MAX] = "", path[PATH_MAX];
tvhpoll_event_t ev;
tvhpoll_t *efd = NULL;
http_client_t *hc;
Expand All @@ -170,9 +235,7 @@ imagecache_image_fetch ( imagecache_image_t *img )
goto error;
if (hts_settings_makedirs(path))
goto error;
snprintf(tmp, sizeof(tmp), "%s.tmp", path);
if (!(fp = tvh_fopen(tmp, "wb")))
goto error;
snprintf(tpath, sizeof(tpath), "%s.tmp", path);

/* Fetch (release lock, incase of delays) */
pthread_mutex_unlock(&global_lock);
Expand Down Expand Up @@ -210,39 +273,30 @@ imagecache_image_fetch ( imagecache_image_t *img )
if (r < 0)
break;
if (r == HTTP_CON_DONE) {
if (hc->hc_code == HTTP_STATUS_OK && hc->hc_data_size > 0) {
fwrite(hc->hc_data, hc->hc_data_size, 1, fp);
res = 0;
}
if (hc->hc_code == HTTP_STATUS_OK && hc->hc_data_size > 0)
res = imagecache_new_contents(img, tpath, path,
(uint8_t *)hc->hc_data, hc->hc_data_size);
break;
}
}
fclose(fp);
fp = NULL;

/* Process */
error_lock:
pthread_mutex_lock(&global_lock);
error:
if (fp)
fclose(fp);
urlreset(&url);
tvhpoll_destroy(efd);
img->state = IDLE;
time(&img->updated); // even if failed (possibly request sooner?)
if (res) {
img->failed = 1;
if (tmp[0])
unlink(tmp);
if (!img->failed) {
img->failed = 1;
imagecache_image_save(img);
}
tvhwarn("imagecache", "failed to download %s", img->url);
} else {
img->failed = 0;
unlink(path);
if (rename(tmp, path))
tvherror("imagecache", "unable to rename file '%s' to '%s'", tmp, path);
tvhdebug("imagecache", "downloaded %s", img->url);
}
imagecache_image_save(img);
pthread_cond_broadcast(&imagecache_cond);

return res;
Expand Down Expand Up @@ -311,7 +365,7 @@ imagecache_init ( void )
htsmsg_t *m, *e;
htsmsg_field_t *f;
imagecache_image_t *img, *i;
const char *url;
const char *url, *sha1;
uint32_t id;

/* Init vars */
Expand Down Expand Up @@ -345,6 +399,9 @@ imagecache_init ( void )
img->id = id;
img->url = strdup(url);
img->updated = htsmsg_get_s64_or_default(e, "updated", 0);
sha1 = htsmsg_get_str(e, "sha1");
if (sha1 && strlen(sha1) == 40)
hex2bin(img->sha1, 20, sha1);
i = RB_INSERT_SORTED(&imagecache_by_url, img, url_link, url_cmp);
if (i) {
hts_settings_remove("imagecache/meta/%d", id);
Expand Down Expand Up @@ -501,7 +558,7 @@ uint32_t
imagecache_get_id ( const char *url )
{
uint32_t id = 0;
imagecache_image_t *i, *j;
imagecache_image_t *i;

lock_assert(&global_lock);

Expand All @@ -522,13 +579,9 @@ imagecache_get_id ( const char *url )
/* Create/Find */
i = RB_INSERT_SORTED(&imagecache_by_url, imagecache_skel, url_link, url_cmp);
if (!i) {
i = imagecache_skel;
i = imagecache_skel;
i->url = strdup(url);
do {
i->id = ++imagecache_id % INT_MAX;
if (!i->id) i->id = ++imagecache_id % INT_MAX;
j = RB_INSERT_SORTED(&imagecache_by_id, i, id_link, id_cmp);
} while (j);
imagecache_new_id(i);
SKEL_USED(imagecache_skel);
#if ENABLE_IMAGECACHE
imagecache_image_add(i);
Expand Down

0 comments on commit 4528915

Please sign in to comment.