efl/src/bin/efreet/efreet_icon_cache_create.c

1196 lines
34 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
2013-07-11 02:22:38 -07:00
#ifdef HAVE_SYS_RESOURCE_H
2013-06-20 04:53:54 -07:00
#include <sys/time.h>
#include <sys/resource.h>
#endif
#ifdef _WIN32
# include <evil_private.h> /* fcntl */
#endif
#include <Eina.h>
#include <Eet.h>
#include <Ecore.h>
#include <Ecore_File.h>
#define EFREET_MODULE_LOG_DOM _efreet_icon_cache_log_dom
static int _efreet_icon_cache_log_dom = -1;
#include "Efreet.h"
#include "efreet_private.h"
#include "efreet_cache_private.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
static Eina_Array *exts = NULL;
static Eina_Array *extra_dirs = NULL;
static Eina_Array *strs = NULL;
static Eina_Hash *icon_themes = NULL;
static Eina_Bool
cache_directory_modified(Eina_Hash *dirs, const char *dir)
{
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
Efreet_Cache_Directory *dcache;
Efreet_Cache_Check check;
if (!dirs) return EINA_TRUE;
if (!efreet_file_cache_fill(dir, &check)) return EINA_FALSE;
dcache = eina_hash_find(dirs, dir);
if (!dcache)
{
2010-11-30 10:41:21 -08:00
dcache = malloc(sizeof (Efreet_Cache_Directory));
if (!dcache) return EINA_TRUE;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
dcache->check = check;
2010-11-30 10:41:21 -08:00
eina_hash_add(dirs, dir, dcache);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
}
else if (efreet_file_cache_check(&check, &dcache->check))
return EINA_FALSE;
else
dcache->check = check;
return EINA_TRUE;
}
static Eina_Bool
cache_extension_lookup(const char *ext)
2010-11-23 08:49:46 -08:00
{
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
unsigned int i;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
for (i = 0; i < exts->count; ++i)
{
if (!strcmp(exts->data[i], ext)) return EINA_TRUE;
}
return EINA_FALSE;
2010-11-23 08:49:46 -08:00
}
static Eina_Bool
cache_fallback_scan_dir(Eina_Hash *icons, Eina_Hash *dirs, const char *dir)
{
Eina_Iterator *it;
Eina_File_Direct_Info *entry;
if (!cache_directory_modified(dirs, dir)) return EINA_TRUE;
it = eina_file_stat_ls(dir);
if (!it) return EINA_TRUE;
EINA_ITERATOR_FOREACH(it, entry)
{
Efreet_Cache_Fallback_Icon *icon;
char *name;
char *ext;
unsigned int i;
void *p;
if (entry->type == EINA_FILE_DIR)
continue;
ext = strrchr(entry->path + entry->name_start, '.');
if (!ext || !cache_extension_lookup(ext))
continue;
/* icon with known extension */
name = entry->path + entry->name_start;
*ext = '\0';
icon = eina_hash_find(icons, name);
if (!icon)
{
icon = NEW(Efreet_Cache_Fallback_Icon, 1);
icon->theme = NULL;
eina_hash_add(icons, name, icon);
}
*ext = '.';
for (i = 0; i < icon->icons_count; ++i)
if (!strcmp(icon->icons[i], entry->path))
break;
if (i != icon->icons_count)
2011-02-01 00:27:53 -08:00
continue;
p = realloc(icon->icons, sizeof (char *) * (icon->icons_count + 1));
if (!p)
{
ERR("Out of memory");
exit(1);
}
icon->icons = p;
icon->icons[icon->icons_count] = eina_stringshare_add(entry->path);
eina_array_push(strs, icon->icons[icon->icons_count++]);
}
eina_iterator_free(it);
return EINA_TRUE;
}
static Eina_Bool
cache_fallback_scan(Eina_Hash *icons, Eina_Hash *dirs)
{
unsigned int i;
Eina_List *xdg_dirs, *l;
const char *dir;
char path[PATH_MAX];
for (i = 0; i < extra_dirs->count; i++)
cache_fallback_scan_dir(icons, dirs, extra_dirs->data[i]);
cache_fallback_scan_dir(icons, dirs, efreet_icon_deprecated_user_dir_get());
cache_fallback_scan_dir(icons, dirs, efreet_icon_user_dir_get());
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/icons", dir);
cache_fallback_scan_dir(icons, dirs, path);
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/pixmaps", dir);
cache_fallback_scan_dir(icons, dirs, path);
}
#endif
cache_fallback_scan_dir(icons, dirs, "/usr/local/share/pixmaps");
cache_fallback_scan_dir(icons, dirs, "/usr/share/pixmaps");
return EINA_TRUE;
}
static Eina_Bool
check_fallback_changed(Efreet_Cache_Icon_Theme *theme)
{
unsigned int i;
Eina_List *xdg_dirs, *l;
const char *dir;
char path[PATH_MAX];
/* Check if the dirs we have cached are changed */
if (theme->dirs)
{
Eina_Iterator *it;
Eina_Bool changed = EINA_FALSE;
it = eina_hash_iterator_key_new(theme->dirs);
EINA_ITERATOR_FOREACH(it, dir)
{
changed = !ecore_file_exists(dir);
if (changed) break;
changed = cache_directory_modified(theme->dirs, dir);
if (changed) break;
}
eina_iterator_free(it);
if (changed) return EINA_TRUE;
}
/* Check if spec dirs have changed */
for (i = 0; i < extra_dirs->count; i++)
if (cache_directory_modified(theme->dirs, extra_dirs->data[i])) return EINA_TRUE;
if (cache_directory_modified(theme->dirs, efreet_icon_deprecated_user_dir_get())) return EINA_TRUE;
if (cache_directory_modified(theme->dirs, efreet_icon_user_dir_get())) return EINA_TRUE;
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/icons", dir);
if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(path, sizeof(path), "%s/pixmaps", dir);
if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
}
#endif
if (cache_directory_modified(theme->dirs, "/usr/local/share/pixmaps")) return EINA_TRUE;
if (cache_directory_modified(theme->dirs, "/usr/share/pixmaps")) return EINA_TRUE;
return EINA_FALSE;
}
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
typedef struct
{
char *path;
int name_start;
} Scanned_Entry;
static Eina_Hash *already_scanned_path = NULL;
static void
cache_theme_change_verify(Efreet_Cache_Icon_Theme *theme)
{
Eina_Bool changed = EINA_FALSE;
Eina_List *l;
Efreet_Icon_Theme_Directory *d;
char buf[PATH_MAX], *tdir, *sep;
tdir = strdup(theme->path);
sep = strrchr(tdir, '/');
if (sep) *sep = 0;
EINA_LIST_FOREACH(theme->theme.directories, l, d)
{
snprintf(buf, sizeof(buf), "%s/%s", tdir, d->name);
if (cache_directory_modified(theme->dirs, buf))
{
changed = EINA_TRUE;
}
}
free(tdir);
if (changed) theme->changed = changed;
}
static Eina_Bool
cache_scan_path_dir(Efreet_Icon_Theme *theme,
const char *path,
Efreet_Icon_Theme_Directory *dir,
Eina_Hash *icons)
{
Eina_Iterator *it;
char buf[PATH_MAX];
Eina_File_Direct_Info *entry;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
Eina_List *dirs = NULL;
Eina_List *l;
char *ext;
Scanned_Entry *scentry;
snprintf(buf, sizeof(buf), "%s/%s", path, dir->name);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
// we wont ever free this - no point
if (!already_scanned_path)
already_scanned_path = eina_hash_string_superfast_new(NULL);
dirs = eina_hash_find(already_scanned_path, buf);
if ((intptr_t)dirs == (intptr_t)(-1L)) return EINA_TRUE;
else if (!dirs)
{
it = eina_file_stat_ls(buf);
if (!it)
{
eina_hash_add(already_scanned_path, buf, (void *)(intptr_t)(-1L));
return EINA_TRUE;
}
EINA_ITERATOR_FOREACH(it, entry)
{
if (entry->type == EINA_FILE_DIR) continue;
ext = strrchr(entry->path + entry->name_start, '.');
if (!ext || !cache_extension_lookup(ext)) continue;
scentry = malloc(sizeof(Scanned_Entry));
if (!scentry)
{
ERR("Out of memory");
exit(1);
}
scentry->name_start = entry->name_start;
scentry->path = strdup(entry->path);
if (!scentry->path)
{
ERR("Out of memory");
exit(1);
}
dirs = eina_list_append(dirs, scentry);
}
eina_iterator_free(it);
if (dirs)
eina_hash_add(already_scanned_path, buf, dirs);
else
eina_hash_add(already_scanned_path, buf, (void *)(intptr_t)(-1L));
}
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
EINA_LIST_FOREACH(dirs, l, scentry)
{
Efreet_Cache_Icon *icon;
char *name;
const char **tmp;
unsigned int i;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
ext = strrchr(scentry->path + scentry->name_start, '.');
/* icon with known extension */
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
name = scentry->path + scentry->name_start;
*ext = '\0';
icon = eina_hash_find(icons, name);
if (!icon)
{
icon = NEW(Efreet_Cache_Icon, 1);
icon->theme = eina_stringshare_add(theme->name.internal);
eina_array_push(strs, icon->theme);
eina_hash_add(icons, name, icon);
}
/* find if we have the same icon in another type */
for (i = 0; i < icon->icons_count; ++i)
{
if ((icon->icons[i]->type == dir->type) &&
(icon->icons[i]->normal == dir->size.normal) &&
(icon->icons[i]->max == dir->size.max) &&
(icon->icons[i]->min == dir->size.min))
break;
}
*ext = '.';
if (i != icon->icons_count)
{
unsigned int j;
/* check if the path already exist */
for (j = 0; j < icon->icons[i]->paths_count; ++j)
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
if (!strcmp(icon->icons[i]->paths[j], scentry->path))
2011-02-01 00:27:53 -08:00
break;
if (j != icon->icons[i]->paths_count)
2011-02-01 00:27:53 -08:00
continue;
/* If we are inherited, check if we already have extension */
if (strcmp(icon->theme, theme->name.internal))
{
const char *ext2;
int has_ext = 0;
for (j = 0; j < icon->icons[i]->paths_count; ++j)
{
ext2 = strrchr(icon->icons[i]->paths[j], '.');
if (ext2)
{
ext2++;
has_ext = !strcmp((ext + 1), ext2);
if (has_ext) break;
}
}
if (has_ext)
continue;
}
}
/* no icon match so add a new one */
/* only allow to add new icon for main theme
* if we allow inherited theme to add new icons,
* we will get weird effects when icon scales
*/
else if (!strcmp(icon->theme, theme->name.internal))
{
Efreet_Cache_Icon_Element **tmp2;
tmp2 = realloc(icon->icons,
sizeof(Efreet_Cache_Icon_Element *) * (++icon->icons_count));
if (!tmp2)
{
ERR("Out of memory");
exit(1);
}
icon->icons = tmp2;
icon->icons[i] = NEW(Efreet_Cache_Icon_Element, 1);
icon->icons[i]->type = dir->type;
icon->icons[i]->normal = dir->size.normal;
icon->icons[i]->min = dir->size.min;
icon->icons[i]->max = dir->size.max;
icon->icons[i]->paths = NULL;
icon->icons[i]->paths_count = 0;
}
else
{
continue;
}
/* and finally store the path */
tmp = realloc(icon->icons[i]->paths,
sizeof(char *) * (icon->icons[i]->paths_count + 1));
if (!tmp)
{
ERR("Out of memory");
exit(1);
}
icon->icons[i]->paths = tmp;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
icon->icons[i]->paths[icon->icons[i]->paths_count] = eina_stringshare_add(scentry->path);
eina_array_push(strs, icon->icons[i]->paths[icon->icons[i]->paths_count++]);
}
return EINA_TRUE;
}
static Eina_Bool
cache_scan_path(Efreet_Icon_Theme *theme, Eina_Hash *icons, const char *path)
{
Eina_List *l;
Efreet_Icon_Theme_Directory *dir;
EINA_LIST_FOREACH(theme->directories, l, dir)
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
{
if (!cache_scan_path_dir(theme, path, dir, icons)) return EINA_FALSE;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
}
return EINA_TRUE;
}
static Eina_Bool
cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eina_Hash *icons)
{
Eina_List *l;
const char *path;
const char *name;
if (!theme) return EINA_TRUE;
if (eina_hash_find(themes, theme->name.internal)) return EINA_TRUE;
eina_hash_direct_add(themes, theme->name.internal, theme);
/* scan theme */
EINA_LIST_FOREACH(theme->paths, l, path)
if (!cache_scan_path(theme, icons, path)) return EINA_FALSE;
/* scan inherits */
if (theme->inherits)
{
EINA_LIST_FOREACH(theme->inherits, l, name)
{
Efreet_Icon_Theme *inherit;
inherit = eina_hash_find(icon_themes, name);
if (!inherit)
INF("Theme `%s` not found for `%s`.",
2011-03-18 13:00:22 -07:00
name, theme->name.internal);
if (!cache_scan(inherit, themes, icons)) return EINA_FALSE;
}
}
else if (strcmp(theme->name.internal, "hicolor"))
{
theme = eina_hash_find(icon_themes, "hicolor");
if (!cache_scan(theme, themes, icons)) return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
check_changed(Efreet_Cache_Icon_Theme *theme)
{
Eina_List *l;
const char *name;
if (!theme) return EINA_FALSE;
if (theme->changed) return EINA_TRUE;
if (theme->theme.inherits)
{
EINA_LIST_FOREACH(theme->theme.inherits, l, name)
{
Efreet_Cache_Icon_Theme *inherit;
inherit = eina_hash_find(icon_themes, name);
if (!inherit)
INF("Theme `%s` not found for `%s`.",
name, theme->theme.name.internal);
if (check_changed(inherit)) return EINA_TRUE;
}
}
else if (strcmp(theme->theme.name.internal, "hicolor"))
{
theme = eina_hash_find(icon_themes, "hicolor");
if (check_changed(theme)) return EINA_TRUE;
}
return EINA_FALSE;
}
static Efreet_Icon_Theme_Directory *
icon_theme_directory_new(Efreet_Ini *ini, const char *name)
{
Efreet_Icon_Theme_Directory *dir;
int val;
const char *tmp;
if (!ini) return NULL;
dir = NEW(Efreet_Icon_Theme_Directory, 1);
if (!dir) return NULL;
dir->name = eina_stringshare_add(name);
eina_array_push(strs, dir->name);
efreet_ini_section_set(ini, name);
tmp = efreet_ini_string_get(ini, "Context");
if (tmp)
{
if (!strcasecmp(tmp, "Actions"))
dir->context = EFREET_ICON_THEME_CONTEXT_ACTIONS;
else if (!strcasecmp(tmp, "Devices"))
dir->context = EFREET_ICON_THEME_CONTEXT_DEVICES;
else if (!strcasecmp(tmp, "FileSystems"))
dir->context = EFREET_ICON_THEME_CONTEXT_FILESYSTEMS;
else if (!strcasecmp(tmp, "MimeTypes"))
dir->context = EFREET_ICON_THEME_CONTEXT_MIMETYPES;
}
/* Threshold is fallback */
dir->type = EFREET_ICON_SIZE_TYPE_THRESHOLD;
tmp = efreet_ini_string_get(ini, "Type");
if (tmp)
{
if (!strcasecmp(tmp, "Fixed"))
dir->type = EFREET_ICON_SIZE_TYPE_FIXED;
else if (!strcasecmp(tmp, "Scalable"))
dir->type = EFREET_ICON_SIZE_TYPE_SCALABLE;
}
dir->size.normal = efreet_ini_int_get(ini, "Size");
if (dir->type == EFREET_ICON_SIZE_TYPE_THRESHOLD)
{
val = efreet_ini_int_get(ini, "Threshold");
if (val < 0) val = 2;
dir->size.max = dir->size.normal + val;
dir->size.min = dir->size.normal - val;
}
else if (dir->type == EFREET_ICON_SIZE_TYPE_SCALABLE)
{
val = efreet_ini_int_get(ini, "MinSize");
if (val < 0) dir->size.min = dir->size.normal;
else dir->size.min = val;
val = efreet_ini_int_get(ini, "MaxSize");
if (val < 0) dir->size.max = dir->size.normal;
else dir->size.max = val;
}
return dir;
}
static Eina_Bool
icon_theme_index_read(Efreet_Cache_Icon_Theme *theme, const char *path)
{
Efreet_Ini *ini;
Efreet_Icon_Theme_Directory *dir;
const char *tmp;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
Efreet_Cache_Check check;
if (!theme || !path) return EINA_FALSE;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
if (!efreet_file_cache_fill(path, &check)) return EINA_FALSE;
if (theme->path && !strcmp(theme->path, path) &&
efreet_file_cache_check(&check, &(theme->check)))
{
/* no change */
theme->valid = 1;
return EINA_TRUE;
}
if (!theme->path || strcmp(theme->path, path))
{
theme->path = eina_stringshare_add(path);
eina_array_push(strs, theme->path);
}
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
theme->check = check;
theme->changed = 1;
ini = efreet_ini_new(path);
if (!ini) return EINA_FALSE;
if (!ini->data)
{
efreet_ini_free(ini);
return EINA_FALSE;
}
efreet_ini_section_set(ini, "Icon Theme");
tmp = efreet_ini_localestring_get(ini, "Name");
if (tmp)
{
theme->theme.name.name = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.name.name);
}
tmp = efreet_ini_localestring_get(ini, "Comment");
if (tmp)
{
theme->theme.comment = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.comment);
}
tmp = efreet_ini_string_get(ini, "Example");
if (tmp)
{
theme->theme.example_icon = eina_stringshare_add(tmp);
eina_array_push(strs, theme->theme.example_icon);
}
theme->hidden = efreet_ini_boolean_get(ini, "Hidden");
theme->valid = 1;
/* Check the inheritance. If there is none we inherit from the hicolor theme */
tmp = efreet_ini_string_get(ini, "Inherits");
if (tmp)
{
char *t, *s, *p;
const char *i;
size_t len;
len = strlen(tmp) + 1;
t = alloca(len);
memcpy(t, tmp, len);
s = t;
p = strchr(s, ',');
while (p)
{
*p = '\0';
i = eina_stringshare_add(s);
theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
eina_array_push(strs, i);
s = ++p;
p = strchr(s, ',');
}
i = eina_stringshare_add(s);
theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
eina_array_push(strs, i);
}
/* make sure this one is done last as setting the directory will change
* the ini section ... */
tmp = efreet_ini_string_get(ini, "Directories");
if (tmp)
{
char *t, *s, *p;
size_t len;
len = strlen(tmp) + 1;
t = alloca(len);
memcpy(t, tmp, len);
s = t;
p = s;
while ((p) && (*s))
{
p = strchr(s, ',');
if (p) *p = '\0';
dir = icon_theme_directory_new(ini, s);
if (!dir) goto error;
theme->theme.directories = eina_list_append(theme->theme.directories, dir);
if (p) s = ++p;
}
}
error:
efreet_ini_free(ini);
return EINA_TRUE;
}
static Eina_Bool
cache_theme_scan(const char *dir)
{
Eina_Iterator *it;
Eina_File_Direct_Info *entry;
it = eina_file_stat_ls(dir);
if (!it) return EINA_TRUE;
EINA_ITERATOR_FOREACH(it, entry)
{
char buf[PATH_MAX];
Efreet_Cache_Icon_Theme *theme;
const char *name;
const char *path;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
Efreet_Cache_Check check;
Efreet_Cache_Directory *d;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
if (!efreet_file_cache_fill(entry->path, &check)) continue;
if ((entry->type != EINA_FILE_DIR) &&
(entry->type != EINA_FILE_LNK))
continue;
if ((entry->type == EINA_FILE_LNK) &&
(!ecore_file_is_dir(entry->path)))
continue;
name = entry->path + entry->name_start;
theme = eina_hash_find(icon_themes, name);
if (!theme)
{
theme = NEW(Efreet_Cache_Icon_Theme, 1);
theme->theme.name.internal = eina_stringshare_add(name);
eina_array_push(strs, theme->theme.name.internal);
eina_hash_direct_add(icon_themes,
(void *)theme->theme.name.internal, theme);
theme->changed = 1;
}
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
d = NULL;
if (theme->dirs)
d = eina_hash_find(theme->dirs, entry->path);
if (!d)
{
if (!theme->dirs)
theme->dirs = eina_hash_string_superfast_new(NULL);
theme->changed = 1;
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
d = NEW(Efreet_Cache_Directory, 1);
d->check = check;
eina_hash_add(theme->dirs, entry->path, d);
}
else
{
if (!efreet_file_cache_check(&check, &(d->check)))
{
d->check = check;
theme->changed = 1;
}
}
/* TODO: We need to handle change in order of included paths */
if (!eina_list_search_unsorted(theme->theme.paths, EINA_COMPARE_CB(strcmp), entry->path))
{
path = eina_stringshare_add(entry->path);
theme->theme.paths = eina_list_append(theme->theme.paths, path);
eina_array_push(strs, path);
theme->changed = 1;
}
/* we're already valid so no reason to check for an index.theme file */
if (theme->valid) continue;
/* if the index.theme file exists we parse it into the theme */
memcpy(buf, entry->path, entry->path_length);
memcpy(buf + entry->path_length, "/index.theme", sizeof("/index.theme"));
if (ecore_file_exists(buf))
{
if (!icon_theme_index_read(theme, buf))
theme->valid = 0;
}
}
eina_iterator_free(it);
return EINA_TRUE;
}
static int
cache_lock_file(void)
{
char file[PATH_MAX];
struct flock fl;
int lockfd;
snprintf(file, sizeof(file), "%s/efreet/icon_data.lock", efreet_cache_home_get());
lockfd = open(file, O_CREAT | O_BINARY | O_RDWR, S_IRUSR | S_IWUSR);
if (lockfd < 0) return -1;
efreet_fsetowner(lockfd);
memset(&fl, 0, sizeof(struct flock));
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
if (fcntl(lockfd, F_SETLK, &fl) < 0)
{
WRN("LOCKED! You may want to delete %s if this persists", file);
close(lockfd);
return -1;
}
return lockfd;
}
static void
icon_theme_free(Efreet_Cache_Icon_Theme *theme)
{
void *data;
eina_list_free(theme->theme.paths);
eina_list_free(theme->theme.inherits);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
EINA_LIST_FREE(theme->theme.directories, data) free(data);
if (theme->dirs) efreet_hash_free(theme->dirs, free);
free(theme);
}
int
main(int argc, char **argv)
{
/* TODO:
* - Add file monitor on files, so that we catch changes on files
* during whilst this program runs.
* - Maybe linger for a while to reduce number of cache re-creates.
*/
Eina_Iterator *it;
Efreet_Cache_Version *icon_version;
Efreet_Cache_Version *theme_version;
Efreet_Cache_Icon_Theme *theme;
Eet_Data_Descriptor *theme_edd;
Eet_Data_Descriptor *icon_edd;
Eet_Data_Descriptor *fallback_edd;
Eet_File *icon_ef;
Eet_File *theme_ef;
Eina_List *xdg_dirs = NULL;
Eina_List *l = NULL;
char file[PATH_MAX];
const char *path;
char *dir = NULL;
Eina_Bool changed = EINA_FALSE;
Eina_Bool flush = EINA_FALSE;
int lockfd = -1;
char **keys;
int num, i;
/* init external subsystems */
if (!eina_init()) return -1;
2011-03-18 13:00:22 -07:00
_efreet_icon_cache_log_dom =
eina_log_domain_register("efreet_icon_cache", EFREET_DEFAULT_LOG_COLOR);
if (_efreet_icon_cache_log_dom < 0)
{
EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_icon_cache.");
return -1;
}
eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_ERR);
exts = eina_array_new(10);
extra_dirs = eina_array_new(10);
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-v"))
2011-03-18 13:00:22 -07:00
eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_DBG);
else if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--h")) ||
(!strcmp(argv[i], "--help")))
{
printf("Options:\n");
printf(" -v Verbose mode\n");
printf(" -e .ext1 .ext2 Extensions\n");
printf(" -d dir1 dir2 Extra dirs\n");
printf(" -f Flush\n");
exit(0);
}
else if (!strcmp(argv[i], "-e"))
{
while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
eina_array_push(exts, argv[++i]);
}
else if (!strcmp(argv[i], "-d"))
{
while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
eina_array_push(extra_dirs, argv[++i]);
}
else if (!strcmp(argv[i], "-f"))
flush = EINA_TRUE;
}
2013-07-11 02:22:38 -07:00
#ifdef HAVE_SYS_RESOURCE_H
2013-06-20 04:53:54 -07:00
setpriority(PRIO_PROCESS, 0, 19);
#elif _WIN32
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
#endif
if (!eet_init()) return -1;
if (!ecore_init()) return -1;
efreet_cache_update = 0;
/* finish efreet init */
if (!efreet_init()) goto on_error;
strs = eina_array_new(32);
/* create homedir */
snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get());
if (!ecore_file_exists(file))
{
if (!ecore_file_mkpath(file)) return -1;
efreet_setowner(file);
}
/* lock process, so that we only run one copy of this program */
lockfd = cache_lock_file();
if (lockfd == -1) goto on_error;
/* Need to init edd's, so they are like we want, not like userspace wants */
icon_edd = efreet_icon_edd();
fallback_edd = efreet_icon_fallback_edd();
theme_edd = efreet_icon_theme_edd(EINA_TRUE);
icon_themes = eina_hash_string_superfast_new(EINA_FREE_CB(icon_theme_free));
INF("opening theme cache");
/* open theme file */
theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
if (!theme_ef) goto on_error_efreet;
theme_version = eet_data_read(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if (theme_version &&
((theme_version->major != EFREET_ICON_CACHE_MAJOR) ||
(theme_version->minor != EFREET_ICON_CACHE_MINOR)))
{
// delete old cache
eet_close(theme_ef);
if (unlink(efreet_icon_theme_cache_file()) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
if (!theme_ef) goto on_error_efreet;
}
if (!theme_version)
theme_version = NEW(Efreet_Cache_Version, 1);
theme_version->major = EFREET_ICON_CACHE_MAJOR;
theme_version->minor = EFREET_ICON_CACHE_MINOR;
if (flush)
changed = EINA_TRUE;
if (exts->count == 0)
{
ERR("Need to pass extensions to icon cache create process");
goto on_error_efreet;
}
keys = eet_list(theme_ef, "*", &num);
if (keys)
{
for (i = 0; i < num; i++)
{
if (!strncmp(keys[i], "__efreet", 8)) continue;
theme = eet_data_read(theme_ef, theme_edd, keys[i]);
if (theme)
{
theme->valid = 0;
eina_hash_direct_add(icon_themes, theme->theme.name.internal, theme);
}
}
free(keys);
}
INF("scan for themes");
/* scan themes */
cache_theme_scan(efreet_icon_deprecated_user_dir_get());
cache_theme_scan(efreet_icon_user_dir_get());
xdg_dirs = efreet_data_dirs_get();
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(file, sizeof(file), "%s/icons", dir);
cache_theme_scan(file);
}
#ifndef STRICT_SPEC
EINA_LIST_FOREACH(xdg_dirs, l, dir)
{
snprintf(file, sizeof(file), "%s/pixmaps", dir);
cache_theme_scan(file);
}
#endif
cache_theme_scan("/usr/local/share/pixmaps");
cache_theme_scan("/usr/share/pixmaps");
/* scan icons */
it = eina_hash_iterator_data_new(icon_themes);
EINA_ITERATOR_FOREACH(it, theme)
{
if (!theme->valid) continue;
#ifndef STRICT_SPEC
if (!theme->theme.name.name) continue;
#endif
INF("scan theme %s", theme->theme.name.name);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
cache_theme_change_verify(theme);
theme->changed = check_changed(theme);
if (flush)
theme->changed = EINA_TRUE;
INF("open icon file");
/* open icon file */
icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if ((theme->changed) || (!icon_version) ||
((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
(icon_version->minor != EFREET_ICON_CACHE_MINOR)))
{
// delete old cache
eet_close(icon_ef);
if (unlink(efreet_icon_cache_file(theme->theme.name.internal)) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
theme->changed = EINA_TRUE;
}
if (theme->changed)
changed = EINA_TRUE;
if (!icon_version)
icon_version = NEW(Efreet_Cache_Version, 1);
icon_version->major = EFREET_ICON_CACHE_MAJOR;
icon_version->minor = EFREET_ICON_CACHE_MINOR;
if (theme->changed)
{
Eina_Hash *themes;
Eina_Hash *icons;
themes = eina_hash_string_superfast_new(NULL);
icons = eina_hash_string_superfast_new(NULL);
INF("scan icons\n");
if (cache_scan(&(theme->theme), themes, icons))
{
Eina_Iterator *icons_it;
Eina_Hash_Tuple *tuple;
INF("generated: '%s' %i (%i)",
theme->theme.name.internal,
theme->changed,
eina_hash_population(icons));
icons_it = eina_hash_iterator_tuple_new(icons);
EINA_ITERATOR_FOREACH(icons_it, tuple)
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(icon_ef, icon_edd, tuple->key, tuple->data, EET_COMPRESSION_SUPERFAST);
eina_iterator_free(icons_it);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
INF("theme change: %s %lld", theme->theme.name.internal, theme->check.mtime);
eet_data_write(theme_ef, theme_edd, theme->theme.name.internal, theme, EET_COMPRESSION_SUPERFAST);
}
eina_hash_free(themes);
eina_hash_free(icons);
changed = EINA_TRUE;
}
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, EET_COMPRESSION_SUPERFAST);
eet_close(icon_ef);
efreet_setowner(efreet_icon_cache_file(theme->theme.name.internal));
free(icon_version);
}
eina_iterator_free(it);
INF("scan fallback icons");
theme = eet_data_read(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK);
if (!theme)
{
theme = NEW(Efreet_Cache_Icon_Theme, 1);
theme->changed = EINA_TRUE;
}
if (flush)
theme->changed = EINA_TRUE;
INF("open fallback file");
/* open icon file */
icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
if (theme->changed || (icon_version &&
((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
(icon_version->minor != EFREET_ICON_CACHE_MINOR))))
{
// delete old cache
eet_close(icon_ef);
if (unlink(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)) < 0)
{
if (errno != ENOENT) goto on_error_efreet;
}
icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
if (!icon_ef) goto on_error_efreet;
theme->changed = EINA_TRUE;
}
if (!theme->changed)
theme->changed = check_fallback_changed(theme);
if (theme->changed && theme->dirs)
{
efreet_hash_free(theme->dirs, free);
theme->dirs = NULL;
}
if (!theme->dirs)
theme->dirs = eina_hash_string_superfast_new(NULL);
if (theme->changed)
changed = EINA_TRUE;
if (!icon_version)
icon_version = NEW(Efreet_Cache_Version, 1);
icon_version->major = EFREET_ICON_CACHE_MAJOR;
icon_version->minor = EFREET_ICON_CACHE_MINOR;
if (theme->changed)
{
Eina_Hash *icons;
icons = eina_hash_string_superfast_new(NULL);
INF("scan fallback icons");
/* Save fallback in the right part */
if (cache_fallback_scan(icons, theme->dirs))
{
Eina_Iterator *icons_it;
Eina_Hash_Tuple *tuple;
INF("generated: fallback %i (%i)", theme->changed, eina_hash_population(icons));
icons_it = eina_hash_iterator_tuple_new(icons);
EINA_ITERATOR_FOREACH(icons_it, tuple)
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(icon_ef, fallback_edd, tuple->key, tuple->data, EET_COMPRESSION_SUPERFAST);
eina_iterator_free(icons_it);
}
eina_hash_free(icons);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK, theme, EET_COMPRESSION_SUPERFAST);
}
icon_theme_free(theme);
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, EET_COMPRESSION_SUPERFAST);
eet_close(icon_ef);
efreet_setowner(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK));
free(icon_version);
eina_hash_free(icon_themes);
/* save data */
efreetd - cache - add more statinfo work around 0 mtime distros some distros 9notably in this case nixos) want to do reproducible builds. to them this means going around setting mtime for all files to 0. this means efreetd not only thinks mtime is invalid/stupid (0 is generally just that as midnight on jan 1 1970 is not exactly a sensible dare for a modified timestamp of a file as no filesystem with any sanity will have not been modified since that time), but it keeps mtime at 0 even when things update. this totally breaks efreetd that expects to find mtime increases over time as things change. it's necessary because it has to perform a "are mu caches up to date" scan of all file data it caches and it needs to know if it should rebuild something based on this. so this does a few things: 1. it makes mtime have to be an exact match to the cache, not cache mtime >= file mtime. so any change forward or back is an inavlidation. 2. it now also uses ctime, mode, size, uid, gid, block count and if a symlink, the sha1 of the symlink path in addition and any change to these == invalid. this adds a lot of code and changes how dirs get scanned a bit but it means it can pick up changes on these 0 mtime distros. interestingly the policy of mtime being 0 is to have a reprodcible fs ... but ctime still changes and is > 0, as does inode info, so it's not actually possible to have it totally work... but they try still, so this is a fix for that problem. whilst i was doing thisi also noticed efreetd re-red dirs many times due to icon theme inhritance. i also fixed that to do a LOT less syscalls by only scanning a dir once as i was rejigging the scanning code at the time anyway. this should optimize thr scan costs at efreetd startup too. @fix @opt
2020-06-18 03:03:02 -07:00
eet_data_write(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION, theme_version, EET_COMPRESSION_SUPERFAST);
eet_close(theme_ef);
theme_ef = NULL;
efreet_setowner(efreet_icon_theme_cache_file());
free(theme_version);
2011-02-22 04:42:46 -08:00
{
char c = 'n';
if (changed) c = 'c';
printf("%c\n", c);
2011-02-22 04:42:46 -08:00
}
INF("done");
on_error_efreet:
efreet_shutdown();
if (theme_ef) eet_close(theme_ef);
on_error:
if (lockfd >= 0) close(lockfd);
while ((path = eina_array_pop(strs)))
2010-11-30 10:41:21 -08:00
eina_stringshare_del(path);
eina_array_free(strs);
eina_array_free(exts);
eina_array_free(extra_dirs);
2010-11-23 08:49:46 -08:00
ecore_shutdown();
eet_shutdown();
2011-03-18 13:00:22 -07:00
eina_log_domain_unregister(_efreet_icon_cache_log_dom);
eina_shutdown();
return 0;
}