aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_file_win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_file_win32.c')
-rw-r--r--libraries/eina/src/lib/eina_file_win32.c2235
1 files changed, 1214 insertions, 1021 deletions
diff --git a/libraries/eina/src/lib/eina_file_win32.c b/libraries/eina/src/lib/eina_file_win32.c
index 1cd8665..5c20fdd 100644
--- a/libraries/eina/src/lib/eina_file_win32.c
+++ b/libraries/eina/src/lib/eina_file_win32.c
@@ -1,1021 +1,1214 @@
1/* EINA - EFL data type library 1/* EINA - EFL data type library
2 * Copyright (C) 2010 Vincent Torri 2 * Copyright (C) 2010 Vincent Torri
3 * 3 *
4 * This library is free software; you can redistribute it and/or 4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public 5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either 6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version. 7 * version 2.1 of the License, or (at your option) any later version.
8 * 8 *
9 * This library is distributed in the hope that it will be useful, 9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details. 12 * Lesser General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU Lesser General Public 14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; 15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>. 16 * if not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19#ifdef HAVE_CONFIG_H 19#ifdef HAVE_CONFIG_H
20# include "config.h" 20# include "config.h"
21#endif 21#endif
22 22
23#ifdef HAVE_ALLOCA_H 23#ifdef HAVE_ALLOCA_H
24# include <alloca.h> 24# include <alloca.h>
25#elif defined __GNUC__ 25#elif defined __GNUC__
26# define alloca __builtin_alloca 26# define alloca __builtin_alloca
27#elif defined _AIX 27#elif defined _AIX
28# define alloca __alloca 28# define alloca __alloca
29#elif defined _MSC_VER 29#elif defined _MSC_VER
30# include <malloc.h> 30# include <malloc.h>
31# define alloca _alloca 31# define alloca _alloca
32#else 32#else
33# include <stddef.h> 33# include <stddef.h>
34# ifdef __cplusplus 34# ifdef __cplusplus
35extern "C" 35extern "C"
36# endif 36# endif
37void *alloca (size_t); 37void *alloca (size_t);
38#endif 38#endif
39 39
40#define WIN32_LEAN_AND_MEAN 40#include <sys/types.h>
41#include <windows.h> 41#include <sys/stat.h>
42#undef WIN32_LEAN_AND_MEAN 42
43 43#define WIN32_LEAN_AND_MEAN
44//#include <Evil.h> 44#include <windows.h>
45 45#undef WIN32_LEAN_AND_MEAN
46#include "eina_config.h" 46
47#include "eina_private.h" 47#include <Evil.h>
48 48
49/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ 49#include "eina_config.h"
50#include "eina_safety_checks.h" 50#include "eina_private.h"
51#include "eina_file.h" 51
52#include "eina_stringshare.h" 52/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
53#include "eina_hash.h" 53#include "eina_safety_checks.h"
54#include "eina_list.h" 54#include "eina_file.h"
55 55#include "eina_stringshare.h"
56/*============================================================================* 56#include "eina_hash.h"
57 * Local * 57#include "eina_list.h"
58 *============================================================================*/ 58#include "eina_lock.h"
59 59#include "eina_log.h"
60/** 60
61 * @cond LOCAL 61/*============================================================================*
62 */ 62 * Local *
63 63 *============================================================================*/
64#ifndef EINA_LOG_COLOR_DEFAULT 64
65#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN 65/**
66#endif 66 * @cond LOCAL
67 67 */
68#ifdef ERR 68
69#undef ERR 69#ifndef EINA_LOG_COLOR_DEFAULT
70#endif 70#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
71#define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__) 71#endif
72 72
73#ifdef WRN 73#ifdef ERR
74#undef WRN 74#undef ERR
75#endif 75#endif
76#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) 76#define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__)
77 77
78#ifdef DBG 78#ifdef WRN
79#undef DBG 79#undef WRN
80#endif 80#endif
81#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__) 81#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__)
82 82
83#ifdef MAP_FAILED 83#ifdef DBG
84# undef MAP_FAILED 84#undef DBG
85#endif 85#endif
86#define MAP_FAILED ((void *)-1) 86#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__)
87 87
88typedef struct _Eina_File_Iterator Eina_File_Iterator; 88#ifdef MAP_FAILED
89typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator; 89# undef MAP_FAILED
90typedef struct _Eina_File_Map Eina_File_Map; 90#endif
91 91#define MAP_FAILED ((void *)-1)
92struct _Eina_File_Iterator 92
93{ 93typedef struct _Eina_File_Iterator Eina_File_Iterator;
94 Eina_Iterator iterator; 94typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
95 95typedef struct _Eina_File_Map Eina_File_Map;
96 WIN32_FIND_DATA data; 96
97 HANDLE handle; 97struct _Eina_File_Iterator
98 size_t length; 98{
99 Eina_Bool is_last : 1; 99 Eina_Iterator iterator;
100 100
101 char dir[1]; 101 WIN32_FIND_DATA data;
102}; 102 HANDLE handle;
103 103 size_t length;
104struct _Eina_File_Direct_Iterator 104 Eina_Bool is_last : 1;
105{ 105
106 Eina_Iterator iterator; 106 char dir[1];
107 107};
108 WIN32_FIND_DATA data; 108
109 HANDLE handle; 109struct _Eina_File_Direct_Iterator
110 size_t length; 110{
111 Eina_Bool is_last : 1; 111 Eina_Iterator iterator;
112 112
113 Eina_File_Direct_Info info; 113 WIN32_FIND_DATA data;
114 114 HANDLE handle;
115 char dir[1]; 115 size_t length;
116}; 116 Eina_Bool is_last : 1;
117 117
118struct _Eina_File 118 Eina_File_Direct_Info info;
119{ 119
120 const char *filename; 120 char dir[1];
121 121};
122 Eina_Hash *map; 122
123 Eina_Hash *rmap; 123struct _Eina_File
124 void *global_map; 124{
125 125 const char *filename;
126 ULONGLONG length; 126
127 ULONGLONG mtime; 127 Eina_Hash *map;
128 128 Eina_Hash *rmap;
129 int refcount; 129 void *global_map;
130 int global_refcount; 130
131 131 Eina_Lock lock;
132 HANDLE handle; 132
133 HANDLE fm; 133 ULONGLONG length;
134 134 ULONGLONG mtime;
135 Eina_Bool shared : 1; 135
136 Eina_Bool delete_me : 1; 136 int refcount;
137}; 137 int global_refcount;
138 138
139struct _Eina_File_Map 139 HANDLE handle;
140{ 140 HANDLE fm;
141 void *map; 141
142 142 Eina_Bool shared : 1;
143 unsigned long int offset; 143 Eina_Bool delete_me : 1;
144 unsigned long int length; 144};
145 145
146 int refcount; 146struct _Eina_File_Map
147}; 147{
148 148 void *map;
149static Eina_Hash *_eina_file_cache = NULL; 149
150static Eina_List *_eina_file_cache_lru = NULL; 150 unsigned long int offset;
151static Eina_List *_eina_file_cache_delete = NULL; 151 unsigned long int length;
152 152
153static int _eina_file_log_dom = -1; 153 int refcount;
154 154};
155static void 155
156_eina_file_win32_backslash_change(char *dir) 156static Eina_Hash *_eina_file_cache = NULL;
157{ 157static Eina_Lock _eina_file_lock_cache;
158 char *tmp; 158
159 159static int _eina_file_log_dom = -1;
160 tmp = dir; 160
161 while (*tmp) 161static void
162 { 162_eina_file_win32_backslash_change(char *dir)
163 if (*tmp == '/') *tmp = '\\'; 163{
164 tmp++; 164 char *tmp;
165 } 165
166} 166 tmp = dir;
167 167 while (*tmp)
168static Eina_Bool 168 {
169_eina_file_win32_is_dir(const char *dir) 169 if (*tmp == '/') *tmp = '\\';
170{ 170 tmp++;
171#ifdef UNICODE 171 }
172 wchar_t *wdir = NULL; 172}
173#endif 173
174 DWORD attr; 174static Eina_Bool
175 175_eina_file_win32_is_dir(const char *dir)
176 /* check if it's a directory */ 176{
177#ifdef UNICODE 177#ifdef UNICODE
178 wdir = evil_char_to_wchar(dir); 178 wchar_t *wdir = NULL;
179 if (!wdir) 179#endif
180 return EINA_FALSE; 180 DWORD attr;
181 181
182 attr = GetFileAttributes(wdir); 182 /* check if it's a directory */
183 free(wdir); 183#ifdef UNICODE
184#else 184 wdir = evil_char_to_wchar(dir);
185 attr = GetFileAttributes(dir); 185 if (!wdir)
186#endif 186 return EINA_FALSE;
187 187
188 if (attr == 0xFFFFFFFF) 188 attr = GetFileAttributes(wdir);
189 return EINA_FALSE; 189 free(wdir);
190 190#else
191 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) 191 attr = GetFileAttributes(dir);
192 return EINA_FALSE; 192#endif
193 193
194 return EINA_TRUE; 194 if (attr == 0xFFFFFFFF)
195} 195 return EINA_FALSE;
196 196
197static char * 197 if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
198_eina_file_win32_dir_new(const char *dir) 198 return EINA_FALSE;
199{ 199
200 char *new_dir; 200 return EINA_TRUE;
201 size_t length; 201}
202 202
203 length = strlen(dir); 203static char *
204 204_eina_file_win32_dir_new(const char *dir)
205 new_dir = (char *)malloc(sizeof(char) * length + 5); 205{
206 if (!new_dir) 206 char *new_dir;
207 return NULL; 207 size_t length;
208 208
209 memcpy(new_dir, dir, length); 209 length = strlen(dir);
210 memcpy(new_dir + length, "\\*.*", 5); 210
211 _eina_file_win32_backslash_change(new_dir); 211 new_dir = (char *)malloc(sizeof(char) * length + 5);
212 212 if (!new_dir)
213 return new_dir; 213 return NULL;
214} 214
215 215 memcpy(new_dir, dir, length);
216static HANDLE 216 memcpy(new_dir + length, "\\*.*", 5);
217_eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd) 217 _eina_file_win32_backslash_change(new_dir);
218{ 218
219 HANDLE h; 219 return new_dir;
220#ifdef UNICODE 220}
221 wchar_t *wdir = NULL; 221
222 222static HANDLE
223 wdir = evil_char_to_wchar(dir); 223_eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd)
224 if (!wdir) 224{
225 return NULL; 225 HANDLE h;
226 226#ifdef UNICODE
227 h = FindFirstFile(wdir, fd); 227 wchar_t *wdir = NULL;
228 free(wdir); 228
229#else 229 wdir = evil_char_to_wchar(dir);
230 h = FindFirstFile(dir, fd); 230 if (!wdir)
231#endif 231 return NULL;
232 232
233 if (!h) 233 h = FindFirstFile(wdir, fd);
234 return NULL; 234 free(wdir);
235 235#else
236 while ((fd->cFileName[0] == '.') && 236 h = FindFirstFile(dir, fd);
237 ((fd->cFileName[1] == '\0') || 237#endif
238 ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0')))) 238
239 { 239 if (!h)
240 if (!FindNextFile(h, fd)) 240 return NULL;
241 return NULL; 241
242 } 242 while ((fd->cFileName[0] == '.') &&
243 243 ((fd->cFileName[1] == '\0') ||
244 return h; 244 ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0'))))
245} 245 {
246 246 if (!FindNextFile(h, fd))
247static Eina_Bool 247 return NULL;
248_eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data) 248 }
249{ 249
250#ifdef UNICODE 250 return h;
251 wchar_t *old_name; 251}
252#else 252
253 char *old_name; 253static Eina_Bool
254#endif 254_eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data)
255 char *name; 255{
256 char *cname; 256#ifdef UNICODE
257 size_t length; 257 wchar_t *old_name;
258 Eina_Bool is_last; 258#else
259 Eina_Bool res = EINA_TRUE; 259 char *old_name;
260 260#endif
261 if (it->handle == INVALID_HANDLE_VALUE) 261 char *name;
262 return EINA_FALSE; 262 char *cname;
263 263 size_t length;
264 is_last = it->is_last; 264 Eina_Bool is_last;
265#ifdef UNICODE 265 Eina_Bool res = EINA_TRUE;
266 old_name = _wcsdup(it->data.cFileName); 266
267#else 267 if (it->handle == INVALID_HANDLE_VALUE)
268 old_name = _strdup(it->data.cFileName); 268 return EINA_FALSE;
269#endif 269
270 if (!old_name) 270 is_last = it->is_last;
271 return EINA_FALSE; 271#ifdef UNICODE
272 272 old_name = _wcsdup(it->data.cFileName);
273 do { 273#else
274 if (!FindNextFile(it->handle, &it->data)) 274 old_name = _strdup(it->data.cFileName);
275 { 275#endif
276 if (GetLastError() == ERROR_NO_MORE_FILES) 276 if (!old_name)
277 it->is_last = EINA_TRUE; 277 return EINA_FALSE;
278 else 278
279 res = EINA_FALSE; 279 do {
280 } 280 if (!FindNextFile(it->handle, &it->data))
281 } while ((it->data.cFileName[0] == '.') && 281 {
282 ((it->data.cFileName[1] == '\0') || 282 if (GetLastError() == ERROR_NO_MORE_FILES)
283 ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ 283 it->is_last = EINA_TRUE;
284 284 else
285#ifdef UNICODE 285 res = EINA_FALSE;
286 cname = evil_wchar_to_char(old_name); 286 }
287 if (!cname) 287 } while ((it->data.cFileName[0] == '.') &&
288 return EINA_FALSE; 288 ((it->data.cFileName[1] == '\0') ||
289#else 289 ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */
290 cname = old_name; 290
291#endif 291#ifdef UNICODE
292 292 cname = evil_wchar_to_char(old_name);
293 length = strlen(cname); 293 if (!cname)
294 name = alloca(length + 2 + it->length); 294 return EINA_FALSE;
295 295#else
296 memcpy(name, it->dir, it->length); 296 cname = old_name;
297 memcpy(name + it->length, "\\", 1); 297#endif
298 memcpy(name + it->length + 1, cname, length + 1); 298
299 299 length = strlen(cname);
300 *data = (char *)eina_stringshare_add(name); 300 name = alloca(length + 2 + it->length);
301 301
302#ifdef UNICODE 302 memcpy(name, it->dir, it->length);
303 free(cname); 303 memcpy(name + it->length, "\\", 1);
304#endif 304 memcpy(name + it->length + 1, cname, length + 1);
305 free(old_name); 305
306 306 *data = (char *)eina_stringshare_add(name);
307 if (is_last) 307
308 res = EINA_FALSE; 308#ifdef UNICODE
309 309 free(cname);
310 return res; 310#endif
311} 311 free(old_name);
312 312
313static HANDLE 313 if (is_last)
314_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it) 314 res = EINA_FALSE;
315{ 315
316 return it->handle; 316 return res;
317} 317}
318 318
319static void 319static HANDLE
320_eina_file_win32_ls_iterator_free(Eina_File_Iterator *it) 320_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it)
321{ 321{
322 if (it->handle != INVALID_HANDLE_VALUE) 322 return it->handle;
323 FindClose(it->handle); 323}
324 324
325 EINA_MAGIC_SET(&it->iterator, 0); 325static void
326 free(it); 326_eina_file_win32_ls_iterator_free(Eina_File_Iterator *it)
327} 327{
328 328 if (it->handle != INVALID_HANDLE_VALUE)
329static Eina_Bool 329 FindClose(it->handle);
330_eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) 330
331{ 331 EINA_MAGIC_SET(&it->iterator, 0);
332#ifdef UNICODE 332 free(it);
333 wchar_t *old_name; 333}
334#else 334
335 char *old_name; 335static Eina_Bool
336#endif 336_eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
337 char *cname; 337{
338 size_t length; 338#ifdef UNICODE
339 DWORD attr; 339 wchar_t *old_name;
340 Eina_Bool is_last; 340#else
341 Eina_Bool res = EINA_TRUE; 341 char *old_name;
342 342#endif
343 if (it->handle == INVALID_HANDLE_VALUE) 343 char *cname;
344 return EINA_FALSE; 344 size_t length;
345 345 DWORD attr;
346 attr = it->data.dwFileAttributes; 346 Eina_Bool is_last;
347 is_last = it->is_last; 347 Eina_Bool res = EINA_TRUE;
348#ifdef UNICODE 348
349 old_name = _wcsdup(it->data.cFileName); 349 if (it->handle == INVALID_HANDLE_VALUE)
350#else 350 return EINA_FALSE;
351 old_name = _strdup(it->data.cFileName); 351
352#endif 352 attr = it->data.dwFileAttributes;
353 if (!old_name) 353 is_last = it->is_last;
354 return EINA_FALSE; 354#ifdef UNICODE
355 355 old_name = _wcsdup(it->data.cFileName);
356 do { 356#else
357 if (!FindNextFile(it->handle, &it->data)) 357 old_name = _strdup(it->data.cFileName);
358 { 358#endif
359 if (GetLastError() == ERROR_NO_MORE_FILES) 359 if (!old_name)
360 it->is_last = EINA_TRUE; 360 return EINA_FALSE;
361 else 361
362 res = EINA_FALSE; 362 do {
363 } 363 if (!FindNextFile(it->handle, &it->data))
364 364 {
365#ifdef UNICODE 365 if (GetLastError() == ERROR_NO_MORE_FILES)
366 length = wcslen(old_name); 366 it->is_last = EINA_TRUE;
367#else 367 else
368 length = strlen(old_name); 368 res = EINA_FALSE;
369#endif 369 }
370 if (it->info.name_start + length + 1 >= PATH_MAX) 370
371 { 371#ifdef UNICODE
372 free(old_name); 372 length = wcslen(old_name);
373#ifdef UNICODE 373#else
374 old_name = _wcsdup(it->data.cFileName); 374 length = strlen(old_name);
375#else 375#endif
376 old_name = _strdup(it->data.cFileName); 376 if (it->info.name_start + length + 1 >= PATH_MAX)
377#endif 377 {
378 continue; 378 free(old_name);
379 } 379#ifdef UNICODE
380 380 old_name = _wcsdup(it->data.cFileName);
381 } while ((it->data.cFileName[0] == '.') && 381#else
382 ((it->data.cFileName[1] == '\0') || 382 old_name = _strdup(it->data.cFileName);
383 ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ 383#endif
384 384 continue;
385#ifdef UNICODE 385 }
386 cname = evil_wchar_to_char(old_name); 386
387 if (!cname) 387 } while ((it->data.cFileName[0] == '.') &&
388 return EINA_FALSE; 388 ((it->data.cFileName[1] == '\0') ||
389#else 389 ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */
390 cname = old_name; 390
391#endif 391#ifdef UNICODE
392 392 cname = evil_wchar_to_char(old_name);
393 memcpy(it->info.path + it->info.name_start, cname, length); 393 if (!cname)
394 it->info.name_length = length; 394 return EINA_FALSE;
395 it->info.path_length = it->info.name_start + length; 395#else
396 it->info.path[it->info.path_length] = '\0'; 396 cname = old_name;
397 397#endif
398 if (attr & FILE_ATTRIBUTE_DIRECTORY) 398
399 it->info.type = EINA_FILE_DIR; 399 memcpy(it->info.path + it->info.name_start, cname, length);
400 else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) 400 it->info.name_length = length;
401 it->info.type = EINA_FILE_LNK; 401 it->info.path_length = it->info.name_start + length;
402 else if (attr & (FILE_ATTRIBUTE_ARCHIVE | 402 it->info.path[it->info.path_length] = '\0';
403 FILE_ATTRIBUTE_COMPRESSED | 403
404 FILE_ATTRIBUTE_COMPRESSED | 404 if (attr & FILE_ATTRIBUTE_DIRECTORY)
405 FILE_ATTRIBUTE_HIDDEN | 405 it->info.type = EINA_FILE_DIR;
406 FILE_ATTRIBUTE_NORMAL | 406 else if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
407 FILE_ATTRIBUTE_SPARSE_FILE | 407 it->info.type = EINA_FILE_LNK;
408 FILE_ATTRIBUTE_TEMPORARY)) 408 else if (attr & (FILE_ATTRIBUTE_ARCHIVE |
409 it->info.type = EINA_FILE_REG; 409 FILE_ATTRIBUTE_COMPRESSED |
410 else 410 FILE_ATTRIBUTE_COMPRESSED |
411 it->info.type = EINA_FILE_UNKNOWN; 411 FILE_ATTRIBUTE_HIDDEN |
412 412 FILE_ATTRIBUTE_NORMAL |
413 *data = &it->info; 413 FILE_ATTRIBUTE_SPARSE_FILE |
414 414 FILE_ATTRIBUTE_TEMPORARY))
415#ifdef UNICODE 415 it->info.type = EINA_FILE_REG;
416 free(cname); 416 else
417#endif 417 it->info.type = EINA_FILE_UNKNOWN;
418 418
419 free(old_name); 419 *data = &it->info;
420 420
421 if (is_last) 421#ifdef UNICODE
422 res = EINA_FALSE; 422 free(cname);
423 423#endif
424 return res; 424
425} 425 free(old_name);
426 426
427static HANDLE 427 if (is_last)
428_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it) 428 res = EINA_FALSE;
429{ 429
430 return it->handle; 430 return res;
431} 431}
432 432
433static void 433static HANDLE
434_eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) 434_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
435{ 435{
436 if (it->handle != INVALID_HANDLE_VALUE) 436 return it->handle;
437 FindClose(it->handle); 437}
438 438
439 EINA_MAGIC_SET(&it->iterator, 0); 439static void
440 free(it); 440_eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
441} 441{
442 442 if (it->handle != INVALID_HANDLE_VALUE)
443static void 443 FindClose(it->handle);
444_eina_file_real_close(Eina_File *file) 444
445{ 445 EINA_MAGIC_SET(&it->iterator, 0);
446 eina_hash_free(file->rmap); 446 free(it);
447 eina_hash_free(file->map); 447}
448 448
449 if (file->global_map != MAP_FAILED) 449static void
450 UnmapViewOfFile(file->global_map); 450_eina_file_real_close(Eina_File *file)
451 451{
452 CloseHandle(file->fm); 452 eina_hash_free(file->rmap);
453 CloseHandle(file->handle); 453 eina_hash_free(file->map);
454 454
455 eina_stringshare_del(file->filename); 455 if (file->global_map != MAP_FAILED)
456 456 UnmapViewOfFile(file->global_map);
457 free(file); 457
458} 458 CloseHandle(file->fm);
459 459 CloseHandle(file->handle);
460static void 460
461_eina_file_map_close(Eina_File_Map *map) 461 free(file);
462{ 462}
463 if (map->map != MAP_FAILED) 463
464 UnmapViewOfFile(map->map); 464static void
465 free(map); 465_eina_file_map_close(Eina_File_Map *map)
466} 466{
467 467 if (map->map != MAP_FAILED)
468static unsigned int 468 UnmapViewOfFile(map->map);
469_eina_file_map_key_length(const void *key __UNUSED__) 469 free(map);
470{ 470}
471 return sizeof (unsigned long int) * 2; 471
472} 472static unsigned int
473 473_eina_file_map_key_length(const void *key __UNUSED__)
474static int 474{
475_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__, 475 return sizeof (unsigned long int) * 2;
476 const unsigned long int *key2, int key2_length __UNUSED__) 476}
477{ 477
478 if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; 478static int
479 return key1[0] - key2[0]; 479_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__,
480} 480 const unsigned long int *key2, int key2_length __UNUSED__)
481 481{
482static int 482 if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
483_eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__) 483 return key1[0] - key2[0];
484{ 484}
485 return eina_hash_int64(&key[0], sizeof (unsigned long int)) 485
486 ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); 486static int
487} 487_eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__)
488 488{
489Eina_Bool 489 return eina_hash_int64(&key[0], sizeof (unsigned long int))
490eina_file_init(void) 490 ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
491{ 491}
492 _eina_file_log_dom = eina_log_domain_register("eina_file", 492
493 EINA_LOG_COLOR_DEFAULT); 493static char *
494 if (_eina_file_log_dom < 0) 494_eina_file_win32_escape(const char *path, size_t *length)
495 { 495{
496 EINA_LOG_ERR("Could not register log domain: eina_file"); 496 char *result = strdup(path ? path : "");
497 return EINA_FALSE; 497 char *p = result;
498 } 498 char *q = result;
499 499 size_t len;
500 _eina_file_cache = eina_hash_string_djb2_new(EINA_FREE_CB(_eina_file_real_close)); 500
501 if (!_eina_file_cache) 501 if (!result)
502 { 502 return NULL;
503 ERR("Could not create cache."); 503
504 eina_log_domain_unregister(_eina_file_log_dom); 504 if (length) len = *length;
505 _eina_file_log_dom = -1; 505 else len = strlen(result);
506 return EINA_FALSE; 506
507 } 507 while ((p = strchr(p, '/')))
508 508 {
509 return EINA_TRUE; 509 // remove double `/'
510} 510 if (p[1] == '/')
511 511 {
512Eina_Bool 512 memmove(p, p + 1, --len - (p - result));
513eina_file_shutdown(void) 513 result[len] = '\0';
514{ 514 }
515 Eina_File *f; 515 else
516 Eina_List *l; 516 if (p[1] == '.'
517 517 && p[2] == '.')
518 EINA_LIST_FREE(_eina_file_cache_delete, f) 518 {
519 _eina_file_real_close(f); 519 // remove `/../'
520 520 if (p[3] == '/')
521 EINA_LIST_FOREACH(_eina_file_cache_lru, l, f) 521 {
522 eina_hash_del(_eina_file_cache, f->filename, f); 522 char tmp;
523 523
524 if (eina_hash_population(_eina_file_cache) > 0) 524 len -= p + 3 - q;
525 { 525 memmove(q, p + 3, len - (q - result));
526 Eina_Iterator *it; 526 result[len] = '\0';
527 const char *key; 527 p = q;
528 528
529 it = eina_hash_iterator_key_new(_eina_file_cache); 529 /* Update q correctly. */
530 EINA_ITERATOR_FOREACH(it, key) 530 tmp = *p;
531 ERR("File [%s] still open !", key); 531 *p = '\0';
532 eina_iterator_free(it); 532 q = strrchr(result, '/');
533 } 533 if (!q) q = result;
534 534 *p = tmp;
535 eina_hash_free(_eina_file_cache); 535 }
536 536 else
537 eina_log_domain_unregister(_eina_file_log_dom); 537 // remove '/..$'
538 _eina_file_log_dom = -1; 538 if (p[3] == '\0')
539 return EINA_TRUE; 539 {
540} 540 len -= p + 2 - q;
541 541 result[len] = '\0';
542 542 q = p;
543/** 543 ++p;
544 * @endcond 544 }
545 */ 545 else
546 546 {
547/*============================================================================* 547 q = p;
548 * Global * 548 ++p;
549 *============================================================================*/ 549 }
550 550 }
551/*============================================================================* 551 else
552 * API * 552 {
553 *============================================================================*/ 553 q = p;
554 554 ++p;
555EAPI Eina_Bool 555 }
556eina_file_dir_list(const char *dir, 556 }
557 Eina_Bool recursive, 557
558 Eina_File_Dir_List_Cb cb, 558 if (length)
559 void *data) 559 *length = len;
560{ 560
561 WIN32_FIND_DATA file; 561 return result;
562 HANDLE h; 562}
563 char *new_dir; 563
564 564
565 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); 565/**
566 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE); 566 * @endcond
567 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE); 567 */
568 568
569 if (!_eina_file_win32_is_dir(dir)) 569/*============================================================================*
570 return EINA_FALSE; 570 * Global *
571 571 *============================================================================*/
572 new_dir = _eina_file_win32_dir_new(dir); 572
573 if (!new_dir) 573Eina_Bool
574 return EINA_FALSE; 574eina_file_init(void)
575 575{
576 h = _eina_file_win32_first_file(new_dir, &file); 576 _eina_file_log_dom = eina_log_domain_register("eina_file",
577 577 EINA_LOG_COLOR_DEFAULT);
578 if (h == INVALID_HANDLE_VALUE) 578 if (_eina_file_log_dom < 0)
579 return EINA_FALSE; 579 {
580 580 EINA_LOG_ERR("Could not register log domain: eina_file");
581 do 581 return EINA_FALSE;
582 { 582 }
583 char *filename; 583
584 584 _eina_file_cache = eina_hash_string_djb2_new(NULL);
585# ifdef UNICODE 585 if (!_eina_file_cache)
586 filename = evil_wchar_to_char(file.cFileName); 586 {
587# else 587 ERR("Could not create cache.");
588 filename = file.cFileName; 588 eina_log_domain_unregister(_eina_file_log_dom);
589# endif /* ! UNICODE */ 589 _eina_file_log_dom = -1;
590 if (!strcmp(filename, ".") || !strcmp(filename, "..")) 590 return EINA_FALSE;
591 continue; 591 }
592 592
593 cb(filename, dir, data); 593 eina_lock_new(&_eina_file_lock_cache);
594 594
595 if (recursive == EINA_TRUE) 595 return EINA_TRUE;
596 { 596}
597 char *path; 597
598 598Eina_Bool
599 path = alloca(strlen(dir) + strlen(filename) + 2); 599eina_file_shutdown(void)
600 strcpy(path, dir); 600{
601 strcat(path, "/"); 601 if (eina_hash_population(_eina_file_cache) > 0)
602 strcat(path, filename); 602 {
603 603 Eina_Iterator *it;
604 if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 604 const char *key;
605 continue; 605
606 606 it = eina_hash_iterator_key_new(_eina_file_cache);
607 eina_file_dir_list(path, recursive, cb, data); 607 EINA_ITERATOR_FOREACH(it, key)
608 } 608 ERR("File [%s] still open !", key);
609 609 eina_iterator_free(it);
610# ifdef UNICODE 610 }
611 free(filename); 611
612# endif /* UNICODE */ 612 eina_hash_free(_eina_file_cache);
613 613
614 } while (FindNextFile(h, &file)); 614 eina_lock_free(&_eina_file_lock_cache);
615 FindClose(h); 615
616 616 eina_log_domain_unregister(_eina_file_log_dom);
617 return EINA_TRUE; 617 _eina_file_log_dom = -1;
618} 618 return EINA_TRUE;
619 619}
620EAPI Eina_Array * 620
621eina_file_split(char *path) 621/*============================================================================*
622{ 622 * API *
623 Eina_Array *ea; 623 *============================================================================*/
624 char *current; 624
625 size_t length; 625
626 626EAPI char *
627 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); 627eina_file_path_sanitize(const char *path)
628 628{
629 ea = eina_array_new(16); 629 char *result = NULL;
630 630 size_t len;
631 if (!ea) 631
632 return NULL; 632 if (!path) return NULL;
633 633
634 for (current = strchr(path, '\\'); 634 len = strlen(path);
635 current; 635 if (len < 3) return NULL;
636 path = current + 1, current = strchr(path, '\\')) 636
637 { 637 if (!evil_path_is_absolute(path))
638 length = current - path; 638 {
639 639 DWORD l;
640 if (length <= 0) 640
641 continue; 641 l = GetCurrentDirectory(0, NULL);
642 642 if (l > 0)
643 eina_array_push(ea, path); 643 {
644 *current = '\0'; 644 char *cwd;
645 } 645 DWORD l2;
646 646
647 if (*path != '\0') 647 cwd = alloca(sizeof(char) * (l + 1));
648 eina_array_push(ea, path); 648 l2 = GetCurrentDirectory(l + 1, cwd);
649 649 if (l2 == l)
650 return ea; 650 {
651} 651 char *tmp;
652 652
653EAPI Eina_Iterator * 653 len += l + 2;
654eina_file_ls(const char *dir) 654 tmp = alloca(sizeof (char) * len);
655{ 655 snprintf(tmp, len, "%s/%s", cwd, path);
656 Eina_File_Iterator *it; 656 tmp[len - 1] = '\0';
657 char *new_dir; 657 result = tmp;
658 size_t length; 658 }
659 659 }
660 if (!dir || !*dir) 660 }
661 return NULL; 661
662 662 return _eina_file_win32_escape(result ? result : path, &len);
663 if (!_eina_file_win32_is_dir(dir)) 663}
664 return NULL; 664
665 665EAPI Eina_Bool
666 length = strlen(dir); 666eina_file_dir_list(const char *dir,
667 667 Eina_Bool recursive,
668 it = calloc(1, sizeof (Eina_File_Iterator) + length); 668 Eina_File_Dir_List_Cb cb,
669 if (!it) 669 void *data)
670 return NULL; 670{
671 671 WIN32_FIND_DATA file;
672 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); 672 HANDLE h;
673 673 char *new_dir;
674 new_dir = _eina_file_win32_dir_new(dir); 674
675 if (!new_dir) 675 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
676 goto free_it; 676 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
677 677 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
678 it->handle = _eina_file_win32_first_file(new_dir, &it->data); 678
679 free(new_dir); 679 if (!_eina_file_win32_is_dir(dir))
680 if (it->handle == INVALID_HANDLE_VALUE) 680 return EINA_FALSE;
681 goto free_it; 681
682 682 new_dir = _eina_file_win32_dir_new(dir);
683 memcpy(it->dir, dir, length + 1); 683 if (!new_dir)
684 if (dir[length - 1] != '\\') 684 return EINA_FALSE;
685 it->length = length; 685
686 else 686 h = _eina_file_win32_first_file(new_dir, &file);
687 it->length = length - 1; 687
688 _eina_file_win32_backslash_change(it->dir); 688 if (h == INVALID_HANDLE_VALUE)
689 689 return EINA_FALSE;
690 it->iterator.version = EINA_ITERATOR_VERSION; 690
691 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next); 691 do
692 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container); 692 {
693 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free); 693 char *filename;
694 694
695 return &it->iterator; 695# ifdef UNICODE
696 696 filename = evil_wchar_to_char(file.cFileName);
697 free_it: 697# else
698 free(it); 698 filename = file.cFileName;
699 699# endif /* ! UNICODE */
700 return NULL; 700 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
701} 701 continue;
702 702
703EAPI Eina_Iterator * 703 cb(filename, dir, data);
704eina_file_direct_ls(const char *dir) 704
705{ 705 if (recursive == EINA_TRUE)
706 Eina_File_Direct_Iterator *it; 706 {
707 char *new_dir; 707 char *path;
708 size_t length; 708
709 709 path = alloca(strlen(dir) + strlen(filename) + 2);
710 if (!dir || !*dir) 710 strcpy(path, dir);
711 return NULL; 711 strcat(path, "/");
712 712 strcat(path, filename);
713 length = strlen(dir); 713
714 714 if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
715 if (length + 12 + 2 >= MAX_PATH) 715 continue;
716 return NULL; 716
717 717 eina_file_dir_list(path, recursive, cb, data);
718 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); 718 }
719 if (!it) 719
720 return NULL; 720# ifdef UNICODE
721 721 free(filename);
722 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); 722# endif /* UNICODE */
723 723
724 new_dir = _eina_file_win32_dir_new(dir); 724 } while (FindNextFile(h, &file));
725 if (!new_dir) 725 FindClose(h);
726 goto free_it; 726
727 727 return EINA_TRUE;
728 it->handle = _eina_file_win32_first_file(new_dir, &it->data); 728}
729 free(new_dir); 729
730 if (it->handle == INVALID_HANDLE_VALUE) 730EAPI Eina_Array *
731 goto free_it; 731eina_file_split(char *path)
732 732{
733 memcpy(it->dir, dir, length + 1); 733 Eina_Array *ea;
734 it->length = length; 734 char *current;
735 _eina_file_win32_backslash_change(it->dir); 735 size_t length;
736 736
737 memcpy(it->info.path, dir, length); 737 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
738 if (dir[length - 1] == '\\') 738
739 it->info.name_start = length; 739 ea = eina_array_new(16);
740 else 740
741 { 741 if (!ea)
742 it->info.path[length] = '\\'; 742 return NULL;
743 it->info.name_start = length + 1; 743
744 } 744 for (current = strchr(path, '\\');
745 _eina_file_win32_backslash_change(it->info.path); 745 current;
746 746 path = current + 1, current = strchr(path, '\\'))
747 it->iterator.version = EINA_ITERATOR_VERSION; 747 {
748 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next); 748 length = current - path;
749 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container); 749
750 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free); 750 if (length <= 0)
751 751 continue;
752 return &it->iterator; 752
753 753 eina_array_push(ea, path);
754 free_it: 754 *current = '\0';
755 free(it); 755 }
756 756
757 return NULL; 757 if (*path != '\0')
758} 758 eina_array_push(ea, path);
759 759
760EAPI Eina_Iterator * 760 return ea;
761eina_file_stat_ls(const char *dir) 761}
762{ 762
763 return eina_file_direct_ls(dir); 763EAPI Eina_Iterator *
764} 764eina_file_ls(const char *dir)
765 765{
766EAPI Eina_File * 766 Eina_File_Iterator *it;
767eina_file_open(const char *filename, Eina_Bool shared) 767 char *new_dir;
768{ 768 size_t length;
769 Eina_File *file; 769
770 Eina_File *n; 770 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
771 HANDLE handle; 771
772 HANDLE fm; 772 if (!dir || !*dir)
773 WIN32_FILE_ATTRIBUTE_DATA fad; 773 return NULL;
774 ULARGE_INTEGER length; 774
775 ULARGE_INTEGER mtime; 775 if (!_eina_file_win32_is_dir(dir))
776 Eina_Bool create = EINA_FALSE; 776 return NULL;
777 777
778 /* FIXME: always open absolute path (need to fix filename according to current 778 length = strlen(dir);
779 directory) */ 779
780 780 it = calloc(1, sizeof (Eina_File_Iterator) + length);
781 /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */ 781 if (!it)
782#if 0 782 return NULL;
783 if (shared) 783
784 handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 784 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
785 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 785
786 NULL); 786 new_dir = _eina_file_win32_dir_new(dir);
787 else 787 if (!new_dir)
788#endif 788 goto free_it;
789 handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 789
790 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 790 it->handle = _eina_file_win32_first_file(new_dir, &it->data);
791 NULL); 791 free(new_dir);
792 792 if (it->handle == INVALID_HANDLE_VALUE)
793 if (handle == INVALID_HANDLE_VALUE) 793 goto free_it;
794 return NULL; 794
795 795 memcpy(it->dir, dir, length + 1);
796 fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL); 796 if (dir[length - 1] != '\\')
797 if (!fm) 797 it->length = length;
798 goto close_handle; 798 else
799 799 it->length = length - 1;
800 if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad)) 800 _eina_file_win32_backslash_change(it->dir);
801 goto close_fm; 801
802 802 it->iterator.version = EINA_ITERATOR_VERSION;
803 length.u.LowPart = fad.nFileSizeLow; 803 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next);
804 length.u.HighPart = fad.nFileSizeHigh; 804 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container);
805 mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime; 805 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free);
806 mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime; 806
807 807 return &it->iterator;
808 file = eina_hash_find(_eina_file_cache, filename); 808
809 if (file && 809 free_it:
810 (file->mtime != mtime.QuadPart || file->length != length.QuadPart)) 810 free(it);
811 { 811
812 create = EINA_TRUE; 812 return NULL;
813 813}
814 if (file->refcount == 0) 814
815 { 815EAPI Eina_Iterator *
816 _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file); 816eina_file_direct_ls(const char *dir)
817 eina_hash_del(_eina_file_cache, file->filename, file); 817{
818 818 Eina_File_Direct_Iterator *it;
819 file = NULL; 819 char *new_dir;
820 } 820 size_t length;
821 else if (!file->delete_me) 821
822 { 822 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
823 file->delete_me = EINA_TRUE; 823
824 _eina_file_cache_delete = eina_list_prepend(_eina_file_cache_delete, file); 824 if (!dir || !*dir)
825 } 825 return NULL;
826 } 826
827 827 length = strlen(dir);
828 if (!file || create) 828
829 { 829 if (length + 12 + 2 >= MAX_PATH)
830 n = calloc(1, sizeof (Eina_File)); 830 return NULL;
831 if (!n) 831
832 goto close_fm; 832 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
833 833 if (!it)
834 n->filename = eina_stringshare_add(filename); 834 return NULL;
835 n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), 835
836 EINA_KEY_CMP(_eina_file_map_key_cmp), 836 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
837 EINA_KEY_HASH(_eina_file_map_key_hash), 837
838 EINA_FREE_CB(_eina_file_map_close), 838 new_dir = _eina_file_win32_dir_new(dir);
839 3); 839 if (!new_dir)
840 n->rmap = eina_hash_pointer_new(NULL); 840 goto free_it;
841 n->global_map = MAP_FAILED; 841
842 n->length = length.QuadPart; 842 it->handle = _eina_file_win32_first_file(new_dir, &it->data);
843 n->mtime = mtime.QuadPart; 843 free(new_dir);
844 n->refcount = 0; 844 if (it->handle == INVALID_HANDLE_VALUE)
845 n->handle = handle; 845 goto free_it;
846 n->fm = fm; 846
847 n->shared = shared; 847 memcpy(it->dir, dir, length + 1);
848 n->delete_me = EINA_FALSE; 848 it->length = length;
849 849 _eina_file_win32_backslash_change(it->dir);
850 eina_hash_set(_eina_file_cache, filename, n); 850
851 } 851 memcpy(it->info.path, dir, length);
852 else 852 if (dir[length - 1] == '\\')
853 { 853 it->info.name_start = length;
854 CloseHandle(fm); 854 else
855 CloseHandle(handle); 855 {
856 856 it->info.path[length] = '\\';
857 n = file; 857 it->info.name_start = length + 1;
858 858 }
859 if (n->refcount == 0) 859 _eina_file_win32_backslash_change(it->info.path);
860 _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n); 860
861 } 861 it->iterator.version = EINA_ITERATOR_VERSION;
862 862 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next);
863 n->refcount++; 863 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container);
864 864 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free);
865 return n; 865
866 866 return &it->iterator;
867 close_fm: 867
868 CloseHandle(fm); 868 free_it:
869 close_handle: 869 free(it);
870 CloseHandle(handle); 870
871 871 return NULL;
872 return NULL; 872}
873} 873
874 874EAPI Eina_Iterator *
875EAPI void 875eina_file_stat_ls(const char *dir)
876eina_file_close(Eina_File *file) 876{
877{ 877 return eina_file_direct_ls(dir);
878 file->refcount--; 878}
879 879
880 if (file->refcount != 0) return ; 880EAPI Eina_File *
881 881eina_file_open(const char *path, Eina_Bool shared)
882 if (file->delete_me) 882{
883 { 883 Eina_File *file;
884 _eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, file); 884 Eina_File *n;
885 _eina_file_real_close(file); 885 char *filename;
886 } 886 HANDLE handle;
887 else 887 HANDLE fm;
888 { 888 WIN32_FILE_ATTRIBUTE_DATA fad;
889 _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file); 889 ULARGE_INTEGER length;
890 } 890 ULARGE_INTEGER mtime;
891} 891
892 892 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
893EAPI size_t 893
894eina_file_size_get(Eina_File *file) 894 filename = eina_file_path_sanitize(path);
895{ 895 if (!filename) return NULL;
896 return file->length; 896
897} 897 /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */
898 898#if 0
899EAPI time_t 899 if (shared)
900eina_file_mtime_get(Eina_File *file) 900 handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
901{ 901 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
902 return file->mtime; 902 NULL);
903} 903 else
904 904#endif
905EAPI const char * 905 handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
906eina_file_filename_get(Eina_File *file) 906 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
907{ 907 NULL);
908 return file->filename; 908
909} 909 if (handle == INVALID_HANDLE_VALUE)
910 910 return NULL;
911EAPI void * 911
912eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__) 912 fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL);
913{ 913 if (!fm)
914 if (file->global_map == MAP_FAILED) 914 goto close_handle;
915 { 915
916 void *data; 916 if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad))
917 917 goto close_fm;
918 data = MapViewOfFile(file->fm, FILE_MAP_READ, 918
919 0, 0, file->length); 919 length.u.LowPart = fad.nFileSizeLow;
920 if (!data) 920 length.u.HighPart = fad.nFileSizeHigh;
921 file->global_map = MAP_FAILED; 921 mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime;
922 else 922 mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime;
923 file->global_map = data; 923
924 } 924 eina_lock_take(&_eina_file_lock_cache);
925 925
926 if (file->global_map != MAP_FAILED) 926 file = eina_hash_find(_eina_file_cache, filename);
927 { 927 if (file &&
928 file->global_refcount++; 928 (file->mtime != mtime.QuadPart || file->length != length.QuadPart))
929 return file->global_map; 929 {
930 } 930 file->delete_me = EINA_TRUE;
931 931 eina_hash_del(_eina_file_cache, file->filename, file);
932 return NULL; 932 _eina_file_real_close(file);
933} 933 file = NULL;
934 934 }
935EAPI void * 935
936eina_file_map_new(Eina_File *file, Eina_File_Populate rule, 936 if (!file)
937 unsigned long int offset, unsigned long int length) 937 {
938{ 938 n = malloc(sizeof (Eina_File) + strlen(filename) + 1);
939 Eina_File_Map *map; 939 if (!n)
940 unsigned long int key[2]; 940 {
941 941 eina_lock_release(&_eina_file_lock_cache);
942 if (offset > file->length) 942 goto close_fm;
943 return NULL; 943 }
944 if (offset + length > file->length) 944
945 return NULL; 945 n->filename = (char*) (n + 1);
946 946 strcpy((char*) n->filename, filename);
947 if (offset == 0 && length == file->length) 947 n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
948 return eina_file_map_all(file, rule); 948 EINA_KEY_CMP(_eina_file_map_key_cmp),
949 949 EINA_KEY_HASH(_eina_file_map_key_hash),
950 key[0] = offset; 950 EINA_FREE_CB(_eina_file_map_close),
951 key[1] = length; 951 3);
952 952 n->rmap = eina_hash_pointer_new(NULL);
953 map = eina_hash_find(file->map, &key); 953 n->global_map = MAP_FAILED;
954 if (!map) 954 n->global_refcount = 0;
955 { 955 n->length = length.QuadPart;
956 void *data; 956 n->mtime = mtime.QuadPart;
957 957 n->refcount = 0;
958 map = malloc(sizeof (Eina_File_Map)); 958 n->handle = handle;
959 if (!map) return NULL; 959 n->fm = fm;
960 960 n->shared = shared;
961 data = MapViewOfFile(file->fm, FILE_MAP_READ, 961 n->delete_me = EINA_FALSE;
962 offset & 0xffff0000, 962 eina_lock_new(&n->lock);
963 offset & 0x0000ffff, 963 eina_hash_direct_add(_eina_file_cache, n->filename, n);
964 length); 964 }
965 if (!data) 965 else
966 map->map = MAP_FAILED; 966 {
967 else 967 CloseHandle(fm);
968 map->map = data; 968 CloseHandle(handle);
969 969
970 map->offset = offset; 970 n = file;
971 map->length = length; 971 }
972 map->refcount = 0; 972 eina_lock_take(&n->lock);
973 973 n->refcount++;
974 if (map->map == MAP_FAILED) 974 eina_lock_release(&n->lock);
975 { 975
976 free(map); 976 eina_lock_release(&_eina_file_lock_cache);
977 return NULL; 977
978 } 978 free(filename);
979 979
980 eina_hash_add(file->map, &key, map); 980 return n;
981 eina_hash_direct_add(file->rmap, map->map, map); 981
982 } 982 close_fm:
983 983 CloseHandle(fm);
984 map->refcount++; 984 close_handle:
985 985 CloseHandle(handle);
986 return map->map; 986
987} 987 return NULL;
988 988}
989EAPI void 989
990eina_file_map_free(Eina_File *file, void *map) 990EAPI void
991{ 991eina_file_close(Eina_File *file)
992 if (file->global_map == map) 992{
993 { 993 EINA_SAFETY_ON_NULL_RETURN(file);
994 file->global_refcount--; 994
995 995 eina_lock_take(&file->lock);
996 if (file->global_refcount > 0) return ; 996 file->refcount--;
997 997 eina_lock_release(&file->lock);
998 /* FIXME: are we sure that file->global_map != MAP_FAILED ? */ 998
999 if (file->global_map != MAP_FAILED) 999 if (file->refcount != 0) return ;
1000 UnmapViewOfFile(file->global_map); 1000 eina_lock_take(&_eina_file_lock_cache);
1001 file->global_map = MAP_FAILED; 1001
1002 } 1002 eina_hash_del(_eina_file_cache, file->filename, file);
1003 else 1003 _eina_file_real_close(file);
1004 { 1004
1005 Eina_File_Map *em; 1005 eina_lock_release(&_eina_file_lock_cache);
1006 unsigned long int key[2]; 1006}
1007 1007
1008 em = eina_hash_find(file->rmap, &map); 1008EAPI size_t
1009 if (!em) return ; 1009eina_file_size_get(Eina_File *file)
1010 1010{
1011 em->refcount--; 1011 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1012 1012 return file->length;
1013 if (em->refcount > 0) return ; 1013}
1014 1014
1015 key[0] = em->offset; 1015EAPI time_t
1016 key[1] = em->length; 1016eina_file_mtime_get(Eina_File *file)
1017 1017{
1018 eina_hash_del(file->rmap, &map, em); 1018 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1019 eina_hash_del(file->map, &key, em); 1019 return file->mtime;
1020 } 1020}
1021} 1021
1022EAPI const char *
1023eina_file_filename_get(Eina_File *file)
1024{
1025 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1026 return file->filename;
1027}
1028
1029EAPI Eina_Iterator *eina_file_xattr_get(Eina_File *file __UNUSED__)
1030{
1031 return NULL;
1032}
1033
1034EAPI Eina_Iterator *eina_file_xattr_value_get(Eina_File *file __UNUSED__)
1035{
1036 return NULL;
1037}
1038
1039EAPI void *
1040eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__)
1041{
1042 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1043
1044 eina_lock_take(&file->lock);
1045 if (file->global_map == MAP_FAILED)
1046 {
1047 void *data;
1048
1049 data = MapViewOfFile(file->fm, FILE_MAP_READ,
1050 0, 0, file->length);
1051 if (!data)
1052 file->global_map = MAP_FAILED;
1053 else
1054 file->global_map = data;
1055 }
1056
1057 if (file->global_map != MAP_FAILED)
1058 {
1059 file->global_refcount++;
1060 return file->global_map;
1061 }
1062
1063 eina_lock_release(&file->lock);
1064 return NULL;
1065}
1066
1067EAPI void *
1068eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
1069 unsigned long int offset, unsigned long int length)
1070{
1071 Eina_File_Map *map;
1072 unsigned long int key[2];
1073
1074 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1075
1076 if (offset > file->length)
1077 return NULL;
1078 if (offset + length > file->length)
1079 return NULL;
1080
1081 if (offset == 0 && length == file->length)
1082 return eina_file_map_all(file, rule);
1083
1084 key[0] = offset;
1085 key[1] = length;
1086
1087 eina_lock_take(&file->lock);
1088
1089 map = eina_hash_find(file->map, &key);
1090 if (!map)
1091 {
1092 void *data;
1093
1094 map = malloc(sizeof (Eina_File_Map));
1095 if (!map)
1096 {
1097 eina_lock_release(&file->lock);
1098 return NULL;
1099 }
1100
1101 data = MapViewOfFile(file->fm, FILE_MAP_READ,
1102 offset & 0xffff0000,
1103 offset & 0x0000ffff,
1104 length);
1105 if (!data)
1106 map->map = MAP_FAILED;
1107 else
1108 map->map = data;
1109
1110 map->offset = offset;
1111 map->length = length;
1112 map->refcount = 0;
1113
1114 if (map->map == MAP_FAILED)
1115 {
1116 free(map);
1117 eina_lock_release(&file->lock);
1118 return NULL;
1119 }
1120
1121 eina_hash_add(file->map, &key, map);
1122 eina_hash_direct_add(file->rmap, map->map, map);
1123 }
1124
1125 map->refcount++;
1126
1127 eina_lock_release(&file->lock);
1128
1129 return map->map;
1130}
1131
1132EAPI void
1133eina_file_map_free(Eina_File *file, void *map)
1134{
1135 EINA_SAFETY_ON_NULL_RETURN(file);
1136
1137 eina_lock_take(&file->lock);
1138
1139 if (file->global_map == map)
1140 {
1141 file->global_refcount--;
1142
1143 if (file->global_refcount > 0) goto on_exit;
1144
1145 UnmapViewOfFile(file->global_map);
1146 file->global_map = MAP_FAILED;
1147 }
1148 else
1149 {
1150 Eina_File_Map *em;
1151 unsigned long int key[2];
1152
1153 em = eina_hash_find(file->rmap, &map);
1154 if (!em) goto on_exit;
1155
1156 em->refcount--;
1157
1158 if (em->refcount > 0) goto on_exit;
1159
1160 key[0] = em->offset;
1161 key[1] = em->length;
1162
1163 eina_hash_del(file->rmap, &map, em);
1164 eina_hash_del(file->map, &key, em);
1165 }
1166
1167 on_exit:
1168 eina_lock_release(&file->lock);
1169}
1170
1171EAPI int
1172eina_file_statat(void *container __UNUSED__, Eina_File_Direct_Info *info, Eina_Stat *st)
1173{
1174 struct __stat64 buf;
1175
1176 EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1);
1177 EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1);
1178
1179 if (stat64(info->path, &buf))
1180 {
1181 if (info->type != EINA_FILE_LNK)
1182 info->type = EINA_FILE_UNKNOWN;
1183 return -1;
1184 }
1185
1186 if (info->type == EINA_FILE_UNKNOWN)
1187 {
1188 if (S_ISREG(buf.st_mode))
1189 info->type = EINA_FILE_REG;
1190 else if (S_ISDIR(buf.st_mode))
1191 info->type = EINA_FILE_DIR;
1192 else
1193 info->type = EINA_FILE_UNKNOWN;
1194 }
1195
1196 st->dev = buf.st_dev;
1197 st->ino = buf.st_ino;
1198 st->mode = buf.st_mode;
1199 st->nlink = buf.st_nlink;
1200 st->uid = buf.st_uid;
1201 st->gid = buf.st_gid;
1202 st->rdev = buf.st_rdev;
1203 st->size = buf.st_size;
1204 st->blksize = 0;
1205 st->blocks = 0;
1206 st->atime = buf.st_atime;
1207 st->mtime = buf.st_mtime;
1208 st->ctime = buf.st_ctime;
1209 st->atimensec = 0;
1210 st->mtimensec = 0;
1211 st->ctimensec = 0;
1212
1213 return 0;
1214}