efl

Форк
0
/
efreetd_cache.c 
1145 строк · 34.3 Кб
1
#ifdef HAVE_CONFIG_H
2
# include <config.h>
3
#endif
4

5
#include <Eina.h>
6
#include <Ecore.h>
7
#include <Ecore_File.h>
8
#include <Eio.h>
9
#include <Eet.h>
10
#include "efreetd.h"
11
#include "efreetd_ipc.h"
12

13
#include "Efreet.h"
14
#define EFREET_MODULE_LOG_DOM efreetd_log_dom
15
#include "efreet_private.h"
16
#include "efreetd_cache.h"
17

18
#include <sys/types.h>
19
#include <sys/stat.h>
20
#include <unistd.h>
21

22
extern FILE *efreetd_log_file;
23

24
static Eina_Hash *icon_change_monitors = NULL;
25
static Eina_Hash *icon_change_monitors_mon = NULL;
26
static Eina_Hash *desktop_change_monitors = NULL;
27
static Eina_Hash *desktop_change_monitors_mon = NULL;
28

29
static Ecore_Event_Handler *cache_exe_del_handler = NULL;
30
static Ecore_Event_Handler *cache_exe_data_handler = NULL;
31
static Ecore_Exe           *icon_cache_exe = NULL;
32
static Ecore_Exe           *desktop_cache_exe = NULL;
33
static Ecore_Timer         *icon_cache_timer = NULL;
34
static Ecore_Timer         *desktop_cache_timer = NULL;
35
static Eina_Prefix         *pfx = NULL;
36

37
static Eina_Bool  desktop_exists = EINA_FALSE;
38

39
static Eina_List *desktop_system_dirs = NULL;
40
static Eina_List *desktop_extra_dirs = NULL;
41
static Eina_List *icon_extra_dirs = NULL;
42
static Eina_List *icon_exts = NULL;
43
static Eina_Bool  icon_flush = EINA_FALSE;
44

45
static Eina_Bool desktop_queue = EINA_FALSE;
46
static Eina_Bool icon_queue = EINA_FALSE;
47

48
static Eina_List *_handlers = NULL;
49

50
static void icon_changes_listen(void);
51
static void desktop_changes_listen(void);
52

53
/* internal */
54
typedef struct _Subdir_Cache Subdir_Cache;
55
typedef struct _Subdir_Cache_Dir Subdir_Cache_Dir;
56

57
struct _Subdir_Cache
58
{
59
   Eina_Hash *dirs;
60
};
61

62
struct _Subdir_Cache_Dir
63
{
64
   unsigned long long dev;
65
   unsigned long long ino;
66
   unsigned long long mode;
67
   unsigned long long uid;
68
   unsigned long long gid;
69
   unsigned long long size;
70
   unsigned long long mtim;
71
   unsigned long long ctim;
72
   const char **dirs;
73
   unsigned int dirs_count;
74
};
75

76
static Eet_Data_Descriptor *subdir_edd = NULL;
77
static Eet_Data_Descriptor *subdir_dir_edd = NULL;
78
static Subdir_Cache        *subdir_cache = NULL;
79
static Eina_Bool            subdir_need_save = EINA_FALSE;
80

81
static Eina_Hash *mime_monitors = NULL;
82
static Eina_Hash *mime_monitors_mon = NULL;
83
static Ecore_Timer *mime_update_timer = NULL;
84
static Ecore_Exe *mime_cache_exe = NULL;
85

86
static void mime_cache_init(void);
87
static void mime_cache_shutdown(void);
88
static Eina_Bool mime_update_cache_cb(void *data EINA_UNUSED);
89

90
static void
91
subdir_cache_dir_free(Subdir_Cache_Dir *cd)
92
{
93
   unsigned int i;
94
   if (!cd) return;
95
   if (cd->dirs)
96
     {
97
        for (i = 0; i < cd->dirs_count; i++)
98
          eina_stringshare_del(cd->dirs[i]);
99
        free(cd->dirs);
100
     }
101
   free(cd);
102
}
103

104
static void *
105
subdir_cache_hash_add(void *hash, const char *key, void *data)
106
{
107
   if (!hash) hash = eina_hash_string_superfast_new(EINA_FREE_CB(subdir_cache_dir_free));
108
   if (!hash) return NULL;
109
   eina_hash_add(hash, key, data);
110
   return hash;
111
}
112

113
static void
114
subdir_cache_init(void)
115
{
116
   Eet_Data_Descriptor_Class eddc;
117
   Eet_File *ef;
118
   Eina_Strbuf *buf = eina_strbuf_new();
119
   if (!buf) return;
120

121
   // set up data codecs for subdirs in memory
122
   eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(Subdir_Cache_Dir), "D", sizeof(Subdir_Cache_Dir));
123
   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Subdir_Cache_Dir);
124
   subdir_dir_edd = eet_data_descriptor_stream_new(&eddc);
125
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "0", dev, EET_T_ULONG_LONG);
126
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "1", ino, EET_T_ULONG_LONG);
127
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "2", mode, EET_T_ULONG_LONG);
128
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "3", uid, EET_T_ULONG_LONG);
129
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "4", gid, EET_T_ULONG_LONG);
130
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "5", size, EET_T_ULONG_LONG);
131
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "6", mtim, EET_T_ULONG_LONG);
132
   EET_DATA_DESCRIPTOR_ADD_BASIC(subdir_dir_edd, Subdir_Cache_Dir, "7", ctim, EET_T_ULONG_LONG);
133
   EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(subdir_dir_edd, Subdir_Cache_Dir, "d", dirs);
134

135
   eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(Subdir_Cache), "C", sizeof(Subdir_Cache));
136
   eddc.func.hash_add = subdir_cache_hash_add;
137
   subdir_edd = eet_data_descriptor_stream_new(&eddc);
138
   EET_DATA_DESCRIPTOR_ADD_HASH(subdir_edd, Subdir_Cache, "dirs", dirs, subdir_dir_edd);
139

140
   // load subdirs from the cache file
141
   eina_strbuf_append_printf(buf, "%s/efreet/subdirs_%s.eet",
142
                             efreet_cache_home_get(), efreet_hostname_get());
143
   ef = eet_open(eina_strbuf_string_get(buf), EET_FILE_MODE_READ);
144
   if (ef)
145
     {
146
        subdir_cache = eet_data_read(ef, subdir_edd, "subdirs");
147
        eet_close(ef);
148
     }
149
   eina_strbuf_free(buf);
150

151
   // if we don't have a decoded subdir cache - allocate one
152
   if (!subdir_cache) subdir_cache = calloc(1, sizeof(Subdir_Cache));
153
   if (!subdir_cache)
154
     {
155
        ERR("Cannot allocate subdir cache in memory");
156
        return;
157
     }
158

159
   // if we don't have a hash in the subdir cache - allocate it
160
   if (!subdir_cache->dirs)
161
     subdir_cache->dirs = eina_hash_string_superfast_new(EINA_FREE_CB(subdir_cache_dir_free));
162
}
163

164
static void
165
subdir_cache_shutdown(void)
166
{
167
   // free up in-memory subdir scan info - don't need it anymore
168
   if (subdir_cache)
169
     {
170
        if (subdir_cache->dirs) eina_hash_free(subdir_cache->dirs);
171
        free(subdir_cache);
172
     }
173
   eet_data_descriptor_free(subdir_dir_edd);
174
   eet_data_descriptor_free(subdir_edd);
175
   subdir_cache = NULL;
176
   subdir_dir_edd = NULL;
177
   subdir_edd = NULL;
178
}
179

180
static void
181
subdir_cache_save(void)
182
{
183
   Eina_Strbuf *buf;
184
   Eet_File *ef;
185
   Eina_Tmpstr *tmpstr = NULL;
186
   int tmpfd;
187

188
   // only if subdirs need saving... and we have subdirs.
189
   if (!subdir_need_save) return;
190
   if (!subdir_cache) return;
191
   if (!subdir_cache->dirs) return;
192

193
   buf = eina_strbuf_new();
194
   if (!buf) return;
195

196
   // save to tmp file first
197
   eina_strbuf_append_printf(buf, "%s/efreet/subdirs_%s.eet.XXXXXX.cache",
198
                             efreet_cache_home_get(), efreet_hostname_get());
199

200
   tmpfd = eina_file_mkstemp(eina_strbuf_string_get(buf), &tmpstr);
201
   if (tmpfd < 0)
202
     {
203
        eina_strbuf_free(buf);
204
        return;
205
     }
206

207
   eina_strbuf_reset(buf);
208

209
   // write out eet file to tmp file
210
   ef = eet_open(tmpstr, EET_FILE_MODE_WRITE);
211
   eet_data_write(ef, subdir_edd, "subdirs", subdir_cache, EET_COMPRESSION_SUPERFAST);
212
   eet_close(ef);
213

214
   /*
215
    * On Windows, buf2 has one remaining ref, hence it can not be renamed below.
216
    * Stupid NTFS... So we close it first. "Magically", on Windows, this
217
    * temporary file is not deleted...
218
    */
219
#ifdef _WIN32
220
   close(tmpfd);
221
#endif
222

223
   // atomically rename subdirs file on top from tmp file
224
   eina_strbuf_append_printf(buf, "%s/efreet/subdirs_%s.eet",
225
                             efreet_cache_home_get(), efreet_hostname_get());
226

227
   if (rename(tmpstr, eina_strbuf_string_get(buf)) < 0)
228
     {
229
        unlink(tmpstr);
230
        ERR("Can't save subdir cache %s", eina_strbuf_string_get(buf));
231
     }
232
   // we dont need saving anymore - we just did
233
   subdir_need_save = EINA_FALSE;
234
   eina_tmpstr_del(tmpstr);
235
   eina_strbuf_free(buf);
236
}
237

238
static const Subdir_Cache_Dir *
239
subdir_cache_get(const struct stat *st, const char *path)
240
{
241
   Eina_Iterator *it;
242
   Eina_File_Direct_Info *info;
243
   Subdir_Cache_Dir *cd;
244
   Eina_List *files = NULL;
245
   int i = 0;
246
   const char *file;
247

248
   // if no subdir cache at all - return null
249
   if (!subdir_cache) return NULL;
250
   if (!subdir_cache->dirs) return NULL;
251

252
   // if found but something invalid in stored stat info...
253
   cd = eina_hash_find(subdir_cache->dirs, path);
254
   if ((cd) &&
255
       ((cd->dev != (unsigned long long)st->st_dev) ||
256
        (cd->ino != (unsigned long long)st->st_ino) ||
257
        (cd->mode != (unsigned long long)st->st_mode) ||
258
        (cd->uid != (unsigned long long)st->st_uid) ||
259
        (cd->gid != (unsigned long long)st->st_gid) ||
260
        (cd->size != (unsigned long long)st->st_size) ||
261
        (cd->mtim != (unsigned long long)st->st_mtime) ||
262
        (cd->ctim != (unsigned long long)st->st_ctime)))
263
     {
264
        // delete old node and prepare to scan a new one
265
        eina_hash_del(subdir_cache->dirs, path, cd);
266
        cd = NULL;
267
     }
268
   // if cached dir is ok by now - return it
269
   if (cd) return cd;
270

271
   // we need a new node (fesh or invalid)
272
   cd = calloc(1, sizeof(Subdir_Cache_Dir));
273
   if (!cd) return NULL;
274

275
   // store stat info
276
   cd->dev = (unsigned long long)st->st_dev;
277
   cd->ino = (unsigned long long)st->st_ino;
278
   cd->mode = (unsigned long long)st->st_mode;
279
   cd->uid = (unsigned long long)st->st_uid;
280
   cd->gid = (unsigned long long)st->st_gid;
281
   cd->size = (unsigned long long)st->st_size;
282
   cd->mtim = (unsigned long long)st->st_mtime;
283
   cd->ctim = (unsigned long long)st->st_ctime;
284

285
   // go through content finding directories
286
   it = eina_file_stat_ls(path);
287
   if (!it) return cd;
288
   
289
   EINA_ITERATOR_FOREACH(it, info)
290
     {
291
        // if ., .. or other "hidden" dot files - ignore
292
        if (info->path[info->name_start] == '.') continue;
293
        // if it's a dir or link to a dir - store it.
294
        if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) ||
295
            (info->type == EINA_FILE_DIR))
296
          {
297
             // store just the name, not the full path
298
             files = eina_list_append
299
               (files, eina_stringshare_add(info->path + info->name_start));
300
          }
301
     }
302
   eina_iterator_free(it);
303
   
304
   // now convert our temporary list into an array of stringshare strings
305
   cd->dirs_count = eina_list_count(files);
306
   if (cd->dirs_count > 0)
307
     {
308
        cd->dirs = malloc(cd->dirs_count * sizeof(char *));
309
        EINA_LIST_FREE(files, file)
310
          {
311
             cd->dirs[i] = file;
312
             i++;
313
          }
314
     }
315
   // add cache dir to hash with full path as key
316
   eina_hash_add(subdir_cache->dirs, path, cd);
317
   // mark subdirs as needing a save - something changed
318
   subdir_need_save = EINA_TRUE;
319
   return cd;
320
}
321

322
static Eina_Bool
323
icon_cache_update_cache_cb(void *data EINA_UNUSED)
324
{
325
   Eina_Strbuf *file = eina_strbuf_new();
326
   if (!file) return EINA_FALSE;
327

328
   icon_cache_timer = NULL;
329

330
   if (icon_cache_exe)
331
     {
332
        icon_queue = EINA_TRUE;
333
        eina_strbuf_free(file);
334
        return ECORE_CALLBACK_CANCEL;
335
     }
336
   icon_queue = EINA_FALSE;
337
   if ((!icon_flush) && (!icon_exts))
338
     {
339
        eina_strbuf_free(file);
340
        return ECORE_CALLBACK_CANCEL;
341
     }
342

343
   if (icon_change_monitors) eina_hash_free(icon_change_monitors);
344
   if (icon_change_monitors_mon) eina_hash_free(icon_change_monitors_mon);
345
   icon_change_monitors = eina_hash_string_superfast_new
346
     (EINA_FREE_CB(eio_monitor_del));
347
   icon_change_monitors_mon = eina_hash_pointer_new(NULL);
348
   icon_changes_listen();
349
   subdir_cache_save();
350

351
   /* TODO: Queue if already running */
352
   eina_strbuf_append_printf(file, "%s/efreet/" MODULE_ARCH "/efreet_icon_cache_create",
353
                             eina_prefix_lib_get(pfx));
354
   if (icon_extra_dirs)
355
     {
356
        Eina_List *ll;
357
        char *p;
358

359
        eina_strbuf_append(file, " -d");
360
        EINA_LIST_FOREACH(icon_extra_dirs, ll, p)
361
          {
362
             eina_strbuf_append(file, " ");
363
             eina_strbuf_append(file, p);
364
          }
365
     }
366
   if (icon_exts)
367
     {
368
        Eina_List *ll;
369
        char *p;
370

371
        eina_strbuf_append(file, " -e");
372
        EINA_LIST_FOREACH(icon_exts, ll, p)
373
          {
374
             eina_strbuf_append(file, " ");
375
             eina_strbuf_append(file, p);
376
          }
377
     }
378
   if (icon_flush)
379
     eina_strbuf_append(file, " -f");
380
   icon_flush = EINA_FALSE;
381
   fprintf(efreetd_log_file, "[%09.3f] Run:\n  %s\n", ecore_time_get(),
382
           eina_strbuf_string_get(file));
383
   fflush(efreetd_log_file);
384
   icon_cache_exe = ecore_exe_pipe_run
385
     (eina_strbuf_string_get(file),
386
      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED,
387
      NULL);
388

389
   eina_strbuf_free(file);
390

391
   return ECORE_CALLBACK_CANCEL;
392
}
393

394
static Eina_Bool
395
desktop_cache_update_cache_cb(void *data EINA_UNUSED)
396
{
397
   Eina_Strbuf *file;
398

399
   desktop_cache_timer = NULL;
400

401
   if (desktop_cache_exe)
402
     {
403
        desktop_queue = EINA_TRUE;
404
        return ECORE_CALLBACK_CANCEL;
405
     }
406
   desktop_queue = EINA_FALSE;
407
   file = eina_strbuf_new();
408

409
   if (desktop_change_monitors) eina_hash_free(desktop_change_monitors);
410
   if (desktop_change_monitors_mon) eina_hash_free(desktop_change_monitors_mon);
411
   desktop_change_monitors = eina_hash_string_superfast_new
412
     (EINA_FREE_CB(eio_monitor_del));
413
   desktop_change_monitors_mon = eina_hash_pointer_new(NULL);
414
   desktop_changes_listen();
415
   subdir_cache_save();
416

417
   eina_strbuf_append_printf(file, "%s/efreet/" MODULE_ARCH "/efreet_desktop_cache_create",
418
                            eina_prefix_lib_get(pfx));
419
   if (desktop_extra_dirs)
420
     {
421
        Eina_List *ll;
422
        const char *str;
423

424
        eina_strbuf_append(file, " -d");
425
        EINA_LIST_FOREACH(desktop_extra_dirs, ll, str)
426
          {
427
             eina_strbuf_append(file, " ");
428
             eina_strbuf_append(file, str);
429
          }
430
     }
431
   INF("Run desktop cache creation: %s", eina_strbuf_string_get(file));
432
   fprintf(efreetd_log_file, "[%09.3f] Run:\n  %s\n", ecore_time_get(),
433
           eina_strbuf_string_get(file));
434
   fflush(efreetd_log_file);
435
   desktop_cache_exe = ecore_exe_pipe_run
436
     (eina_strbuf_string_get(file),
437
      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED,
438
      NULL);
439

440
   eina_strbuf_free(file);
441

442
   return ECORE_CALLBACK_CANCEL;
443
}
444

445
static void
446
cache_icon_update(Eina_Bool flush)
447
{
448
   if (icon_cache_timer) ecore_timer_del(icon_cache_timer);
449
   if (flush) icon_flush = flush;
450
   icon_cache_timer = ecore_timer_add(0.2, icon_cache_update_cache_cb, NULL);
451
}
452

453
void
454
cache_desktop_update(void)
455
{
456
   if (desktop_cache_timer) ecore_timer_del(desktop_cache_timer);
457
   desktop_cache_timer = ecore_timer_add(0.2, desktop_cache_update_cache_cb, NULL);
458
}
459

460
static Eina_Bool
461
_cb_monitor_event(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
462
{
463
   Eio_Monitor_Event *ev = event;
464

465
   // if it's an icon
466
   if (eina_hash_find(icon_change_monitors_mon, &(ev->monitor)))
467
     {
468
        cache_icon_update(EINA_FALSE);
469
     }
470
   // if it's a desktop
471
   else if (eina_hash_find(desktop_change_monitors_mon, &(ev->monitor)))
472
     {
473
        cache_desktop_update();
474
     }
475
   // if it's a mime file
476
   else if (eina_hash_find(mime_monitors_mon, &(ev->monitor)))
477
     {
478
        if ((!strcmp("/etc/mime.types", ev->filename)) ||
479
            (!strcmp("globs", ecore_file_file_get(ev->filename))))
480
          {
481
             mime_cache_shutdown();
482
             mime_cache_init();
483
             if (mime_update_timer) ecore_timer_del(mime_update_timer);
484
             mime_update_timer = ecore_timer_add(0.2, mime_update_cache_cb, NULL);
485
          }
486
     }
487
   return ECORE_CALLBACK_PASS_ON;
488
}
489

490
static void
491
icon_changes_monitor_add(const struct stat *st, const char *path)
492
{
493
   Eio_Monitor *mon;
494
   char *realp = NULL;
495
   const char *monpath = path;
496

497
   if (eina_hash_find(icon_change_monitors, path)) return;
498
#ifndef _WIN32
499
   if (S_ISLNK(st->st_mode))
500
     {
501
        realp = ecore_file_realpath(path);
502
        if (!realp) return;
503
        monpath = realp;
504
     }
505
#endif
506
   if (ecore_file_is_dir(monpath))
507
     {
508
        mon = eio_monitor_add(monpath);
509
        if (mon)
510
          {
511
             eina_hash_add(icon_change_monitors, path, mon);
512
             eina_hash_add(icon_change_monitors_mon, &mon, mon);
513
          }
514
     }
515
   free(realp);
516
}
517

518
static void
519
desktop_changes_monitor_add(const struct stat *st, const char *path)
520
{
521
   Eio_Monitor *mon;
522
   char *realp = NULL;
523
   const char *monpath = path;
524

525
   if (eina_hash_find(desktop_change_monitors, path)) return;
526
#ifndef _WIN32
527
   if (S_ISLNK(st->st_mode))
528
     {
529
        realp = ecore_file_realpath(path);
530
        if (!realp) return;
531
        monpath = realp;
532
     }
533
#endif
534
   if (ecore_file_is_dir(monpath))
535
     {
536
        mon = eio_monitor_add(monpath);
537
        if (mon)
538
          {
539
             eina_hash_add(desktop_change_monitors, path, mon);
540
             eina_hash_add(desktop_change_monitors_mon, &mon, mon);
541
          }
542
     }
543
   free(realp);
544
}
545

546
static int
547
stat_cmp(const void *a, const void *b)
548
{
549
   const struct stat *st1 = a;
550
   const struct stat *st2 = b;
551

552
   if ((st2->st_dev == st1->st_dev) && (st2->st_ino == st1->st_ino))
553
     return 0;
554
   return 1;
555
}
556

557
static Eina_Bool
558
_check_recurse_monitor_sanity(Eina_Inarray *stack, const char *path, unsigned int stack_limit)
559
{
560
   const char *home = eina_environment_home_get();
561

562
   // protect against too deep recursion even if it's valid.
563
   if (eina_inarray_count(stack) >= stack_limit)
564
     {
565
        ERR("Recursing too far. Level %i. Stopping at %s\n", stack_limit, path);
566
        return EINA_FALSE;
567
     }
568
   // detect if we start recursing at $HOME - a sign of something wrong
569
   if ((home) && (!strcmp(home, path)))
570
     {
571
        ERR("Recursively monitor homedir! Ignore.");
572
        return EINA_FALSE;
573
     }
574
   return EINA_TRUE;
575
}
576

577
static void
578
icon_changes_listen_recursive(Eina_Inarray *stack, const char *path, Eina_Bool base)
579
{
580
   struct stat *st = eina_mempool_malloc(efreetd_mp_stat, sizeof(struct stat));
581
   if (!st) return;
582

583
   if (stat(path, st) == -1) return;
584
   if (eina_inarray_search(stack, st, stat_cmp) >= 0) return;
585
   if (!_check_recurse_monitor_sanity(stack, path, 10)) return;
586
   eina_inarray_push(stack, st);
587

588
   if ((!S_ISDIR(st->st_mode)) && (base))
589
     {
590
        // XXX: if it doesn't exist... walk the parent dirs back down
591
        // to this path until we find one that doesn't exist, then
592
        // monitor its parent, and treat it specially as it needs
593
        // to look for JUST the creation of this specific child
594
        // and when this child is created, replace this monitor with
595
        // monitoring the next specific child dir down until we are
596
        // monitoring the original path again.
597
     }
598
   if (S_ISDIR(st->st_mode))
599
     {
600
        unsigned int i;
601
        const Subdir_Cache_Dir *cd = subdir_cache_get(st, path);
602
        icon_changes_monitor_add(st, path);
603
        if (cd)
604
          {
605
             Eina_Strbuf *buf = eina_strbuf_new();
606
             if (!buf) return;
607
             for (i = 0; i < cd->dirs_count; i++)
608
               {
609

610
                  eina_strbuf_append_printf(buf,  "%s/%s", path, cd->dirs[i]);
611
                  icon_changes_listen_recursive(stack, eina_strbuf_string_get(buf), EINA_FALSE);
612
                  eina_strbuf_reset(buf);
613
               }
614
             eina_strbuf_free(buf);
615
          }
616
     }
617
   eina_inarray_pop(stack);
618
   eina_mempool_free(efreetd_mp_stat, st);
619
}
620

621
static void
622
desktop_changes_listen_recursive(Eina_Inarray *stack, const char *path, Eina_Bool base)
623
{
624
   struct stat *st = eina_mempool_malloc(efreetd_mp_stat, sizeof(struct stat));
625
   if (!st) return;
626

627
   if (stat(path, st) == -1) return;
628
   if (eina_inarray_search(stack, st, stat_cmp) >= 0) return;
629
   if (!_check_recurse_monitor_sanity(stack, path, 10)) return;
630
   eina_inarray_push(stack, st);
631

632
   if ((!S_ISDIR(st->st_mode)) && (base))
633
     {
634
        // XXX: if it doesn't exist... walk the parent dirs back down
635
        // to this path until we find one that doesn't exist, then
636
        // monitor its parent, and treat it specially as it needs
637
        // to look for JUST the creation of this specific child
638
        // and when this child is created, replace this monitor with
639
        // monitoring the next specific child dir down until we are
640
        // monitoring the original path again.
641
     }
642
   if (S_ISDIR(st->st_mode))
643
     {
644
        unsigned int i;
645
        const Subdir_Cache_Dir *cd = subdir_cache_get(st, path);
646
        desktop_changes_monitor_add(st, path);
647
        if (cd)
648
          {
649
             Eina_Strbuf *buf = eina_strbuf_new();
650
             if (!buf) return;
651
             for (i = 0; i < cd->dirs_count; i++)
652
               {
653
                  eina_strbuf_append_printf(buf, "%s/%s", path, cd->dirs[i]);
654
                  desktop_changes_listen_recursive(stack, eina_strbuf_string_get(buf), EINA_FALSE);
655
                  eina_strbuf_reset(buf);
656
               }
657
             eina_strbuf_free(buf);
658
          }
659
     }
660
   eina_inarray_pop(stack);
661
   eina_mempool_free(efreetd_mp_stat, st);
662
}
663

664
static void
665
icon_changes_listen(void)
666
{
667
   Eina_List *l;
668
   Eina_List *xdg_dirs;
669
   const char *dir;
670
   Eina_Inarray *stack;
671
   Eina_Strbuf *buf = eina_strbuf_new();
672
   if (!buf) return;
673

674
   stack = eina_inarray_new(sizeof(struct stat), 16);
675
   if (!stack)
676
     {
677
        eina_strbuf_free(buf);
678
        return;
679
     }
680
   icon_changes_listen_recursive(stack, efreet_icon_deprecated_user_dir_get(), EINA_TRUE);
681
   eina_inarray_flush(stack);
682
   icon_changes_listen_recursive(stack, efreet_icon_user_dir_get(), EINA_TRUE);
683
   EINA_LIST_FOREACH(icon_extra_dirs, l, dir)
684
     {
685
        if (!strcmp(dir, "/")) continue;
686
        eina_inarray_flush(stack);
687
        icon_changes_listen_recursive(stack, dir, EINA_TRUE);
688
     }
689

690
   xdg_dirs = efreet_data_dirs_get();
691
   EINA_LIST_FOREACH(xdg_dirs, l, dir)
692
     {
693
        eina_strbuf_append_printf(buf, "%s/icons", dir);
694
        eina_inarray_flush(stack);
695
        icon_changes_listen_recursive(stack, eina_strbuf_string_get(buf), EINA_TRUE);
696
        eina_strbuf_reset(buf);
697
     }
698

699
#ifndef STRICT_SPEC
700
   EINA_LIST_FOREACH(xdg_dirs, l, dir)
701
     {
702
        eina_strbuf_append_printf(buf, "%s/pixmaps", dir);
703
        eina_inarray_flush(stack);
704
        icon_changes_listen_recursive(stack, eina_strbuf_string_get(buf), EINA_TRUE);
705
        eina_strbuf_reset(buf);
706
     }
707
#endif
708
   eina_inarray_flush(stack);
709
   icon_changes_listen_recursive(stack, "/usr/local/share/pixmaps", EINA_TRUE);
710
   icon_changes_listen_recursive(stack, "/usr/share/pixmaps", EINA_TRUE);
711
   eina_inarray_free(stack);
712
   eina_strbuf_free(buf);
713
}
714

715
static void
716
desktop_changes_listen(void)
717
{
718
   Eina_List *l;
719
   const char *path;
720
   Eina_Inarray *stack;
721

722
   stack = eina_inarray_new(sizeof(struct stat), 16);
723
   if (!stack) return;
724
   EINA_LIST_FOREACH(desktop_system_dirs, l, path)
725
     {
726
        eina_inarray_flush(stack);
727
        desktop_changes_listen_recursive(stack, path, EINA_TRUE);
728
     }
729
   EINA_LIST_FOREACH(desktop_extra_dirs, l, path)
730
     {
731
        eina_inarray_flush(stack);
732
        desktop_changes_listen_recursive(stack, path, EINA_TRUE);
733
     }
734
   eina_inarray_free(stack);
735
}
736

737
static void
738
fill_list(const char *file, Eina_List **l)
739
{
740
   Eina_File *f = NULL;
741
   Eina_Iterator *it = NULL;
742
   Eina_File_Line *line = NULL;
743
   Eina_Strbuf *buf = eina_strbuf_new();
744
   if (!buf) return;
745

746
   eina_strbuf_append_printf(buf, "%s/efreet/%s", efreet_cache_home_get(), file);
747
   f = eina_file_open(eina_strbuf_string_get(buf), EINA_FALSE);
748
   if (!f) goto error_buf;
749
   it = eina_file_map_lines(f);
750
   if (!it) goto error;
751
   EINA_ITERATOR_FOREACH(it, line)
752
     {
753
        if (line->end > line->start)
754
          {
755
             const char *s = eina_stringshare_add_length(line->start, line->end - line->start);
756
             if (s) *l = eina_list_append(*l, s);
757
          }
758
     }
759
   eina_iterator_free(it);
760
error:
761
   eina_file_close(f);
762
error_buf:
763
   eina_strbuf_free(buf);
764
}
765

766
static void
767
read_lists(void)
768
{
769
// dont use extra dirs as the only way to get extra dirs is by loading a
770
// specific desktop file at a specific path, and this is wrong
771
//   fill_list("extra_desktops.dirs", &desktop_extra_dirs);
772
   fill_list("extra_icons.dirs", &icon_extra_dirs);
773
   fill_list("icons.exts", &icon_exts);
774
}
775

776
static void
777
save_list(const char *file, Eina_List *l)
778
{
779
   FILE *f;
780
   Eina_List *ll;
781
   const char *path;
782
   Eina_Strbuf *buf = eina_strbuf_new();
783
   if (!buf) return;
784

785
   eina_strbuf_append_printf(buf, "%s/efreet/%s", efreet_cache_home_get(), file);
786
   f = fopen(eina_strbuf_string_get(buf), "wb");
787
   if (!f)
788
     {
789
        eina_strbuf_free(buf);
790
        return;
791
     }
792
   EINA_LIST_FOREACH(l, ll, path)
793
      fprintf(f, "%s\n", path);
794
   fclose(f);
795
   eina_strbuf_free(buf);
796
}
797

798
static int
799
strcmplen(const void *data1, const void *data2)
800
{
801
   return strncmp(data1, data2, eina_stringshare_strlen(data1));
802
}
803

804
static Eina_Bool
805
cache_exe_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
806
{
807
   Ecore_Exe_Event_Data *ev = event;
808

809
   if (ev->exe == desktop_cache_exe)
810
     {
811
        Eina_Bool update = EINA_FALSE;
812

813
        fprintf(efreetd_log_file, "[%09.3f] Data desktop_cache_create\n", ecore_time_get());
814
        fflush(efreetd_log_file);
815
        if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE;
816
        if (!desktop_exists)
817
          send_signal_desktop_cache_build();
818
        desktop_exists = EINA_TRUE;
819
        send_signal_desktop_cache_update(update);
820
     }
821
   else if (ev->exe == icon_cache_exe)
822
     {
823
        Eina_Bool update = EINA_FALSE;
824

825
        fprintf(efreetd_log_file, "[%09.3f] Data icon_cache_create\n", ecore_time_get());
826
        fflush(efreetd_log_file);
827
        if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE;
828
        send_signal_icon_cache_update(update);
829
     }
830
   else if (ev->exe == mime_cache_exe)
831
     {
832
        fprintf(efreetd_log_file, "[%09.3f] Data mime_cache_create\n", ecore_time_get());
833
        fflush(efreetd_log_file);
834
        // XXX: ZZZ: handle stdout here from cache updater... if needed
835
     }
836
   return ECORE_CALLBACK_RENEW;
837
}
838

839
static Eina_Bool
840
cache_exe_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
841
{
842
   Ecore_Exe_Event_Del *ev = event;
843

844
   if (ev->exe == desktop_cache_exe)
845
     {
846
        fprintf(efreetd_log_file, "[%09.3f] Exit desktop_cache_create\n", ecore_time_get());
847
        fflush(efreetd_log_file);
848
        desktop_cache_exe = NULL;
849
        if (desktop_queue) cache_desktop_update();
850
     }
851
   else if (ev->exe == icon_cache_exe)
852
     {
853
        fprintf(efreetd_log_file, "[%09.3f] Exit icon_cache_create\n", ecore_time_get());
854
        fflush(efreetd_log_file);
855
        icon_cache_exe = NULL;
856
        if (icon_queue) cache_icon_update(EINA_FALSE);
857
     }
858
   else if (ev->exe == mime_cache_exe)
859
     {
860
        fprintf(efreetd_log_file, "[%09.3f] Exit mime_cache_create\n", ecore_time_get());
861
        fflush(efreetd_log_file);
862
        mime_cache_exe = NULL;
863
        send_signal_mime_cache_build();
864
     }
865
   return ECORE_CALLBACK_RENEW;
866
}
867

868
/* external */
869
void
870
cache_desktop_dir_add(const char *dir)
871
{
872
   char *san;
873
   Eina_List *l;
874

875
   san = eina_file_path_sanitize(dir);
876
   if (!san) return;
877
   if ((l = eina_list_search_unsorted_list(desktop_system_dirs, strcmplen, san)))
878
     {
879
        /* Path is registered, but maybe not monitored */
880
        const char *path = eina_list_data_get(l);
881
        if (!eina_hash_find(desktop_change_monitors, path))
882
          cache_desktop_update();
883
     }
884
   else if (!eina_list_search_unsorted_list(desktop_extra_dirs, EINA_COMPARE_CB(strcmp), san))
885
     {
886
        /* Not a registered path */
887
        desktop_extra_dirs = eina_list_append(desktop_extra_dirs, eina_stringshare_add(san));
888
        save_list("extra_desktops.dirs", desktop_extra_dirs);
889
        cache_desktop_update();
890
     }
891
   free(san);
892
}
893

894
void
895
cache_icon_dir_add(const char *dir)
896
{
897
   char *san;
898

899
   san = eina_file_path_sanitize(dir);
900
   if (!san) return;
901
   if (!eina_list_search_unsorted_list(icon_extra_dirs, EINA_COMPARE_CB(strcmp), san))
902
     {
903
        if (!strcmp(san, "/")) goto out;
904
        icon_extra_dirs = eina_list_append(icon_extra_dirs, eina_stringshare_add(san));
905
        save_list("extra_icons.dirs", icon_extra_dirs);
906
        cache_icon_update(EINA_TRUE);
907
     }
908
out:
909
   free(san);
910
}
911

912
void
913
cache_icon_ext_add(const char *ext)
914
{
915
   if (!eina_list_search_unsorted_list(icon_exts, EINA_COMPARE_CB(strcmp), ext))
916
     {
917
        icon_exts = eina_list_append(icon_exts, eina_stringshare_add(ext));
918
        save_list("icons.exts", icon_exts);
919
        cache_icon_update(EINA_TRUE);
920
     }
921
}
922

923
Eina_Bool
924
cache_desktop_exists(void)
925
{
926
   return desktop_exists;
927
}
928

929
static void
930
mime_update_launch(void)
931
{
932
   Eina_Strbuf *file = eina_strbuf_new();
933
   if (!file) return;
934

935
   eina_strbuf_append_printf(file,
936
            "%s/efreet/" MODULE_ARCH "/efreet_mime_cache_create",
937
            eina_prefix_lib_get(pfx));
938
   mime_cache_exe = ecore_exe_pipe_run(eina_strbuf_string_get(file),
939
                                       ECORE_EXE_PIPE_READ |
940
                                       ECORE_EXE_PIPE_READ_LINE_BUFFERED,
941
                                       NULL);
942
   eina_strbuf_free(file);
943
}
944

945
static Eina_Bool
946
mime_update_cache_cb(void *data EINA_UNUSED)
947
{
948
   mime_update_timer = NULL;
949
   if (mime_cache_exe)
950
     {
951
        ecore_exe_kill(mime_cache_exe);
952
        ecore_exe_free(mime_cache_exe);
953
     }
954
   mime_update_launch();
955
   return EINA_FALSE;
956
}
957

958
static void
959
mime_cache_init(void)
960
{
961
   Eio_Monitor *mon;
962
   Eina_List *datadirs, *l;
963
   const char *s;
964
   Eina_Strbuf *buf = eina_strbuf_new();
965
   if (!buf) return;
966

967
   mime_monitors = eina_hash_string_superfast_new
968
     (EINA_FREE_CB(eio_monitor_del));
969
   mime_monitors_mon = eina_hash_pointer_new(NULL);
970

971
   if (ecore_file_is_dir("/etc"))
972
     {
973
        mon = eio_monitor_add("/etc"); // specifically look at /etc/mime.types
974
        if (mon)
975
          {
976
             eina_hash_add(mime_monitors, "/etc", mon);
977
             eina_hash_add(mime_monitors_mon, &mon, mon);
978
          }
979
     }
980
   if (ecore_file_is_dir("/usr/share/mime"))
981
     {
982
        mon = eio_monitor_add("/usr/share/mime"); // specifically look at /usr/share/mime/globs
983
        if (mon)
984
          {
985
             eina_hash_add(mime_monitors, "/usr/share/mime", mon);
986
             eina_hash_add(mime_monitors_mon, &mon, mon);
987
          }
988
     }
989

990
   datadirs = efreet_data_dirs_get();
991
   EINA_LIST_FOREACH(datadirs, l, s)
992
     {
993
        eina_strbuf_append_printf(buf, "%s/mime", s); // specifically lok at XXX/mime/globs
994
        if (ecore_file_is_dir(eina_strbuf_string_get(buf)))
995
          {
996
             if (!eina_hash_find(mime_monitors, eina_strbuf_string_get(buf)))
997
               {
998
                  mon = eio_monitor_add(eina_strbuf_string_get(buf));
999
                  if (mon)
1000
                    {
1001
                       eina_hash_add(mime_monitors, eina_strbuf_string_get(buf), mon);
1002
                       eina_hash_add(mime_monitors_mon, &mon, mon);
1003
                    }
1004
               }
1005
          }
1006
     }
1007
   eina_strbuf_free(buf);
1008
}
1009

1010
static void
1011
mime_cache_shutdown(void)
1012
{
1013
   if (mime_update_timer)
1014
     {
1015
        ecore_timer_del(mime_update_timer);
1016
        mime_update_timer = NULL;
1017
     }
1018
   if (mime_monitors)
1019
     {
1020
        eina_hash_free(mime_monitors);
1021
        mime_monitors = NULL;
1022
     }
1023
   if (mime_monitors_mon)
1024
     {
1025
        eina_hash_free(mime_monitors_mon);
1026
        mime_monitors_mon = NULL;
1027
     }
1028
}
1029

1030
Eina_Bool
1031
cache_init(void)
1032
{
1033
   char **argv;
1034

1035
   ecore_app_args_get(NULL, &argv);
1036

1037
   pfx = eina_prefix_new(argv[0], cache_init,
1038
                         "EFREET", "efreet", "checkme",
1039
                         PACKAGE_BIN_DIR,
1040
                         PACKAGE_LIB_DIR,
1041
                         PACKAGE_DATA_DIR,
1042
                         PACKAGE_DATA_DIR);
1043

1044
   cache_exe_del_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
1045
                                                   cache_exe_del_cb, NULL);
1046
   if (!cache_exe_del_handler)
1047
     {
1048
        ERR("Failed to add exe del handler");
1049
        goto error;
1050
     }
1051
   cache_exe_data_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
1052
                                                    cache_exe_data_cb, NULL);
1053
   if (!cache_exe_data_handler)
1054
     {
1055
        ERR("Failed to add exe data handler");
1056
        goto error;
1057
     }
1058

1059
   icon_change_monitors = eina_hash_string_superfast_new
1060
     (EINA_FREE_CB(eio_monitor_del));
1061
   icon_change_monitors_mon = eina_hash_pointer_new(NULL);
1062
   desktop_change_monitors = eina_hash_string_superfast_new
1063
     (EINA_FREE_CB(eio_monitor_del));
1064
   desktop_change_monitors_mon = eina_hash_pointer_new(NULL);
1065

1066
   efreet_cache_update = 0;
1067
   if (!efreet_init()) goto error;
1068
   eio_init();
1069

1070
#define MONITOR_EVENT(ev, fn) \
1071
_handlers = eina_list_append(_handlers, ecore_event_handler_add(ev, fn, NULL))
1072
   MONITOR_EVENT(EIO_MONITOR_FILE_CREATED,       _cb_monitor_event);
1073
   MONITOR_EVENT(EIO_MONITOR_FILE_DELETED,       _cb_monitor_event);
1074
   MONITOR_EVENT(EIO_MONITOR_FILE_MODIFIED,      _cb_monitor_event);
1075
   MONITOR_EVENT(EIO_MONITOR_DIRECTORY_CREATED,  _cb_monitor_event);
1076
   MONITOR_EVENT(EIO_MONITOR_DIRECTORY_DELETED,  _cb_monitor_event);
1077
   MONITOR_EVENT(EIO_MONITOR_DIRECTORY_MODIFIED, _cb_monitor_event);
1078
   MONITOR_EVENT(EIO_MONITOR_SELF_RENAME,        _cb_monitor_event);
1079
   MONITOR_EVENT(EIO_MONITOR_SELF_DELETED,       _cb_monitor_event);
1080

1081
   subdir_cache_init();
1082
   mime_cache_init();
1083
   mime_update_launch();
1084
   read_lists();
1085
   /* TODO: Should check if system dirs has changed and handles extra_dirs */
1086
   desktop_system_dirs = efreet_default_dirs_get(efreet_data_home_get(),
1087
                                                 efreet_data_dirs_get(), "applications");
1088
   desktop_system_dirs =
1089
      eina_list_merge(
1090
         desktop_system_dirs, efreet_default_dirs_get(efreet_data_home_get(),
1091
                                                      efreet_data_dirs_get(), "desktop-directories"));
1092
   icon_changes_listen();
1093
   desktop_changes_listen();
1094
   cache_icon_update(EINA_FALSE);
1095
   cache_desktop_update();
1096
   subdir_cache_save();
1097

1098
   return EINA_TRUE;
1099
error:
1100
   if (cache_exe_del_handler) ecore_event_handler_del(cache_exe_del_handler);
1101
   cache_exe_del_handler = NULL;
1102
   if (cache_exe_data_handler) ecore_event_handler_del(cache_exe_data_handler);
1103
   cache_exe_data_handler = NULL;
1104
   return EINA_FALSE;
1105
}
1106

1107
Eina_Bool
1108
cache_shutdown(void)
1109
{
1110
   const char *data;
1111
   Ecore_Event_Handler *handler;
1112

1113
   eina_prefix_free(pfx);
1114
   pfx = NULL;
1115

1116
   mime_cache_shutdown();
1117
   subdir_cache_shutdown();
1118
   efreet_shutdown();
1119

1120
   if (cache_exe_del_handler) ecore_event_handler_del(cache_exe_del_handler);
1121
   cache_exe_del_handler = NULL;
1122
   if (cache_exe_data_handler) ecore_event_handler_del(cache_exe_data_handler);
1123
   cache_exe_data_handler = NULL;
1124

1125
   if (icon_change_monitors) eina_hash_free(icon_change_monitors);
1126
   icon_change_monitors = NULL;
1127
   if (icon_change_monitors_mon) eina_hash_free(icon_change_monitors_mon);
1128
   icon_change_monitors_mon = NULL;
1129
   if (desktop_change_monitors) eina_hash_free(desktop_change_monitors);
1130
   desktop_change_monitors = NULL;
1131
   if (desktop_change_monitors_mon) eina_hash_free(desktop_change_monitors_mon);
1132
   desktop_change_monitors_mon = NULL;
1133
   EINA_LIST_FREE(desktop_system_dirs, data)
1134
      eina_stringshare_del(data);
1135
   EINA_LIST_FREE(desktop_extra_dirs, data)
1136
      eina_stringshare_del(data);
1137
   EINA_LIST_FREE(icon_extra_dirs, data)
1138
      eina_stringshare_del(data);
1139
   EINA_LIST_FREE(icon_exts, data)
1140
      eina_stringshare_del(data);
1141
   EINA_LIST_FREE(_handlers, handler)
1142
      ecore_event_handler_del(handler);
1143
   eio_shutdown();
1144
   return EINA_TRUE;
1145
}
1146

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.