summaryrefslogtreecommitdiff
path: root/src/lib/eina/eina_file.c
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@samsung.com>2013-03-14 20:49:45 +0900
committerCedric BAIL <cedric.bail@samsung.com>2013-03-15 11:05:25 +0900
commite70502f1a15e26e634bfb356d565fe27943a671a (patch)
tree05ddf3cf20e857204950caf78cd446182b4f5310 /src/lib/eina/eina_file.c
parentf90726cf35bb89f14af7b57d8360848a8228dce9 (diff)
eina: improve portability of Eina_File.
Diffstat (limited to 'src/lib/eina/eina_file.c')
-rw-r--r--src/lib/eina/eina_file.c367
1 files changed, 37 insertions, 330 deletions
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index e498794..d54b703 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -53,6 +53,7 @@
53#include "eina_mmap.h" 53#include "eina_mmap.h"
54#include "eina_log.h" 54#include "eina_log.h"
55#include "eina_xattr.h" 55#include "eina_xattr.h"
56#include "eina_file_common.h"
56 57
57#ifdef HAVE_ESCAPE 58#ifdef HAVE_ESCAPE
58# include <Escape.h> 59# include <Escape.h>
@@ -106,50 +107,6 @@ struct _Eina_File_Iterator
106}; 107};
107#endif 108#endif
108 109
109struct _Eina_File
110{
111 const char *filename;
112
113 Eina_Hash *map;
114 Eina_Hash *rmap;
115 void *global_map;
116
117 Eina_Lock lock;
118
119 unsigned long long length;
120 time_t mtime;
121 ino_t inode;
122#ifdef _STAT_VER_LINUX
123 unsigned long int mtime_nsec;
124#endif
125
126 int refcount;
127 int global_refcount;
128
129 int fd;
130
131 Eina_Bool shared : 1;
132 Eina_Bool delete_me : 1;
133 Eina_Bool global_faulty : 1;
134};
135
136typedef struct _Eina_File_Map Eina_File_Map;
137struct _Eina_File_Map
138{
139 void *map;
140
141 unsigned long int offset;
142 unsigned long int length;
143
144 int refcount;
145
146 Eina_Bool hugetlb : 1;
147 Eina_Bool faulty : 1;
148};
149
150static Eina_Hash *_eina_file_cache = NULL;
151static Eina_Lock _eina_file_lock_cache;
152
153static int _eina_file_log_dom = -1; 110static int _eina_file_log_dom = -1;
154 111
155/* 112/*
@@ -368,8 +325,8 @@ _eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
368} 325}
369#endif 326#endif
370 327
371static void 328void
372_eina_file_real_close(Eina_File *file) 329eina_file_real_close(Eina_File *file)
373{ 330{
374 if (file->refcount != 0) return; 331 if (file->refcount != 0) return;
375 332
@@ -488,90 +445,6 @@ slprintf(char *str, size_t size, const char *format, ...)
488 va_end(ap); 445 va_end(ap);
489} 446}
490 447
491static char *
492_eina_file_escape(const char *path, int *length)
493{
494 char *result;
495 char *p;
496 char *q;
497 size_t len;
498
499 result = strdup(path ? path : "");
500 p = result;
501 q = result;
502
503 if (!result)
504 return NULL;
505
506 if (length) len = *length;
507 else len = strlen(result);
508
509 while ((p = strchr(p, '/')))
510 {
511 // remove double `/'
512 if (p[1] == '/')
513 {
514 memmove(p, p + 1, --len - (p - result));
515 result[len] = '\0';
516 }
517 else
518 if (p[1] == '.'
519 && p[2] == '.')
520 {
521 // remove `/../'
522 if (p[3] == '/')
523 {
524 char tmp;
525
526 len -= p + 3 - q;
527 memmove(q, p + 3, len - (q - result));
528 result[len] = '\0';
529 p = q;
530
531 /* Update q correctly. */
532 tmp = *p;
533 *p = '\0';
534 q = strrchr(result, '/');
535 if (!q) q = result;
536 *p = tmp;
537 }
538 else
539 // remove '/..$'
540 if (p[3] == '\0')
541 {
542 len -= p + 2 - q;
543 result[len] = '\0';
544 break;
545 }
546 else
547 {
548 q = p;
549 ++p;
550 }
551 }
552 else
553 if (p[1] == '.'
554 && p[2] == '/')
555 {
556 // remove '/./'
557 len -= 2;
558 memmove(p, p + 2, len - (p - result));
559 result[len] = '\0';
560 q = p;
561 ++p;
562 }
563 else
564 {
565 q = p;
566 ++p;
567 }
568 }
569
570 if (length)
571 *length = len;
572 return result;
573}
574
575/** 448/**
576 * @endcond 449 * @endcond
577 */ 450 */
@@ -683,39 +556,51 @@ eina_file_mmap_faulty(void *addr, long page_size)
683 eina_lock_release(&_eina_file_lock_cache); 556 eina_lock_release(&_eina_file_lock_cache);
684} 557}
685 558
686/*============================================================================* 559/* ================================================================ *
687 * API * 560 * Simplified logic for portability layer with eina_file_common *
688 *============================================================================*/ 561 * ================================================================ */
689 562
690EAPI char * 563Eina_Bool
691eina_file_path_sanitize(const char *path) 564eina_file_path_relative(const char *path)
692{ 565{
693 char *result = NULL; 566 if (*path != '/') return EINA_TRUE;
694 int len; 567 return EINA_FALSE;
568}
695 569
696 if (!path) return NULL; 570Eina_Tmpstr *
571eina_file_current_directory_get(const char *path, size_t len)
572{
573 char cwd[PATH_MAX];
574 char *tmp = NULL;
697 575
698 len = strlen(path); 576 tmp = getcwd(cwd, PATH_MAX);
577 if (!tmp) return NULL;
699 578
700 if (*path != '/') 579 len += strlen(cwd) + 2;
701 { 580 tmp = alloca(sizeof (char) * len);
702 char cwd[PATH_MAX];
703 char *tmp = NULL;
704 581
705 tmp = getcwd(cwd, PATH_MAX); 582 slprintf(tmp, len, "%s/%s", cwd, path);
706 if (!tmp) return NULL;
707 583
708 len += strlen(cwd) + 2; 584 return eina_tmpstr_add_length(tmp, len);
709 tmp = alloca(sizeof (char) * len); 585}
710 586
711 slprintf(tmp, len, "%s/%s", cwd, path); 587char *
588eina_file_cleanup(Eina_Tmpstr *path)
589{
590 char *result;
712 591
713 result = tmp; 592 result = strdup(path ? path : "");
714 } 593 eina_tmpstr_del(path);
715 594
716 return _eina_file_escape(result ? result : path, &len); 595 return result;
717} 596}
718 597
598/*============================================================================*
599 * API *
600 *============================================================================*/
601
602
603
719EAPI Eina_Bool 604EAPI Eina_Bool
720eina_file_dir_list(const char *dir, 605eina_file_dir_list(const char *dir,
721 Eina_Bool recursive, 606 Eina_Bool recursive,
@@ -997,7 +882,7 @@ eina_file_open(const char *path, Eina_Bool shared)
997 { 882 {
998 file->delete_me = EINA_TRUE; 883 file->delete_me = EINA_TRUE;
999 eina_hash_del(_eina_file_cache, file->filename, file); 884 eina_hash_del(_eina_file_cache, file->filename, file);
1000 _eina_file_real_close(file); 885 eina_file_real_close(file);
1001 file = NULL; 886 file = NULL;
1002 } 887 }
1003 888
@@ -1056,45 +941,6 @@ eina_file_open(const char *path, Eina_Bool shared)
1056 return NULL; 941 return NULL;
1057} 942}
1058 943
1059EAPI void
1060eina_file_close(Eina_File *file)
1061{
1062 EINA_SAFETY_ON_NULL_RETURN(file);
1063
1064 eina_lock_take(&file->lock);
1065 file->refcount--;
1066 eina_lock_release(&file->lock);
1067
1068 if (file->refcount != 0) return;
1069 eina_lock_take(&_eina_file_lock_cache);
1070
1071 eina_hash_del(_eina_file_cache, file->filename, file);
1072 _eina_file_real_close(file);
1073
1074 eina_lock_release(&_eina_file_lock_cache);
1075}
1076
1077EAPI size_t
1078eina_file_size_get(Eina_File *file)
1079{
1080 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1081 return file->length;
1082}
1083
1084EAPI time_t
1085eina_file_mtime_get(Eina_File *file)
1086{
1087 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1088 return file->mtime;
1089}
1090
1091EAPI const char *
1092eina_file_filename_get(Eina_File *file)
1093{
1094 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1095 return file->filename;
1096}
1097
1098EAPI void * 944EAPI void *
1099eina_file_map_all(Eina_File *file, Eina_File_Populate rule) 945eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
1100{ 946{
@@ -1139,145 +985,6 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
1139 return ret; 985 return ret;
1140} 986}
1141 987
1142typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator;
1143struct _Eina_Lines_Iterator
1144{
1145 Eina_Iterator iterator;
1146
1147 Eina_File *fp;
1148 const char *map;
1149 const char *end;
1150
1151 int boundary;
1152
1153 Eina_File_Line current;
1154};
1155
1156/* search '\r' and '\n' by preserving cache locality and page locality
1157 in doing a search inside 4K boundary.
1158 */
1159static inline const char *
1160_eina_fine_eol(const char *start, int boundary, const char *end)
1161{
1162 const char *cr;
1163 const char *lf;
1164 unsigned long long chunk;
1165
1166 while (start < end)
1167 {
1168 chunk = start + boundary < end ? boundary : end - start;
1169 cr = memchr(start, '\r', chunk);
1170 lf = memchr(start, '\n', chunk);
1171 if (cr)
1172 {
1173 if (lf && lf < cr)
1174 return lf + 1;
1175 return cr + 1;
1176 }
1177 else if (lf)
1178 return lf + 1;
1179
1180 start += chunk;
1181 boundary = 4096;
1182 }
1183
1184 return end;
1185}
1186
1187static Eina_Bool
1188_eina_file_map_lines_iterator_next(Eina_Lines_Iterator *it, void **data)
1189{
1190 const char *eol;
1191 unsigned char match;
1192
1193 if (it->current.end >= it->end)
1194 return EINA_FALSE;
1195
1196 match = *it->current.end;
1197 while ((*it->current.end == '\n' || *it->current.end == '\r')
1198 && it->current.end < it->end)
1199 {
1200 if (match == *it->current.end)
1201 it->current.index++;
1202 it->current.end++;
1203 }
1204 it->current.index++;
1205
1206 if (it->current.end == it->end)
1207 return EINA_FALSE;
1208
1209 eol = _eina_fine_eol(it->current.end,
1210 it->boundary,
1211 it->end);
1212 it->boundary = (uintptr_t) eol & 0x3FF;
1213 if (it->boundary == 0) it->boundary = 4096;
1214
1215 it->current.start = it->current.end;
1216
1217 it->current.end = eol;
1218 it->current.length = eol - it->current.start - 1;
1219
1220 *data = &it->current;
1221 return EINA_TRUE;
1222}
1223
1224static Eina_File *
1225_eina_file_map_lines_iterator_container(Eina_Lines_Iterator *it)
1226{
1227 return it->fp;
1228}
1229
1230static void
1231_eina_file_map_lines_iterator_free(Eina_Lines_Iterator *it)
1232{
1233 eina_file_map_free(it->fp, (void*) it->map);
1234 eina_file_close(it->fp);
1235
1236 EINA_MAGIC_SET(&it->iterator, 0);
1237 free(it);
1238}
1239
1240EAPI Eina_Iterator *
1241eina_file_map_lines(Eina_File *file)
1242{
1243 Eina_Lines_Iterator *it;
1244
1245 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1246
1247 if (file->length == 0) return NULL;
1248
1249 it = calloc(1, sizeof (Eina_Lines_Iterator));
1250 if (!it) return NULL;
1251
1252 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1253
1254 it->map = eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
1255 if (!it->map)
1256 {
1257 free(it);
1258 return NULL;
1259 }
1260
1261 eina_lock_take(&file->lock);
1262 file->refcount++;
1263 eina_lock_release(&file->lock);
1264
1265 it->fp = file;
1266 it->boundary = 4096;
1267 it->current.start = it->map;
1268 it->current.end = it->current.start;
1269 it->current.index = 0;
1270 it->current.length = 0;
1271 it->end = it->map + it->fp->length;
1272
1273 it->iterator.version = EINA_ITERATOR_VERSION;
1274 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_map_lines_iterator_next);
1275 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_map_lines_iterator_container);
1276 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_map_lines_iterator_free);
1277
1278 return &it->iterator;
1279}
1280
1281EAPI void * 988EAPI void *
1282eina_file_map_new(Eina_File *file, Eina_File_Populate rule, 989eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
1283 unsigned long int offset, unsigned long int length) 990 unsigned long int offset, unsigned long int length)