diff options
author | Vincent Torri <vincent dot torri at gmail dot com> | 2015-10-01 07:29:11 +0200 |
---|---|---|
committer | Cedric BAIL <cedric@osg.samsung.com> | 2015-10-12 17:21:59 -0700 |
commit | b9ed3375f2d9a822d83a383ff3d6691470b1c348 (patch) | |
tree | 321e57ebb45e4939842cfb021a484bac89b3f8b0 /src/lib/ecore_file/ecore_file.c | |
parent | ce4ef2cf91144df407614cfe91c113625865922d (diff) |
ecore_file: fix ecore_file management function on Windows
On windows, stat() returns -1 if a path is finished with a \ or /,
so replace all stat() calls with a function which removes the trailing
slash or backslash on Windows
At this stage the code duplicate many code path for avoiding potential
borkage on Unix system. During 1.17 release cycle, it would be nice to
refactor this piece.
@fix
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
Diffstat (limited to '')
-rw-r--r-- | src/lib/ecore_file/ecore_file.c | 116 |
1 files changed, 94 insertions, 22 deletions
diff --git a/src/lib/ecore_file/ecore_file.c b/src/lib/ecore_file/ecore_file.c index 7dba323895..015a9b9675 100644 --- a/src/lib/ecore_file/ecore_file.c +++ b/src/lib/ecore_file/ecore_file.c | |||
@@ -27,9 +27,61 @@ | |||
27 | 27 | ||
28 | #include "ecore_file_private.h" | 28 | #include "ecore_file_private.h" |
29 | 29 | ||
30 | /* | ||
31 | * FIXME: the following functions will certainly not work on Windows: | ||
32 | * ecore_file_file_get() | ||
33 | * ecore_file_app_exe_get() | ||
34 | * ecore_file_escape_name() | ||
35 | */ | ||
36 | |||
30 | int _ecore_file_log_dom = -1; | 37 | int _ecore_file_log_dom = -1; |
31 | static int _ecore_file_init_count = 0; | 38 | static int _ecore_file_init_count = 0; |
32 | 39 | ||
40 | static Eina_Bool | ||
41 | _ecore_file_stat(const char *file, | ||
42 | long long *mtime, | ||
43 | long long *size, | ||
44 | mode_t *mode, | ||
45 | Eina_Bool *is_dir, | ||
46 | Eina_Bool *is_reg) | ||
47 | { | ||
48 | struct stat st; | ||
49 | #ifdef _WIN32 | ||
50 | /* | ||
51 | * On Windows, stat() returns -1 is file is a path finishing with | ||
52 | * a slash or blackslash | ||
53 | * see https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx | ||
54 | * ("Return Value" section) | ||
55 | * | ||
56 | * so we ensure that file never finishes with \ or / | ||
57 | */ | ||
58 | char f[MAX_PATH]; | ||
59 | size_t len; | ||
60 | |||
61 | len = strlen(file); | ||
62 | if ((len + 1) > MAX_PATH) | ||
63 | return EINA_FALSE; | ||
64 | |||
65 | memcpy(f, file, len + 1); | ||
66 | if ((f[len - 1] == '/') || (f[len - 1] == '\\')) | ||
67 | f[len - 1] = '\0'; | ||
68 | |||
69 | if (stat(f, &st) < 0) | ||
70 | return EINA_FALSE; | ||
71 | #else | ||
72 | if (stat(file, &st) < 0) | ||
73 | return EINA_FALSE; | ||
74 | #endif | ||
75 | |||
76 | if (mtime) *mtime = st.st_mtime; | ||
77 | if (size) *size = st.st_size; | ||
78 | if (mode) *mode = st.st_mode; | ||
79 | if (is_dir) *is_dir = S_ISDIR(st.st_mode); | ||
80 | if (is_reg) *is_reg = S_ISREG(st.st_mode); | ||
81 | |||
82 | return EINA_TRUE; | ||
83 | } | ||
84 | |||
33 | /* externally accessible functions */ | 85 | /* externally accessible functions */ |
34 | 86 | ||
35 | /** | 87 | /** |
@@ -134,10 +186,12 @@ ecore_file_shutdown() | |||
134 | EAPI long long | 186 | EAPI long long |
135 | ecore_file_mod_time(const char *file) | 187 | ecore_file_mod_time(const char *file) |
136 | { | 188 | { |
137 | struct stat st; | 189 | long long time; |
190 | |||
191 | if (!_ecore_file_stat(file, &time, NULL, NULL, NULL, NULL)) | ||
192 | return 0; | ||
138 | 193 | ||
139 | if (stat(file, &st) < 0) return 0; | 194 | return time; |
140 | return st.st_mtime; | ||
141 | } | 195 | } |
142 | 196 | ||
143 | /** | 197 | /** |
@@ -152,10 +206,12 @@ ecore_file_mod_time(const char *file) | |||
152 | EAPI long long | 206 | EAPI long long |
153 | ecore_file_size(const char *file) | 207 | ecore_file_size(const char *file) |
154 | { | 208 | { |
155 | struct stat st; | 209 | long long size; |
210 | |||
211 | if (!_ecore_file_stat(file, NULL, &size, NULL, NULL, NULL)) | ||
212 | return 0; | ||
156 | 213 | ||
157 | if (stat(file, &st) < 0) return 0; | 214 | return size; |
158 | return st.st_size; | ||
159 | } | 215 | } |
160 | 216 | ||
161 | /** | 217 | /** |
@@ -170,12 +226,17 @@ ecore_file_size(const char *file) | |||
170 | EAPI Eina_Bool | 226 | EAPI Eina_Bool |
171 | ecore_file_exists(const char *file) | 227 | ecore_file_exists(const char *file) |
172 | { | 228 | { |
229 | #ifdef _WIN32 | ||
230 | /* I prefer not touching the specific UNIX code... */ | ||
231 | return _ecore_file_stat(file, NULL, NULL, NULL, NULL, NULL); | ||
232 | #else | ||
173 | struct stat st; | 233 | struct stat st; |
174 | if (!file) return EINA_FALSE; | 234 | if (!file) return EINA_FALSE; |
175 | 235 | ||
176 | /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/ | 236 | /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/ |
177 | if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE; | 237 | if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE; |
178 | return EINA_TRUE; | 238 | return EINA_TRUE; |
239 | #endif | ||
179 | } | 240 | } |
180 | 241 | ||
181 | /** | 242 | /** |
@@ -191,11 +252,12 @@ ecore_file_exists(const char *file) | |||
191 | EAPI Eina_Bool | 252 | EAPI Eina_Bool |
192 | ecore_file_is_dir(const char *file) | 253 | ecore_file_is_dir(const char *file) |
193 | { | 254 | { |
194 | struct stat st; | 255 | Eina_Bool is_dir; |
195 | 256 | ||
196 | if (stat(file, &st) < 0) return EINA_FALSE; | 257 | if (!_ecore_file_stat(file, NULL, NULL, NULL, &is_dir, NULL)) |
197 | if (S_ISDIR(st.st_mode)) return EINA_TRUE; | 258 | return EINA_FALSE; |
198 | return EINA_FALSE; | 259 | |
260 | return is_dir; | ||
199 | } | 261 | } |
200 | 262 | ||
201 | static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; | 263 | static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
@@ -299,16 +361,21 @@ ecore_file_mksubdirs(const char *base, const char **subdirs) | |||
299 | i = 0; | 361 | i = 0; |
300 | for (; *subdirs; subdirs++) | 362 | for (; *subdirs; subdirs++) |
301 | { | 363 | { |
364 | #ifdef HAVE_ATFILE_SOURCE | ||
302 | struct stat st; | 365 | struct stat st; |
366 | #endif | ||
367 | Eina_Bool is_dir; | ||
303 | 368 | ||
304 | #ifndef HAVE_ATFILE_SOURCE | 369 | #ifndef HAVE_ATFILE_SOURCE |
305 | eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen); | 370 | eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen); |
306 | if (stat(buf, &st) == 0) | 371 | if (_ecore_file_stat(buf, NULL, NULL, NULL, &is_dir, NULL)) |
372 | { | ||
307 | #else | 373 | #else |
308 | if (fstatat(fd, *subdirs, &st, 0) == 0) | 374 | if (fstatat(fd, *subdirs, &st, 0) == 0) |
309 | #endif | ||
310 | { | 375 | { |
311 | if (S_ISDIR(st.st_mode)) | 376 | is_dir = S_ISDIR(st.st_mode); |
377 | #endif | ||
378 | if (is_dir) | ||
312 | { | 379 | { |
313 | i++; | 380 | i++; |
314 | continue; | 381 | continue; |
@@ -399,21 +466,25 @@ ecore_file_remove(const char *file) | |||
399 | EAPI Eina_Bool | 466 | EAPI Eina_Bool |
400 | ecore_file_recursive_rm(const char *dir) | 467 | ecore_file_recursive_rm(const char *dir) |
401 | { | 468 | { |
469 | #ifndef _WIN32 | ||
402 | struct stat st; | 470 | struct stat st; |
471 | #endif | ||
472 | Eina_Bool is_dir; | ||
403 | 473 | ||
404 | #ifdef _WIN32 | 474 | #ifdef _WIN32 |
405 | char buf[PATH_MAX]; | 475 | char buf[PATH_MAX]; |
406 | 476 | ||
407 | if (readlink(dir, buf, sizeof(buf) - 1) > 0) | 477 | if (readlink(dir, buf, sizeof(buf) - 1) > 0) |
408 | return ecore_file_unlink(dir); | 478 | return ecore_file_unlink(dir); |
409 | if (stat(dir, &st) == -1) | 479 | if (!_ecore_file_stat(buf, NULL, NULL, NULL, &is_dir, NULL)) |
410 | return EINA_FALSE; | 480 | return EINA_FALSE; |
411 | #else | 481 | #else |
412 | if (lstat(dir, &st) == -1) | 482 | if (lstat(dir, &st) == -1) |
413 | return EINA_FALSE; | 483 | return EINA_FALSE; |
484 | is_dir = S_ISDIR(st.st_mode); | ||
414 | #endif | 485 | #endif |
415 | 486 | ||
416 | if (S_ISDIR(st.st_mode)) | 487 | if (is_dir) |
417 | { | 488 | { |
418 | Eina_File_Direct_Info *info; | 489 | Eina_File_Direct_Info *info; |
419 | Eina_Iterator *it; | 490 | Eina_Iterator *it; |
@@ -443,7 +514,7 @@ ecore_file_recursive_rm(const char *dir) | |||
443 | static inline Eina_Bool | 514 | static inline Eina_Bool |
444 | _ecore_file_mkpath_if_not_exists(const char *path) | 515 | _ecore_file_mkpath_if_not_exists(const char *path) |
445 | { | 516 | { |
446 | struct stat st; | 517 | Eina_Bool is_dir; |
447 | 518 | ||
448 | /* Windows: path like C: or D: etc are valid, but stat() returns an error */ | 519 | /* Windows: path like C: or D: etc are valid, but stat() returns an error */ |
449 | #ifdef _WIN32 | 520 | #ifdef _WIN32 |
@@ -454,9 +525,9 @@ _ecore_file_mkpath_if_not_exists(const char *path) | |||
454 | return EINA_TRUE; | 525 | return EINA_TRUE; |
455 | #endif | 526 | #endif |
456 | 527 | ||
457 | if (stat(path, &st) < 0) | 528 | if (!_ecore_file_stat(path, NULL, NULL, NULL, &is_dir, NULL)) |
458 | return ecore_file_mkdir(path); | 529 | return ecore_file_mkdir(path); |
459 | else if (!S_ISDIR(st.st_mode)) | 530 | else if (!is_dir) |
460 | return EINA_FALSE; | 531 | return EINA_FALSE; |
461 | else | 532 | else |
462 | return EINA_TRUE; | 533 | return EINA_TRUE; |
@@ -587,13 +658,14 @@ ecore_file_mv(const char *src, const char *dst) | |||
587 | // it resides on a different mount point. | 658 | // it resides on a different mount point. |
588 | if (errno == EXDEV) | 659 | if (errno == EXDEV) |
589 | { | 660 | { |
590 | struct stat st; | 661 | mode_t mode; |
662 | Eina_Bool is_reg; | ||
591 | 663 | ||
592 | // Make sure this is a regular file before | 664 | // Make sure this is a regular file before |
593 | // we do anything fancy. | 665 | // we do anything fancy. |
594 | if (stat(src, &st) == -1) | 666 | if (!_ecore_file_stat(src, NULL, NULL, &mode, NULL, &is_reg)) |
595 | goto FAIL; | 667 | goto FAIL; |
596 | if (S_ISREG(st.st_mode)) | 668 | if (is_reg) |
597 | { | 669 | { |
598 | char *dir; | 670 | char *dir; |
599 | 671 | ||
@@ -613,7 +685,7 @@ ecore_file_mv(const char *src, const char *dst) | |||
613 | goto FAIL; | 685 | goto FAIL; |
614 | 686 | ||
615 | // Set file permissions of temp file to match src | 687 | // Set file permissions of temp file to match src |
616 | if (chmod(buf, st.st_mode) == -1) goto FAIL; | 688 | if (chmod(buf, mode) == -1) goto FAIL; |
617 | 689 | ||
618 | // Try to atomically move temp file to dst | 690 | // Try to atomically move temp file to dst |
619 | if (rename(buf, dst)) | 691 | if (rename(buf, dst)) |