replace fixed sizes with sizeof when passing string length since size wasn't always...
[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 #else
49 #include <unistd.h> // for read close
50 #include <sys/param.h>
51 #endif
52
53 #include "MEM_guardedalloc.h"
54
55 #include "BLI_blenlib.h"
56
57 #include "BKE_utildefines.h"
58
59 #include "BLO_sys_types.h" // for intptr_t support
60
61
62 /* gzip the file in from and write it to "to". 
63  return -1 if zlib fails, -2 if the originating file does not exist
64  note: will remove the "from" file
65   */
66 int BLI_file_gzip(const char *from, const char *to)
67 {
68         char buffer[10240];
69         int file;
70         int readsize = 0;
71         int rval= 0, err;
72         gzFile gzfile;
73
74         /* level 1 is very close to 3 (the default) in terms of file size,
75          * but about twice as fast, best use for speedy saving - campbell */
76         gzfile = gzopen(to, "wb1");
77         if(gzfile == NULL)
78                 return -1;
79         
80         file = open(from, O_BINARY|O_RDONLY);
81         if(file < 0)
82                 return -2;
83
84         while(1) {
85                 readsize = read(file, buffer, sizeof(buffer));
86
87                 if(readsize < 0) {
88                         rval= -2; /* error happened in reading */
89                         fprintf(stderr, "Error reading file %s: %s.\n", from, strerror(errno));
90                         break;
91                 }
92                 else if(readsize == 0)
93                         break; /* done reading */
94                 
95                 if(gzwrite(gzfile, buffer, readsize) <= 0) {
96                         rval= -1; /* error happened in writing */
97                         fprintf(stderr, "Error writing gz file %s: %s.\n", to, gzerror(gzfile, &err));
98                         break;
99                 }
100         }
101         
102         gzclose(gzfile);
103         close(file);
104
105         return rval;
106 }
107
108 /* gzip the file in from_file and write it to memery to_mem, at most size bytes.
109    return the unziped size
110   */
111 char *BLI_file_ungzip_to_mem(const char *from_file, int *size_r)
112 {
113         gzFile gzfile;
114         int readsize, size, alloc_size=0;
115         char *mem= NULL;
116         const int chunk_size= 512*1024;
117
118         size= 0;
119
120         gzfile = gzopen( from_file, "rb" );
121
122         for(;;) {
123                 if(mem==NULL) {
124                         mem= MEM_callocN(chunk_size, "BLI_ungzip_to_mem");
125                         alloc_size= chunk_size;
126                 } else {
127                         mem= MEM_reallocN(mem, size+chunk_size);
128                         alloc_size+= chunk_size;
129                 }
130
131                 readsize= gzread(gzfile, mem+size, chunk_size);
132                 if(readsize>0) {
133                         size+= readsize;
134                 }
135                 else break;
136         }
137
138         if(size==0) {
139                 MEM_freeN(mem);
140                 mem= NULL;
141         }
142         else if(alloc_size!=size)
143                 mem= MEM_reallocN(mem, size);
144
145         *size_r= size;
146
147         return mem;
148 }
149
150
151 /* return 1 when file can be written */
152 int BLI_file_is_writable(const char *filename)
153 {
154         int file;
155         
156         /* first try to open without creating */
157         file = open(filename, O_BINARY | O_RDWR, 0666);
158         
159         if (file < 0) {
160                 /* now try to open and create. a test without actually
161                  * creating a file would be nice, but how? */
162                 file = open(filename, O_BINARY | O_RDWR | O_CREAT, 0666);
163                 
164                 if(file < 0) {
165                         return 0;
166                 }
167                 else {
168                         /* success, delete the file we create */
169                         close(file);
170                         BLI_delete(filename, 0, 0);
171                         return 1;
172                 }
173         }
174         else {
175                 close(file);
176                 return 1;
177         }
178 }
179
180 int BLI_file_touch(const char *file)
181 {
182         FILE *f = fopen(file,"r+b");
183         if (f != NULL) {
184                 char c = getc(f);
185                 rewind(f);
186                 putc(c,f);
187         } else {
188                 f = fopen(file,"wb");
189         }
190         if (f) {
191                 fclose(f);
192                 return 1;
193         }
194         return 0;
195 }
196
197 #ifdef WIN32
198
199 static char str[MAXPATHLEN+12];
200
201 int BLI_delete(const char *file, int dir, int recursive)
202 {
203         int err;
204
205         if (recursive) {
206                 callLocalErrorCallBack("Recursive delete is unsupported on Windows");
207                 err= 1;
208         } else if (dir) {
209                 err= !RemoveDirectory(file);
210                 if (err) printf ("Unable to remove directory");
211         } else {
212                 err= !DeleteFile(file);
213                 if (err) callLocalErrorCallBack("Unable to delete file");
214         }
215
216         return err;
217 }
218
219 int BLI_move(const char *file, const char *to)
220 {
221         int err;
222
223         // windows doesn't support moveing to a directory
224         // it has to be 'mv filename filename' and not
225         // 'mv filename destdir'
226
227         BLI_strncpy(str, to, sizeof(str));
228         // points 'to' to a directory ?
229         if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
230                 if (BLI_last_slash(file) != NULL) {
231                         strcat(str, BLI_last_slash(file) + 1);
232                 }
233         }
234
235         err= !MoveFile(file, str);
236         if (err) {
237                 callLocalErrorCallBack("Unable to move file");
238                 printf(" Move from '%s' to '%s' failed\n", file, str);
239         }
240
241         return err;
242 }
243
244
245 int BLI_copy(const char *file, const char *to)
246 {
247         int err;
248
249         // windows doesn't support copying to a directory
250         // it has to be 'cp filename filename' and not
251         // 'cp filename destdir'
252
253         BLI_strncpy(str, to, sizeof(str));
254         // points 'to' to a directory ?
255         if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
256                 if (BLI_last_slash(file) != NULL) {
257                         strcat(str, BLI_last_slash(file) + 1);
258                 }
259         }
260
261         err= !CopyFile(file,str,FALSE);
262         
263         if (err) {
264                 callLocalErrorCallBack("Unable to copy file!");
265                 printf(" Copy from '%s' to '%s' failed\n", file, str);
266         }
267
268         return err;
269 }
270
271 int BLI_create_symlink(const char *file, const char *to)
272 {
273         callLocalErrorCallBack("Linking files is unsupported on Windows");
274         (void)file;
275         (void)to;
276         return 1;
277 }
278
279 void BLI_dir_create_recursive(const char *dirname)
280 {
281         char *lslash;
282         char tmp[MAXPATHLEN];
283         
284         // First remove possible slash at the end of the dirname.
285         // This routine otherwise tries to create
286         // blah1/blah2/ (with slash) after creating
287         // blah1/blah2 (without slash)
288
289         BLI_strncpy(tmp, dirname, sizeof(tmp));
290         lslash= BLI_last_slash(tmp);
291
292         if (lslash == tmp + strlen(tmp) - 1) {
293                 *lslash = 0;
294         }
295         
296         if (BLI_exists(tmp)) return;
297                 
298         lslash= BLI_last_slash(tmp);
299         if (lslash) {
300                         /* Split about the last slash and recurse */    
301                 *lslash = 0;
302                 BLI_dir_create_recursive(tmp);
303         }
304         
305         if(dirname[0]) /* patch, this recursive loop tries to create a nameless directory */
306                 if (!CreateDirectory(dirname, NULL))
307                         callLocalErrorCallBack("Unable to create directory\n");
308 }
309
310 int BLI_rename(const char *from, const char *to)
311 {
312         if (!BLI_exists(from)) return 0;
313
314         /* make sure the filenames are different (case insensitive) before removing */
315         if (BLI_exists(to) && BLI_strcasecmp(from, to))
316                 if(BLI_delete(to, 0, 0)) return 1;
317
318         return rename(from, to);
319 }
320
321 #else /* The UNIX world */
322
323 /*
324  * but the UNIX world is tied to the interface, and the system
325  * timer, and... We implement a callback mechanism. The system will
326  * have to initialise the callback before the functions will work!
327  * */
328 static char str[12 + (MAXPATHLEN * 2)];
329
330 int BLI_delete(const char *file, int dir, int recursive) 
331 {
332         if(strchr(file, '"')) {
333                 printf("Error: not deleted file %s because of quote!\n", file);
334         }
335         else {
336                 if (recursive) {
337                         BLI_snprintf(str, sizeof(str), "/bin/rm -rf \"%s\"", file);
338                         return system(str);
339                 }
340                 else if (dir) {
341                         BLI_snprintf(str, sizeof(str), "/bin/rmdir \"%s\"", file);
342                         return system(str);
343                 }
344                 else {
345                         return remove(file); //BLI_snprintf(str, sizeof(str), "/bin/rm -f \"%s\"", file);
346                 }
347         }
348         return -1;
349 }
350
351 int BLI_move(const char *file, const char *to)
352 {
353         BLI_snprintf(str, sizeof(str), "/bin/mv -f \"%s\" \"%s\"", file, to);
354
355         return system(str);
356 }
357
358 int BLI_copy(const char *file, const char *to)
359 {
360         BLI_snprintf(str, sizeof(str), "/bin/cp -rf \"%s\" \"%s\"", file, to);
361
362         return system(str);
363 }
364
365 int BLI_create_symlink(const char *file, const char *to)
366 {
367         BLI_snprintf(str, sizeof(str), "/bin/ln -f \"%s\" \"%s\"", file, to);
368         
369         return system(str);
370 }
371
372 void BLI_dir_create_recursive(const char *dirname)
373 {
374         char *lslash;
375         char tmp[MAXPATHLEN];
376                 
377         if (BLI_exists(dirname)) return;
378
379         BLI_strncpy(tmp, dirname, sizeof(tmp));
380                 
381         lslash= BLI_last_slash(tmp);
382         if (lslash) {
383                         /* Split about the last slash and recurse */    
384                 *lslash = 0;
385                 BLI_dir_create_recursive(tmp);
386         }
387
388         mkdir(dirname, 0777);
389 }
390
391 int BLI_rename(const char *from, const char *to)
392 {
393         if (!BLI_exists(from)) return 0;
394         
395         if (BLI_exists(to))     if(BLI_delete(to, 0, 0)) return 1;
396
397         return rename(from, to);
398 }
399
400 #endif
401