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