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