Cleanup: style, use braces for blenlib
[blender.git] / source / blender / blenlib / intern / fileops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bli
22  */
23
24
25 #include <stdlib.h>  /* malloc */
26 #include <string.h>
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31
32 #include <errno.h>
33
34 #include "zlib.h"
35
36 #ifdef WIN32
37 #  include <io.h>
38 #  include "BLI_winstuff.h"
39 #  include "BLI_callbacks.h"
40 #  include "BLI_fileops_types.h"
41 #  include "utf_winfunc.h"
42 #  include "utfconv.h"
43 #else
44 #  include <sys/param.h>
45 #  include <dirent.h>
46 #  include <unistd.h>
47 #  include <sys/stat.h>
48 #endif
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_utildefines.h"
53 #include "BLI_string.h"
54 #include "BLI_path_util.h"
55 #include "BLI_fileops.h"
56 #include "BLI_sys_types.h" // for intptr_t support
57
58 #if 0  /* UNUSED */
59 /* gzip the file in from and write it to "to".
60  * return -1 if zlib fails, -2 if the originating file does not exist
61  * note: will remove the "from" file
62  */
63 int BLI_file_gzip(const char *from, const char *to)
64 {
65         char buffer[10240];
66         int file;
67         int readsize = 0;
68         int rval = 0, err;
69         gzFile gzfile;
70
71         /* level 1 is very close to 3 (the default) in terms of file size,
72          * but about twice as fast, best use for speedy saving - campbell */
73         gzfile = BLI_gzopen(to, "wb1");
74         if (gzfile == NULL)
75                 return -1;
76         file = BLI_open(from, O_BINARY | O_RDONLY, 0);
77         if (file == -1)
78                 return -2;
79
80         while (1) {
81                 readsize = read(file, buffer, sizeof(buffer));
82
83                 if (readsize < 0) {
84                         rval = -2; /* error happened in reading */
85                         fprintf(stderr, "Error reading file %s: %s.\n", from, strerror(errno));
86                         break;
87                 }
88                 else if (readsize == 0)
89                         break;  /* done reading */
90
91                 if (gzwrite(gzfile, buffer, readsize) <= 0) {
92                         rval = -1; /* error happened in writing */
93                         fprintf(stderr, "Error writing gz file %s: %s.\n", to, gzerror(gzfile, &err));
94                         break;
95                 }
96         }
97
98         gzclose(gzfile);
99         close(file);
100
101         return rval;
102 }
103 #endif
104
105 /* gzip the file in from_file and write it to memory to_mem, at most size bytes.
106  * return the unziped size
107  */
108 char *BLI_file_ungzip_to_mem(const char *from_file, int *r_size)
109 {
110         gzFile gzfile;
111         int readsize, size, alloc_size = 0;
112         char *mem = NULL;
113         const int chunk_size = 512 * 1024;
114
115         size = 0;
116
117         gzfile = BLI_gzopen(from_file, "rb");
118         for (;; ) {
119                 if (mem == NULL) {
120                         mem = MEM_callocN(chunk_size, "BLI_ungzip_to_mem");
121                         alloc_size = chunk_size;
122                 }
123                 else {
124                         mem = MEM_reallocN(mem, size + chunk_size);
125                         alloc_size += chunk_size;
126                 }
127
128                 readsize = gzread(gzfile, mem + size, chunk_size);
129                 if (readsize > 0) {
130                         size += readsize;
131                 }
132                 else {
133                         break;
134                 }
135         }
136
137         gzclose(gzfile);
138
139         if (size == 0) {
140                 MEM_freeN(mem);
141                 mem = NULL;
142         }
143         else if (alloc_size != size) {
144                 mem = MEM_reallocN(mem, size);
145         }
146
147         *r_size = size;
148
149         return mem;
150 }
151
152 /**
153  * Returns true if the file with the specified name can be written.
154  * This implementation uses access(2), which makes the check according
155  * to the real UID and GID of the process, not its effective UID and GID.
156  * This shouldn't matter for Blender, which is not going to run privileged
157  * anyway.
158  */
159 bool BLI_file_is_writable(const char *filename)
160 {
161         bool writable;
162         if (BLI_access(filename, W_OK) == 0) {
163                 /* file exists and I can write to it */
164                 writable = true;
165         }
166         else if (errno != ENOENT) {
167                 /* most likely file or containing directory cannot be accessed */
168                 writable = false;
169         }
170         else {
171                 /* file doesn't exist -- check I can create it in parent directory */
172                 char parent[FILE_MAX];
173                 BLI_split_dirfile(filename, parent, NULL, sizeof(parent), 0);
174 #ifdef WIN32
175                 /* windows does not have X_OK */
176                 writable = BLI_access(parent, W_OK) == 0;
177 #else
178                 writable = BLI_access(parent, X_OK | W_OK) == 0;
179 #endif
180         }
181         return writable;
182 }
183
184 /**
185  * Creates the file with nothing in it, or updates its last-modified date if it already exists.
186  * Returns true if successful (like the unix touch command).
187  */
188 bool BLI_file_touch(const char *file)
189 {
190         FILE *f = BLI_fopen(file, "r+b");
191
192         if (f != NULL) {
193                 int c = getc(f);
194
195                 if (c == EOF) {
196                         /* Empty file, reopen in truncate write mode... */
197                         fclose(f);
198                         f = BLI_fopen(file, "w+b");
199                 }
200                 else {
201                         /* Otherwise, rewrite first byte. */
202                         rewind(f);
203                         putc(c, f);
204                 }
205         }
206         else {
207                 f = BLI_fopen(file, "wb");
208         }
209         if (f) {
210                 fclose(f);
211                 return true;
212         }
213         return false;
214 }
215
216 #ifdef WIN32
217
218 static void callLocalErrorCallBack(const char *err)
219 {
220         printf("%s\n", err);
221 }
222
223 FILE *BLI_fopen(const char *filename, const char *mode)
224 {
225         BLI_assert(!BLI_path_is_rel(filename));
226
227         return ufopen(filename, mode);
228 }
229
230 void BLI_get_short_name(char short_name[256], const char *filename)
231 {
232         wchar_t short_name_16[256];
233         int i = 0;
234
235         UTF16_ENCODE(filename);
236
237         GetShortPathNameW(filename_16, short_name_16, 256);
238
239         for (i = 0; i < 256; i++) {
240                 short_name[i] = (char)short_name_16[i];
241         }
242
243         UTF16_UN_ENCODE(filename);
244 }
245
246 void *BLI_gzopen(const char *filename, const char *mode)
247 {
248         gzFile gzfile;
249
250         BLI_assert(!BLI_path_is_rel(filename));
251
252         /* xxx Creates file before transcribing the path */
253         if (mode[0] == 'w') {
254                 fclose(ufopen(filename, "a"));
255         }
256
257         /* temporary #if until we update all libraries to 1.2.7
258          * for correct wide char path handling */
259 #if ZLIB_VERNUM >= 0x1270
260         UTF16_ENCODE(filename);
261
262         gzfile = gzopen_w(filename_16, mode);
263
264         UTF16_UN_ENCODE(filename);
265 #else
266         {
267                 char short_name[256];
268                 BLI_get_short_name(short_name, filename);
269                 gzfile = gzopen(short_name, mode);
270         }
271 #endif
272
273         return gzfile;
274 }
275
276 int   BLI_open(const char *filename, int oflag, int pmode)
277 {
278         BLI_assert(!BLI_path_is_rel(filename));
279
280         return uopen(filename, oflag, pmode);
281 }
282
283 int   BLI_access(const char *filename, int mode)
284 {
285         BLI_assert(!BLI_path_is_rel(filename));
286
287         return uaccess(filename, mode);
288 }
289
290 static bool delete_unique(const char *path, const bool dir)
291 {
292         bool err;
293
294         UTF16_ENCODE(path);
295
296         if (dir) {
297                 err = !RemoveDirectoryW(path_16);
298                 if (err) {
299                         printf("Unable to remove directory\n");
300                 }
301         }
302         else {
303                 err = !DeleteFileW(path_16);
304                 if (err) {
305                         callLocalErrorCallBack("Unable to delete file");
306                 }
307         }
308
309         UTF16_UN_ENCODE(path);
310
311         return err;
312 }
313
314 static bool delete_recursive(const char *dir)
315 {
316         struct direntry *filelist, *fl;
317         bool err = false;
318         uint nbr, i;
319
320         i = nbr = BLI_filelist_dir_contents(dir, &filelist);
321         fl = filelist;
322         while (i--) {
323                 const char *file = BLI_path_basename(fl->path);
324
325                 if (FILENAME_IS_CURRPAR(file)) {
326                         /* Skip! */
327                 }
328                 else if (S_ISDIR(fl->type)) {
329                         char path[FILE_MAXDIR];
330
331                         /* dir listing produces dir path without trailing slash... */
332                         BLI_strncpy(path, fl->path, sizeof(path));
333                         BLI_add_slash(path);
334
335                         if (delete_recursive(path)) {
336                                 err = true;
337                         }
338                 }
339                 else {
340                         if (delete_unique(fl->path, false)) {
341                                 err = true;
342                         }
343                 }
344                 ++fl;
345         }
346
347         if (!err && delete_unique(dir, true)) {
348                 err = true;
349         }
350
351         BLI_filelist_free(filelist, nbr);
352
353         return err;
354 }
355
356 int BLI_delete(const char *file, bool dir, bool recursive)
357 {
358         int err;
359
360         BLI_assert(!BLI_path_is_rel(file));
361
362         if (recursive) {
363                 err = delete_recursive(file);
364         }
365         else {
366                 err = delete_unique(file, dir);
367         }
368
369         return err;
370 }
371
372 /* Not used anywhere! */
373 #if 0
374 int BLI_move(const char *file, const char *to)
375 {
376         char str[MAXPATHLEN + 12];
377         int err;
378
379         /* windows doesn't support moving to a directory
380          * it has to be 'mv filename filename' and not
381          * 'mv filename destdir' */
382
383         BLI_strncpy(str, to, sizeof(str));
384         /* points 'to' to a directory ? */
385         if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
386                 if (BLI_last_slash(file) != NULL) {
387                         strcat(str, BLI_last_slash(file) + 1);
388                 }
389         }
390
391         UTF16_ENCODE(file);
392         UTF16_ENCODE(str);
393         err = !MoveFileW(file_16, str_16);
394         UTF16_UN_ENCODE(str);
395         UTF16_UN_ENCODE(file);
396
397         if (err) {
398                 callLocalErrorCallBack("Unable to move file");
399                 printf(" Move from '%s' to '%s' failed\n", file, str);
400         }
401
402         return err;
403 }
404 #endif
405
406 int BLI_copy(const char *file, const char *to)
407 {
408         char str[MAXPATHLEN + 12];
409         int err;
410
411         /* windows doesn't support copying to a directory
412          * it has to be 'cp filename filename' and not
413          * 'cp filename destdir' */
414
415         BLI_strncpy(str, to, sizeof(str));
416         /* points 'to' to a directory ? */
417         if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
418                 if (BLI_last_slash(file) != NULL) {
419                         strcat(str, BLI_last_slash(file) + 1);
420                 }
421         }
422
423         UTF16_ENCODE(file);
424         UTF16_ENCODE(str);
425         err = !CopyFileW(file_16, str_16, false);
426         UTF16_UN_ENCODE(str);
427         UTF16_UN_ENCODE(file);
428
429         if (err) {
430                 callLocalErrorCallBack("Unable to copy file!");
431                 printf(" Copy from '%s' to '%s' failed\n", file, str);
432         }
433
434         return err;
435 }
436
437 #if 0
438 int BLI_create_symlink(const char *file, const char *to)
439 {
440         /* See patch from T30870, should this ever become needed. */
441         callLocalErrorCallBack("Linking files is unsupported on Windows");
442         (void)file;
443         (void)to;
444         return 1;
445 }
446 #endif
447
448 /** \return true on success (i.e. given path now exists on FS), false otherwise. */
449 bool BLI_dir_create_recursive(const char *dirname)
450 {
451         char *lslash;
452         char tmp[MAXPATHLEN];
453         bool ret = true;
454
455         /* First remove possible slash at the end of the dirname.
456          * This routine otherwise tries to create
457          * blah1/blah2/ (with slash) after creating
458          * blah1/blah2 (without slash) */
459
460         BLI_strncpy(tmp, dirname, sizeof(tmp));
461         BLI_del_slash(tmp);
462
463         /* check special case "c:\foo", don't try create "c:", harmless but prints an error below */
464         if (isalpha(tmp[0]) && (tmp[1] == ':') && tmp[2] == '\0') {
465                 return true;
466         }
467
468         if (BLI_is_dir(tmp)) {
469                 return true;
470         }
471         else if (BLI_exists(tmp)) {
472                 return false;
473         }
474
475         lslash = (char *)BLI_last_slash(tmp);
476
477         if (lslash) {
478                 /* Split about the last slash and recurse */
479                 *lslash = 0;
480                 if (!BLI_dir_create_recursive(tmp)) {
481                         ret = false;
482                 }
483         }
484
485         if (ret && dirname[0]) {  /* patch, this recursive loop tries to create a nameless directory */
486                 if (umkdir(dirname) == -1) {
487                         printf("Unable to create directory %s\n", dirname);
488                         ret = false;
489                 }
490         }
491         return ret;
492 }
493
494 int BLI_rename(const char *from, const char *to)
495 {
496         if (!BLI_exists(from)) {
497                 return 0;
498         }
499
500         /* make sure the filenames are different (case insensitive) before removing */
501         if (BLI_exists(to) && BLI_strcasecmp(from, to)) {
502                 if (BLI_delete(to, false, false)) {
503                         return 1;
504                 }
505         }
506
507         return urename(from, to);
508 }
509
510 #else /* The UNIX world */
511
512 /* results from recursive_operation and its callbacks */
513 enum {
514         /* operation succeeded */
515         RecursiveOp_Callback_OK = 0,
516
517         /* operation requested not to perform recursive digging for current path */
518         RecursiveOp_Callback_StopRecurs = 1,
519
520         /* error occured in callback and recursive walking should stop immediately */
521         RecursiveOp_Callback_Error = 2,
522 };
523
524 typedef int (*RecursiveOp_Callback)(const char *from, const char *to);
525
526 /* appending of filename to dir (ensures for buffer size before appending) */
527 static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, const char *file)
528 {
529         size_t len = strlen(dir) + strlen(file) + 1;
530
531         if (*dst == NULL) {
532                 *dst = MEM_mallocN(len + 1, "join_dirfile_alloc path");
533         }
534         else if (*alloc_len < len) {
535                 *dst = MEM_reallocN(*dst, len + 1);
536         }
537
538         *alloc_len = len;
539
540         BLI_join_dirfile(*dst, len + 1, dir, file);
541 }
542
543 static char *strip_last_slash(const char *dir)
544 {
545         char *result = BLI_strdup(dir);
546         BLI_del_slash(result);
547
548         return result;
549 }
550
551
552
553 /**
554  * Scans \a startfrom, generating a corresponding destination name for each item found by
555  * prefixing it with startto, recursively scanning subdirectories, and invoking the specified
556  * callbacks for files and subdirectories found as appropriate.
557  *
558  * \param startfrom: Top-level source path.
559  * \param startto: Top-level destination path.
560  * \param callback_dir_pre: Optional, to be invoked before entering a subdirectory, can return
561  *                          RecursiveOp_Callback_StopRecurs to skip the subdirectory.
562  * \param callback_file: Optional, to be invoked on each file found.
563  * \param callback_dir_post: optional, to be invoked after leaving a subdirectory.
564  * \return
565  */
566 static int recursive_operation(const char *startfrom, const char *startto,
567                                RecursiveOp_Callback callback_dir_pre,
568                                RecursiveOp_Callback callback_file, RecursiveOp_Callback callback_dir_post)
569 {
570         struct stat st;
571         char *from = NULL, *to = NULL;
572         char *from_path = NULL, *to_path = NULL;
573         struct dirent **dirlist = NULL;
574         size_t from_alloc_len = -1, to_alloc_len = -1;
575         int i, n = 0, ret = 0;
576
577         do {  /* once */
578                 /* ensure there's no trailing slash in file path */
579                 from = strip_last_slash(startfrom);
580                 if (startto) {
581                         to = strip_last_slash(startto);
582                 }
583
584                 ret = lstat(from, &st);
585                 if (ret < 0) {
586                         /* source wasn't found, nothing to operate with */
587                         break;
588                 }
589
590                 if (!S_ISDIR(st.st_mode)) {
591                         /* source isn't a directory, can't do recursive walking for it,
592                          * so just call file callback and leave */
593                         if (callback_file != NULL) {
594                                 ret = callback_file(from, to);
595                                 if (ret != RecursiveOp_Callback_OK) {
596                                         ret = -1;
597                                 }
598                         }
599                         break;
600                 }
601
602                 n = scandir(startfrom, &dirlist, NULL, alphasort);
603                 if (n < 0) {
604                         /* error opening directory for listing */
605                         perror("scandir");
606                         ret = -1;
607                         break;
608                 }
609
610                 if (callback_dir_pre != NULL) {
611                         ret = callback_dir_pre(from, to);
612                         if (ret != RecursiveOp_Callback_OK) {
613                                 if (ret == RecursiveOp_Callback_StopRecurs) {
614                                         /* callback requested not to perform recursive walking, not an error */
615                                         ret = 0;
616                                 }
617                                 else {
618                                         ret = -1;
619                                 }
620                                 break;
621                         }
622                 }
623
624                 for (i = 0; i < n; i++) {
625                         const struct dirent * const dirent = dirlist[i];
626
627                         if (FILENAME_IS_CURRPAR(dirent->d_name)) {
628                                 continue;
629                         }
630
631                         join_dirfile_alloc(&from_path, &from_alloc_len, from, dirent->d_name);
632                         if (to) {
633                                 join_dirfile_alloc(&to_path, &to_alloc_len, to, dirent->d_name);
634                         }
635
636                         bool is_dir;
637
638 #ifdef __HAIKU__
639                         {
640                                 struct stat st_dir;
641                                 char filename[FILE_MAX];
642                                 BLI_path_join(filename, sizeof(filename), startfrom, dirent->d_name, NULL);
643                                 lstat(filename, &st_dir);
644                                 is_dir = S_ISDIR(st_dir.st_mode);
645                         }
646 #else
647                         is_dir = (dirent->d_type == DT_DIR);
648 #endif
649
650                         if (is_dir) {
651                                 /* recursively dig into a subfolder */
652                                 ret = recursive_operation(from_path, to_path, callback_dir_pre, callback_file, callback_dir_post);
653                         }
654                         else if (callback_file != NULL) {
655                                 ret = callback_file(from_path, to_path);
656                                 if (ret != RecursiveOp_Callback_OK) {
657                                         ret = -1;
658                                 }
659                         }
660
661                         if (ret != 0) {
662                                 break;
663                         }
664                 }
665                 if (ret != 0) {
666                         break;
667                 }
668
669                 if (callback_dir_post != NULL) {
670                         ret = callback_dir_post(from, to);
671                         if (ret != RecursiveOp_Callback_OK) {
672                                 ret = -1;
673                         }
674                 }
675         } while (false);
676
677         if (dirlist != NULL) {
678                 for (i = 0; i < n; i++) {
679                         free(dirlist[i]);
680                 }
681                 free(dirlist);
682         }
683         if (from_path != NULL) {
684                 MEM_freeN(from_path);
685         }
686         if (to_path != NULL) {
687                 MEM_freeN(to_path);
688         }
689         if (from != NULL) {
690                 MEM_freeN(from);
691         }
692         if (to != NULL) {
693                 MEM_freeN(to);
694         }
695
696         return ret;
697 }
698
699 static int delete_callback_post(const char *from, const char *UNUSED(to))
700 {
701         if (rmdir(from)) {
702                 perror("rmdir");
703
704                 return RecursiveOp_Callback_Error;
705         }
706
707         return RecursiveOp_Callback_OK;
708 }
709
710 static int delete_single_file(const char *from, const char *UNUSED(to))
711 {
712         if (unlink(from)) {
713                 perror("unlink");
714
715                 return RecursiveOp_Callback_Error;
716         }
717
718         return RecursiveOp_Callback_OK;
719 }
720
721 FILE *BLI_fopen(const char *filename, const char *mode)
722 {
723         BLI_assert(!BLI_path_is_rel(filename));
724
725         return fopen(filename, mode);
726 }
727
728 void *BLI_gzopen(const char *filename, const char *mode)
729 {
730         BLI_assert(!BLI_path_is_rel(filename));
731
732         return gzopen(filename, mode);
733 }
734
735 int BLI_open(const char *filename, int oflag, int pmode)
736 {
737         BLI_assert(!BLI_path_is_rel(filename));
738
739         return open(filename, oflag, pmode);
740 }
741
742 int   BLI_access(const char *filename, int mode)
743 {
744         BLI_assert(!BLI_path_is_rel(filename));
745
746         return access(filename, mode);
747 }
748
749
750 /**
751  * Deletes the specified file or directory (depending on dir), optionally
752  * doing recursive delete of directory contents.
753  *
754  * \return zero on success (matching 'remove' behavior).
755  */
756 int BLI_delete(const char *file, bool dir, bool recursive)
757 {
758         BLI_assert(!BLI_path_is_rel(file));
759
760         if (recursive) {
761                 return recursive_operation(file, NULL, NULL, delete_single_file, delete_callback_post);
762         }
763         else if (dir) {
764                 return rmdir(file);
765         }
766         else {
767                 return remove(file);
768         }
769 }
770
771 /**
772  * Do the two paths denote the same filesystem object?
773  */
774 static bool check_the_same(const char *path_a, const char *path_b)
775 {
776         struct stat st_a, st_b;
777
778         if (lstat(path_a, &st_a)) {
779                 return false;
780         }
781
782         if (lstat(path_b, &st_b)) {
783                 return false;
784         }
785
786         return st_a.st_dev == st_b.st_dev && st_a.st_ino == st_b.st_ino;
787 }
788
789 /**
790  * Sets the mode and ownership of file to the values from st.
791  */
792 static int set_permissions(const char *file, const struct stat *st)
793 {
794         if (chown(file, st->st_uid, st->st_gid)) {
795                 perror("chown");
796                 return -1;
797         }
798
799         if (chmod(file, st->st_mode)) {
800                 perror("chmod");
801                 return -1;
802         }
803
804         return 0;
805 }
806
807 /* pre-recursive callback for copying operation
808  * creates a destination directory where all source content fill be copied to */
809 static int copy_callback_pre(const char *from, const char *to)
810 {
811         struct stat st;
812
813         if (check_the_same(from, to)) {
814                 fprintf(stderr, "%s: '%s' is the same as '%s'\n", __func__, from, to);
815                 return RecursiveOp_Callback_Error;
816         }
817
818         if (lstat(from, &st)) {
819                 perror("stat");
820                 return RecursiveOp_Callback_Error;
821         }
822
823         /* create a directory */
824         if (mkdir(to, st.st_mode)) {
825                 perror("mkdir");
826                 return RecursiveOp_Callback_Error;
827         }
828
829         /* set proper owner and group on new directory */
830         if (chown(to, st.st_uid, st.st_gid)) {
831                 perror("chown");
832                 return RecursiveOp_Callback_Error;
833         }
834
835         return RecursiveOp_Callback_OK;
836 }
837
838 static int copy_single_file(const char *from, const char *to)
839 {
840         FILE *from_stream, *to_stream;
841         struct stat st;
842         char buf[4096];
843         size_t len;
844
845         if (check_the_same(from, to)) {
846                 fprintf(stderr, "%s: '%s' is the same as '%s'\n", __func__, from, to);
847                 return RecursiveOp_Callback_Error;
848         }
849
850         if (lstat(from, &st)) {
851                 perror("lstat");
852                 return RecursiveOp_Callback_Error;
853         }
854
855         if (S_ISLNK(st.st_mode)) {
856                 /* symbolic links should be copied in special way */
857                 char *link_buffer;
858                 int need_free;
859                 ssize_t link_len;
860
861                 /* get large enough buffer to read link content */
862                 if ((st.st_size + 1) < sizeof(buf)) {
863                         link_buffer = buf;
864                         need_free = 0;
865                 }
866                 else {
867                         link_buffer = MEM_callocN(st.st_size + 2, "copy_single_file link_buffer");
868                         need_free = 1;
869                 }
870
871                 link_len = readlink(from, link_buffer, st.st_size + 1);
872                 if (link_len < 0) {
873                         perror("readlink");
874
875                         if (need_free) {
876                                 MEM_freeN(link_buffer);
877                         }
878
879                         return RecursiveOp_Callback_Error;
880                 }
881
882                 link_buffer[link_len] = '\0';
883
884                 if (symlink(link_buffer, to)) {
885                         perror("symlink");
886                         if (need_free) {
887                                 MEM_freeN(link_buffer);
888                         }
889                         return RecursiveOp_Callback_Error;
890                 }
891
892                 if (need_free) {
893                         MEM_freeN(link_buffer);
894                 }
895
896                 return RecursiveOp_Callback_OK;
897         }
898         else if (S_ISCHR(st.st_mode) ||
899                  S_ISBLK(st.st_mode) ||
900                  S_ISFIFO(st.st_mode) ||
901                  S_ISSOCK(st.st_mode))
902         {
903                 /* copy special type of file */
904                 if (mknod(to, st.st_mode, st.st_rdev)) {
905                         perror("mknod");
906                         return RecursiveOp_Callback_Error;
907                 }
908
909                 if (set_permissions(to, &st)) {
910                         return RecursiveOp_Callback_Error;
911                 }
912
913                 return RecursiveOp_Callback_OK;
914         }
915         else if (!S_ISREG(st.st_mode)) {
916                 fprintf(stderr, "Copying of this kind of files isn't supported yet\n");
917                 return RecursiveOp_Callback_Error;
918         }
919
920         from_stream = fopen(from, "rb");
921         if (!from_stream) {
922                 perror("fopen");
923                 return RecursiveOp_Callback_Error;
924         }
925
926         to_stream = fopen(to, "wb");
927         if (!to_stream) {
928                 perror("fopen");
929                 fclose(from_stream);
930                 return RecursiveOp_Callback_Error;
931         }
932
933         while ((len = fread(buf, 1, sizeof(buf), from_stream)) > 0) {
934                 fwrite(buf, 1, len, to_stream);
935         }
936
937         fclose(to_stream);
938         fclose(from_stream);
939
940         if (set_permissions(to, &st)) {
941                 return RecursiveOp_Callback_Error;
942         }
943
944         return RecursiveOp_Callback_OK;
945 }
946
947 /* Not used anywhere! */
948 #if 0
949 static int move_callback_pre(const char *from, const char *to)
950 {
951         int ret = rename(from, to);
952
953         if (ret)
954                 return copy_callback_pre(from, to);
955
956         return RecursiveOp_Callback_StopRecurs;
957 }
958
959 static int move_single_file(const char *from, const char *to)
960 {
961         int ret = rename(from, to);
962
963         if (ret)
964                 return copy_single_file(from, to);
965
966         return RecursiveOp_Callback_OK;
967 }
968
969 /* if *file represents a directory, moves all its contents into *to, else renames
970  * file itself to *to. */
971 int BLI_move(const char *file, const char *to)
972 {
973         int ret = recursive_operation(file, to, move_callback_pre, move_single_file, NULL);
974
975         if (ret && ret != -1) {
976                 return recursive_operation(file, NULL, NULL, delete_single_file, delete_callback_post);
977         }
978
979         return ret;
980 }
981 #endif
982
983 static const char *check_destination(const char *file, const char *to)
984 {
985         struct stat st;
986
987         if (!stat(to, &st)) {
988                 if (S_ISDIR(st.st_mode)) {
989                         char *str, *path;
990                         const char *filename;
991                         size_t len = 0;
992
993                         str = strip_last_slash(file);
994                         filename = BLI_last_slash(str);
995
996                         if (!filename) {
997                                 MEM_freeN(str);
998                                 return (char *)to;
999                         }
1000
1001                         /* skip slash */
1002                         filename += 1;
1003
1004                         len = strlen(to) + strlen(filename) + 1;
1005                         path = MEM_callocN(len + 1, "check_destination path");
1006                         BLI_join_dirfile(path, len + 1, to, filename);
1007
1008                         MEM_freeN(str);
1009
1010                         return path;
1011                 }
1012         }
1013
1014         return to;
1015 }
1016
1017 int BLI_copy(const char *file, const char *to)
1018 {
1019         const char *actual_to = check_destination(file, to);
1020         int ret;
1021
1022         ret = recursive_operation(file, actual_to, copy_callback_pre, copy_single_file, NULL);
1023
1024         if (actual_to != to) {
1025                 MEM_freeN((void *)actual_to);
1026         }
1027
1028         return ret;
1029 }
1030
1031 #if 0
1032 int BLI_create_symlink(const char *file, const char *to)
1033 {
1034         return symlink(to, file);
1035 }
1036 #endif
1037
1038 /** \return true on success (i.e. given path now exists on FS), false otherwise. */
1039 bool BLI_dir_create_recursive(const char *dirname)
1040 {
1041         char *lslash;
1042         size_t size;
1043 #ifdef MAXPATHLEN
1044         char static_buf[MAXPATHLEN];
1045 #endif
1046         char *tmp;
1047         bool ret = true;
1048
1049         if (BLI_is_dir(dirname)) {
1050                 return true;
1051         }
1052         else if (BLI_exists(dirname)) {
1053                 return false;
1054         }
1055
1056 #ifdef MAXPATHLEN
1057         size = MAXPATHLEN;
1058         tmp = static_buf;
1059 #else
1060         size = strlen(dirname) + 1;
1061         tmp = MEM_callocN(size, __func__);
1062 #endif
1063
1064         BLI_strncpy(tmp, dirname, size);
1065
1066         /* Avoids one useless recursion in case of '/foo/bar/' path... */
1067         BLI_del_slash(tmp);
1068
1069         lslash = (char *)BLI_last_slash(tmp);
1070         if (lslash) {
1071                 /* Split about the last slash and recurse */
1072                 *lslash = 0;
1073                 if (!BLI_dir_create_recursive(tmp)) {
1074                         ret = false;
1075                 }
1076         }
1077
1078 #ifndef MAXPATHLEN
1079         MEM_freeN(tmp);
1080 #endif
1081
1082         if (ret) {
1083                 ret = (mkdir(dirname, 0777) == 0);
1084         }
1085         return ret;
1086 }
1087
1088 /**
1089  * \return zero on success (matching 'rename' behavior).
1090  */
1091 int BLI_rename(const char *from, const char *to)
1092 {
1093         if (!BLI_exists(from)) {
1094                 return 1;
1095         }
1096
1097         if (BLI_exists(to)) {
1098                 if (BLI_delete(to, false, false)) {
1099                         return 1;
1100                 }
1101         }
1102
1103         return rename(from, to);
1104 }
1105
1106 #endif