Fix:Core:Made file_mkdir actually work
[navit-package] / navit / file.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
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
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #define _FILE_OFFSET_BITS 64
21 #define _LARGEFILE_SOURCE
22 #define _LARGEFILE64_SOURCE
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <dirent.h>
29 #include <stdio.h>
30 #include <wordexp.h>
31 #include <glib.h>
32 #include <zlib.h>
33 #include "debug.h"
34 #include "file.h"
35 #include "config.h"
36
37 #ifndef O_LARGEFILE
38 #define O_LARGEFILE 0
39 #endif
40
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
44
45 static struct file *file_list;
46
47 struct file *
48 file_create(char *name)
49 {
50         struct stat stat;
51         struct file *file= g_new0(struct file,1);
52
53         if (! file)
54                 return file;
55         file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
56         if (file->fd < 0) {
57                 g_free(file);
58                 return NULL;
59         }
60         fstat(file->fd, &stat);
61         file->size=stat.st_size;
62         file->name = g_strdup(name);
63         g_assert(file != NULL);
64         file->next=file_list;
65         file_list=file;
66         return file;
67 }
68
69 int file_is_dir(char *name)
70 {
71         struct stat buf;
72         if (! stat(name, &buf)) {
73                 return S_ISDIR(buf.st_mode);
74         }
75         return 0;
76
77 }
78
79 int file_mkdir(char *name, int pflag)
80 {
81         char buffer[strlen(name)+1];
82         int ret;
83         char *curr, *next;
84         dbg(1,"enter %s %d\n",name,pflag);
85         if (!pflag) {
86                 if (file_is_dir(name))
87                         return 0;
88                 return mkdir(name, 0777);
89         }
90         strcpy(buffer, name);
91         next=buffer;
92         while (next=strchr(next, '/')) {
93                 *next='\0';
94                 if (*buffer) {
95                         ret=file_mkdir(buffer, 0);
96                         if (ret)
97                                 return ret;
98                 }
99                 *next++='/';
100         }
101         return file_mkdir(buffer, 0);
102 }
103
104 int
105 file_mmap(struct file *file)
106 {
107 #ifdef _WIN32
108     file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
109 #else
110         file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
111         g_assert(file->begin != NULL);
112         if (file->begin == (void *)0xffffffff) {
113                 perror("mmap");
114                 return 0;
115         }
116 #endif
117         g_assert(file->begin != (void *)0xffffffff);
118         file->end=file->begin+file->size;
119
120         return 1;
121 }
122
123 unsigned char *
124 file_data_read(struct file *file, long long offset, int size)
125 {
126         void *ret;
127         if (file->begin)
128                 return file->begin+offset;
129         ret=g_malloc(size);
130         lseek(file->fd, offset, SEEK_SET);
131         if (read(file->fd, ret, size) != size) {
132                 g_free(ret);
133                 ret=NULL;
134         }
135         return ret;
136
137 }
138
139 static int
140 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
141 {
142         z_stream stream;
143         int err;
144
145         stream.next_in = (Bytef*)source;
146         stream.avail_in = (uInt)sourceLen;
147         stream.next_out = dest;
148         stream.avail_out = (uInt)*destLen;
149
150         stream.zalloc = (alloc_func)0;
151         stream.zfree = (free_func)0;
152
153         err = inflateInit2(&stream, -MAX_WBITS);
154         if (err != Z_OK) return err;
155
156         err = inflate(&stream, Z_FINISH);
157         if (err != Z_STREAM_END) {
158         inflateEnd(&stream);
159         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
160                 return Z_DATA_ERROR;
161                 return err;
162         }
163         *destLen = stream.total_out;
164
165         err = inflateEnd(&stream);
166         return err;
167 }
168
169 unsigned char *
170 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
171 {
172         void *ret;
173         char buffer[size];
174         uLongf destLen=size_uncomp;
175
176         ret=g_malloc(size_uncomp);
177         lseek(file->fd, offset, SEEK_SET);
178         if (read(file->fd, buffer, size) != size) {
179                 g_free(ret);
180                 ret=NULL;
181         } else {
182                 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
183                         dbg(0,"uncompress failed\n");
184                         g_free(ret);
185                         ret=NULL;
186                 }
187         }
188         return ret;
189 }
190
191 void
192 file_data_free(struct file *file, unsigned char *data)
193 {
194         if (file->begin && data >= file->begin && data < file->end)
195                 return;
196         g_free(data);
197 }
198
199 int
200 file_exists(char *name)
201 {
202         struct stat buf;
203         if (! stat(name, &buf))
204                 return 1;
205         return 0;
206 }
207
208 void
209 file_remap_readonly(struct file *f)
210 {
211 #ifdef _WIN32
212 #else
213         void *begin;
214         munmap(f->begin, f->size);
215         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
216         if (f->begin != begin)
217                 printf("remap failed\n");
218 #endif
219 }
220
221 void
222 file_remap_readonly_all(void)
223 {
224         struct file *f=file_list;
225         int limit=1000;
226
227         while (f && limit-- > 0) {
228                 file_remap_readonly(f);
229                 f=f->next;
230         }
231 }
232
233 void
234 file_unmap(struct file *f)
235 {
236 #ifdef _WIN32
237     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
238 #else
239         munmap(f->begin, f->size);
240 #endif
241 }
242
243 void
244 file_unmap_all(void)
245 {
246         struct file *f=file_list;
247         int limit=1000;
248
249         while (f && limit-- > 0) {
250                 file_unmap(f);
251                 f=f->next;
252         }
253 }
254
255
256
257 void *
258 file_opendir(char *dir)
259 {
260         return opendir(dir);
261 }
262
263 char *
264 file_readdir(void *hnd)
265 {
266         struct dirent *ent;
267
268         ent=readdir(hnd);
269         if (! ent)
270                 return NULL;
271         return ent->d_name;
272 }
273
274 void
275 file_closedir(void *hnd)
276 {
277         closedir(hnd);
278 }
279
280 struct file *
281 file_create_caseinsensitive(char *name)
282 {
283         char dirname[strlen(name)+1];
284         char *filename;
285         char *p;
286         void *d;
287         struct file *ret;
288
289         ret=file_create(name);
290         if (ret)
291                 return ret;
292
293         strcpy(dirname, name);
294         p=dirname+strlen(name);
295         while (p > dirname) {
296                 if (*p == '/')
297                         break;
298                 p--;
299         }
300         *p=0;
301         d=file_opendir(dirname);
302         if (d) {
303                 *p++='/';
304                 while ((filename=file_readdir(d))) {
305                         if (!strcasecmp(filename, p)) {
306                                 strcpy(p, filename);
307                                 ret=file_create(dirname);
308                                 if (ret)
309                                         break;
310                         }
311                 }
312                 file_closedir(d);
313         }
314         return ret;
315 }
316
317 void
318 file_destroy(struct file *f)
319 {
320         close(f->fd);
321
322     if ( f->begin != NULL )
323     {
324         file_unmap( f );
325     }
326
327         g_free(f->name);
328         g_free(f);
329 }
330
331 struct file_wordexp {
332         int err;
333         wordexp_t we;
334 };
335
336 struct file_wordexp *
337 file_wordexp_new(const char *pattern)
338 {
339         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
340
341         ret->err=wordexp(pattern, &ret->we, 0);
342         if (ret->err)
343                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
344         return ret;
345 }
346
347 int
348 file_wordexp_get_count(struct file_wordexp *wexp)
349 {
350         return wexp->we.we_wordc;
351 }
352
353 char **
354 file_wordexp_get_array(struct file_wordexp *wexp)
355 {
356         return wexp->we.we_wordv;
357 }
358
359 void
360 file_wordexp_destroy(struct file_wordexp *wexp)
361 {
362         if (! wexp->err)
363                 wordfree(&wexp->we);
364         g_free(wexp);
365 }
366
367
368 int
369 file_get_param(struct file *file, struct param_list *param, int count)
370 {
371         int i=count;
372         param_add_string("Filename", file->name, &param, &count);
373         param_add_hex("Size", file->size, &param, &count);
374         return i-count;
375 }