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