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