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