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