1 /* EINA - EFL data type library
2 * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
3 * Copyright (C) 2010-2011 Cedric Bail
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.
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.
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/>.
26 #elif defined __GNUC__
27 # define alloca __builtin_alloca
29 # define alloca __alloca
30 #elif defined _MSC_VER
32 # define alloca _alloca
38 void *alloca (size_t);
48 #include <sys/types.h>
51 #ifdef HAVE_SYS_MMAN_H
52 # include <sys/mman.h>
56 #define PATH_DELIM '/'
58 #include "eina_config.h"
59 #include "eina_private.h"
61 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
62 #include "eina_safety_checks.h"
63 #include "eina_file.h"
64 #include "eina_stringshare.h"
65 #include "eina_hash.h"
66 #include "eina_list.h"
67 #include "eina_lock.h"
68 #include "eina_mmap.h"
70 #include "eina_xattr.h"
76 /*============================================================================*
78 *============================================================================*/
84 #ifndef EINA_LOG_COLOR_DEFAULT
85 #define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
91 #define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__)
96 #define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__)
101 #define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__)
103 #define EINA_SMALL_PAGE 4096
104 # define EINA_HUGE_PAGE 16 * 1024 * 1024
107 typedef struct _Eina_File_Iterator Eina_File_Iterator;
108 struct _Eina_File_Iterator
110 Eina_Iterator iterator;
121 const char *filename;
129 unsigned long long length;
132 #ifdef _STAT_VER_LINUX
133 unsigned long int mtime_nsec;
141 Eina_Bool shared : 1;
142 Eina_Bool delete_me : 1;
143 Eina_Bool global_faulty : 1;
146 typedef struct _Eina_File_Map Eina_File_Map;
147 struct _Eina_File_Map
151 unsigned long int offset;
152 unsigned long int length;
156 Eina_Bool hugetlb : 1;
157 Eina_Bool faulty : 1;
160 static Eina_Hash *_eina_file_cache = NULL;
161 static Eina_Lock _eina_file_lock_cache;
163 static int _eina_file_log_dom = -1;
166 * This complex piece of code is needed due to possible race condition.
167 * The code and description of the issue can be found at :
168 * http://womble.decadent.org.uk/readdir_r-advisory.html
172 _eina_name_max(DIR *dirp)
176 #if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
177 name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
181 # if defined(NAME_MAX)
182 name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
188 # if defined(NAME_MAX)
189 name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
192 # warning "buffer size for readdir_r cannot be determined safely, best effort, but racy"
193 name_max = pathconf(dirp, _PC_NAME_MAX);
195 # error "buffer size for readdir_r cannot be determined safely"
204 _eina_dirent_buffer_size(DIR *dirp)
206 long name_max = _eina_name_max(dirp);
209 name_end = (size_t) offsetof(struct dirent, d_name) + name_max + 1;
211 return (name_end > sizeof (struct dirent) ? name_end : sizeof (struct dirent));
215 _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
221 dp = alloca(_eina_dirent_buffer_size(it->dirp));
225 if (readdir_r(it->dirp, dp, &dp))
230 while ((dp->d_name[0] == '.') &&
231 ((dp->d_name[1] == '\0') ||
232 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
234 #ifdef _DIRENT_HAVE_D_NAMLEN
235 length = dp->d_namlen;
237 length = strlen(dp->d_name);
239 name = alloca(length + 2 + it->length);
241 memcpy(name, it->dir, it->length);
242 memcpy(name + it->length, "/", 1);
243 memcpy(name + it->length + 1, dp->d_name, length + 1);
245 *data = (char *)eina_stringshare_add(name);
250 _eina_file_ls_iterator_container(Eina_File_Iterator *it)
256 _eina_file_ls_iterator_free(Eina_File_Iterator *it)
260 EINA_MAGIC_SET(&it->iterator, 0);
264 typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
265 struct _Eina_File_Direct_Iterator
267 Eina_Iterator iterator;
272 Eina_File_Direct_Info info;
278 _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
283 dp = alloca(_eina_dirent_buffer_size(it->dirp));
287 if (readdir_r(it->dirp, dp, &dp))
292 #ifdef _DIRENT_HAVE_D_NAMLEN
293 length = dp->d_namlen;
295 length = strlen(dp->d_name);
297 if (it->info.name_start + length + 1 >= EINA_PATH_MAX)
300 while ((dp->d_name[0] == '.') &&
301 ((dp->d_name[1] == '\0') ||
302 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
304 memcpy(it->info.path + it->info.name_start, dp->d_name, length);
305 it->info.name_length = length;
306 it->info.path_length = it->info.name_start + length;
307 it->info.path[it->info.path_length] = '\0';
309 #ifdef _DIRENT_HAVE_D_TYPE
313 it->info.type = EINA_FILE_FIFO;
316 it->info.type = EINA_FILE_CHR;
319 it->info.type = EINA_FILE_DIR;
322 it->info.type = EINA_FILE_BLK;
325 it->info.type = EINA_FILE_REG;
328 it->info.type = EINA_FILE_LNK;
331 it->info.type = EINA_FILE_SOCK;
334 it->info.type = EINA_FILE_WHT;
337 it->info.type = EINA_FILE_UNKNOWN;
341 it->info.type = EINA_FILE_UNKNOWN;
349 _eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
355 _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
359 EINA_MAGIC_SET(&it->iterator, 0);
364 _eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
368 if (!_eina_file_direct_ls_iterator_next(it, data))
371 if (it->info.type == EINA_FILE_UNKNOWN)
373 if (eina_file_statat(it->dirp, &it->info, &st) != 0)
374 it->info.type = EINA_FILE_UNKNOWN;
382 _eina_file_real_close(Eina_File *file)
384 if (file->refcount != 0) return;
386 eina_hash_free(file->rmap);
387 eina_hash_free(file->map);
389 if (file->global_map != MAP_FAILED)
390 munmap(file->global_map, file->length);
398 _eina_file_map_close(Eina_File_Map *map)
400 munmap(map->map, map->length);
405 _eina_file_map_key_length(const void *key __UNUSED__)
407 return sizeof (unsigned long int) * 2;
411 _eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__,
412 const unsigned long int *key2, int key2_length __UNUSED__)
414 if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
415 return key1[0] - key2[0];
419 _eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__)
421 return eina_hash_int64(&key[0], sizeof (unsigned long int))
422 ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
427 _eina_file_map_populate(char *map, unsigned int size, Eina_Bool hugetlb)
429 unsigned int r = 0xDEADBEEF;
433 s = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE;
435 for (i = 0; i < size; i += s)
445 _eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int size, Eina_Bool hugetlb)
448 int flag = MADV_RANDOM;
452 case EINA_FILE_RANDOM: flag = MADV_RANDOM; break;
453 case EINA_FILE_SEQUENTIAL: flag = MADV_SEQUENTIAL; break;
454 case EINA_FILE_POPULATE: flag = MADV_WILLNEED; break;
455 case EINA_FILE_WILLNEED: flag = MADV_WILLNEED; break;
458 madvise(addr, size, flag);
461 if (rule == EINA_FILE_POPULATE)
462 tmp ^= _eina_file_map_populate(addr, size, hugetlb);
471 _eina_file_timestamp_compare(Eina_File *f, struct stat *st)
473 if (f->mtime != st->st_mtime) return EINA_FALSE;
474 if (f->length != (unsigned long long) st->st_size) return EINA_FALSE;
475 if (f->inode != st->st_ino) return EINA_FALSE;
476 #ifdef _STAT_VER_LINUX
477 # if (defined __USE_MISC && defined st_mtime)
478 if (f->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
481 if (f->mtime_nsec != (unsigned long int)st->st_mtimensec)
489 slprintf(char *str, size_t size, const char *format, ...)
493 va_start(ap, format);
495 vsnprintf(str, size, format, ap);
502 _eina_file_escape(const char *path, int *length)
509 result = strdup(path ? path : "");
516 if (length) len = *length;
517 else len = strlen(result);
519 while ((p = strchr(p, '/')))
524 memmove(p, p + 1, --len - (p - result));
537 memmove(q, p + 3, len - (q - result));
541 /* Update q correctly. */
544 q = strrchr(result, '/');
579 /*============================================================================*
581 *============================================================================*/
586 _eina_file_log_dom = eina_log_domain_register("eina_file",
587 EINA_LOG_COLOR_DEFAULT);
588 if (_eina_file_log_dom < 0)
590 EINA_LOG_ERR("Could not register log domain: eina_file");
594 _eina_file_cache = eina_hash_string_djb2_new(NULL);
595 if (!_eina_file_cache)
597 ERR("Could not create cache.");
598 eina_log_domain_unregister(_eina_file_log_dom);
599 _eina_file_log_dom = -1;
603 eina_lock_new(&_eina_file_lock_cache);
609 eina_file_shutdown(void)
611 if (eina_hash_population(_eina_file_cache) > 0)
616 it = eina_hash_iterator_key_new(_eina_file_cache);
617 EINA_ITERATOR_FOREACH(it, key)
618 ERR("File [%s] still open !", key);
619 eina_iterator_free(it);
622 eina_hash_free(_eina_file_cache);
624 eina_lock_free(&_eina_file_lock_cache);
626 eina_log_domain_unregister(_eina_file_log_dom);
627 _eina_file_log_dom = -1;
632 eina_file_mmap_faulty(void *addr, long page_size)
639 /* NOTE: I actually don't know if other thread are running, I will try to take the lock.
640 It may be possible that if other thread are not running and they were in the middle of
641 accessing an Eina_File this lock are still taken and we will result as a deadlock. */
642 eina_lock_take(&_eina_file_lock_cache);
644 itf = eina_hash_iterator_data_new(_eina_file_cache);
645 EINA_ITERATOR_FOREACH(itf, f)
647 Eina_Bool faulty = EINA_FALSE;
649 eina_lock_take(&f->lock);
653 if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) &&
654 (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map)
656 f->global_faulty = EINA_TRUE;
663 itm = eina_hash_iterator_data_new(f->map);
664 EINA_ITERATOR_FOREACH(itm, m)
666 if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) &&
667 (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map)
669 m->faulty = EINA_TRUE;
674 eina_iterator_free(itm);
677 eina_lock_release(&f->lock);
681 eina_iterator_free(itf);
683 eina_lock_release(&_eina_file_lock_cache);
686 /*============================================================================*
688 *============================================================================*/
691 eina_file_path_sanitize(const char *path)
696 if (!path) return NULL;
705 tmp = getcwd(cwd, PATH_MAX);
706 if (!tmp) return NULL;
708 len += strlen(cwd) + 2;
709 tmp = alloca(sizeof (char) * len);
711 slprintf(tmp, len, "%s/%s", cwd, path);
716 return _eina_file_escape(result ? result : path, &len);
720 eina_file_dir_list(const char *dir,
722 Eina_File_Dir_List_Cb cb,
725 Eina_File_Direct_Info *info;
728 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
729 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
730 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
732 it = eina_file_stat_ls(dir);
736 EINA_ITERATOR_FOREACH(it, info)
738 cb(info->path + info->name_start, dir, data);
740 if (recursive == EINA_TRUE && info->type == EINA_FILE_DIR)
742 eina_file_dir_list(info->path, recursive, cb, data);
746 eina_iterator_free(it);
752 eina_file_split(char *path)
758 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
760 ea = eina_array_new(16);
765 for (current = strchr(path, PATH_DELIM);
767 path = current + 1, current = strchr(path, PATH_DELIM))
769 length = current - path;
774 eina_array_push(ea, path);
779 eina_array_push(ea, path);
785 eina_file_ls(const char *dir)
788 Eina_File_Iterator *it;
791 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
793 length = strlen(dir);
797 it = calloc(1, sizeof (Eina_File_Iterator) + length);
801 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
803 it->dirp = opendir(dir);
810 memcpy(it->dir, dir, length + 1);
811 if (dir[length - 1] != '/')
814 it->length = length - 1;
816 it->iterator.version = EINA_ITERATOR_VERSION;
817 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
818 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
819 _eina_file_ls_iterator_container);
820 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
822 return &it->iterator;
830 eina_file_direct_ls(const char *dir)
833 Eina_File_Direct_Iterator *it;
836 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
838 length = strlen(dir);
842 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
846 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
848 it->dirp = opendir(dir);
855 if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
857 _eina_file_direct_ls_iterator_free(it);
861 memcpy(it->dir, dir, length + 1);
864 memcpy(it->info.path, dir, length);
865 if (dir[length - 1] == '/')
866 it->info.name_start = length;
869 it->info.path[length] = '/';
870 it->info.name_start = length + 1;
873 it->iterator.version = EINA_ITERATOR_VERSION;
874 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
875 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
876 _eina_file_direct_ls_iterator_container);
877 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
879 return &it->iterator;
887 eina_file_stat_ls(const char *dir)
890 Eina_File_Direct_Iterator *it;
893 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
895 length = strlen(dir);
899 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
903 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
905 it->dirp = opendir(dir);
912 if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
914 _eina_file_direct_ls_iterator_free(it);
918 memcpy(it->dir, dir, length + 1);
921 memcpy(it->info.path, dir, length);
922 if (dir[length - 1] == '/')
923 it->info.name_start = length;
926 it->info.path[length] = '/';
927 it->info.name_start = length + 1;
930 it->iterator.version = EINA_ITERATOR_VERSION;
931 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_stat_ls_iterator_next);
932 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
933 _eina_file_direct_ls_iterator_container);
934 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
936 return &it->iterator;
944 eina_file_open(const char *path, Eina_Bool shared)
949 struct stat file_stat;
955 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
957 filename = eina_file_path_sanitize(path);
958 if (!filename) return NULL;
962 fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
967 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
969 if (fd < 0) goto on_error;
972 flags = fcntl(fd, F_GETFD);
977 if (fcntl(fd, F_SETFD, flags) == -1)
981 if (fstat(fd, &file_stat))
984 eina_lock_take(&_eina_file_lock_cache);
986 file = eina_hash_find(_eina_file_cache, filename);
987 if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
989 file->delete_me = EINA_TRUE;
990 eina_hash_del(_eina_file_cache, file->filename, file);
991 _eina_file_real_close(file);
997 n = malloc(sizeof(Eina_File) + strlen(filename) + 1);
1000 eina_lock_release(&_eina_file_lock_cache);
1004 memset(n, 0, sizeof(Eina_File));
1005 n->filename = (char*) (n + 1);
1006 strcpy((char*) n->filename, filename);
1007 n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
1008 EINA_KEY_CMP(_eina_file_map_key_cmp),
1009 EINA_KEY_HASH(_eina_file_map_key_hash),
1010 EINA_FREE_CB(_eina_file_map_close),
1012 n->rmap = eina_hash_pointer_new(NULL);
1013 n->global_map = MAP_FAILED;
1014 n->length = file_stat.st_size;
1015 n->mtime = file_stat.st_mtime;
1016 #ifdef _STAT_VER_LINUX
1017 # if (defined __USE_MISC && defined st_mtime)
1018 n->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec;
1020 n->mtime_nsec = (unsigned long int)file_stat.st_mtimensec;
1023 n->inode = file_stat.st_ino;
1026 eina_lock_new(&n->lock);
1027 eina_hash_direct_add(_eina_file_cache, n->filename, n);
1034 eina_lock_take(&n->lock);
1036 eina_lock_release(&n->lock);
1038 eina_lock_release(&_eina_file_lock_cache);
1046 if (fd >= 0) close(fd);
1051 eina_file_close(Eina_File *file)
1053 EINA_SAFETY_ON_NULL_RETURN(file);
1055 eina_lock_take(&file->lock);
1057 eina_lock_release(&file->lock);
1059 if (file->refcount != 0) return;
1060 eina_lock_take(&_eina_file_lock_cache);
1062 eina_hash_del(_eina_file_cache, file->filename, file);
1063 _eina_file_real_close(file);
1065 eina_lock_release(&_eina_file_lock_cache);
1069 eina_file_size_get(Eina_File *file)
1071 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1072 return file->length;
1076 eina_file_mtime_get(Eina_File *file)
1078 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1083 eina_file_filename_get(Eina_File *file)
1085 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1086 return file->filename;
1090 eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
1092 int flags = MAP_SHARED;
1095 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1097 // bsd people will lack this feature
1099 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
1102 if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
1105 eina_mmap_safety_enabled_set(EINA_TRUE);
1106 eina_lock_take(&file->lock);
1107 if (file->global_map == MAP_FAILED)
1108 file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
1110 if ((file->global_map == MAP_FAILED) && (flags & MAP_HUGETLB))
1112 flags &= ~MAP_HUGETLB;
1113 file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
1117 if (file->global_map != MAP_FAILED)
1119 Eina_Bool hugetlb = EINA_FALSE;
1122 hugetlb = !!(flags & MAP_HUGETLB);
1124 _eina_file_map_rule_apply(rule, file->global_map, file->length, hugetlb);
1125 file->global_refcount++;
1126 ret = file->global_map;
1129 eina_lock_release(&file->lock);
1133 typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator;
1134 struct _Eina_Lines_Iterator
1136 Eina_Iterator iterator;
1144 Eina_File_Line current;
1147 /* search '\r' and '\n' by preserving cache locality and page locality
1148 in doing a search inside 4K boundary.
1150 static inline const char *
1151 _eina_fine_eol(const char *start, int boundary, const char *end)
1155 unsigned long long chunk;
1159 chunk = start + boundary < end ? boundary : end - start;
1160 cr = memchr(start, '\r', chunk);
1161 lf = memchr(start, '\n', chunk);
1179 _eina_file_map_lines_iterator_next(Eina_Lines_Iterator *it, void **data)
1182 unsigned char match;
1184 if (it->current.end >= it->end)
1187 match = *it->current.end;
1188 while ((*it->current.end == '\n' || *it->current.end == '\r')
1189 && it->current.end < it->end)
1191 if (match == *it->current.end)
1192 it->current.index++;
1195 it->current.index++;
1197 if (it->current.end == it->end)
1200 eol = _eina_fine_eol(it->current.end,
1203 it->boundary = (uintptr_t) eol & 0x3FF;
1204 if (it->boundary == 0) it->boundary = 4096;
1206 it->current.start = it->current.end;
1208 it->current.end = eol;
1209 it->current.length = eol - it->current.start - 1;
1211 *data = &it->current;
1216 _eina_file_map_lines_iterator_container(Eina_Lines_Iterator *it)
1222 _eina_file_map_lines_iterator_free(Eina_Lines_Iterator *it)
1224 eina_file_map_free(it->fp, (void*) it->map);
1225 eina_file_close(it->fp);
1227 EINA_MAGIC_SET(&it->iterator, 0);
1231 EAPI Eina_Iterator *
1232 eina_file_map_lines(Eina_File *file)
1234 Eina_Lines_Iterator *it;
1236 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1238 if (file->length == 0) return NULL;
1240 it = calloc(1, sizeof (Eina_Lines_Iterator));
1241 if (!it) return NULL;
1243 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1245 it->map = eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
1252 eina_lock_take(&file->lock);
1254 eina_lock_release(&file->lock);
1257 it->boundary = 4096;
1258 it->current.start = it->map;
1259 it->current.end = it->current.start;
1260 it->current.index = 0;
1261 it->current.length = 0;
1262 it->end = it->map + it->fp->length;
1264 it->iterator.version = EINA_ITERATOR_VERSION;
1265 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_map_lines_iterator_next);
1266 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_map_lines_iterator_container);
1267 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_map_lines_iterator_free);
1269 return &it->iterator;
1273 eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
1274 unsigned long int offset, unsigned long int length)
1277 unsigned long int key[2];
1279 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1281 if (offset > file->length)
1283 if (offset + length > file->length)
1286 if (offset == 0 && length == file->length)
1287 return eina_file_map_all(file, rule);
1292 eina_mmap_safety_enabled_set(EINA_TRUE);
1293 eina_lock_take(&file->lock);
1295 map = eina_hash_find(file->map, &key);
1298 int flags = MAP_SHARED;
1300 // bsd people will lack this feature
1302 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
1305 if (length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
1308 map = malloc(sizeof (Eina_File_Map));
1309 if (!map) goto on_error;
1311 map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
1313 if (map->map == MAP_FAILED && (flags & MAP_HUGETLB))
1315 flags &= ~MAP_HUGETLB;
1316 map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
1319 map->hugetlb = !!(flags & MAP_HUGETLB);
1321 map->hugetlb = EINA_FALSE;
1323 map->offset = offset;
1324 map->length = length;
1327 if (map->map == MAP_FAILED) goto on_error;
1329 eina_hash_add(file->map, &key, map);
1330 eina_hash_direct_add(file->rmap, map->map, map);
1335 _eina_file_map_rule_apply(rule, map->map, length, map->hugetlb);
1337 eina_lock_release(&file->lock);
1343 eina_lock_release(&file->lock);
1349 eina_file_map_free(Eina_File *file, void *map)
1351 EINA_SAFETY_ON_NULL_RETURN(file);
1353 eina_lock_take(&file->lock);
1355 if (file->global_map == map)
1357 file->global_refcount--;
1359 if (file->global_refcount > 0) goto on_exit;
1361 munmap(file->global_map, file->length);
1362 file->global_map = MAP_FAILED;
1367 unsigned long int key[2];
1369 em = eina_hash_find(file->rmap, &map);
1370 if (!em) goto on_exit;
1374 if (em->refcount > 0) goto on_exit;
1376 key[0] = em->offset;
1377 key[1] = em->length;
1379 eina_hash_del(file->rmap, &map, em);
1380 eina_hash_del(file->map, &key, em);
1384 eina_lock_release(&file->lock);
1388 eina_file_map_faulted(Eina_File *file, void *map)
1391 Eina_Bool r = EINA_FALSE;
1393 EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
1395 eina_lock_take(&file->lock);
1397 if (file->global_map == map)
1399 r = file->global_faulty;
1403 em = eina_hash_find(file->rmap, &map);
1404 if (em) r = em->faulty;
1407 eina_lock_release(&file->lock);
1412 EAPI Eina_Iterator *
1413 eina_file_xattr_get(Eina_File *file)
1415 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1417 return eina_xattr_fd_ls(file->fd);
1420 EAPI Eina_Iterator *
1421 eina_file_xattr_value_get(Eina_File *file)
1423 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1425 return eina_xattr_value_fd_ls(file->fd);
1429 eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
1436 EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1);
1437 EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1);
1440 fd = dirfd((DIR*) container);
1441 if (fstatat(fd, info->path + info->name_start, &buf, 0))
1444 if (stat(info->path, &buf))
1447 if (info->type != EINA_FILE_LNK)
1448 info->type = EINA_FILE_UNKNOWN;
1452 if (info->type == EINA_FILE_UNKNOWN)
1454 if (S_ISREG(buf.st_mode))
1455 info->type = EINA_FILE_REG;
1456 else if (S_ISDIR(buf.st_mode))
1457 info->type = EINA_FILE_DIR;
1458 else if (S_ISCHR(buf.st_mode))
1459 info->type = EINA_FILE_CHR;
1460 else if (S_ISBLK(buf.st_mode))
1461 info->type = EINA_FILE_BLK;
1462 else if (S_ISFIFO(buf.st_mode))
1463 info->type = EINA_FILE_FIFO;
1464 else if (S_ISLNK(buf.st_mode))
1465 info->type = EINA_FILE_LNK;
1466 else if (S_ISSOCK(buf.st_mode))
1467 info->type = EINA_FILE_SOCK;
1469 info->type = EINA_FILE_UNKNOWN;
1472 st->dev = buf.st_dev;
1473 st->ino = buf.st_ino;
1474 st->mode = buf.st_mode;
1475 st->nlink = buf.st_nlink;
1476 st->uid = buf.st_uid;
1477 st->gid = buf.st_gid;
1478 st->rdev = buf.st_rdev;
1479 st->size = buf.st_size;
1480 st->blksize = buf.st_blksize;
1481 st->blocks = buf.st_blocks;
1482 st->atime = buf.st_atime;
1483 st->mtime = buf.st_mtime;
1484 st->ctime = buf.st_ctime;
1485 #ifdef _STAT_VER_LINUX
1486 # if (defined __USE_MISC && defined st_mtime)
1487 st->atimensec = buf.st_atim.tv_nsec;
1488 st->mtimensec = buf.st_mtim.tv_nsec;
1489 st->ctimensec = buf.st_ctim.tv_nsec;
1491 st->atimensec = buf.st_atimensec;
1492 st->mtimensec = buf.st_mtimensec;
1493 st->ctimensec = buf.st_ctimensec;