Fix:Core:Replaced g_assert with dbg_assert
[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 "cache.h"
35 #include "file.h"
36 #include "config.h"
37
38 #ifndef O_LARGEFILE
39 #define O_LARGEFILE 0
40 #endif
41
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
45
46 static struct file *file_list;
47
48 static GHashTable *file_name_hash;
49 static int file_name_id;
50 static struct cache *file_cache;
51
52 struct file_cache_id {
53         long long offset;
54         int size;
55         int file_name_id;
56         int method;
57 };
58
59 struct file *
60 file_create(char *name)
61 {
62         struct stat stat;
63         struct file *file= g_new0(struct file,1);
64
65         if (! file)
66                 return file;
67         file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
68         if (file->fd < 0) {
69                 g_free(file);
70                 return NULL;
71         }
72         fstat(file->fd, &stat);
73         file->size=stat.st_size;
74         file->name = g_strdup(name);
75         dbg_assert(file != NULL);
76         file->next=file_list;
77         file_list=file;
78         return file;
79 }
80
81 int file_is_dir(char *name)
82 {
83         struct stat buf;
84         if (! stat(name, &buf)) {
85                 return S_ISDIR(buf.st_mode);
86         }
87         return 0;
88
89 }
90
91 int file_mkdir(char *name, int pflag)
92 {
93         char buffer[strlen(name)+1];
94         int ret;
95         char *next;
96         dbg(1,"enter %s %d\n",name,pflag);
97         if (!pflag) {
98                 if (file_is_dir(name))
99                         return 0;
100                 return mkdir(name, 0777);
101         }
102         strcpy(buffer, name);
103         next=buffer;
104         while ((next=strchr(next, '/'))) {
105                 *next='\0';
106                 if (*buffer) {
107                         ret=file_mkdir(buffer, 0);
108                         if (ret)
109                                 return ret;
110                 }
111                 *next++='/';
112         }
113         if (pflag == 2)
114                 return 0;
115         return file_mkdir(buffer, 0);
116 }
117
118 int
119 file_mmap(struct file *file)
120 {
121 #if defined(_WIN32) || defined(__CEGCC__)
122     file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
123 #else
124         file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
125         dbg_assert(file->begin != NULL);
126         if (file->begin == (void *)0xffffffff) {
127                 perror("mmap");
128                 return 0;
129         }
130 #endif
131         dbg_assert(file->begin != (void *)0xffffffff);
132         file->end=file->begin+file->size;
133
134         return 1;
135 }
136
137 unsigned char *
138 file_data_read(struct file *file, long long offset, int size)
139 {
140         void *ret;
141         if (file->begin)
142                 return file->begin+offset;
143         if (file_cache) {
144                 struct file_cache_id id={offset,size,file->name_id,0};
145                 ret=cache_lookup(file_cache,&id); 
146                 if (ret)
147                         return ret;
148                 ret=cache_insert_new(file_cache,&id,size);
149         } else
150                 ret=g_malloc(size);
151         lseek(file->fd, offset, SEEK_SET);
152         if (read(file->fd, ret, size) != size) {
153                 file_data_free(file, ret);
154                 ret=NULL;
155         }
156         return ret;
157
158 }
159
160 static int
161 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
162 {
163         z_stream stream;
164         int err;
165
166         stream.next_in = (Bytef*)source;
167         stream.avail_in = (uInt)sourceLen;
168         stream.next_out = dest;
169         stream.avail_out = (uInt)*destLen;
170
171         stream.zalloc = (alloc_func)0;
172         stream.zfree = (free_func)0;
173
174         err = inflateInit2(&stream, -MAX_WBITS);
175         if (err != Z_OK) return err;
176
177         err = inflate(&stream, Z_FINISH);
178         if (err != Z_STREAM_END) {
179         inflateEnd(&stream);
180         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
181                 return Z_DATA_ERROR;
182                 return err;
183         }
184         *destLen = stream.total_out;
185
186         err = inflateEnd(&stream);
187         return err;
188 }
189
190 unsigned char *
191 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
192 {
193         void *ret;
194         char buffer[size];
195         uLongf destLen=size_uncomp;
196
197         if (file_cache) {
198                 struct file_cache_id id={offset,size,file->name_id,1};
199                 ret=cache_lookup(file_cache,&id); 
200                 if (ret)
201                         return ret;
202                 ret=cache_insert_new(file_cache,&id,size_uncomp);
203         } else 
204                 ret=g_malloc(size_uncomp);
205         lseek(file->fd, offset, SEEK_SET);
206         if (read(file->fd, buffer, size) != size) {
207                 g_free(ret);
208                 ret=NULL;
209         } else {
210                 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
211                         dbg(0,"uncompress failed\n");
212                         g_free(ret);
213                         ret=NULL;
214                 }
215         }
216         return ret;
217 }
218
219 void
220 file_data_free(struct file *file, unsigned char *data)
221 {
222         if (file->begin && data >= file->begin && data < file->end)
223                 return;
224         if (file_cache) {
225                 cache_entry_destroy(file_cache, data);
226         } else
227                 g_free(data);
228 }
229
230 int
231 file_exists(char *name)
232 {
233         struct stat buf;
234         if (! stat(name, &buf))
235                 return 1;
236         return 0;
237 }
238
239 void
240 file_remap_readonly(struct file *f)
241 {
242 #if defined(_WIN32) || defined(__CEGCC__)
243 #else
244         void *begin;
245         munmap(f->begin, f->size);
246         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
247         if (f->begin != begin)
248                 printf("remap failed\n");
249 #endif
250 }
251
252 void
253 file_remap_readonly_all(void)
254 {
255         struct file *f=file_list;
256         int limit=1000;
257
258         while (f && limit-- > 0) {
259                 file_remap_readonly(f);
260                 f=f->next;
261         }
262 }
263
264 void
265 file_unmap(struct file *f)
266 {
267 #if defined(_WIN32) || defined(__CEGCC__)
268     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
269 #else
270         munmap(f->begin, f->size);
271 #endif
272 }
273
274 void
275 file_unmap_all(void)
276 {
277         struct file *f=file_list;
278         int limit=1000;
279
280         while (f && limit-- > 0) {
281                 file_unmap(f);
282                 f=f->next;
283         }
284 }
285
286
287
288 void *
289 file_opendir(char *dir)
290 {
291         return opendir(dir);
292 }
293
294 char *
295 file_readdir(void *hnd)
296 {
297         struct dirent *ent;
298
299         ent=readdir(hnd);
300         if (! ent)
301                 return NULL;
302         return ent->d_name;
303 }
304
305 void
306 file_closedir(void *hnd)
307 {
308         closedir(hnd);
309 }
310
311 struct file *
312 file_create_caseinsensitive(char *name)
313 {
314         char dirname[strlen(name)+1];
315         char *filename;
316         char *p;
317         void *d;
318         struct file *ret;
319
320         ret=file_create(name);
321         if (ret)
322                 return ret;
323
324         strcpy(dirname, name);
325         p=dirname+strlen(name);
326         while (p > dirname) {
327                 if (*p == '/')
328                         break;
329                 p--;
330         }
331         *p=0;
332         d=file_opendir(dirname);
333         if (d) {
334                 *p++='/';
335                 while ((filename=file_readdir(d))) {
336                         if (!strcasecmp(filename, p)) {
337                                 strcpy(p, filename);
338                                 ret=file_create(dirname);
339                                 if (ret)
340                                         break;
341                         }
342                 }
343                 file_closedir(d);
344         }
345         return ret;
346 }
347
348 void
349 file_destroy(struct file *f)
350 {
351         close(f->fd);
352
353     if ( f->begin != NULL )
354     {
355         file_unmap( f );
356     }
357
358         g_free(f->name);
359         g_free(f);
360 }
361
362 struct file_wordexp {
363         int err;
364         wordexp_t we;
365 };
366
367 struct file_wordexp *
368 file_wordexp_new(const char *pattern)
369 {
370         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
371
372         ret->err=wordexp(pattern, &ret->we, 0);
373         if (ret->err)
374                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
375         return ret;
376 }
377
378 int
379 file_wordexp_get_count(struct file_wordexp *wexp)
380 {
381         return wexp->we.we_wordc;
382 }
383
384 char **
385 file_wordexp_get_array(struct file_wordexp *wexp)
386 {
387         return wexp->we.we_wordv;
388 }
389
390 void
391 file_wordexp_destroy(struct file_wordexp *wexp)
392 {
393         if (! wexp->err)
394                 wordfree(&wexp->we);
395         g_free(wexp);
396 }
397
398
399 int
400 file_get_param(struct file *file, struct param_list *param, int count)
401 {
402         int i=count;
403         param_add_string("Filename", file->name, &param, &count);
404         param_add_hex("Size", file->size, &param, &count);
405         return i-count;
406 }
407
408 void
409 file_init(void)
410 {
411 #if 0
412         file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
413         file_cache=cache_new(sizeof(struct file_cache_id), 2*1024*1024);
414 #endif
415 }
416