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