12 #include <Ecore_File.h>
14 #define EFREET_MODULE_LOG_DOM _efreet_desktop_cache_log_dom
15 static int _efreet_desktop_cache_log_dom = -1;
18 #include "efreet_private.h"
19 #include "efreet_cache_private.h"
21 static Eet_Data_Descriptor *edd = NULL;
22 static Eet_File *ef = NULL;
23 static Eet_File *util_ef = NULL;
25 static Eina_Hash *desktops = NULL;
27 static Eina_Hash *file_ids = NULL;
28 static Eina_Hash *paths = NULL;
30 static Eina_Hash *mime_types = NULL;
31 static Eina_Hash *categories = NULL;
32 static Eina_Hash *startup_wm_class = NULL;
33 static Eina_Hash *name = NULL;
34 static Eina_Hash *generic_name = NULL;
35 static Eina_Hash *comment = NULL;
36 static Eina_Hash *exec = NULL;
39 strcmplen(const void *data1, const void *data2)
41 return strncmp(data1, data2, eina_stringshare_strlen(data1));
45 cache_add(const char *path, const char *file_id, int priority __UNUSED__, int *changed)
50 INF("FOUND: %s", path);
51 if (file_id) INF(" (id): %s", file_id);
52 ext = strrchr(path, '.');
53 if (!ext || (strcmp(ext, ".desktop") && strcmp(ext, ".directory"))) return 1;
54 desk = efreet_desktop_new(path);
60 /* This file isn't in cache */
64 else if (ecore_file_mod_time(desk->orig_path) != desk->load_time)
66 efreet_desktop_free(desk);
68 desk = efreet_desktop_uncached_new(path);
69 if (desk) INF(" CHANGED");
70 else INF(" NO UNCACHED");
73 if (!eina_hash_find(paths, desk->orig_path))
75 if (!eet_data_write(ef, edd, desk->orig_path, desk, 0))
77 eina_hash_add(paths, desk->orig_path, (void *)1);
79 /* TODO: We should check priority, and not just hope we search in right order */
80 /* TODO: We need to find out if prioritized file id has changed because of
81 * changed search order. */
82 if (!desk->hidden && desk->type == EFREET_DESKTOP_TYPE_APPLICATION &&
83 file_id && !eina_hash_find(file_ids, file_id))
87 Efreet_Cache_Array_String *array;
89 #define ADD_LIST(list, hash) \
90 EINA_LIST_FOREACH((list), l, data) \
92 array = eina_hash_find((hash), data); \
94 array = NEW(Efreet_Cache_Array_String, 1); \
95 array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \
96 array->array[array->array_count++] = desk->orig_path; \
97 eina_hash_set((hash), data, array); \
99 #define ADD_ELEM(elem, hash) \
103 array = eina_hash_find((hash), data); \
105 array = NEW(Efreet_Cache_Array_String, 1); \
106 array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \
107 array->array[array->array_count++] = desk->orig_path; \
108 eina_hash_set((hash), data, array); \
110 ADD_LIST(desk->mime_types, mime_types);
111 ADD_LIST(desk->categories, categories);
112 ADD_ELEM(desk->startup_wm_class, startup_wm_class);
113 ADD_ELEM(desk->name, name);
114 ADD_ELEM(desk->generic_name, generic_name);
115 ADD_ELEM(desk->comment, comment);
116 ADD_ELEM(desk->exec, exec);
117 eina_hash_add(file_ids, file_id, desk->orig_path);
118 eina_hash_add(desktops, desk->orig_path, desk);
121 efreet_desktop_free(desk);
127 cache_scan(const char *path, const char *base_id, int priority, int recurse, int *changed)
129 char *file_id = NULL;
135 if (!ecore_file_is_dir(path)) return 1;
137 files = opendir(path);
138 if (!files) return 1;
140 while ((ent = readdir(files)))
143 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
148 snprintf(id, sizeof(id), "%s-%s", base_id, ent->d_name);
150 strcpy(id, ent->d_name);
154 snprintf(buf, sizeof(buf), "%s/%s", path, ent->d_name);
155 if (ecore_file_is_dir(buf))
158 cache_scan(buf, file_id, priority, recurse, changed);
162 if (!cache_add(buf, file_id, priority, changed))
174 cache_lock_file(void)
180 snprintf(file, sizeof(file), "%s/efreet/desktop_data.lock", efreet_cache_home_get());
181 lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
182 if (lockfd < 0) return -1;
183 efreet_fsetowner(lockfd);
185 memset(&fl, 0, sizeof(struct flock));
187 fl.l_whence = SEEK_SET;
188 if (fcntl(lockfd, F_SETLK, &fl) < 0)
190 INF("LOCKED! You may want to delete %s if this persists", file);
199 main(int argc, char **argv)
202 * - Add file monitor on files, so that we catch changes on files
203 * during whilst this program runs.
204 * - Maybe linger for a while to reduce number of cache re-creates.
206 Efreet_Cache_Hash hash;
207 Efreet_Cache_Version version;
208 Eina_List *dirs = NULL;
209 Eina_List *systemdirs = NULL;
210 Efreet_Cache_Array_String *user_dirs = NULL;
211 Eina_List *extra_dirs = NULL;
212 Eina_List *store_dirs = NULL;
216 int lockfd = -1, tmpfd;
219 char file[PATH_MAX] = { '\0' };
220 char util_file[PATH_MAX] = { '\0' };
222 if (!eina_init()) goto eina_error;
223 _efreet_desktop_cache_log_dom =
224 eina_log_domain_register("efreet_desktop_cache", EFREET_DEFAULT_LOG_COLOR);
225 if (_efreet_desktop_cache_log_dom < 0)
227 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop_cache.");
231 for (i = 1; i < argc; i++)
233 if (!strcmp(argv[i], "-v"))
234 eina_log_domain_level_set("efreet_desktop_cache", EINA_LOG_LEVEL_DBG);
235 else if ((!strcmp(argv[i], "-h")) ||
236 (!strcmp(argv[i], "-help")) ||
237 (!strcmp(argv[i], "--h")) ||
238 (!strcmp(argv[i], "--help")))
240 printf("Options:\n");
241 printf(" -v Verbose mode\n");
242 printf(" -d dir1 dir2 Extra dirs\n");
245 else if (!strcmp(argv[i], "-d"))
247 while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
248 extra_dirs = eina_list_append(extra_dirs, argv[++i]);
251 extra_dirs = eina_list_sort(extra_dirs, -1, EINA_COMPARE_CB(strcmp));
253 /* init external subsystems */
254 if (!eet_init()) goto eet_error;
255 if (!ecore_init()) goto ecore_error;
257 efreet_cache_update = 0;
258 /* finish efreet init */
259 if (!efreet_init()) goto efreet_error;
262 snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get());
263 if (!ecore_file_exists(file))
265 if (!ecore_file_mkpath(file)) goto efreet_error;
266 efreet_setowner(file);
269 /* lock process, so that we only run one copy of this program */
270 lockfd = cache_lock_file();
271 if (lockfd == -1) goto efreet_error;
273 edd = efreet_desktop_edd();
274 if (!edd) goto edd_error;
276 /* read user dirs from old cache */
277 ef = eet_open(efreet_desktop_cache_file(), EET_FILE_MODE_READ);
280 user_dirs = eet_data_read(ef, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS);
285 snprintf(file, sizeof(file), "%s.XXXXXX", efreet_desktop_cache_file());
286 tmpfd = mkstemp(file);
287 if (tmpfd < 0) goto error;
289 ef = eet_open(file, EET_FILE_MODE_READ_WRITE);
292 snprintf(util_file, sizeof(util_file), "%s.XXXXXX", efreet_desktop_util_cache_file());
293 tmpfd = mkstemp(util_file);
294 if (tmpfd < 0) goto error;
296 util_ef = eet_open(util_file, EET_FILE_MODE_READ_WRITE);
297 if (!util_ef) goto error;
299 /* write cache version */
300 version.major = EFREET_DESKTOP_UTILS_CACHE_MAJOR;
301 version.minor = EFREET_DESKTOP_UTILS_CACHE_MINOR;
302 eet_data_write(util_ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1);
303 version.major = EFREET_DESKTOP_CACHE_MAJOR;
304 version.minor = EFREET_DESKTOP_CACHE_MINOR;
305 eet_data_write(ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1);
307 desktops = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_desktop_free));
309 file_ids = eina_hash_string_superfast_new(NULL);
310 paths = eina_hash_string_superfast_new(NULL);
312 mime_types = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
313 categories = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
314 startup_wm_class = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
315 name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
316 generic_name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
317 comment = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
318 exec = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
320 dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
322 if (!dirs) goto error;
324 EINA_LIST_FREE(dirs, path)
326 char file_id[PATH_MAX] = { '\0' };
328 if (!cache_scan(path, file_id, priority++, 1, &changed)) goto error;
329 systemdirs = eina_list_append(systemdirs, path);
336 for (j = 0; j < user_dirs->array_count; j++)
338 if (eina_list_search_unsorted_list(systemdirs, strcmplen, user_dirs->array[j]))
340 if (!ecore_file_is_dir(user_dirs->array[j])) continue;
341 if (!cache_scan(user_dirs->array[j], NULL, priority, 0, &changed)) goto error;
343 store_dirs = eina_list_append(store_dirs, user_dirs->array[j]);
345 store_dirs = eina_list_sort(store_dirs, -1, EINA_COMPARE_CB(strcmp));
352 EINA_LIST_FOREACH(extra_dirs, l, path)
354 if (eina_list_search_unsorted_list(systemdirs, strcmplen, path))
356 if (eina_list_search_unsorted_list(store_dirs, EINA_COMPARE_CB(strcmp), path))
358 if (!ecore_file_is_dir(path)) continue;
360 /* If we scan a passed dir, we must have changed */
362 if (!cache_scan(path, NULL, priority, 0, &changed)) goto error;
364 store_dirs = eina_list_append(store_dirs, path);
366 store_dirs = eina_list_sort(store_dirs, -1, EINA_COMPARE_CB(strcmp));
371 IF_FREE(user_dirs->array);
375 /* store user dirs */
380 user_dirs = NEW(Efreet_Cache_Array_String, 1);
381 user_dirs->array = NEW(char *, eina_list_count(store_dirs));
382 user_dirs->array_count = 0;
383 EINA_LIST_FOREACH(store_dirs, l, path)
384 user_dirs->array[user_dirs->array_count++] = path;
386 eet_data_write(ef, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS, user_dirs, 1);
387 IF_FREE(user_dirs->array);
392 #define STORE_HASH_ARRAY(_hash) \
393 if (eina_hash_population((_hash)) > 0) \
396 Efreet_Cache_Array_String array; \
399 hash.hash = (_hash); \
400 eet_data_write(util_ef, efreet_hash_array_string_edd(), #_hash "_hash", &hash, 1); \
401 array.array_count = 0; \
402 array.array = malloc(eina_hash_population(hash.hash) * sizeof(char *)); \
403 it = eina_hash_iterator_key_new(hash.hash); \
404 EINA_ITERATOR_FOREACH(it, str) \
405 array.array[array.array_count++] = str; \
406 eina_iterator_free(it); \
407 eet_data_write(util_ef, efreet_array_string_edd(), #_hash "_list", &array, 1); \
410 STORE_HASH_ARRAY(mime_types);
411 STORE_HASH_ARRAY(categories);
412 STORE_HASH_ARRAY(startup_wm_class);
413 STORE_HASH_ARRAY(name);
414 STORE_HASH_ARRAY(generic_name);
415 STORE_HASH_ARRAY(comment);
416 STORE_HASH_ARRAY(exec);
417 if (eina_hash_population(file_ids) > 0)
419 hash.hash = file_ids;
420 eet_data_write(util_ef, efreet_hash_string_edd(), "file_id", &hash, 1);
423 eina_hash_free(mime_types);
424 eina_hash_free(categories);
425 eina_hash_free(startup_wm_class);
426 eina_hash_free(name);
427 eina_hash_free(generic_name);
428 eina_hash_free(comment);
429 eina_hash_free(exec);
431 eina_hash_free(file_ids);
432 eina_hash_free(paths);
434 eina_hash_free(desktops);
436 /* check if old and new caches contain the same number of entries */
441 old = eet_open(efreet_desktop_cache_file(), EET_FILE_MODE_READ);
442 if (!old || eet_num_entries(old) != eet_num_entries(ef)) changed = 1;
443 if (old) eet_close(old);
444 old = eet_open(efreet_desktop_util_cache_file(), EET_FILE_MODE_READ);
445 if (!old || eet_num_entries(old) != eet_num_entries(util_ef)) changed = 1;
446 if (old) eet_close(old);
453 /* unlink old cache files */
456 if (unlink(efreet_desktop_cache_file()) < 0)
458 if (errno != ENOENT) goto error;
460 if (unlink(efreet_desktop_util_cache_file()) < 0)
462 if (errno != ENOENT) goto error;
464 /* rename tmp files to real files */
465 if (rename(util_file, efreet_desktop_util_cache_file()) < 0) goto error;
466 efreet_setowner(efreet_desktop_util_cache_file());
467 if (rename(file, efreet_desktop_cache_file()) < 0) goto error;
468 efreet_setowner(efreet_desktop_cache_file());
476 /* touch update file */
477 snprintf(file, sizeof(file), "%s/efreet/desktop_data.update", efreet_cache_home_get());
478 tmpfd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
483 efreet_fsetowner(tmpfd);
484 if (changed) c = 'c';
485 if (write(tmpfd, &c, 1) != 1) perror("write");
489 EINA_LIST_FREE(systemdirs, dir)
490 eina_stringshare_del(dir);
491 eina_list_free(extra_dirs);
492 eina_list_free(store_dirs);
496 eina_log_domain_unregister(_efreet_desktop_cache_log_dom);
503 if (user_dirs) efreet_cache_array_string_free(user_dirs);
510 EINA_LIST_FREE(systemdirs, dir)
511 eina_stringshare_del(dir);
512 eina_list_free(extra_dirs);
513 eina_list_free(store_dirs);
514 eina_log_domain_unregister(_efreet_desktop_cache_log_dom);
517 if (lockfd >= 0) close(lockfd);