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