diff options
Diffstat (limited to 'libraries/eina/src/lib/eina_file.c')
-rw-r--r-- | libraries/eina/src/lib/eina_file.c | 1359 |
1 files changed, 0 insertions, 1359 deletions
diff --git a/libraries/eina/src/lib/eina_file.c b/libraries/eina/src/lib/eina_file.c deleted file mode 100644 index c465301..0000000 --- a/libraries/eina/src/lib/eina_file.c +++ /dev/null | |||
@@ -1,1359 +0,0 @@ | |||
1 | /* EINA - EFL data type library | ||
2 | * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri | ||
3 | * Copyright (C) 2010-2011 Cedric Bail | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; | ||
17 | * if not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #ifdef HAVE_CONFIG_H | ||
21 | # include "config.h" | ||
22 | #endif | ||
23 | |||
24 | #ifdef HAVE_ALLOCA_H | ||
25 | # include <alloca.h> | ||
26 | #elif defined __GNUC__ | ||
27 | # define alloca __builtin_alloca | ||
28 | #elif defined _AIX | ||
29 | # define alloca __alloca | ||
30 | #elif defined _MSC_VER | ||
31 | # include <malloc.h> | ||
32 | # define alloca _alloca | ||
33 | #else | ||
34 | # include <stddef.h> | ||
35 | # ifdef __cplusplus | ||
36 | extern "C" | ||
37 | # endif | ||
38 | void *alloca (size_t); | ||
39 | #endif | ||
40 | |||
41 | #include <stdlib.h> | ||
42 | #include <string.h> | ||
43 | #include <stddef.h> | ||
44 | #ifdef HAVE_DIRENT_H | ||
45 | # include <dirent.h> | ||
46 | #endif | ||
47 | #include <sys/types.h> | ||
48 | #include <sys/stat.h> | ||
49 | #include <unistd.h> | ||
50 | #ifdef HAVE_SYS_MMAN_H | ||
51 | # include <sys/mman.h> | ||
52 | #endif | ||
53 | #include <fcntl.h> | ||
54 | |||
55 | #define PATH_DELIM '/' | ||
56 | |||
57 | #include "eina_config.h" | ||
58 | #include "eina_private.h" | ||
59 | |||
60 | /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ | ||
61 | #include "eina_safety_checks.h" | ||
62 | #include "eina_file.h" | ||
63 | #include "eina_stringshare.h" | ||
64 | #include "eina_hash.h" | ||
65 | #include "eina_list.h" | ||
66 | #include "eina_lock.h" | ||
67 | #include "eina_mmap.h" | ||
68 | #include "eina_log.h" | ||
69 | #include "eina_xattr.h" | ||
70 | |||
71 | #ifdef HAVE_ESCAPE_H | ||
72 | # include <Escape.h> | ||
73 | #endif | ||
74 | |||
75 | /*============================================================================* | ||
76 | * Local * | ||
77 | *============================================================================*/ | ||
78 | |||
79 | /** | ||
80 | * @cond LOCAL | ||
81 | */ | ||
82 | |||
83 | #ifndef EINA_LOG_COLOR_DEFAULT | ||
84 | #define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN | ||
85 | #endif | ||
86 | |||
87 | #ifdef ERR | ||
88 | #undef ERR | ||
89 | #endif | ||
90 | #define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__) | ||
91 | |||
92 | #ifdef WRN | ||
93 | #undef WRN | ||
94 | #endif | ||
95 | #define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) | ||
96 | |||
97 | #ifdef DBG | ||
98 | #undef DBG | ||
99 | #endif | ||
100 | #define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__) | ||
101 | |||
102 | #define EINA_SMALL_PAGE 4096 | ||
103 | # define EINA_HUGE_PAGE 16 * 1024 * 1024 | ||
104 | |||
105 | #ifdef HAVE_DIRENT_H | ||
106 | typedef struct _Eina_File_Iterator Eina_File_Iterator; | ||
107 | struct _Eina_File_Iterator | ||
108 | { | ||
109 | Eina_Iterator iterator; | ||
110 | |||
111 | DIR *dirp; | ||
112 | int length; | ||
113 | |||
114 | char dir[1]; | ||
115 | }; | ||
116 | #endif | ||
117 | |||
118 | struct _Eina_File | ||
119 | { | ||
120 | const char *filename; | ||
121 | |||
122 | Eina_Hash *map; | ||
123 | Eina_Hash *rmap; | ||
124 | void *global_map; | ||
125 | |||
126 | Eina_Lock lock; | ||
127 | |||
128 | unsigned long long length; | ||
129 | time_t mtime; | ||
130 | ino_t inode; | ||
131 | #ifdef _STAT_VER_LINUX | ||
132 | unsigned long int mtime_nsec; | ||
133 | #endif | ||
134 | |||
135 | int refcount; | ||
136 | int global_refcount; | ||
137 | |||
138 | int fd; | ||
139 | |||
140 | Eina_Bool shared : 1; | ||
141 | Eina_Bool delete_me : 1; | ||
142 | Eina_Bool global_faulty : 1; | ||
143 | }; | ||
144 | |||
145 | typedef struct _Eina_File_Map Eina_File_Map; | ||
146 | struct _Eina_File_Map | ||
147 | { | ||
148 | void *map; | ||
149 | |||
150 | unsigned long int offset; | ||
151 | unsigned long int length; | ||
152 | |||
153 | int refcount; | ||
154 | |||
155 | Eina_Bool hugetlb : 1; | ||
156 | Eina_Bool faulty : 1; | ||
157 | }; | ||
158 | |||
159 | static Eina_Hash *_eina_file_cache = NULL; | ||
160 | static Eina_Lock _eina_file_lock_cache; | ||
161 | |||
162 | static int _eina_file_log_dom = -1; | ||
163 | |||
164 | /* | ||
165 | * This complex piece of code is needed due to possible race condition. | ||
166 | * The code and description of the issue can be found at : | ||
167 | * http://womble.decadent.org.uk/readdir_r-advisory.html | ||
168 | */ | ||
169 | #ifdef HAVE_DIRENT_H | ||
170 | static long | ||
171 | _eina_name_max(DIR *dirp) | ||
172 | { | ||
173 | long name_max; | ||
174 | |||
175 | #if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX) | ||
176 | name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); | ||
177 | |||
178 | if (name_max == -1) | ||
179 | { | ||
180 | # if defined(NAME_MAX) | ||
181 | name_max = (NAME_MAX > 255) ? NAME_MAX : 255; | ||
182 | # else | ||
183 | name_max = PATH_MAX; | ||
184 | # endif | ||
185 | } | ||
186 | #else | ||
187 | # if defined(NAME_MAX) | ||
188 | name_max = (NAME_MAX > 255) ? NAME_MAX : 255; | ||
189 | # else | ||
190 | # ifdef _PC_NAME_MAX | ||
191 | # warning "buffer size for readdir_r cannot be determined safely, best effort, but racy" | ||
192 | name_max = pathconf(dirp, _PC_NAME_MAX); | ||
193 | # else | ||
194 | # error "buffer size for readdir_r cannot be determined safely" | ||
195 | # endif | ||
196 | # endif | ||
197 | #endif | ||
198 | |||
199 | return name_max; | ||
200 | } | ||
201 | |||
202 | static size_t | ||
203 | _eina_dirent_buffer_size(DIR *dirp) | ||
204 | { | ||
205 | long name_max = _eina_name_max(dirp); | ||
206 | size_t name_end; | ||
207 | |||
208 | name_end = (size_t) offsetof(struct dirent, d_name) + name_max + 1; | ||
209 | |||
210 | return (name_end > sizeof (struct dirent) ? name_end : sizeof (struct dirent)); | ||
211 | } | ||
212 | |||
213 | static Eina_Bool | ||
214 | _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data) | ||
215 | { | ||
216 | struct dirent *dp; | ||
217 | char *name; | ||
218 | size_t length; | ||
219 | |||
220 | dp = alloca(_eina_dirent_buffer_size(it->dirp)); | ||
221 | |||
222 | do | ||
223 | { | ||
224 | if (readdir_r(it->dirp, dp, &dp)) | ||
225 | return EINA_FALSE; | ||
226 | if (dp == NULL) | ||
227 | return EINA_FALSE; | ||
228 | } | ||
229 | while ((dp->d_name[0] == '.') && | ||
230 | ((dp->d_name[1] == '\0') || | ||
231 | ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0')))); | ||
232 | |||
233 | #ifdef _DIRENT_HAVE_D_NAMLEN | ||
234 | length = dp->d_namlen; | ||
235 | #else | ||
236 | length = strlen(dp->d_name); | ||
237 | #endif | ||
238 | name = alloca(length + 2 + it->length); | ||
239 | |||
240 | memcpy(name, it->dir, it->length); | ||
241 | memcpy(name + it->length, "/", 1); | ||
242 | memcpy(name + it->length + 1, dp->d_name, length + 1); | ||
243 | |||
244 | *data = (char *)eina_stringshare_add(name); | ||
245 | return EINA_TRUE; | ||
246 | } | ||
247 | |||
248 | static DIR * | ||
249 | _eina_file_ls_iterator_container(Eina_File_Iterator *it) | ||
250 | { | ||
251 | return it->dirp; | ||
252 | } | ||
253 | |||
254 | static void | ||
255 | _eina_file_ls_iterator_free(Eina_File_Iterator *it) | ||
256 | { | ||
257 | closedir(it->dirp); | ||
258 | |||
259 | EINA_MAGIC_SET(&it->iterator, 0); | ||
260 | free(it); | ||
261 | } | ||
262 | |||
263 | typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator; | ||
264 | struct _Eina_File_Direct_Iterator | ||
265 | { | ||
266 | Eina_Iterator iterator; | ||
267 | |||
268 | DIR *dirp; | ||
269 | int length; | ||
270 | |||
271 | Eina_File_Direct_Info info; | ||
272 | |||
273 | char dir[1]; | ||
274 | }; | ||
275 | |||
276 | static Eina_Bool | ||
277 | _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) | ||
278 | { | ||
279 | struct dirent *dp; | ||
280 | size_t length; | ||
281 | |||
282 | dp = alloca(_eina_dirent_buffer_size(it->dirp)); | ||
283 | |||
284 | do | ||
285 | { | ||
286 | if (readdir_r(it->dirp, dp, &dp)) | ||
287 | return EINA_FALSE; | ||
288 | if (!dp) | ||
289 | return EINA_FALSE; | ||
290 | |||
291 | #ifdef _DIRENT_HAVE_D_NAMLEN | ||
292 | length = dp->d_namlen; | ||
293 | #else | ||
294 | length = strlen(dp->d_name); | ||
295 | #endif | ||
296 | if (it->info.name_start + length + 1 >= EINA_PATH_MAX) | ||
297 | continue; | ||
298 | } | ||
299 | while ((dp->d_name[0] == '.') && | ||
300 | ((dp->d_name[1] == '\0') || | ||
301 | ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0')))); | ||
302 | |||
303 | memcpy(it->info.path + it->info.name_start, dp->d_name, length); | ||
304 | it->info.name_length = length; | ||
305 | it->info.path_length = it->info.name_start + length; | ||
306 | it->info.path[it->info.path_length] = '\0'; | ||
307 | |||
308 | #ifdef _DIRENT_HAVE_D_TYPE | ||
309 | switch (dp->d_type) | ||
310 | { | ||
311 | case DT_FIFO: | ||
312 | it->info.type = EINA_FILE_FIFO; | ||
313 | break; | ||
314 | case DT_CHR: | ||
315 | it->info.type = EINA_FILE_CHR; | ||
316 | break; | ||
317 | case DT_DIR: | ||
318 | it->info.type = EINA_FILE_DIR; | ||
319 | break; | ||
320 | case DT_BLK: | ||
321 | it->info.type = EINA_FILE_BLK; | ||
322 | break; | ||
323 | case DT_REG: | ||
324 | it->info.type = EINA_FILE_REG; | ||
325 | break; | ||
326 | case DT_LNK: | ||
327 | it->info.type = EINA_FILE_LNK; | ||
328 | break; | ||
329 | case DT_SOCK: | ||
330 | it->info.type = EINA_FILE_SOCK; | ||
331 | break; | ||
332 | case DT_WHT: | ||
333 | it->info.type = EINA_FILE_WHT; | ||
334 | break; | ||
335 | default: | ||
336 | it->info.type = EINA_FILE_UNKNOWN; | ||
337 | break; | ||
338 | } | ||
339 | #else | ||
340 | it->info.type = EINA_FILE_UNKNOWN; | ||
341 | #endif | ||
342 | |||
343 | *data = &it->info; | ||
344 | return EINA_TRUE; | ||
345 | } | ||
346 | |||
347 | static DIR * | ||
348 | _eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it) | ||
349 | { | ||
350 | return it->dirp; | ||
351 | } | ||
352 | |||
353 | static void | ||
354 | _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) | ||
355 | { | ||
356 | closedir(it->dirp); | ||
357 | |||
358 | EINA_MAGIC_SET(&it->iterator, 0); | ||
359 | free(it); | ||
360 | } | ||
361 | |||
362 | static Eina_Bool | ||
363 | _eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) | ||
364 | { | ||
365 | Eina_Stat st; | ||
366 | |||
367 | if (!_eina_file_direct_ls_iterator_next(it, data)) | ||
368 | return EINA_FALSE; | ||
369 | |||
370 | if (it->info.type == EINA_FILE_UNKNOWN) | ||
371 | { | ||
372 | if (eina_file_statat(it->dirp, &it->info, &st) != 0) | ||
373 | it->info.type = EINA_FILE_UNKNOWN; | ||
374 | } | ||
375 | |||
376 | return EINA_TRUE; | ||
377 | } | ||
378 | #endif | ||
379 | |||
380 | static void | ||
381 | _eina_file_real_close(Eina_File *file) | ||
382 | { | ||
383 | if (file->refcount != 0) return; | ||
384 | |||
385 | eina_hash_free(file->rmap); | ||
386 | eina_hash_free(file->map); | ||
387 | |||
388 | if (file->global_map != MAP_FAILED) | ||
389 | munmap(file->global_map, file->length); | ||
390 | |||
391 | close(file->fd); | ||
392 | |||
393 | free(file); | ||
394 | } | ||
395 | |||
396 | static void | ||
397 | _eina_file_map_close(Eina_File_Map *map) | ||
398 | { | ||
399 | munmap(map->map, map->length); | ||
400 | free(map); | ||
401 | } | ||
402 | |||
403 | static unsigned int | ||
404 | _eina_file_map_key_length(const void *key __UNUSED__) | ||
405 | { | ||
406 | return sizeof (unsigned long int) * 2; | ||
407 | } | ||
408 | |||
409 | static int | ||
410 | _eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__, | ||
411 | const unsigned long int *key2, int key2_length __UNUSED__) | ||
412 | { | ||
413 | if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; | ||
414 | return key1[0] - key2[0]; | ||
415 | } | ||
416 | |||
417 | static int | ||
418 | _eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__) | ||
419 | { | ||
420 | return eina_hash_int64(&key[0], sizeof (unsigned long int)) | ||
421 | ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); | ||
422 | } | ||
423 | |||
424 | #ifndef MAP_POPULATE | ||
425 | static unsigned int | ||
426 | _eina_file_map_populate(char *map, unsigned int size, Eina_Bool hugetlb) | ||
427 | { | ||
428 | unsigned int r = 0xDEADBEEF; | ||
429 | unsigned int i; | ||
430 | unsigned int s; | ||
431 | |||
432 | s = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE; | ||
433 | |||
434 | for (i = 0; i < size; i += s) | ||
435 | r ^= map[i]; | ||
436 | |||
437 | r ^= map[size]; | ||
438 | |||
439 | return r; | ||
440 | } | ||
441 | #endif | ||
442 | |||
443 | static int | ||
444 | _eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int size, Eina_Bool hugetlb) | ||
445 | { | ||
446 | int tmp = 42; | ||
447 | int flag = MADV_RANDOM; | ||
448 | |||
449 | switch (rule) | ||
450 | { | ||
451 | case EINA_FILE_RANDOM: flag = MADV_RANDOM; break; | ||
452 | case EINA_FILE_SEQUENTIAL: flag = MADV_SEQUENTIAL; break; | ||
453 | case EINA_FILE_POPULATE: flag = MADV_WILLNEED; break; | ||
454 | case EINA_FILE_WILLNEED: flag = MADV_WILLNEED; break; | ||
455 | } | ||
456 | |||
457 | madvise(addr, size, flag); | ||
458 | |||
459 | #ifndef MAP_POPULATE | ||
460 | if (rule == EINA_FILE_POPULATE) | ||
461 | tmp ^= _eina_file_map_populate(addr, size, hugetlb); | ||
462 | #else | ||
463 | (void) hugetlb; | ||
464 | #endif | ||
465 | |||
466 | return tmp; | ||
467 | } | ||
468 | |||
469 | static Eina_Bool | ||
470 | _eina_file_timestamp_compare(Eina_File *f, struct stat *st) | ||
471 | { | ||
472 | if (f->mtime != st->st_mtime) return EINA_FALSE; | ||
473 | if (f->length != (unsigned long long) st->st_size) return EINA_FALSE; | ||
474 | if (f->inode != st->st_ino) return EINA_FALSE; | ||
475 | #ifdef _STAT_VER_LINUX | ||
476 | # if (defined __USE_MISC && defined st_mtime) | ||
477 | if (f->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec) | ||
478 | return EINA_FALSE; | ||
479 | # else | ||
480 | if (f->mtime_nsec != (unsigned long int)st->st_mtimensec) | ||
481 | return EINA_FALSE; | ||
482 | # endif | ||
483 | #endif | ||
484 | return EINA_TRUE; | ||
485 | } | ||
486 | |||
487 | static void | ||
488 | slprintf(char *str, size_t size, const char *format, ...) | ||
489 | { | ||
490 | va_list ap; | ||
491 | |||
492 | va_start(ap, format); | ||
493 | |||
494 | vsnprintf(str, size, format, ap); | ||
495 | str[size - 1] = 0; | ||
496 | |||
497 | va_end(ap); | ||
498 | } | ||
499 | |||
500 | static char * | ||
501 | _eina_file_escape(const char *path, int *length) | ||
502 | { | ||
503 | char *result = strdup(path ? path : ""); | ||
504 | char *p = result; | ||
505 | char *q = result; | ||
506 | int len; | ||
507 | |||
508 | if (!result) | ||
509 | return NULL; | ||
510 | |||
511 | if (length) len = *length; | ||
512 | else len = strlen(result); | ||
513 | |||
514 | while ((p = strchr(p, '/'))) | ||
515 | { | ||
516 | // remove double `/' | ||
517 | if (p[1] == '/') | ||
518 | { | ||
519 | memmove(p, p + 1, --len - (p - result)); | ||
520 | result[len] = '\0'; | ||
521 | } | ||
522 | else | ||
523 | if (p[1] == '.' | ||
524 | && p[2] == '.') | ||
525 | { | ||
526 | // remove `/../' | ||
527 | if (p[3] == '/') | ||
528 | { | ||
529 | char tmp; | ||
530 | |||
531 | len -= p + 3 - q; | ||
532 | memmove(q, p + 3, len - (q - result)); | ||
533 | result[len] = '\0'; | ||
534 | p = q; | ||
535 | |||
536 | /* Update q correctly. */ | ||
537 | tmp = *p; | ||
538 | *p = '\0'; | ||
539 | q = strrchr(result, '/'); | ||
540 | if (!q) q = result; | ||
541 | *p = tmp; | ||
542 | } | ||
543 | else | ||
544 | // remove '/..$' | ||
545 | if (p[3] == '\0') | ||
546 | { | ||
547 | len -= p + 2 - q; | ||
548 | result[len] = '\0'; | ||
549 | q = p; | ||
550 | ++p; | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | q = p; | ||
555 | ++p; | ||
556 | } | ||
557 | } | ||
558 | else | ||
559 | { | ||
560 | q = p; | ||
561 | ++p; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (length) | ||
566 | *length = len; | ||
567 | return result; | ||
568 | } | ||
569 | |||
570 | /** | ||
571 | * @endcond | ||
572 | */ | ||
573 | |||
574 | /*============================================================================* | ||
575 | * Global * | ||
576 | *============================================================================*/ | ||
577 | |||
578 | Eina_Bool | ||
579 | eina_file_init(void) | ||
580 | { | ||
581 | _eina_file_log_dom = eina_log_domain_register("eina_file", | ||
582 | EINA_LOG_COLOR_DEFAULT); | ||
583 | if (_eina_file_log_dom < 0) | ||
584 | { | ||
585 | EINA_LOG_ERR("Could not register log domain: eina_file"); | ||
586 | return EINA_FALSE; | ||
587 | } | ||
588 | |||
589 | _eina_file_cache = eina_hash_string_djb2_new(NULL); | ||
590 | if (!_eina_file_cache) | ||
591 | { | ||
592 | ERR("Could not create cache."); | ||
593 | eina_log_domain_unregister(_eina_file_log_dom); | ||
594 | _eina_file_log_dom = -1; | ||
595 | return EINA_FALSE; | ||
596 | } | ||
597 | |||
598 | eina_lock_new(&_eina_file_lock_cache); | ||
599 | |||
600 | return EINA_TRUE; | ||
601 | } | ||
602 | |||
603 | Eina_Bool | ||
604 | eina_file_shutdown(void) | ||
605 | { | ||
606 | if (eina_hash_population(_eina_file_cache) > 0) | ||
607 | { | ||
608 | Eina_Iterator *it; | ||
609 | const char *key; | ||
610 | |||
611 | it = eina_hash_iterator_key_new(_eina_file_cache); | ||
612 | EINA_ITERATOR_FOREACH(it, key) | ||
613 | ERR("File [%s] still open !", key); | ||
614 | eina_iterator_free(it); | ||
615 | } | ||
616 | |||
617 | eina_hash_free(_eina_file_cache); | ||
618 | |||
619 | eina_lock_free(&_eina_file_lock_cache); | ||
620 | |||
621 | eina_log_domain_unregister(_eina_file_log_dom); | ||
622 | _eina_file_log_dom = -1; | ||
623 | return EINA_TRUE; | ||
624 | } | ||
625 | |||
626 | void | ||
627 | eina_file_mmap_faulty(void *addr, long page_size) | ||
628 | { | ||
629 | Eina_File_Map *m; | ||
630 | Eina_File *f; | ||
631 | Eina_Iterator *itf; | ||
632 | Eina_Iterator *itm; | ||
633 | |||
634 | /* NOTE: I actually don't know if other thread are running, I will try to take the lock. | ||
635 | It may be possible that if other thread are not running and they were in the middle of | ||
636 | accessing an Eina_File this lock are still taken and we will result as a deadlock. */ | ||
637 | eina_lock_take(&_eina_file_lock_cache); | ||
638 | |||
639 | itf = eina_hash_iterator_data_new(_eina_file_cache); | ||
640 | EINA_ITERATOR_FOREACH(itf, f) | ||
641 | { | ||
642 | Eina_Bool faulty = EINA_FALSE; | ||
643 | |||
644 | eina_lock_take(&f->lock); | ||
645 | |||
646 | if (f->global_map) | ||
647 | { | ||
648 | if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) && | ||
649 | (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map) | ||
650 | { | ||
651 | f->global_faulty = EINA_TRUE; | ||
652 | faulty = EINA_TRUE; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | if (!faulty) | ||
657 | { | ||
658 | itm = eina_hash_iterator_data_new(f->map); | ||
659 | EINA_ITERATOR_FOREACH(itm, m) | ||
660 | { | ||
661 | if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) && | ||
662 | (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map) | ||
663 | { | ||
664 | m->faulty = EINA_TRUE; | ||
665 | faulty = EINA_TRUE; | ||
666 | break; | ||
667 | } | ||
668 | } | ||
669 | eina_iterator_free(itm); | ||
670 | } | ||
671 | |||
672 | eina_lock_release(&f->lock); | ||
673 | |||
674 | if (faulty) break; | ||
675 | } | ||
676 | eina_iterator_free(itf); | ||
677 | |||
678 | eina_lock_release(&_eina_file_lock_cache); | ||
679 | } | ||
680 | |||
681 | /*============================================================================* | ||
682 | * API * | ||
683 | *============================================================================*/ | ||
684 | |||
685 | EAPI char * | ||
686 | eina_file_path_sanitize(const char *path) | ||
687 | { | ||
688 | char *result = NULL; | ||
689 | int len; | ||
690 | |||
691 | if (!path) return NULL; | ||
692 | |||
693 | len = strlen(path); | ||
694 | |||
695 | if (*path != '/') | ||
696 | { | ||
697 | char cwd[PATH_MAX]; | ||
698 | char *tmp = NULL; | ||
699 | |||
700 | tmp = getcwd(cwd, PATH_MAX); | ||
701 | if (!tmp) return NULL; | ||
702 | |||
703 | len += strlen(cwd) + 2; | ||
704 | tmp = alloca(sizeof (char) * len); | ||
705 | |||
706 | slprintf(tmp, len, "%s/%s", cwd, path); | ||
707 | |||
708 | result = tmp; | ||
709 | } | ||
710 | |||
711 | return _eina_file_escape(result ? result : path, &len); | ||
712 | } | ||
713 | |||
714 | EAPI Eina_Bool | ||
715 | eina_file_dir_list(const char *dir, | ||
716 | Eina_Bool recursive, | ||
717 | Eina_File_Dir_List_Cb cb, | ||
718 | void *data) | ||
719 | { | ||
720 | Eina_File_Direct_Info *info; | ||
721 | Eina_Iterator *it; | ||
722 | |||
723 | EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); | ||
724 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE); | ||
725 | EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE); | ||
726 | |||
727 | it = eina_file_stat_ls(dir); | ||
728 | if (!it) | ||
729 | return EINA_FALSE; | ||
730 | |||
731 | EINA_ITERATOR_FOREACH(it, info) | ||
732 | { | ||
733 | cb(info->path + info->name_start, dir, data); | ||
734 | |||
735 | if (recursive == EINA_TRUE && info->type == EINA_FILE_DIR) | ||
736 | { | ||
737 | eina_file_dir_list(info->path, recursive, cb, data); | ||
738 | } | ||
739 | } | ||
740 | |||
741 | eina_iterator_free(it); | ||
742 | |||
743 | return EINA_TRUE; | ||
744 | } | ||
745 | |||
746 | EAPI Eina_Array * | ||
747 | eina_file_split(char *path) | ||
748 | { | ||
749 | Eina_Array *ea; | ||
750 | char *current; | ||
751 | size_t length; | ||
752 | |||
753 | EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); | ||
754 | |||
755 | ea = eina_array_new(16); | ||
756 | |||
757 | if (!ea) | ||
758 | return NULL; | ||
759 | |||
760 | for (current = strchr(path, PATH_DELIM); | ||
761 | current; | ||
762 | path = current + 1, current = strchr(path, PATH_DELIM)) | ||
763 | { | ||
764 | length = current - path; | ||
765 | |||
766 | if (length <= 0) | ||
767 | continue; | ||
768 | |||
769 | eina_array_push(ea, path); | ||
770 | *current = '\0'; | ||
771 | } | ||
772 | |||
773 | if (*path != '\0') | ||
774 | eina_array_push(ea, path); | ||
775 | |||
776 | return ea; | ||
777 | } | ||
778 | |||
779 | EAPI Eina_Iterator * | ||
780 | eina_file_ls(const char *dir) | ||
781 | { | ||
782 | #ifdef HAVE_DIRENT_H | ||
783 | Eina_File_Iterator *it; | ||
784 | size_t length; | ||
785 | |||
786 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); | ||
787 | |||
788 | length = strlen(dir); | ||
789 | if (length < 1) | ||
790 | return NULL; | ||
791 | |||
792 | it = calloc(1, sizeof (Eina_File_Iterator) + length); | ||
793 | if (!it) | ||
794 | return NULL; | ||
795 | |||
796 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
797 | |||
798 | it->dirp = opendir(dir); | ||
799 | if (!it->dirp) | ||
800 | { | ||
801 | free(it); | ||
802 | return NULL; | ||
803 | } | ||
804 | |||
805 | memcpy(it->dir, dir, length + 1); | ||
806 | if (dir[length - 1] != '/') | ||
807 | it->length = length; | ||
808 | else | ||
809 | it->length = length - 1; | ||
810 | |||
811 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
812 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next); | ||
813 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER( | ||
814 | _eina_file_ls_iterator_container); | ||
815 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free); | ||
816 | |||
817 | return &it->iterator; | ||
818 | #else | ||
819 | (void) dir; | ||
820 | return NULL; | ||
821 | #endif | ||
822 | } | ||
823 | |||
824 | EAPI Eina_Iterator * | ||
825 | eina_file_direct_ls(const char *dir) | ||
826 | { | ||
827 | #ifdef HAVE_DIRENT_H | ||
828 | Eina_File_Direct_Iterator *it; | ||
829 | size_t length; | ||
830 | |||
831 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); | ||
832 | |||
833 | length = strlen(dir); | ||
834 | if (length < 1) | ||
835 | return NULL; | ||
836 | |||
837 | it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); | ||
838 | if (!it) | ||
839 | return NULL; | ||
840 | |||
841 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
842 | |||
843 | it->dirp = opendir(dir); | ||
844 | if (!it->dirp) | ||
845 | { | ||
846 | free(it); | ||
847 | return NULL; | ||
848 | } | ||
849 | |||
850 | if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX) | ||
851 | { | ||
852 | _eina_file_direct_ls_iterator_free(it); | ||
853 | return NULL; | ||
854 | } | ||
855 | |||
856 | memcpy(it->dir, dir, length + 1); | ||
857 | it->length = length; | ||
858 | |||
859 | memcpy(it->info.path, dir, length); | ||
860 | if (dir[length - 1] == '/') | ||
861 | it->info.name_start = length; | ||
862 | else | ||
863 | { | ||
864 | it->info.path[length] = '/'; | ||
865 | it->info.name_start = length + 1; | ||
866 | } | ||
867 | |||
868 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
869 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next); | ||
870 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER( | ||
871 | _eina_file_direct_ls_iterator_container); | ||
872 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free); | ||
873 | |||
874 | return &it->iterator; | ||
875 | #else | ||
876 | (void) dir; | ||
877 | return NULL; | ||
878 | #endif | ||
879 | } | ||
880 | |||
881 | EAPI Eina_Iterator * | ||
882 | eina_file_stat_ls(const char *dir) | ||
883 | { | ||
884 | #ifdef HAVE_DIRENT_H | ||
885 | Eina_File_Direct_Iterator *it; | ||
886 | size_t length; | ||
887 | |||
888 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); | ||
889 | |||
890 | length = strlen(dir); | ||
891 | if (length < 1) | ||
892 | return NULL; | ||
893 | |||
894 | it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); | ||
895 | if (!it) | ||
896 | return NULL; | ||
897 | |||
898 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
899 | |||
900 | it->dirp = opendir(dir); | ||
901 | if (!it->dirp) | ||
902 | { | ||
903 | free(it); | ||
904 | return NULL; | ||
905 | } | ||
906 | |||
907 | if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX) | ||
908 | { | ||
909 | _eina_file_direct_ls_iterator_free(it); | ||
910 | return NULL; | ||
911 | } | ||
912 | |||
913 | memcpy(it->dir, dir, length + 1); | ||
914 | it->length = length; | ||
915 | |||
916 | memcpy(it->info.path, dir, length); | ||
917 | if (dir[length - 1] == '/') | ||
918 | it->info.name_start = length; | ||
919 | else | ||
920 | { | ||
921 | it->info.path[length] = '/'; | ||
922 | it->info.name_start = length + 1; | ||
923 | } | ||
924 | |||
925 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
926 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_stat_ls_iterator_next); | ||
927 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER( | ||
928 | _eina_file_direct_ls_iterator_container); | ||
929 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free); | ||
930 | |||
931 | return &it->iterator; | ||
932 | #else | ||
933 | (void) dir; | ||
934 | return NULL; | ||
935 | #endif | ||
936 | } | ||
937 | |||
938 | EAPI Eina_File * | ||
939 | eina_file_open(const char *path, Eina_Bool shared) | ||
940 | { | ||
941 | Eina_File *file; | ||
942 | Eina_File *n; | ||
943 | char *filename; | ||
944 | struct stat file_stat; | ||
945 | int fd = -1; | ||
946 | #ifdef HAVE_EXECVP | ||
947 | int flags; | ||
948 | #endif | ||
949 | |||
950 | EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); | ||
951 | |||
952 | filename = eina_file_path_sanitize(path); | ||
953 | if (!filename) return NULL; | ||
954 | |||
955 | if (shared) | ||
956 | #ifdef HAVE_SHMOPEN | ||
957 | fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); | ||
958 | #else | ||
959 | goto on_error; | ||
960 | #endif | ||
961 | else | ||
962 | fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); | ||
963 | |||
964 | if (fd < 0) goto on_error; | ||
965 | |||
966 | #ifdef HAVE_EXECVP | ||
967 | flags = fcntl(fd, F_GETFD); | ||
968 | if (flags == -1) | ||
969 | goto on_error; | ||
970 | |||
971 | flags |= FD_CLOEXEC; | ||
972 | if (fcntl(fd, F_SETFD, flags) == -1) | ||
973 | goto on_error; | ||
974 | #endif | ||
975 | |||
976 | if (fstat(fd, &file_stat)) | ||
977 | goto on_error; | ||
978 | |||
979 | eina_lock_take(&_eina_file_lock_cache); | ||
980 | |||
981 | file = eina_hash_find(_eina_file_cache, filename); | ||
982 | if ((file) && !_eina_file_timestamp_compare(file, &file_stat)) | ||
983 | { | ||
984 | file->delete_me = EINA_TRUE; | ||
985 | eina_hash_del(_eina_file_cache, file->filename, file); | ||
986 | _eina_file_real_close(file); | ||
987 | file = NULL; | ||
988 | } | ||
989 | |||
990 | if (!file) | ||
991 | { | ||
992 | n = malloc(sizeof (Eina_File) + strlen(filename) + 1); | ||
993 | if (!n) | ||
994 | { | ||
995 | eina_lock_release(&_eina_file_lock_cache); | ||
996 | goto on_error; | ||
997 | } | ||
998 | |||
999 | n->filename = (char*) (n + 1); | ||
1000 | strcpy((char*) n->filename, filename); | ||
1001 | n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), | ||
1002 | EINA_KEY_CMP(_eina_file_map_key_cmp), | ||
1003 | EINA_KEY_HASH(_eina_file_map_key_hash), | ||
1004 | EINA_FREE_CB(_eina_file_map_close), | ||
1005 | 3); | ||
1006 | n->rmap = eina_hash_pointer_new(NULL); | ||
1007 | n->global_map = MAP_FAILED; | ||
1008 | n->global_refcount = 0; | ||
1009 | n->length = file_stat.st_size; | ||
1010 | n->mtime = file_stat.st_mtime; | ||
1011 | #ifdef _STAT_VER_LINUX | ||
1012 | # if (defined __USE_MISC && defined st_mtime) | ||
1013 | n->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec; | ||
1014 | # else | ||
1015 | n->mtime_nsec = (unsigned long int)file_stat.st_mtimensec; | ||
1016 | # endif | ||
1017 | #endif | ||
1018 | n->inode = file_stat.st_ino; | ||
1019 | n->refcount = 0; | ||
1020 | n->fd = fd; | ||
1021 | n->shared = shared; | ||
1022 | n->delete_me = EINA_FALSE; | ||
1023 | eina_lock_new(&n->lock); | ||
1024 | eina_hash_direct_add(_eina_file_cache, n->filename, n); | ||
1025 | } | ||
1026 | else | ||
1027 | { | ||
1028 | close(fd); | ||
1029 | n = file; | ||
1030 | } | ||
1031 | eina_lock_take(&n->lock); | ||
1032 | n->refcount++; | ||
1033 | eina_lock_release(&n->lock); | ||
1034 | |||
1035 | eina_lock_release(&_eina_file_lock_cache); | ||
1036 | |||
1037 | free(filename); | ||
1038 | |||
1039 | return n; | ||
1040 | |||
1041 | on_error: | ||
1042 | free(filename); | ||
1043 | if (fd >= 0) close(fd); | ||
1044 | return NULL; | ||
1045 | } | ||
1046 | |||
1047 | EAPI void | ||
1048 | eina_file_close(Eina_File *file) | ||
1049 | { | ||
1050 | EINA_SAFETY_ON_NULL_RETURN(file); | ||
1051 | |||
1052 | eina_lock_take(&file->lock); | ||
1053 | file->refcount--; | ||
1054 | eina_lock_release(&file->lock); | ||
1055 | |||
1056 | if (file->refcount != 0) return; | ||
1057 | eina_lock_take(&_eina_file_lock_cache); | ||
1058 | |||
1059 | eina_hash_del(_eina_file_cache, file->filename, file); | ||
1060 | _eina_file_real_close(file); | ||
1061 | |||
1062 | eina_lock_release(&_eina_file_lock_cache); | ||
1063 | } | ||
1064 | |||
1065 | EAPI size_t | ||
1066 | eina_file_size_get(Eina_File *file) | ||
1067 | { | ||
1068 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); | ||
1069 | return file->length; | ||
1070 | } | ||
1071 | |||
1072 | EAPI time_t | ||
1073 | eina_file_mtime_get(Eina_File *file) | ||
1074 | { | ||
1075 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); | ||
1076 | return file->mtime; | ||
1077 | } | ||
1078 | |||
1079 | EAPI const char * | ||
1080 | eina_file_filename_get(Eina_File *file) | ||
1081 | { | ||
1082 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1083 | return file->filename; | ||
1084 | } | ||
1085 | |||
1086 | EAPI void * | ||
1087 | eina_file_map_all(Eina_File *file, Eina_File_Populate rule) | ||
1088 | { | ||
1089 | int flags = MAP_SHARED; | ||
1090 | void *ret = NULL; | ||
1091 | |||
1092 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1093 | |||
1094 | // bsd people will lack this feature | ||
1095 | #ifdef MAP_POPULATE | ||
1096 | if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; | ||
1097 | #endif | ||
1098 | #ifdef MAP_HUGETLB | ||
1099 | if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB; | ||
1100 | #endif | ||
1101 | |||
1102 | eina_mmap_safety_enabled_set(EINA_TRUE); | ||
1103 | eina_lock_take(&file->lock); | ||
1104 | if (file->global_map == MAP_FAILED) | ||
1105 | file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0); | ||
1106 | #ifdef MAP_HUGETLB | ||
1107 | if ((file->global_map == MAP_FAILED) && (flags & MAP_HUGETLB)) | ||
1108 | { | ||
1109 | flags &= ~MAP_HUGETLB; | ||
1110 | file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0); | ||
1111 | } | ||
1112 | #endif | ||
1113 | |||
1114 | if (file->global_map != MAP_FAILED) | ||
1115 | { | ||
1116 | Eina_Bool hugetlb = EINA_FALSE; | ||
1117 | |||
1118 | #ifdef MAP_HUGETLB | ||
1119 | hugetlb = !!(flags & MAP_HUGETLB); | ||
1120 | #endif | ||
1121 | _eina_file_map_rule_apply(rule, file->global_map, file->length, hugetlb); | ||
1122 | file->global_refcount++; | ||
1123 | ret = file->global_map; | ||
1124 | } | ||
1125 | |||
1126 | eina_lock_release(&file->lock); | ||
1127 | return ret; | ||
1128 | } | ||
1129 | |||
1130 | EAPI void * | ||
1131 | eina_file_map_new(Eina_File *file, Eina_File_Populate rule, | ||
1132 | unsigned long int offset, unsigned long int length) | ||
1133 | { | ||
1134 | Eina_File_Map *map; | ||
1135 | unsigned long int key[2]; | ||
1136 | |||
1137 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1138 | |||
1139 | if (offset > file->length) | ||
1140 | return NULL; | ||
1141 | if (offset + length > file->length) | ||
1142 | return NULL; | ||
1143 | |||
1144 | if (offset == 0 && length == file->length) | ||
1145 | return eina_file_map_all(file, rule); | ||
1146 | |||
1147 | key[0] = offset; | ||
1148 | key[1] = length; | ||
1149 | |||
1150 | eina_mmap_safety_enabled_set(EINA_TRUE); | ||
1151 | eina_lock_take(&file->lock); | ||
1152 | |||
1153 | map = eina_hash_find(file->map, &key); | ||
1154 | if (!map) | ||
1155 | { | ||
1156 | int flags = MAP_SHARED; | ||
1157 | |||
1158 | // bsd people will lack this feature | ||
1159 | #ifdef MAP_POPULATE | ||
1160 | if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; | ||
1161 | #endif | ||
1162 | #ifdef MAP_HUGETLB | ||
1163 | if (length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB; | ||
1164 | #endif | ||
1165 | |||
1166 | map = malloc(sizeof (Eina_File_Map)); | ||
1167 | if (!map) goto on_error; | ||
1168 | |||
1169 | map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset); | ||
1170 | #ifdef MAP_HUGETLB | ||
1171 | if (map->map == MAP_FAILED && (flags & MAP_HUGETLB)) | ||
1172 | { | ||
1173 | flags &= ~MAP_HUGETLB; | ||
1174 | map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset); | ||
1175 | } | ||
1176 | |||
1177 | map->hugetlb = !!(flags & MAP_HUGETLB); | ||
1178 | #else | ||
1179 | map->hugetlb = EINA_FALSE; | ||
1180 | #endif | ||
1181 | map->offset = offset; | ||
1182 | map->length = length; | ||
1183 | map->refcount = 0; | ||
1184 | |||
1185 | if (map->map == MAP_FAILED) goto on_error; | ||
1186 | |||
1187 | eina_hash_add(file->map, &key, map); | ||
1188 | eina_hash_direct_add(file->rmap, map->map, map); | ||
1189 | } | ||
1190 | |||
1191 | map->refcount++; | ||
1192 | |||
1193 | _eina_file_map_rule_apply(rule, map->map, length, map->hugetlb); | ||
1194 | |||
1195 | eina_lock_release(&file->lock); | ||
1196 | |||
1197 | return map->map; | ||
1198 | |||
1199 | on_error: | ||
1200 | free(map); | ||
1201 | eina_lock_release(&file->lock); | ||
1202 | |||
1203 | return NULL; | ||
1204 | } | ||
1205 | |||
1206 | EAPI void | ||
1207 | eina_file_map_free(Eina_File *file, void *map) | ||
1208 | { | ||
1209 | EINA_SAFETY_ON_NULL_RETURN(file); | ||
1210 | |||
1211 | eina_lock_take(&file->lock); | ||
1212 | |||
1213 | if (file->global_map == map) | ||
1214 | { | ||
1215 | file->global_refcount--; | ||
1216 | |||
1217 | if (file->global_refcount > 0) goto on_exit; | ||
1218 | |||
1219 | munmap(file->global_map, file->length); | ||
1220 | file->global_map = MAP_FAILED; | ||
1221 | } | ||
1222 | else | ||
1223 | { | ||
1224 | Eina_File_Map *em; | ||
1225 | unsigned long int key[2]; | ||
1226 | |||
1227 | em = eina_hash_find(file->rmap, &map); | ||
1228 | if (!em) goto on_exit; | ||
1229 | |||
1230 | em->refcount--; | ||
1231 | |||
1232 | if (em->refcount > 0) goto on_exit; | ||
1233 | |||
1234 | key[0] = em->offset; | ||
1235 | key[1] = em->length; | ||
1236 | |||
1237 | eina_hash_del(file->rmap, &map, em); | ||
1238 | eina_hash_del(file->map, &key, em); | ||
1239 | } | ||
1240 | |||
1241 | on_exit: | ||
1242 | eina_lock_release(&file->lock); | ||
1243 | } | ||
1244 | |||
1245 | EAPI Eina_Bool | ||
1246 | eina_file_map_faulted(Eina_File *file, void *map) | ||
1247 | { | ||
1248 | Eina_File_Map *em; | ||
1249 | Eina_Bool r = EINA_FALSE; | ||
1250 | |||
1251 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); | ||
1252 | |||
1253 | eina_lock_take(&file->lock); | ||
1254 | |||
1255 | if (file->global_map == map) | ||
1256 | { | ||
1257 | r = file->global_faulty; | ||
1258 | } | ||
1259 | else | ||
1260 | { | ||
1261 | em = eina_hash_find(file->rmap, &map); | ||
1262 | if (em) r = em->faulty; | ||
1263 | } | ||
1264 | |||
1265 | eina_lock_release(&file->lock); | ||
1266 | |||
1267 | return r; | ||
1268 | } | ||
1269 | |||
1270 | EAPI Eina_Iterator * | ||
1271 | eina_file_xattr_get(Eina_File *file) | ||
1272 | { | ||
1273 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1274 | |||
1275 | return eina_xattr_fd_ls(file->fd); | ||
1276 | } | ||
1277 | |||
1278 | EAPI Eina_Iterator * | ||
1279 | eina_file_xattr_value_get(Eina_File *file) | ||
1280 | { | ||
1281 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1282 | |||
1283 | return eina_xattr_value_fd_ls(file->fd); | ||
1284 | } | ||
1285 | |||
1286 | EAPI int | ||
1287 | eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st) | ||
1288 | { | ||
1289 | struct stat buf; | ||
1290 | #ifdef HAVE_FSTATAT | ||
1291 | int fd; | ||
1292 | #endif | ||
1293 | |||
1294 | EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1); | ||
1295 | EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1); | ||
1296 | |||
1297 | #ifdef HAVE_FSTATAT | ||
1298 | fd = dirfd((DIR*) container); | ||
1299 | if (fstatat(fd, info->path + info->name_start, &buf, 0)) | ||
1300 | #else | ||
1301 | (void)container; | ||
1302 | if (stat(info->path, &buf)) | ||
1303 | #endif | ||
1304 | { | ||
1305 | if (info->type != EINA_FILE_LNK) | ||
1306 | info->type = EINA_FILE_UNKNOWN; | ||
1307 | return -1; | ||
1308 | } | ||
1309 | |||
1310 | if (info->type == EINA_FILE_UNKNOWN) | ||
1311 | { | ||
1312 | if (S_ISREG(buf.st_mode)) | ||
1313 | info->type = EINA_FILE_REG; | ||
1314 | else if (S_ISDIR(buf.st_mode)) | ||
1315 | info->type = EINA_FILE_DIR; | ||
1316 | else if (S_ISCHR(buf.st_mode)) | ||
1317 | info->type = EINA_FILE_CHR; | ||
1318 | else if (S_ISBLK(buf.st_mode)) | ||
1319 | info->type = EINA_FILE_BLK; | ||
1320 | else if (S_ISFIFO(buf.st_mode)) | ||
1321 | info->type = EINA_FILE_FIFO; | ||
1322 | else if (S_ISLNK(buf.st_mode)) | ||
1323 | info->type = EINA_FILE_LNK; | ||
1324 | else if (S_ISSOCK(buf.st_mode)) | ||
1325 | info->type = EINA_FILE_SOCK; | ||
1326 | else | ||
1327 | info->type = EINA_FILE_UNKNOWN; | ||
1328 | } | ||
1329 | |||
1330 | st->dev = buf.st_dev; | ||
1331 | st->ino = buf.st_ino; | ||
1332 | st->mode = buf.st_mode; | ||
1333 | st->nlink = buf.st_nlink; | ||
1334 | st->uid = buf.st_uid; | ||
1335 | st->gid = buf.st_gid; | ||
1336 | st->rdev = buf.st_rdev; | ||
1337 | st->size = buf.st_size; | ||
1338 | st->blksize = buf.st_blksize; | ||
1339 | st->blocks = buf.st_blocks; | ||
1340 | st->atime = buf.st_atime; | ||
1341 | st->mtime = buf.st_mtime; | ||
1342 | st->ctime = buf.st_ctime; | ||
1343 | #ifdef _STAT_VER_LINUX | ||
1344 | # if (defined __USE_MISC && defined st_mtime) | ||
1345 | st->atimensec = buf.st_atim.tv_nsec; | ||
1346 | st->mtimensec = buf.st_mtim.tv_nsec; | ||
1347 | st->ctimensec = buf.st_ctim.tv_nsec; | ||
1348 | # else | ||
1349 | st->atimensec = buf.st_atimensec; | ||
1350 | st->mtimensec = buf.st_mtimensec; | ||
1351 | st->ctimensec = buf.st_ctimensec; | ||
1352 | # endif | ||
1353 | #else | ||
1354 | st->atimensec = 0; | ||
1355 | st->mtimensec = 0; | ||
1356 | st->ctimensec = 0; | ||
1357 | #endif | ||
1358 | return 0; | ||
1359 | } | ||