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)
504 char *result = strdup(path ? path : "");
512 if (length) len = *length;
513 else len = strlen(result);
515 while ((p = strchr(p, '/')))
520 memmove(p, p + 1, --len - (p - result));
533 memmove(q, p + 3, len - (q - result));
537 /* Update q correctly. */
540 q = strrchr(result, '/');
575 /*============================================================================*
577 *============================================================================*/
582 _eina_file_log_dom = eina_log_domain_register("eina_file",
583 EINA_LOG_COLOR_DEFAULT);
584 if (_eina_file_log_dom < 0)
586 EINA_LOG_ERR("Could not register log domain: eina_file");
590 _eina_file_cache = eina_hash_string_djb2_new(NULL);
591 if (!_eina_file_cache)
593 ERR("Could not create cache.");
594 eina_log_domain_unregister(_eina_file_log_dom);
595 _eina_file_log_dom = -1;
599 eina_lock_new(&_eina_file_lock_cache);
605 eina_file_shutdown(void)
607 if (eina_hash_population(_eina_file_cache) > 0)
612 it = eina_hash_iterator_key_new(_eina_file_cache);
613 EINA_ITERATOR_FOREACH(it, key)
614 ERR("File [%s] still open !", key);
615 eina_iterator_free(it);
618 eina_hash_free(_eina_file_cache);
620 eina_lock_free(&_eina_file_lock_cache);
622 eina_log_domain_unregister(_eina_file_log_dom);
623 _eina_file_log_dom = -1;
628 eina_file_mmap_faulty(void *addr, long page_size)
635 /* NOTE: I actually don't know if other thread are running, I will try to take the lock.
636 It may be possible that if other thread are not running and they were in the middle of
637 accessing an Eina_File this lock are still taken and we will result as a deadlock. */
638 eina_lock_take(&_eina_file_lock_cache);
640 itf = eina_hash_iterator_data_new(_eina_file_cache);
641 EINA_ITERATOR_FOREACH(itf, f)
643 Eina_Bool faulty = EINA_FALSE;
645 eina_lock_take(&f->lock);
649 if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) &&
650 (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map)
652 f->global_faulty = EINA_TRUE;
659 itm = eina_hash_iterator_data_new(f->map);
660 EINA_ITERATOR_FOREACH(itm, m)
662 if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) &&
663 (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map)
665 m->faulty = EINA_TRUE;
670 eina_iterator_free(itm);
673 eina_lock_release(&f->lock);
677 eina_iterator_free(itf);
679 eina_lock_release(&_eina_file_lock_cache);
682 /*============================================================================*
684 *============================================================================*/
687 eina_file_path_sanitize(const char *path)
692 if (!path) return NULL;
701 tmp = getcwd(cwd, PATH_MAX);
702 if (!tmp) return NULL;
704 len += strlen(cwd) + 2;
705 tmp = alloca(sizeof (char) * len);
707 slprintf(tmp, len, "%s/%s", cwd, path);
712 return _eina_file_escape(result ? result : path, &len);
716 eina_file_dir_list(const char *dir,
718 Eina_File_Dir_List_Cb cb,
721 Eina_File_Direct_Info *info;
724 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
725 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
726 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
728 it = eina_file_stat_ls(dir);
732 EINA_ITERATOR_FOREACH(it, info)
734 cb(info->path + info->name_start, dir, data);
736 if (recursive == EINA_TRUE && info->type == EINA_FILE_DIR)
738 eina_file_dir_list(info->path, recursive, cb, data);
742 eina_iterator_free(it);
748 eina_file_split(char *path)
754 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
756 ea = eina_array_new(16);
761 for (current = strchr(path, PATH_DELIM);
763 path = current + 1, current = strchr(path, PATH_DELIM))
765 length = current - path;
770 eina_array_push(ea, path);
775 eina_array_push(ea, path);
781 eina_file_ls(const char *dir)
784 Eina_File_Iterator *it;
787 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
789 length = strlen(dir);
793 it = calloc(1, sizeof (Eina_File_Iterator) + length);
797 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
799 it->dirp = opendir(dir);
806 memcpy(it->dir, dir, length + 1);
807 if (dir[length - 1] != '/')
810 it->length = length - 1;
812 it->iterator.version = EINA_ITERATOR_VERSION;
813 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
814 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
815 _eina_file_ls_iterator_container);
816 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
818 return &it->iterator;
826 eina_file_direct_ls(const char *dir)
829 Eina_File_Direct_Iterator *it;
832 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
834 length = strlen(dir);
838 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
842 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
844 it->dirp = opendir(dir);
851 if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
853 _eina_file_direct_ls_iterator_free(it);
857 memcpy(it->dir, dir, length + 1);
860 memcpy(it->info.path, dir, length);
861 if (dir[length - 1] == '/')
862 it->info.name_start = length;
865 it->info.path[length] = '/';
866 it->info.name_start = length + 1;
869 it->iterator.version = EINA_ITERATOR_VERSION;
870 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
871 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
872 _eina_file_direct_ls_iterator_container);
873 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
875 return &it->iterator;
883 eina_file_stat_ls(const char *dir)
886 Eina_File_Direct_Iterator *it;
889 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
891 length = strlen(dir);
895 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
899 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
901 it->dirp = opendir(dir);
908 if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
910 _eina_file_direct_ls_iterator_free(it);
914 memcpy(it->dir, dir, length + 1);
917 memcpy(it->info.path, dir, length);
918 if (dir[length - 1] == '/')
919 it->info.name_start = length;
922 it->info.path[length] = '/';
923 it->info.name_start = length + 1;
926 it->iterator.version = EINA_ITERATOR_VERSION;
927 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_stat_ls_iterator_next);
928 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
929 _eina_file_direct_ls_iterator_container);
930 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
932 return &it->iterator;
940 eina_file_open(const char *path, Eina_Bool shared)
945 struct stat file_stat;
951 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
953 filename = eina_file_path_sanitize(path);
954 if (!filename) return NULL;
958 fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
963 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
965 if (fd < 0) goto on_error;
968 flags = fcntl(fd, F_GETFD);
973 if (fcntl(fd, F_SETFD, flags) == -1)
977 if (fstat(fd, &file_stat))
980 eina_lock_take(&_eina_file_lock_cache);
982 file = eina_hash_find(_eina_file_cache, filename);
983 if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
985 file->delete_me = EINA_TRUE;
986 eina_hash_del(_eina_file_cache, file->filename, file);
987 _eina_file_real_close(file);
993 n = malloc(sizeof(Eina_File) + strlen(filename) + 1);
996 eina_lock_release(&_eina_file_lock_cache);
1000 memset(n, 0, sizeof(Eina_File));
1001 n->filename = (char*) (n + 1);
1002 strcpy((char*) n->filename, filename);
1003 n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
1004 EINA_KEY_CMP(_eina_file_map_key_cmp),
1005 EINA_KEY_HASH(_eina_file_map_key_hash),
1006 EINA_FREE_CB(_eina_file_map_close),
1008 n->rmap = eina_hash_pointer_new(NULL);
1009 n->global_map = MAP_FAILED;
1010 n->length = file_stat.st_size;
1011 n->mtime = file_stat.st_mtime;
1012 #ifdef _STAT_VER_LINUX
1013 # if (defined __USE_MISC && defined st_mtime)
1014 n->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec;
1016 n->mtime_nsec = (unsigned long int)file_stat.st_mtimensec;
1019 n->inode = file_stat.st_ino;
1022 eina_lock_new(&n->lock);
1023 eina_hash_direct_add(_eina_file_cache, n->filename, n);
1030 eina_lock_take(&n->lock);
1032 eina_lock_release(&n->lock);
1034 eina_lock_release(&_eina_file_lock_cache);
1042 if (fd >= 0) close(fd);
1047 eina_file_close(Eina_File *file)
1049 EINA_SAFETY_ON_NULL_RETURN(file);
1051 eina_lock_take(&file->lock);
1053 eina_lock_release(&file->lock);
1055 if (file->refcount != 0) return;
1056 eina_lock_take(&_eina_file_lock_cache);
1058 eina_hash_del(_eina_file_cache, file->filename, file);
1059 _eina_file_real_close(file);
1061 eina_lock_release(&_eina_file_lock_cache);
1065 eina_file_size_get(Eina_File *file)
1067 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1068 return file->length;
1072 eina_file_mtime_get(Eina_File *file)
1074 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1079 eina_file_filename_get(Eina_File *file)
1081 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1082 return file->filename;
1086 eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
1088 int flags = MAP_SHARED;
1091 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1093 // bsd people will lack this feature
1095 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
1098 if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
1101 eina_mmap_safety_enabled_set(EINA_TRUE);
1102 eina_lock_take(&file->lock);
1103 if (file->global_map == MAP_FAILED)
1104 file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
1106 if ((file->global_map == MAP_FAILED) && (flags & MAP_HUGETLB))
1108 flags &= ~MAP_HUGETLB;
1109 file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
1113 if (file->global_map != MAP_FAILED)
1115 Eina_Bool hugetlb = EINA_FALSE;
1118 hugetlb = !!(flags & MAP_HUGETLB);
1120 _eina_file_map_rule_apply(rule, file->global_map, file->length, hugetlb);
1121 file->global_refcount++;
1122 ret = file->global_map;
1125 eina_lock_release(&file->lock);
1129 typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator;
1130 struct _Eina_Lines_Iterator
1132 Eina_Iterator iterator;
1140 Eina_File_Line current;
1143 /* search '\r' and '\n' by preserving cache locality and page locality
1144 in doing a search inside 4K boundary.
1146 static inline const char *
1147 _eina_fine_eol(const char *start, int boundary, const char *end)
1151 unsigned long long chunk;
1155 chunk = start + boundary < end ? boundary : end - start;
1156 cr = memchr(start, '\r', chunk);
1157 lf = memchr(start, '\n', chunk);
1175 _eina_file_map_lines_iterator_next(Eina_Lines_Iterator *it, void **data)
1178 unsigned char match;
1180 if (it->current.end >= it->end)
1183 match = *it->current.end;
1184 while ((*it->current.end == '\n' || *it->current.end == '\r')
1185 && it->current.end < it->end)
1187 if (match == *it->current.end)
1188 it->current.index++;
1191 it->current.index++;
1193 if (it->current.end == it->end)
1196 eol = _eina_fine_eol(it->current.end,
1199 it->boundary = (uintptr_t) eol & 0x3FF;
1200 if (it->boundary == 0) it->boundary = 4096;
1202 it->current.start = it->current.end;
1204 it->current.end = eol;
1205 it->current.length = eol - it->current.start - 1;
1207 *data = &it->current;
1212 _eina_file_map_lines_iterator_container(Eina_Lines_Iterator *it)
1218 _eina_file_map_lines_iterator_free(Eina_Lines_Iterator *it)
1220 eina_file_map_free(it->fp, (void*) it->map);
1221 eina_file_close(it->fp);
1223 EINA_MAGIC_SET(&it->iterator, 0);
1227 EAPI Eina_Iterator *
1228 eina_file_map_lines(Eina_File *file)
1230 Eina_Lines_Iterator *it;
1232 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1234 if (file->length == 0) return NULL;
1236 it = calloc(1, sizeof (Eina_Lines_Iterator));
1237 if (!it) return NULL;
1239 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1241 it->map = eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
1248 eina_lock_take(&file->lock);
1250 eina_lock_release(&file->lock);
1253 it->boundary = 4096;
1254 it->current.start = it->map;
1255 it->current.end = it->current.start;
1256 it->current.index = 0;
1257 it->current.length = 0;
1258 it->end = it->map + it->fp->length;
1260 it->iterator.version = EINA_ITERATOR_VERSION;
1261 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_map_lines_iterator_next);
1262 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_map_lines_iterator_container);
1263 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_map_lines_iterator_free);
1265 return &it->iterator;
1269 eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
1270 unsigned long int offset, unsigned long int length)
1273 unsigned long int key[2];
1275 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1277 if (offset > file->length)
1279 if (offset + length > file->length)
1282 if (offset == 0 && length == file->length)
1283 return eina_file_map_all(file, rule);
1288 eina_mmap_safety_enabled_set(EINA_TRUE);
1289 eina_lock_take(&file->lock);
1291 map = eina_hash_find(file->map, &key);
1294 int flags = MAP_SHARED;
1296 // bsd people will lack this feature
1298 if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
1301 if (length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
1304 map = malloc(sizeof (Eina_File_Map));
1305 if (!map) goto on_error;
1307 map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
1309 if (map->map == MAP_FAILED && (flags & MAP_HUGETLB))
1311 flags &= ~MAP_HUGETLB;
1312 map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
1315 map->hugetlb = !!(flags & MAP_HUGETLB);
1317 map->hugetlb = EINA_FALSE;
1319 map->offset = offset;
1320 map->length = length;
1323 if (map->map == MAP_FAILED) goto on_error;
1325 eina_hash_add(file->map, &key, map);
1326 eina_hash_direct_add(file->rmap, map->map, map);
1331 _eina_file_map_rule_apply(rule, map->map, length, map->hugetlb);
1333 eina_lock_release(&file->lock);
1339 eina_lock_release(&file->lock);
1345 eina_file_map_free(Eina_File *file, void *map)
1347 EINA_SAFETY_ON_NULL_RETURN(file);
1349 eina_lock_take(&file->lock);
1351 if (file->global_map == map)
1353 file->global_refcount--;
1355 if (file->global_refcount > 0) goto on_exit;
1357 munmap(file->global_map, file->length);
1358 file->global_map = MAP_FAILED;
1363 unsigned long int key[2];
1365 em = eina_hash_find(file->rmap, &map);
1366 if (!em) goto on_exit;
1370 if (em->refcount > 0) goto on_exit;
1372 key[0] = em->offset;
1373 key[1] = em->length;
1375 eina_hash_del(file->rmap, &map, em);
1376 eina_hash_del(file->map, &key, em);
1380 eina_lock_release(&file->lock);
1384 eina_file_map_faulted(Eina_File *file, void *map)
1387 Eina_Bool r = EINA_FALSE;
1389 EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
1391 eina_lock_take(&file->lock);
1393 if (file->global_map == map)
1395 r = file->global_faulty;
1399 em = eina_hash_find(file->rmap, &map);
1400 if (em) r = em->faulty;
1403 eina_lock_release(&file->lock);
1408 EAPI Eina_Iterator *
1409 eina_file_xattr_get(Eina_File *file)
1411 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1413 return eina_xattr_fd_ls(file->fd);
1416 EAPI Eina_Iterator *
1417 eina_file_xattr_value_get(Eina_File *file)
1419 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1421 return eina_xattr_value_fd_ls(file->fd);
1425 eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
1432 EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1);
1433 EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1);
1436 fd = dirfd((DIR*) container);
1437 if (fstatat(fd, info->path + info->name_start, &buf, 0))
1440 if (stat(info->path, &buf))
1443 if (info->type != EINA_FILE_LNK)
1444 info->type = EINA_FILE_UNKNOWN;
1448 if (info->type == EINA_FILE_UNKNOWN)
1450 if (S_ISREG(buf.st_mode))
1451 info->type = EINA_FILE_REG;
1452 else if (S_ISDIR(buf.st_mode))
1453 info->type = EINA_FILE_DIR;
1454 else if (S_ISCHR(buf.st_mode))
1455 info->type = EINA_FILE_CHR;
1456 else if (S_ISBLK(buf.st_mode))
1457 info->type = EINA_FILE_BLK;
1458 else if (S_ISFIFO(buf.st_mode))
1459 info->type = EINA_FILE_FIFO;
1460 else if (S_ISLNK(buf.st_mode))
1461 info->type = EINA_FILE_LNK;
1462 else if (S_ISSOCK(buf.st_mode))
1463 info->type = EINA_FILE_SOCK;
1465 info->type = EINA_FILE_UNKNOWN;
1468 st->dev = buf.st_dev;
1469 st->ino = buf.st_ino;
1470 st->mode = buf.st_mode;
1471 st->nlink = buf.st_nlink;
1472 st->uid = buf.st_uid;
1473 st->gid = buf.st_gid;
1474 st->rdev = buf.st_rdev;
1475 st->size = buf.st_size;
1476 st->blksize = buf.st_blksize;
1477 st->blocks = buf.st_blocks;
1478 st->atime = buf.st_atime;
1479 st->mtime = buf.st_mtime;
1480 st->ctime = buf.st_ctime;
1481 #ifdef _STAT_VER_LINUX
1482 # if (defined __USE_MISC && defined st_mtime)
1483 st->atimensec = buf.st_atim.tv_nsec;
1484 st->mtimensec = buf.st_mtim.tv_nsec;
1485 st->ctimensec = buf.st_ctim.tv_nsec;
1487 st->atimensec = buf.st_atimensec;
1488 st->mtimensec = buf.st_mtimensec;
1489 st->ctimensec = buf.st_ctimensec;