Add:map_binfile:Not yet working auto-download support of maps
[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 #ifdef CACHE_SIZE
47 static GHashTable *file_name_hash;
48 #endif
49
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 } __attribute__ ((packed));
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         file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
66         if (file->fd == -1) {
67                 g_free(file);
68                 return NULL;
69         }
70         dbg(1,"fd=%d\n", file->fd);
71         fstat(file->fd, &stat);
72         file->size=stat.st_size;
73         dbg(1,"size=%Ld\n", file->size);
74         file->name = g_strdup(name);
75         dbg_assert(file != NULL);
76         return file;
77 }
78
79 #if 0
80 struct file *
81 file_create_url(char *url)
82 {
83         struct file *file= g_new0(struct file,1);
84         char *cmd=g_strdup_printf("curl %s",url);
85         file->name = g_strdup(url);
86         file->stdfile=popen(cmd,"r");
87         file->fd=fileno(file->stdfile);
88         file->special=1;
89         g_free(cmd);
90         return file;
91 }
92 #endif
93
94 int file_is_dir(char *name)
95 {
96         struct stat buf;
97         if (! stat(name, &buf)) {
98                 return S_ISDIR(buf.st_mode);
99         }
100         return 0;
101
102 }
103
104 long long
105 file_size(struct file *file)
106 {
107         return file->size;
108 }
109
110 int file_mkdir(char *name, int pflag)
111 {
112         char buffer[strlen(name)+1];
113         int ret;
114         char *next;
115         dbg(1,"enter %s %d\n",name,pflag);
116         if (!pflag) {
117                 if (file_is_dir(name))
118                         return 0;
119 #ifdef HAVE_API_WIN32_BASE
120                 return mkdir(name);
121 #else
122                 return mkdir(name, 0777);
123 #endif
124         }
125         strcpy(buffer, name);
126         next=buffer;
127         while ((next=strchr(next, '/'))) {
128                 *next='\0';
129                 if (*buffer) {
130                         ret=file_mkdir(buffer, 0);
131                         if (ret)
132                                 return ret;
133                 }
134                 *next++='/';
135         }
136         if (pflag == 2)
137                 return 0;
138         return file_mkdir(buffer, 0);
139 }
140
141 int
142 file_mmap(struct file *file)
143 {
144 #if defined(_WIN32) || defined(__CEGCC__)
145     file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
146 #else
147         file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
148         dbg_assert(file->begin != NULL);
149         if (file->begin == (void *)0xffffffff) {
150                 perror("mmap");
151                 return 0;
152         }
153 #endif
154         dbg_assert(file->begin != (void *)0xffffffff);
155         file->end=file->begin+file->size;
156
157         return 1;
158 }
159
160 unsigned char *
161 file_data_read(struct file *file, long long offset, int size)
162 {
163         void *ret;
164         if (file->special)
165                 return NULL;
166         if (file->begin)
167                 return file->begin+offset;
168         if (file_cache) {
169                 struct file_cache_id id={offset,size,file->name_id,0};
170                 ret=cache_lookup(file_cache,&id); 
171                 if (ret)
172                         return ret;
173                 ret=cache_insert_new(file_cache,&id,size);
174         } else
175                 ret=g_malloc(size);
176         lseek(file->fd, offset, SEEK_SET);
177         if (read(file->fd, ret, size) != size) {
178                 file_data_free(file, ret);
179                 ret=NULL;
180         }
181         return ret;
182
183 }
184
185 unsigned char *
186 file_data_read_special(struct file *file, int size, int *size_ret)
187 {
188         void *ret;
189         if (!file->special)
190                 return NULL;
191         ret=g_malloc(size);
192         *size_ret=read(file->fd, ret, size);
193         return ret;
194 }
195
196 unsigned char *
197 file_data_read_all(struct file *file)
198 {
199         return file_data_read(file, 0, file->size);
200 }
201
202 int
203 file_data_write(struct file *file, long long offset, int size, unsigned char *data)
204 {
205         if (file_cache) {
206                 struct file_cache_id id={offset,size,file->name_id,0};
207                 cache_flush(file_cache,&id);
208         }
209         lseek(file->fd, offset, SEEK_SET);
210         if (write(file->fd, data, size) != size)
211                 return 0;
212         if (file->size < offset+size)
213                 file->size=offset+size;
214         return 1;
215 }
216
217 int
218 file_get_contents(char *name, unsigned char **buffer, int *size)
219 {
220         struct file *file;
221         file=file_create(name);
222         if (!file)
223                 return 0;
224         *size=file_size(file);
225         *buffer=file_data_read_all(file);
226         file_destroy(file);
227         return 1;       
228 }
229
230
231 static int
232 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
233 {
234         z_stream stream;
235         int err;
236
237         stream.next_in = (Bytef*)source;
238         stream.avail_in = (uInt)sourceLen;
239         stream.next_out = dest;
240         stream.avail_out = (uInt)*destLen;
241
242         stream.zalloc = (alloc_func)0;
243         stream.zfree = (free_func)0;
244
245         err = inflateInit2(&stream, -MAX_WBITS);
246         if (err != Z_OK) return err;
247
248         err = inflate(&stream, Z_FINISH);
249         if (err != Z_STREAM_END) {
250         inflateEnd(&stream);
251         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
252                 return Z_DATA_ERROR;
253                 return err;
254         }
255         *destLen = stream.total_out;
256
257         err = inflateEnd(&stream);
258         return err;
259 }
260
261 unsigned char *
262 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
263 {
264         void *ret;
265         char *buffer = 0;
266         uLongf destLen=size_uncomp;
267
268         if (file_cache) {
269                 struct file_cache_id id={offset,size,file->name_id,1};
270                 ret=cache_lookup(file_cache,&id); 
271                 if (ret)
272                         return ret;
273                 ret=cache_insert_new(file_cache,&id,size_uncomp);
274         } else 
275                 ret=g_malloc(size_uncomp);
276         lseek(file->fd, offset, SEEK_SET);
277
278         buffer = (char *)g_malloc(size);
279         if (read(file->fd, buffer, size) != size) {
280                 g_free(ret);
281                 ret=NULL;
282         } else {
283                 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
284                         dbg(0,"uncompress failed\n");
285                         g_free(ret);
286                         ret=NULL;
287                 }
288         }
289         g_free(buffer);
290
291         return ret;
292 }
293
294 void
295 file_data_free(struct file *file, unsigned char *data)
296 {
297         if (file->begin && data >= file->begin && data < file->end)
298                 return;
299         if (file_cache) {
300                 cache_entry_destroy(file_cache, data);
301         } else
302                 g_free(data);
303 }
304
305 int
306 file_exists(char *name)
307 {
308         struct stat buf;
309         if (! stat(name, &buf))
310                 return 1;
311         return 0;
312 }
313
314 void
315 file_remap_readonly(struct file *f)
316 {
317 #if defined(_WIN32) || defined(__CEGCC__)
318 #else
319         void *begin;
320         munmap(f->begin, f->size);
321         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
322         if (f->begin != begin)
323                 printf("remap failed\n");
324 #endif
325 }
326
327 void
328 file_unmap(struct file *f)
329 {
330 #if defined(_WIN32) || defined(__CEGCC__)
331     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
332 #else
333         munmap(f->begin, f->size);
334 #endif
335 }
336
337 void *
338 file_opendir(char *dir)
339 {
340         return opendir(dir);
341 }
342
343 char *
344 file_readdir(void *hnd)
345 {
346         struct dirent *ent;
347
348         ent=readdir(hnd);
349         if (! ent)
350                 return NULL;
351         return ent->d_name;
352 }
353
354 void
355 file_closedir(void *hnd)
356 {
357         closedir(hnd);
358 }
359
360 struct file *
361 file_create_caseinsensitive(char *name)
362 {
363         char dirname[strlen(name)+1];
364         char *filename;
365         char *p;
366         void *d;
367         struct file *ret;
368
369         ret=file_create(name);
370         if (ret)
371                 return ret;
372
373         strcpy(dirname, name);
374         p=dirname+strlen(name);
375         while (p > dirname) {
376                 if (*p == '/')
377                         break;
378                 p--;
379         }
380         *p=0;
381         d=file_opendir(dirname);
382         if (d) {
383                 *p++='/';
384                 while ((filename=file_readdir(d))) {
385                         if (!strcasecmp(filename, p)) {
386                                 strcpy(p, filename);
387                                 ret=file_create(dirname);
388                                 if (ret)
389                                         break;
390                         }
391                 }
392                 file_closedir(d);
393         }
394         return ret;
395 }
396
397 void
398 file_destroy(struct file *f)
399 {
400         switch (f->special) {
401         case 0:
402                 close(f->fd);
403                 break;
404 #if 0
405         case 1:
406                 pclose(f->stdfile);
407                 break;
408 #endif
409         }
410
411     if ( f->begin != NULL )
412     {
413         file_unmap( f );
414     }
415
416         g_free(f->name);
417         g_free(f);
418 }
419
420 struct file_wordexp {
421         int err;
422         wordexp_t we;
423 };
424
425 struct file_wordexp *
426 file_wordexp_new(const char *pattern)
427 {
428         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
429
430         ret->err=wordexp(pattern, &ret->we, 0);
431         if (ret->err)
432                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
433         return ret;
434 }
435
436 int
437 file_wordexp_get_count(struct file_wordexp *wexp)
438 {
439         return wexp->we.we_wordc;
440 }
441
442 char **
443 file_wordexp_get_array(struct file_wordexp *wexp)
444 {
445         return wexp->we.we_wordv;
446 }
447
448 void
449 file_wordexp_destroy(struct file_wordexp *wexp)
450 {
451         if (! wexp->err)
452                 wordfree(&wexp->we);
453         g_free(wexp);
454 }
455
456
457 int
458 file_get_param(struct file *file, struct param_list *param, int count)
459 {
460         int i=count;
461         param_add_string("Filename", file->name, &param, &count);
462         param_add_hex("Size", file->size, &param, &count);
463         return i-count;
464 }
465
466 int
467 file_version(struct file *file, int byname)
468 {
469 #ifndef __CEGCC__
470         struct stat st;
471         int error;
472         if (byname)
473                 error=stat(file->name, &st);
474         else
475                 error=fstat(file->fd, &st);
476         if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
477                 file->mtime=st.st_mtime;
478                 file->ctime=st.st_ctime;
479                 file->version++;
480                 dbg(0,"%s now version %d\n", file->name, file->version);
481         }
482         return file->version;
483 #else
484         return 0;
485 #endif
486 }
487
488 void *
489 file_get_os_handle(struct file *file)
490 {
491         return (void *)(file->fd);
492 }
493
494 void
495 file_init(void)
496 {
497 #ifdef CACHE_SIZE
498         file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
499         file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
500 #endif
501 }
502