diff options
Diffstat (limited to 'libraries/ecore/src/lib/ecore_file/ecore_file.c')
-rw-r--r-- | libraries/ecore/src/lib/ecore_file/ecore_file.c | 1109 |
1 files changed, 0 insertions, 1109 deletions
diff --git a/libraries/ecore/src/lib/ecore_file/ecore_file.c b/libraries/ecore/src/lib/ecore_file/ecore_file.c deleted file mode 100644 index cb03717..0000000 --- a/libraries/ecore/src/lib/ecore_file/ecore_file.c +++ /dev/null | |||
@@ -1,1109 +0,0 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #ifndef _MSC_VER | ||
10 | # include <unistd.h> | ||
11 | # include <libgen.h> | ||
12 | #endif | ||
13 | |||
14 | #ifdef _WIN32 | ||
15 | # include <direct.h> | ||
16 | #endif | ||
17 | |||
18 | #ifdef HAVE_FEATURES_H | ||
19 | # include <features.h> | ||
20 | #endif | ||
21 | #include <ctype.h> | ||
22 | #include <errno.h> | ||
23 | |||
24 | #ifdef HAVE_ATFILE_SOURCE | ||
25 | # include <dirent.h> | ||
26 | #endif | ||
27 | |||
28 | #include "ecore_file_private.h" | ||
29 | |||
30 | int _ecore_file_log_dom = -1; | ||
31 | static int _ecore_file_init_count = 0; | ||
32 | |||
33 | /* externally accessible functions */ | ||
34 | |||
35 | /** | ||
36 | * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions | ||
37 | * | ||
38 | * @{ | ||
39 | */ | ||
40 | |||
41 | /** | ||
42 | * @brief Initialize the Ecore_File library. | ||
43 | * | ||
44 | * @return 1 or greater on success, 0 on error. | ||
45 | * | ||
46 | * This function sets up Ecore_File and the services it will use | ||
47 | * (monitoring, downloading, PATH related feature). It returns 0 on | ||
48 | * failure, otherwise it returns the number of times it has already | ||
49 | * been called. | ||
50 | * | ||
51 | * When Ecore_File is not used anymore, call ecore_file_shutdown() | ||
52 | * to shut down the Ecore_File library. | ||
53 | */ | ||
54 | EAPI int | ||
55 | ecore_file_init() | ||
56 | { | ||
57 | if (++_ecore_file_init_count != 1) | ||
58 | return _ecore_file_init_count; | ||
59 | |||
60 | if (!ecore_init()) | ||
61 | return --_ecore_file_init_count; | ||
62 | |||
63 | _ecore_file_log_dom = eina_log_domain_register | ||
64 | ("ecore_file", ECORE_FILE_DEFAULT_LOG_COLOR); | ||
65 | if(_ecore_file_log_dom < 0) | ||
66 | { | ||
67 | EINA_LOG_ERR("Impossible to create a log domain for the ecore file module."); | ||
68 | return --_ecore_file_init_count; | ||
69 | } | ||
70 | ecore_file_path_init(); | ||
71 | ecore_file_monitor_init(); | ||
72 | ecore_file_download_init(); | ||
73 | |||
74 | /* FIXME: were the tests disabled for a good reason ? */ | ||
75 | |||
76 | /* | ||
77 | if (!ecore_file_monitor_init()) | ||
78 | goto shutdown_ecore_file_path; | ||
79 | |||
80 | if (!ecore_file_download_init()) | ||
81 | goto shutdown_ecore_file_monitor; | ||
82 | */ | ||
83 | |||
84 | return _ecore_file_init_count; | ||
85 | |||
86 | /* | ||
87 | shutdown_ecore_file_monitor: | ||
88 | ecore_file_monitor_shutdown(); | ||
89 | shutdown_ecore_file_path: | ||
90 | ecore_file_path_shutdown(); | ||
91 | |||
92 | return --_ecore_file_init_count; | ||
93 | */ | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * @brief Shut down the Ecore_File library. | ||
98 | * | ||
99 | * @return 0 when the library is completely shut down, 1 or | ||
100 | * greater otherwise. | ||
101 | * | ||
102 | * This function shuts down the Ecore_File library. It returns 0 when it has | ||
103 | * been called the same number of times than ecore_file_init(). In that case | ||
104 | * it shuts down all the services it uses. | ||
105 | */ | ||
106 | EAPI int | ||
107 | ecore_file_shutdown() | ||
108 | { | ||
109 | if (--_ecore_file_init_count != 0) | ||
110 | return _ecore_file_init_count; | ||
111 | |||
112 | ecore_file_download_shutdown(); | ||
113 | ecore_file_monitor_shutdown(); | ||
114 | ecore_file_path_shutdown(); | ||
115 | |||
116 | eina_log_domain_unregister(_ecore_file_log_dom); | ||
117 | _ecore_file_log_dom = -1; | ||
118 | |||
119 | ecore_shutdown(); | ||
120 | |||
121 | return _ecore_file_init_count; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * @brief Get the time of the last modification to the given file. | ||
126 | * | ||
127 | * @param file The name of the file. | ||
128 | * @return Return the time of the last data modification, or 0 on | ||
129 | * failure. | ||
130 | * | ||
131 | * This function returns the time of the last modification of | ||
132 | * @p file. On failure, it returns 0. | ||
133 | */ | ||
134 | EAPI long long | ||
135 | ecore_file_mod_time(const char *file) | ||
136 | { | ||
137 | struct stat st; | ||
138 | |||
139 | if (stat(file, &st) < 0) return 0; | ||
140 | return st.st_mtime; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * @brief Get the size of the given file. | ||
145 | * | ||
146 | * @param file The name of the file. | ||
147 | * @return Return the size of the file in bytes, or 0 on failure. | ||
148 | * | ||
149 | * This function returns the size of @p file in bytes. On failure, it | ||
150 | * returns 0. | ||
151 | */ | ||
152 | EAPI long long | ||
153 | ecore_file_size(const char *file) | ||
154 | { | ||
155 | struct stat st; | ||
156 | |||
157 | if (stat(file, &st) < 0) return 0; | ||
158 | return st.st_size; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * @brief Check if the given file exists. | ||
163 | * | ||
164 | * @param file The name of the file. | ||
165 | * @return Return EINA_TRUE if the file exists, EINA_FALSE otherwise. | ||
166 | * | ||
167 | * This function returns EINA_TRUE if @p file exists on local filesystem, | ||
168 | * EINA_FALSE otherwise. | ||
169 | */ | ||
170 | EAPI Eina_Bool | ||
171 | ecore_file_exists(const char *file) | ||
172 | { | ||
173 | struct stat st; | ||
174 | if (!file) return EINA_FALSE; | ||
175 | |||
176 | /*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; | ||
178 | return EINA_TRUE; | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * @brief Check if the given file is a directory. | ||
183 | * | ||
184 | * @param file The name of the file. | ||
185 | * @return Return EINA_TRUE if the file exists and is a directory, | ||
186 | * EINA_FALSE otherwise. | ||
187 | * | ||
188 | * This function returns EINA_TRUE if @p file exists exists and is a | ||
189 | * directory on local filesystem, EINA_FALSE otherwise. | ||
190 | */ | ||
191 | EAPI Eina_Bool | ||
192 | ecore_file_is_dir(const char *file) | ||
193 | { | ||
194 | struct stat st; | ||
195 | |||
196 | if (stat(file, &st) < 0) return EINA_FALSE; | ||
197 | if (S_ISDIR(st.st_mode)) return EINA_TRUE; | ||
198 | return EINA_FALSE; | ||
199 | } | ||
200 | |||
201 | static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; | ||
202 | |||
203 | /** | ||
204 | * @brief Create a new directory. | ||
205 | * | ||
206 | * @param dir The name of the directory to create | ||
207 | * @return EINA_TRUE on successful creation, EINA_FALSE otherwise. | ||
208 | * | ||
209 | * This function creates the directory @p dir with the mode S_IRUSR | | ||
210 | * S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH. On | ||
211 | * success, it returns EINA_TRUE, EINA_FALSE otherwise. | ||
212 | */ | ||
213 | EAPI Eina_Bool | ||
214 | ecore_file_mkdir(const char *dir) | ||
215 | { | ||
216 | if (mkdir(dir, default_mode) < 0) return EINA_FALSE; | ||
217 | return EINA_TRUE; | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * @brief Create complete directory in a batch. | ||
222 | * | ||
223 | * @param dirs The list of directories, null terminated. | ||
224 | * @return The number of successful directories created, -1 if dirs is | ||
225 | * @c NULL. | ||
226 | * | ||
227 | * This function creates all the directories that are in the null | ||
228 | * terminated array @p dirs. The function loops over the directories | ||
229 | * and call ecore_file_mkdir(). This function returns -1 if @p dirs is | ||
230 | * @c NULL, otherwise if returns the number of suceesfully created | ||
231 | * directories. | ||
232 | */ | ||
233 | EAPI int | ||
234 | ecore_file_mkdirs(const char **dirs) | ||
235 | { | ||
236 | int i = 0; | ||
237 | |||
238 | if (!dirs) return -1; | ||
239 | |||
240 | for (; *dirs; dirs++) | ||
241 | if (ecore_file_mkdir(*dirs)) | ||
242 | i++; | ||
243 | return i; | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * @brief Create complete list of sub-directories in a batch (optimized). | ||
248 | * | ||
249 | * @param base The base directory to act on. | ||
250 | * @param subdirs The list of directories, null terminated. | ||
251 | * @return number of successful directories created, -1 on failure. | ||
252 | * | ||
253 | * This function creates all the directories that are in the null | ||
254 | * terminated array @p dirs in the @p base directory. If @p base does | ||
255 | * not exist, it will be created. The function loops over the directories | ||
256 | * and call ecore_file_mkdir(). The whole path of the directories must | ||
257 | * exist. So if base/a/b/c wants to be created, @p subdirs must | ||
258 | * contain "a", "a/b" and "a/b/c", in that order. This function | ||
259 | * returns -1 if @p dirs or @p base are @c NULL, or if @p base is | ||
260 | * empty ("\0"). It returns 0 is @p base is not a directory or | ||
261 | * invalid, or if it can't be created. Otherwise if returns the number | ||
262 | * of suceesfully created directories. | ||
263 | */ | ||
264 | EAPI int | ||
265 | ecore_file_mksubdirs(const char *base, const char **subdirs) | ||
266 | { | ||
267 | #ifndef HAVE_ATFILE_SOURCE | ||
268 | char buf[PATH_MAX]; | ||
269 | int baselen; | ||
270 | #else | ||
271 | int fd; | ||
272 | DIR *dir; | ||
273 | #endif | ||
274 | int i; | ||
275 | |||
276 | if (!subdirs) return -1; | ||
277 | if ((!base) || (base[0] == '\0')) return -1; | ||
278 | |||
279 | if ((!ecore_file_is_dir(base)) && (!ecore_file_mkpath(base))) | ||
280 | return 0; | ||
281 | |||
282 | #ifndef HAVE_ATFILE_SOURCE | ||
283 | baselen = eina_strlcpy(buf, base, sizeof(buf)); | ||
284 | if ((baselen < 1) || (baselen + 1 >= (int)sizeof(buf))) | ||
285 | return 0; | ||
286 | |||
287 | if (buf[baselen - 1] != '/') | ||
288 | { | ||
289 | buf[baselen] = '/'; | ||
290 | baselen++; | ||
291 | } | ||
292 | #else | ||
293 | dir = opendir(base); | ||
294 | if (!dir) | ||
295 | return 0; | ||
296 | fd = dirfd(dir); | ||
297 | #endif | ||
298 | |||
299 | i = 0; | ||
300 | for (; *subdirs; subdirs++) | ||
301 | { | ||
302 | struct stat st; | ||
303 | |||
304 | #ifndef HAVE_ATFILE_SOURCE | ||
305 | eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen); | ||
306 | if (stat(buf, &st) == 0) | ||
307 | #else | ||
308 | if (fstatat(fd, *subdirs, &st, 0) == 0) | ||
309 | #endif | ||
310 | { | ||
311 | if (S_ISDIR(st.st_mode)) | ||
312 | { | ||
313 | i++; | ||
314 | continue; | ||
315 | } | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | if (errno == ENOENT) | ||
320 | { | ||
321 | #ifndef HAVE_ATFILE_SOURCE | ||
322 | if (mkdir(buf, default_mode) == 0) | ||
323 | #else | ||
324 | if (mkdirat(fd, *subdirs, default_mode) == 0) | ||
325 | #endif | ||
326 | { | ||
327 | i++; | ||
328 | continue; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | #ifdef HAVE_ATFILE_SOURCE | ||
335 | closedir(dir); | ||
336 | #endif | ||
337 | |||
338 | return i; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * @brief Delete the given directory. | ||
343 | * | ||
344 | * @param dir The name of the directory to delete. | ||
345 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
346 | * | ||
347 | * This function deletes @p dir. It returns EINA_TRUE on success, | ||
348 | * EINA_FALSE otherwise. | ||
349 | */ | ||
350 | EAPI Eina_Bool | ||
351 | ecore_file_rmdir(const char *dir) | ||
352 | { | ||
353 | if (rmdir(dir) < 0) return EINA_FALSE; | ||
354 | return EINA_TRUE; | ||
355 | } | ||
356 | |||
357 | /** | ||
358 | * @brief Delete the given file. | ||
359 | * | ||
360 | * @param file The name of the file to delete. | ||
361 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
362 | * | ||
363 | * This function deletes @p file. It returns EINA_TRUE on success, | ||
364 | * EINA_FALSE otherwise. | ||
365 | */ | ||
366 | EAPI Eina_Bool | ||
367 | ecore_file_unlink(const char *file) | ||
368 | { | ||
369 | if (unlink(file) < 0) return EINA_FALSE; | ||
370 | return EINA_TRUE; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * @brief Remove the given file or directory. | ||
375 | * | ||
376 | * @param file The name of the file or directory to delete. | ||
377 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
378 | * | ||
379 | * This function removes @p file. It returns EINA_TRUE on success, | ||
380 | * EINA_FALSE otherwise. | ||
381 | */ | ||
382 | EAPI Eina_Bool | ||
383 | ecore_file_remove(const char *file) | ||
384 | { | ||
385 | if (remove(file) < 0) return EINA_FALSE; | ||
386 | return EINA_TRUE; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * @brief Delete the given directory and all its contents. | ||
391 | * | ||
392 | * @param dir The name of the directory to delete. | ||
393 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
394 | * | ||
395 | * This function delete @p dir and all its contents. If @p dir is a | ||
396 | * link only the link is removed. It returns EINA_TRUE on success, | ||
397 | * EINA_FALSE otherwise. | ||
398 | */ | ||
399 | EAPI Eina_Bool | ||
400 | ecore_file_recursive_rm(const char *dir) | ||
401 | { | ||
402 | Eina_Iterator *it; | ||
403 | char buf[PATH_MAX]; | ||
404 | struct stat st; | ||
405 | int ret; | ||
406 | |||
407 | if (readlink(dir, buf, sizeof(buf)) > 0) | ||
408 | return ecore_file_unlink(dir); | ||
409 | |||
410 | ret = stat(dir, &st); | ||
411 | if ((ret == 0) && (S_ISDIR(st.st_mode))) | ||
412 | { | ||
413 | Eina_File_Direct_Info *info; | ||
414 | |||
415 | ret = 1; | ||
416 | if (stat(dir, &st) == -1) return EINA_FALSE; /* WOOT: WHY ARE WE CALLING STAT TWO TIMES ??? */ | ||
417 | |||
418 | it = eina_file_direct_ls(dir); | ||
419 | EINA_ITERATOR_FOREACH(it, info) | ||
420 | { | ||
421 | if (!ecore_file_recursive_rm(info->path)) | ||
422 | ret = 0; | ||
423 | } | ||
424 | eina_iterator_free(it); | ||
425 | |||
426 | if (!ecore_file_rmdir(dir)) ret = 0; | ||
427 | if (ret) | ||
428 | return EINA_TRUE; | ||
429 | else | ||
430 | return EINA_FALSE; | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | if (ret == -1) return EINA_FALSE; | ||
435 | return ecore_file_unlink(dir); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | static inline Eina_Bool | ||
440 | _ecore_file_mkpath_if_not_exists(const char *path) | ||
441 | { | ||
442 | struct stat st; | ||
443 | |||
444 | /* Windows: path like C: or D: etc are valid, but stat() returns an error */ | ||
445 | #ifdef _WIN32 | ||
446 | if ((strlen(path) == 2) && | ||
447 | ((path[0] >= 'a' && path[0] <= 'z') || | ||
448 | (path[0] >= 'A' && path[0] <= 'Z')) && | ||
449 | (path[1] == ':')) | ||
450 | return EINA_TRUE; | ||
451 | #endif | ||
452 | |||
453 | if (stat(path, &st) < 0) | ||
454 | return ecore_file_mkdir(path); | ||
455 | else if (!S_ISDIR(st.st_mode)) | ||
456 | return EINA_FALSE; | ||
457 | else | ||
458 | return EINA_TRUE; | ||
459 | } | ||
460 | |||
461 | /** | ||
462 | * @brief Create a complete path. | ||
463 | * | ||
464 | * @param path The path to create | ||
465 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
466 | * | ||
467 | * This function creates @p path and all the subdirectories it | ||
468 | * contains. The separator is '/' or '\'. If @p path exists, this | ||
469 | * function returns EINA_TRUE immediately. It returns EINA_TRUE on | ||
470 | * success, EINA_FALSE otherwise. | ||
471 | */ | ||
472 | EAPI Eina_Bool | ||
473 | ecore_file_mkpath(const char *path) | ||
474 | { | ||
475 | char ss[PATH_MAX]; | ||
476 | unsigned int i; | ||
477 | |||
478 | if (ecore_file_is_dir(path)) | ||
479 | return EINA_TRUE; | ||
480 | |||
481 | for (i = 0; path[i] != '\0'; ss[i] = path[i], i++) | ||
482 | { | ||
483 | if (i == sizeof(ss) - 1) return EINA_FALSE; | ||
484 | if (((path[i] == '/') || (path[i] == '\\')) && (i > 0)) | ||
485 | { | ||
486 | ss[i] = '\0'; | ||
487 | if (!_ecore_file_mkpath_if_not_exists(ss)) | ||
488 | return EINA_FALSE; | ||
489 | } | ||
490 | } | ||
491 | ss[i] = '\0'; | ||
492 | return _ecore_file_mkpath_if_not_exists(ss); | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * @brief Create complete paths in a batch. | ||
497 | * | ||
498 | * @param paths list of paths, null terminated. | ||
499 | * @return number of successful paths created, -1 if paths is NULL. | ||
500 | * | ||
501 | * This function creates all the directories that are in the null | ||
502 | * terminated array @p paths. The function loops over the directories | ||
503 | * and call ecore_file_mkpath(), hence on Windows, '\' must be | ||
504 | * replaced by '/' before calling that function. This function | ||
505 | * returns -1 if @p paths is @c NULL. Otherwise if returns the number | ||
506 | * of suceesfully created directories. | ||
507 | */ | ||
508 | EAPI int | ||
509 | ecore_file_mkpaths(const char **paths) | ||
510 | { | ||
511 | int i = 0; | ||
512 | |||
513 | if (!paths) return -1; | ||
514 | |||
515 | for (; *paths; paths++) | ||
516 | if (ecore_file_mkpath(*paths)) | ||
517 | i++; | ||
518 | return i; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * @brief Copy the given file to the given destination. | ||
523 | * | ||
524 | * @param src The name of the source file. | ||
525 | * @param dst The name of the destination file. | ||
526 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
527 | * | ||
528 | * This function copies @p src to @p dst. If the absolute path name of | ||
529 | * @p src and @p dst can not be computed, or if they are equal, or if | ||
530 | * the copy fails, the function returns EINA_FALSE, otherwise it | ||
531 | * returns EINA_TRUE. | ||
532 | */ | ||
533 | EAPI Eina_Bool | ||
534 | ecore_file_cp(const char *src, const char *dst) | ||
535 | { | ||
536 | FILE *f1, *f2; | ||
537 | char buf[16384]; | ||
538 | char realpath1[PATH_MAX], realpath2[PATH_MAX]; | ||
539 | size_t num; | ||
540 | Eina_Bool ret = EINA_TRUE; | ||
541 | |||
542 | if (!realpath(src, realpath1)) return EINA_FALSE; | ||
543 | if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE; | ||
544 | |||
545 | f1 = fopen(src, "rb"); | ||
546 | if (!f1) return EINA_FALSE; | ||
547 | f2 = fopen(dst, "wb"); | ||
548 | if (!f2) | ||
549 | { | ||
550 | fclose(f1); | ||
551 | return EINA_FALSE; | ||
552 | } | ||
553 | while ((num = fread(buf, 1, sizeof(buf), f1)) > 0) | ||
554 | { | ||
555 | if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE; | ||
556 | } | ||
557 | fclose(f1); | ||
558 | fclose(f2); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * @brief Move the given file to the given destination. | ||
564 | * | ||
565 | * @param src The name of the source file. | ||
566 | * @param dst The name of the destination file. | ||
567 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
568 | * | ||
569 | * This function moves @p src to @p dst. It returns EINA_TRUE on | ||
570 | * success, EINA_FALSE otherwise. | ||
571 | */ | ||
572 | EAPI Eina_Bool | ||
573 | ecore_file_mv(const char *src, const char *dst) | ||
574 | { | ||
575 | char buf[PATH_MAX]; | ||
576 | int fd; | ||
577 | |||
578 | if (rename(src, dst)) | ||
579 | { | ||
580 | // File cannot be moved directly because | ||
581 | // it resides on a different mount point. | ||
582 | if (errno == EXDEV) | ||
583 | { | ||
584 | struct stat st; | ||
585 | |||
586 | // Make sure this is a regular file before | ||
587 | // we do anything fancy. | ||
588 | stat(src, &st); | ||
589 | if (S_ISREG(st.st_mode)) | ||
590 | { | ||
591 | char *dir; | ||
592 | |||
593 | dir = ecore_file_dir_get(dst); | ||
594 | // Since we can't directly rename, try to | ||
595 | // copy to temp file in the dst directory | ||
596 | // and then rename. | ||
597 | snprintf(buf, sizeof(buf), "%s/.%s.tmp.XXXXXX", | ||
598 | dir, ecore_file_file_get(dst)); | ||
599 | free(dir); | ||
600 | fd = mkstemp(buf); | ||
601 | if (fd < 0) goto FAIL; | ||
602 | close(fd); | ||
603 | |||
604 | // Copy to temp file | ||
605 | if (!ecore_file_cp(src, buf)) | ||
606 | goto FAIL; | ||
607 | |||
608 | // Set file permissions of temp file to match src | ||
609 | chmod(buf, st.st_mode); | ||
610 | |||
611 | // Try to atomically move temp file to dst | ||
612 | if (rename(buf, dst)) | ||
613 | { | ||
614 | // If we still cannot atomically move | ||
615 | // do a normal copy and hope for the best. | ||
616 | if (!ecore_file_cp(buf, dst)) | ||
617 | goto FAIL; | ||
618 | } | ||
619 | |||
620 | // Delete temporary file and src | ||
621 | ecore_file_unlink(buf); | ||
622 | ecore_file_unlink(src); | ||
623 | goto PASS; | ||
624 | } | ||
625 | } | ||
626 | goto FAIL; | ||
627 | } | ||
628 | |||
629 | PASS: | ||
630 | return EINA_TRUE; | ||
631 | |||
632 | FAIL: | ||
633 | return EINA_FALSE; | ||
634 | } | ||
635 | |||
636 | /** | ||
637 | * @brief Create a symbolic link. | ||
638 | * | ||
639 | * @param src The name of the file to link. | ||
640 | * @param dest The name of link. | ||
641 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
642 | * | ||
643 | * This function create the symbolic link @p dest of @p src. This | ||
644 | * function does not work on Windows. It returns EINA_TRUE on success, | ||
645 | * EINA_FALSE otherwise. | ||
646 | */ | ||
647 | EAPI Eina_Bool | ||
648 | ecore_file_symlink(const char *src, const char *dest) | ||
649 | { | ||
650 | if (!symlink(src, dest)) return EINA_TRUE; | ||
651 | |||
652 | return EINA_FALSE; | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * @brief Get the canonicalized absolute path name. | ||
657 | * | ||
658 | * @param file The file path. | ||
659 | * @return The canonicalized absolute pathname or an empty string on | ||
660 | * failure. | ||
661 | * | ||
662 | * This function returns the absolute path name of @p file as a newly | ||
663 | * allocated string. If @p file is @c NULL, or on error, this function | ||
664 | * returns an empty string. Otherwise, it returns the absolute path | ||
665 | * name. When not needed anymore, the returned value must be freed. | ||
666 | */ | ||
667 | EAPI char * | ||
668 | ecore_file_realpath(const char *file) | ||
669 | { | ||
670 | char buf[PATH_MAX]; | ||
671 | |||
672 | /* | ||
673 | * Some implementations of realpath do not conform to the SUS. | ||
674 | * And as a result we must prevent a null arg from being passed. | ||
675 | */ | ||
676 | if (!file) return strdup(""); | ||
677 | if (!realpath(file, buf)) return strdup(""); | ||
678 | |||
679 | return strdup(buf); | ||
680 | } | ||
681 | |||
682 | /** | ||
683 | * Get the filename from a given path. | ||
684 | * | ||
685 | * @param path The complete path. | ||
686 | * @return The file name. | ||
687 | * | ||
688 | * This function returns the file name of @p path. If @p path is | ||
689 | * @c NULL, the functions returns @c NULL. | ||
690 | */ | ||
691 | EAPI const char * | ||
692 | ecore_file_file_get(const char *path) | ||
693 | { | ||
694 | char *result = NULL; | ||
695 | |||
696 | if (!path) return NULL; | ||
697 | if ((result = strrchr(path, '/'))) result++; | ||
698 | else result = (char *)path; | ||
699 | return result; | ||
700 | } | ||
701 | |||
702 | /** | ||
703 | * @brief Get the directory where the given file resides. | ||
704 | * | ||
705 | * @param file The name of the file. | ||
706 | * @return The directory name. | ||
707 | * | ||
708 | * This function returns the directory where @p file resides as anewly | ||
709 | * allocated string. If @p file is @c NULL or on error, this function | ||
710 | * returns @c NULL. When not needed anymore, the returned value must | ||
711 | * be freed. | ||
712 | */ | ||
713 | EAPI char * | ||
714 | ecore_file_dir_get(const char *file) | ||
715 | { | ||
716 | char *p; | ||
717 | char buf[PATH_MAX]; | ||
718 | |||
719 | if (!file) return NULL; | ||
720 | strncpy(buf, file, PATH_MAX); | ||
721 | buf[PATH_MAX - 1] = 0; | ||
722 | p = dirname(buf); | ||
723 | return strdup(p); | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * @brief Check if the given file can be read. | ||
728 | * | ||
729 | * @param file The name of the file. | ||
730 | * @return EINA_TRUE if the file is readable, EINA_FALSE otherwise. | ||
731 | * | ||
732 | * This function returns EINA_TRUE if @p file can be read, EINA_FALSE | ||
733 | * otherwise. | ||
734 | */ | ||
735 | EAPI Eina_Bool | ||
736 | ecore_file_can_read(const char *file) | ||
737 | { | ||
738 | if (!file) return EINA_FALSE; | ||
739 | if (!access(file, R_OK)) return EINA_TRUE; | ||
740 | return EINA_FALSE; | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * @brief Check if the given file can be written. | ||
745 | * | ||
746 | * @param file The name of the file. | ||
747 | * @return EINA_TRUE if the file is writable, EINA_FALSE otherwise. | ||
748 | * | ||
749 | * This function returns EINA_TRUE if @p file can be written, EINA_FALSE | ||
750 | * otherwise. | ||
751 | */ | ||
752 | EAPI Eina_Bool | ||
753 | ecore_file_can_write(const char *file) | ||
754 | { | ||
755 | if (!file) return EINA_FALSE; | ||
756 | if (!access(file, W_OK)) return EINA_TRUE; | ||
757 | return EINA_FALSE; | ||
758 | } | ||
759 | |||
760 | /** | ||
761 | * @brief Check if the given file can be executed. | ||
762 | * | ||
763 | * @param file The name of the file. | ||
764 | * @return EINA_TRUE if the file can be executed, EINA_FALSE otherwise. | ||
765 | * | ||
766 | * This function returns EINA_TRUE if @p file can be executed, EINA_FALSE | ||
767 | * otherwise. | ||
768 | */ | ||
769 | EAPI Eina_Bool | ||
770 | ecore_file_can_exec(const char *file) | ||
771 | { | ||
772 | if (!file) return EINA_FALSE; | ||
773 | if (!access(file, X_OK)) return EINA_TRUE; | ||
774 | return EINA_FALSE; | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * @brief Get the path pointed by the given link. | ||
779 | * | ||
780 | * @param lnk The name of the link. | ||
781 | * @return The path pointed by link or NULL. | ||
782 | * | ||
783 | * This function returns the path pointed by @p link as a newly | ||
784 | * allocated string. This function does not work on Windows. On | ||
785 | * failure, the function returns @c NULL. When not needed anymore, the | ||
786 | * returned value must be freed. | ||
787 | */ | ||
788 | EAPI char * | ||
789 | ecore_file_readlink(const char *lnk) | ||
790 | { | ||
791 | char buf[PATH_MAX]; | ||
792 | int count; | ||
793 | |||
794 | if ((count = readlink(lnk, buf, sizeof(buf) - 1)) < 0) return NULL; | ||
795 | buf[count] = 0; | ||
796 | return strdup(buf); | ||
797 | } | ||
798 | |||
799 | /** | ||
800 | * @brief Get the list of the files and directories in the given | ||
801 | * directory. | ||
802 | * | ||
803 | * @param dir The name of the directory to list | ||
804 | * @return Return an Eina_List containing all the files in the directory; | ||
805 | * on failure it returns NULL. | ||
806 | * | ||
807 | * This function returns a list of allocated strings of all the files | ||
808 | * and directories contained in @p dir. The list will be sorted with | ||
809 | * strcoll as compare function. That means that you may want to set | ||
810 | * the current locale for the category LC_COLLATE with | ||
811 | * setlocale(). For more information see the manual pages of strcoll | ||
812 | * and setlocale. The list will not contain the directory entries for | ||
813 | * '.' and '..'. On failure, @c NULL is returned. When not needed | ||
814 | * anymore, the list elements must be freed. | ||
815 | */ | ||
816 | EAPI Eina_List * | ||
817 | ecore_file_ls(const char *dir) | ||
818 | { | ||
819 | Eina_File_Direct_Info *info; | ||
820 | Eina_Iterator *ls; | ||
821 | Eina_List *list = NULL; | ||
822 | |||
823 | ls = eina_file_direct_ls(dir); | ||
824 | if (!ls) return NULL; | ||
825 | |||
826 | EINA_ITERATOR_FOREACH(ls, info) | ||
827 | { | ||
828 | char *f; | ||
829 | |||
830 | f = strdup(info->path + info->name_start); | ||
831 | list = eina_list_append(list, f); | ||
832 | } | ||
833 | eina_iterator_free(ls); | ||
834 | |||
835 | list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll)); | ||
836 | |||
837 | return list; | ||
838 | } | ||
839 | |||
840 | /** | ||
841 | * @brief Return the executable from the given command. | ||
842 | * | ||
843 | * @param app The application command, with parameters. | ||
844 | * | ||
845 | * This function returns the executable from @p app as a newly | ||
846 | * allocated string. Arguments are removed and escae characters are | ||
847 | * handled. If @p app is @c NULL, or on failure, the function returns | ||
848 | * @c NULL. When not needed anymore, the returned value must be freed. | ||
849 | */ | ||
850 | EAPI char * | ||
851 | ecore_file_app_exe_get(const char *app) | ||
852 | { | ||
853 | char *p, *pp, *exe1 = NULL, *exe2 = NULL; | ||
854 | char *exe = NULL; | ||
855 | int in_quot_dbl = 0, in_quot_sing = 0, restart = 0; | ||
856 | |||
857 | if (!app) return NULL; | ||
858 | |||
859 | p = (char *)app; | ||
860 | restart: | ||
861 | while ((*p) && (isspace((unsigned char)*p))) p++; | ||
862 | exe1 = p; | ||
863 | while (*p) | ||
864 | { | ||
865 | if (in_quot_sing) | ||
866 | { | ||
867 | if (*p == '\'') | ||
868 | in_quot_sing = 0; | ||
869 | } | ||
870 | else if (in_quot_dbl) | ||
871 | { | ||
872 | if (*p == '\"') | ||
873 | in_quot_dbl = 0; | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | if (*p == '\'') | ||
878 | in_quot_sing = 1; | ||
879 | else if (*p == '\"') | ||
880 | in_quot_dbl = 1; | ||
881 | if ((isspace((unsigned char)*p)) && ((p <= app) || (p[-1] == '\\'))) | ||
882 | break; | ||
883 | } | ||
884 | p++; | ||
885 | } | ||
886 | exe2 = p; | ||
887 | if (exe2 == exe1) return NULL; | ||
888 | if (*exe1 == '~') | ||
889 | { | ||
890 | char *homedir; | ||
891 | int len; | ||
892 | |||
893 | /* Skip ~ */ | ||
894 | exe1++; | ||
895 | |||
896 | homedir = getenv("HOME"); | ||
897 | if (!homedir) return NULL; | ||
898 | len = strlen(homedir); | ||
899 | if (exe) free(exe); | ||
900 | exe = malloc(len + exe2 - exe1 + 2); | ||
901 | if (!exe) return NULL; | ||
902 | pp = exe; | ||
903 | if (len) | ||
904 | { | ||
905 | strcpy(exe, homedir); | ||
906 | pp += len; | ||
907 | if (*(pp - 1) != '/') | ||
908 | { | ||
909 | *pp = '/'; | ||
910 | pp++; | ||
911 | } | ||
912 | } | ||
913 | } | ||
914 | else | ||
915 | { | ||
916 | if (exe) free(exe); | ||
917 | exe = malloc(exe2 - exe1 + 1); | ||
918 | if (!exe) return NULL; | ||
919 | pp = exe; | ||
920 | } | ||
921 | p = exe1; | ||
922 | restart = 0; | ||
923 | in_quot_dbl = 0; | ||
924 | in_quot_sing = 0; | ||
925 | while (*p) | ||
926 | { | ||
927 | if (in_quot_sing) | ||
928 | { | ||
929 | if (*p == '\'') | ||
930 | in_quot_sing = 0; | ||
931 | else | ||
932 | { | ||
933 | *pp = *p; | ||
934 | pp++; | ||
935 | } | ||
936 | } | ||
937 | else if (in_quot_dbl) | ||
938 | { | ||
939 | if (*p == '\"') | ||
940 | in_quot_dbl = 0; | ||
941 | else | ||
942 | { | ||
943 | /* technically this is wrong. double quotes also accept | ||
944 | * special chars: | ||
945 | * | ||
946 | * $, `, \ | ||
947 | */ | ||
948 | *pp = *p; | ||
949 | pp++; | ||
950 | } | ||
951 | } | ||
952 | else | ||
953 | { | ||
954 | /* technically we should handle special chars: | ||
955 | * | ||
956 | * $, `, \, etc. | ||
957 | */ | ||
958 | if ((p > exe1) && (p[-1] == '\\')) | ||
959 | { | ||
960 | if (*p != '\n') | ||
961 | { | ||
962 | *pp = *p; | ||
963 | pp++; | ||
964 | } | ||
965 | } | ||
966 | else if ((p > exe1) && (*p == '=')) | ||
967 | { | ||
968 | restart = 1; | ||
969 | *pp = *p; | ||
970 | pp++; | ||
971 | } | ||
972 | else if (*p == '\'') | ||
973 | in_quot_sing = 1; | ||
974 | else if (*p == '\"') | ||
975 | in_quot_dbl = 1; | ||
976 | else if (isspace((unsigned char)*p)) | ||
977 | { | ||
978 | if (restart) | ||
979 | goto restart; | ||
980 | else | ||
981 | break; | ||
982 | } | ||
983 | else | ||
984 | { | ||
985 | *pp = *p; | ||
986 | pp++; | ||
987 | } | ||
988 | } | ||
989 | p++; | ||
990 | } | ||
991 | *pp = 0; | ||
992 | return exe; | ||
993 | } | ||
994 | |||
995 | /** | ||
996 | * @brief Add the escape sequence ('\\') to the given file name. | ||
997 | * | ||
998 | * @param filename The file name. | ||
999 | * @return The file name with special characters escaped. | ||
1000 | * | ||
1001 | * This function adds the escape sequence ('\\') to the given file | ||
1002 | * name and returns the result as a newly allocated string. If the | ||
1003 | * length of the returned string is longer than PATH_MAX, or on | ||
1004 | * failure, @c NULL is returned. When not needed anymore, the returned | ||
1005 | * value must be freed. | ||
1006 | */ | ||
1007 | EAPI char * | ||
1008 | ecore_file_escape_name(const char *filename) | ||
1009 | { | ||
1010 | const char *p; | ||
1011 | char *q; | ||
1012 | char buf[PATH_MAX]; | ||
1013 | |||
1014 | p = filename; | ||
1015 | q = buf; | ||
1016 | while (*p) | ||
1017 | { | ||
1018 | if ((q - buf) > (PATH_MAX - 6)) return NULL; | ||
1019 | if ( | ||
1020 | (*p == ' ') || (*p == '\t') || (*p == '\n') || | ||
1021 | (*p == '\\') || (*p == '\'') || (*p == '\"') || | ||
1022 | (*p == ';') || (*p == '!') || (*p == '#') || | ||
1023 | (*p == '$') || (*p == '%') || (*p == '&') || | ||
1024 | (*p == '*') || (*p == '(') || (*p == ')') || | ||
1025 | (*p == '[') || (*p == ']') || (*p == '{') || | ||
1026 | (*p == '}') || (*p == '|') || (*p == '<') || | ||
1027 | (*p == '>') || (*p == '?') | ||
1028 | ) | ||
1029 | { | ||
1030 | *q = '\\'; | ||
1031 | q++; | ||
1032 | } | ||
1033 | *q = *p; | ||
1034 | q++; | ||
1035 | p++; | ||
1036 | } | ||
1037 | *q = 0; | ||
1038 | return strdup(buf); | ||
1039 | } | ||
1040 | |||
1041 | /** | ||
1042 | * @brief Remove the extension from the given file name. | ||
1043 | * | ||
1044 | * @param path The name of the file. | ||
1045 | * @return A newly allocated string with the extension stripped out or | ||
1046 | * NULL on errors. | ||
1047 | * | ||
1048 | * This function removes the extension from @p path and returns the | ||
1049 | * result as a newly allocated string. If @p path is @c NULL, or on | ||
1050 | * failure, the function returns @c NULL. When not needed anymore, the | ||
1051 | * returned value must be freed. | ||
1052 | */ | ||
1053 | EAPI char * | ||
1054 | ecore_file_strip_ext(const char *path) | ||
1055 | { | ||
1056 | char *p, *file = NULL; | ||
1057 | |||
1058 | if (!path) | ||
1059 | return NULL; | ||
1060 | |||
1061 | p = strrchr(path, '.'); | ||
1062 | if (!p) | ||
1063 | file = strdup(path); | ||
1064 | else if (p != path) | ||
1065 | { | ||
1066 | file = malloc(((p - path) + 1) * sizeof(char)); | ||
1067 | if (file) | ||
1068 | { | ||
1069 | memcpy(file, path, (p - path)); | ||
1070 | file[p - path] = 0; | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | return file; | ||
1075 | } | ||
1076 | |||
1077 | /** | ||
1078 | * @brief Check if the given directory is empty. | ||
1079 | * | ||
1080 | * @param dir The name of the directory to check. | ||
1081 | * @return 1 if directory is empty, 0 if it has at least one file or | ||
1082 | * -1 in case of errors. | ||
1083 | * | ||
1084 | * This functions checks if @p dir is empty. The '.' and '..' files | ||
1085 | * will be ignored. If @p dir is empty, 1 is returned, if it contains | ||
1086 | * at least 1 file, 0 is returned. On failure, -1 is returned. | ||
1087 | */ | ||
1088 | EAPI int | ||
1089 | ecore_file_dir_is_empty(const char *dir) | ||
1090 | { | ||
1091 | Eina_File_Direct_Info *info; | ||
1092 | Eina_Iterator *it; | ||
1093 | |||
1094 | it = eina_file_direct_ls(dir); | ||
1095 | if (!it) return -1; | ||
1096 | |||
1097 | EINA_ITERATOR_FOREACH(it, info) | ||
1098 | { | ||
1099 | eina_iterator_free(it); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | eina_iterator_free(it); | ||
1104 | return 1; | ||
1105 | } | ||
1106 | |||
1107 | /** | ||
1108 | * @} | ||
1109 | */ | ||