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