Fix:map_csv:Disable default notification of each deleted item.
[profile/ivi/navit.git] / navit / navit / file.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2011 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 "config.h"
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef _MSC_VER
28 #include <windows.h>
29 #else
30 #include <dirent.h>
31 #endif /* _MSC_VER */
32 #include <string.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <sys/mman.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <wordexp.h>
39 #include <glib.h>
40 #include <zlib.h>
41 #include "debug.h"
42 #include "cache.h"
43 #include "file.h"
44 #include "atom.h"
45 #include "item.h"
46 #include "util.h"
47 #include "types.h"
48 #include "zipfile.h"
49 #ifdef HAVE_SOCKET
50 #include <sys/socket.h>
51 #include <netdb.h>
52 #endif
53
54 extern char *version;
55
56 #ifdef HAVE_LIBCRYPTO
57 #include <openssl/sha.h>
58 #include <openssl/hmac.h>
59 #include <openssl/aes.h>
60 #include <openssl/evp.h>
61 #include <openssl/rand.h>
62 #endif
63
64 #ifdef HAVE_API_ANDROID
65 #define lseek lseek64
66 #endif
67
68 #ifndef O_LARGEFILE
69 #define O_LARGEFILE 0
70 #endif
71
72 #ifndef O_BINARY
73 #define O_BINARY 0
74 #endif
75
76 #ifdef CACHE_SIZE
77 static GHashTable *file_name_hash;
78 #endif
79
80 static struct cache *file_cache;
81
82 #ifdef HAVE_PRAGMA_PACK
83 #pragma pack(push)
84 #pragma pack(1)
85 #endif
86
87 struct file_cache_id {
88         long long offset;
89         int size;
90         int file_name_id;
91         int method;
92 } ATTRIBUTE_PACKED;
93
94 #ifdef HAVE_PRAGMA_PACK
95 #pragma pack(pop)
96 #endif
97
98 #ifdef HAVE_SOCKET
99 static int
100 file_socket_connect(char *host, char *service)
101 {
102         struct addrinfo hints;
103         struct addrinfo *result, *rp;
104         int fd=-1,s;
105
106         memset(&hints, 0, sizeof(struct addrinfo));
107         hints.ai_family = AF_UNSPEC;
108         hints.ai_socktype = SOCK_STREAM;
109         hints.ai_flags = 0;
110         hints.ai_protocol = 0;
111         s = getaddrinfo(host, service, &hints, &result);
112         if (s != 0) {
113                 dbg(0,"getaddrinfo error %s\n",gai_strerror(s));
114                 return -1;
115         }
116         for (rp = result; rp != NULL; rp = rp->ai_next) {
117                 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
118                 if (fd != -1) {
119                         if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
120                                 break;
121                         close(fd);
122                         fd=-1;
123                 }
124         }
125         freeaddrinfo(result);
126         return fd;
127 }
128
129 static void
130 file_http_request(struct file *file, char *method, char *host, char *path, char *header, int persistent)
131 {
132         char *request=g_strdup_printf("%s %s HTTP/1.0\r\nUser-Agent: navit %s\r\nHost: %s\r\n%s%s%s\r\n",method,path,version,host,persistent?"Connection: Keep-Alive\r\n":"",header?header:"",header?"\r\n":"");
133         write(file->fd, request, strlen(request));
134         dbg(1,"%s\n",request);
135         file->requests++;
136 }
137
138 static int
139 file_request_do(struct file *file, struct attr **options, int connect)
140 {
141         struct attr *attr;
142         char *name;
143
144         if (!options)
145                 return 0;
146         attr=attr_search(options, NULL, attr_url);
147         if (!attr)
148                 return 0;
149         name=attr->u.str;
150         if (!name)
151                 return 0;
152         g_free(file->name);
153         file->name = g_strdup(name);
154         if (!strncmp(name,"http://",7)) {
155                 char *host=g_strdup(name+7);
156                 char *port=strchr(host,':');
157                 char *path=strchr(name+7,'/');
158                 char *method="GET";
159                 char *header=NULL;
160                 int persistent=0;
161                 if ((attr=attr_search(options, NULL, attr_http_method)) && attr->u.str)
162                         method=attr->u.str;
163                 if ((attr=attr_search(options, NULL, attr_http_header)) && attr->u.str)
164                         header=attr->u.str;
165                 if ((attr=attr_search(options, NULL, attr_persistent)))
166                         persistent=attr->u.num;
167                 if (path) 
168                         host[path-name-7]='\0';
169                 if (port)
170                         *port++='\0';
171                 dbg(1,"host=%s path=%s\n",host,path);
172                 if (connect) 
173                         file->fd=file_socket_connect(host,port?port:"80");
174                 file_http_request(file,method,host,path,header,persistent);
175                 file->special=1;
176                 g_free(host);
177         }
178         return 1;
179 }
180 #endif
181
182 static unsigned char *
183 file_http_header_end(unsigned char *str, int len)
184 {
185         int i;
186         for (i=0; i+1<len; i+=2) {
187                 if (str[i+1]=='\n') {
188                         if (str[i]=='\n')
189                                 return str+i+2;
190                         else if (str[i]=='\r' && i+3<len && str[i+2]=='\r' && str[i+3]=='\n')
191                                 return str+i+4;
192                         --i;
193                 } else if (str[i+1]=='\r') {
194                         if (i+4<len && str[i+2]=='\n' && str[i+3]=='\r' && str[i+4]=='\n')
195                                 return str+i+5;
196                         --i;
197                 }
198         }
199         return NULL;
200 }
201
202 int
203 file_request(struct file *f, struct attr **options)
204 {
205 #ifdef HAVE_SOCKET
206         return file_request_do(f, options, 0);
207 #else
208         return 0;
209 #endif
210 }
211
212 char *
213 file_http_header(struct file *f, char *header)
214 {
215         if (!f->headers)
216                 return NULL;
217         return g_hash_table_lookup(f->headers, header);
218 }
219
220 struct file *
221 file_create(char *name, struct attr **options)
222 {
223         struct file *file= g_new0(struct file,1);
224         struct attr *attr;
225         int open_flags=O_LARGEFILE|O_BINARY;
226
227         if (options && (attr=attr_search(options, NULL, attr_url))) {
228 #ifdef HAVE_SOCKET
229                 file_request_do(file, options, 1);
230 #endif
231         } else {
232                 if (options && (attr=attr_search(options, NULL, attr_readwrite)) && attr->u.num) {
233                         open_flags |= O_RDWR;
234                         if ((attr=attr_search(options, NULL, attr_create)) && attr->u.num)
235                                 open_flags |= O_CREAT;
236                 } else
237                         open_flags |= O_RDONLY;
238                 file->name = g_strdup(name);
239                 file->fd=open(name, open_flags, 0666);
240                 if (file->fd == -1) {
241                         g_free(file);
242                         return NULL;
243                 }
244                 dbg(1,"fd=%d\n", file->fd);
245                 file->size=lseek(file->fd, 0, SEEK_END);
246                 dbg(1,"size="LONGLONG_FMT"\n", file->size);
247                 file->name_id = (long)atom(name);
248         }
249 #ifdef CACHE_SIZE
250         if (!options || !(attr=attr_search(options, NULL, attr_cache)) || attr->u.num)
251                 file->cache=1;
252 #endif
253         dbg_assert(file != NULL);
254         return file;
255 }
256
257 #if 0
258 struct file *
259 file_create_url(char *url)
260 {
261 }
262 #endif
263
264 #ifndef S_ISDIR
265 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
266 #endif
267 #ifndef S_ISREG
268 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
269 #endif
270
271 int file_is_dir(char *name)
272 {
273         struct stat buf;
274         if (! stat(name, &buf)) {
275                 return S_ISDIR(buf.st_mode);
276         }
277         return 0;
278
279 }
280
281 int file_is_reg(char *name)
282 {
283         struct stat buf;
284         if (! stat(name, &buf)) {
285                 return S_ISREG(buf.st_mode);
286         }
287         return 0;
288 }
289
290 long long
291 file_size(struct file *file)
292 {
293         return file->size;
294 }
295
296 int file_mkdir(char *name, int pflag)
297 {
298         char *buffer=g_alloca(sizeof(char)*(strlen(name)+1));
299         int ret;
300         char *next;
301         dbg(1,"enter %s %d\n",name,pflag);
302         if (!pflag) {
303                 if (file_is_dir(name))
304                         return 0;
305 #if defined HAVE_API_WIN32_BASE || defined _MSC_VER
306                 return mkdir(name);
307 #else
308                 return mkdir(name, 0777);
309 #endif
310         }
311         strcpy(buffer, name);
312         next=buffer;
313         while ((next=strchr(next, '/'))) {
314                 *next='\0';
315                 if (*buffer) {
316                         ret=file_mkdir(buffer, 0);
317                         if (ret)
318                                 return ret;
319                 }
320                 *next++='/';
321         }
322         if (pflag == 2)
323                 return 0;
324         return file_mkdir(buffer, 0);
325 }
326
327 int
328 file_mmap(struct file *file)
329 {
330 #if 0
331         int mmap_size=file->size+1024*1024;
332 #else
333         int mmap_size=file->size;
334 #endif
335 #ifdef HAVE_API_WIN32_BASE
336         file->begin = (unsigned char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
337 #else
338         file->begin=mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
339         dbg_assert(file->begin != NULL);
340         if (file->begin == (void *)0xffffffff) {
341                 perror("mmap");
342                 return 0;
343         }
344 #endif
345         dbg_assert(file->begin != (void *)0xffffffff);
346         file->mmap_end=file->begin+mmap_size;
347         file->end=file->begin+file->size;
348
349         return 1;
350 }
351
352 unsigned char *
353 file_data_read(struct file *file, long long offset, int size)
354 {
355         void *ret;
356         if (file->special)
357                 return NULL;
358         if (file->begin)
359                 return file->begin+offset;
360         if (file->cache) {
361                 struct file_cache_id id={offset,size,file->name_id,0};
362                 ret=cache_lookup(file_cache,&id); 
363                 if (ret)
364                         return ret;
365                 ret=cache_insert_new(file_cache,&id,size);
366         } else
367                 ret=g_malloc(size);
368         lseek(file->fd, offset, SEEK_SET);
369         if (read(file->fd, ret, size) != size) {
370                 file_data_free(file, ret);
371                 ret=NULL;
372         }
373         return ret;
374
375 }
376
377 static void
378 file_process_headers(struct file *file, unsigned char *headers)
379 {
380         char *tok;
381         char *cl;
382         if (file->headers)
383                 g_hash_table_destroy(file->headers);
384         file->headers=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
385         while ((tok=strtok((char*)headers, "\r\n"))) {
386                 char *sep;
387                 tok=g_strdup(tok);
388                 sep=strchr(tok,':');
389                 if (!sep)
390                         sep=strchr(tok,'/');
391                 if (!sep) {
392                         g_free(tok);
393                         continue;
394                 }
395                 *sep++='\0';
396                 if (*sep == ' ')
397                         sep++;
398                 strtolower(tok, tok);
399                 dbg(1,"header '%s'='%s'\n",tok,sep);
400                 g_hash_table_insert(file->headers, tok, sep);
401                 headers=NULL;
402         }
403         cl=g_hash_table_lookup(file->headers, "content-length");
404         if (cl) 
405 #ifdef HAVE__ATOI64
406                 file->size=_atoi64(cl);
407 #else
408                 file->size=atoll(cl);
409 #endif
410 }
411
412 static void
413 file_shift_buffer(struct file *file, int amount)
414 {
415         memmove(file->buffer, file->buffer+amount, file->buffer_len-amount);
416         file->buffer_len-=amount;
417 }
418
419 unsigned char *
420 file_data_read_special(struct file *file, int size, int *size_ret)
421 {
422         unsigned char *ret,*hdr;
423         int rets=0,rd;
424         int buffer_size=8192;
425         int eof=0;
426         if (!file->special)
427                 return NULL;
428         if (!file->buffer)
429                 file->buffer=g_malloc(buffer_size);
430         ret=g_malloc(size);
431         while ((size > 0 || file->requests) && (!eof || file->buffer_len)) {
432                 int toread=buffer_size-file->buffer_len;
433                 if (toread >= 4096 && !eof) {
434                         if (!file->requests && toread > size)
435                                 toread=size;
436                         rd=read(file->fd, file->buffer+file->buffer_len, toread);
437                         if (rd > 0) {
438                                 file->buffer_len+=rd;
439                         } else
440                                 eof=1;
441                 }
442                 if (file->requests) {
443                         dbg(1,"checking header\n");
444                         if ((hdr=file_http_header_end(file->buffer, file->buffer_len))) {
445                                 hdr[-1]='\0';
446                                 dbg(1,"found %s (%d bytes)\n",file->buffer,sizeof(file->buffer));
447                                 file_process_headers(file, file->buffer);
448                                 file_shift_buffer(file, hdr-file->buffer);
449                                 file->requests--;
450                                 if (file_http_header(file, "location"))
451                                         break;
452                         }
453                 }
454                 if (!file->requests) {
455                         rd=file->buffer_len;
456                         if (rd > size)
457                                 rd=size;
458                         memcpy(ret+rets, file->buffer, rd);
459                         file_shift_buffer(file, rd);
460                         rets+=rd;
461                         size-=rd;
462                 }
463         }
464         *size_ret=rets;
465         return ret;
466 }
467
468 unsigned char *
469 file_data_read_all(struct file *file)
470 {
471         return file_data_read(file, 0, file->size);
472 }
473
474 void
475 file_data_flush(struct file *file, long long offset, int size)
476 {
477         if (file->cache) {
478                 struct file_cache_id id={offset,size,file->name_id,0};
479                 cache_flush(file_cache,&id);
480                 dbg(1,"Flushing "LONGLONG_FMT" %d bytes\n",offset,size);
481         }
482 }
483
484 int
485 file_data_write(struct file *file, long long offset, int size, unsigned char *data)
486 {
487         file_data_flush(file, offset, size);
488         lseek(file->fd, offset, SEEK_SET);
489         if (write(file->fd, data, size) != size)
490                 return 0;
491         if (file->size < offset+size)
492                 file->size=offset+size;
493         return 1;
494 }
495
496 int
497 file_get_contents(char *name, unsigned char **buffer, int *size)
498 {
499         struct file *file;
500         file=file_create(name, 0);
501         if (!file)
502                 return 0;
503         file->cache=0;
504         *size=file_size(file);
505         *buffer=file_data_read_all(file);
506         file_destroy(file);
507         return 1;       
508 }
509
510
511 static int
512 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
513 {
514         z_stream stream;
515         int err;
516
517         stream.next_in = (Bytef*)source;
518         stream.avail_in = (uInt)sourceLen;
519         stream.next_out = dest;
520         stream.avail_out = (uInt)*destLen;
521
522         stream.zalloc = (alloc_func)0;
523         stream.zfree = (free_func)0;
524
525         err = inflateInit2(&stream, -MAX_WBITS);
526         if (err != Z_OK) return err;
527
528         err = inflate(&stream, Z_FINISH);
529         if (err != Z_STREAM_END) {
530         inflateEnd(&stream);
531         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
532                 return Z_DATA_ERROR;
533                 return err;
534         }
535         *destLen = stream.total_out;
536
537         err = inflateEnd(&stream);
538         return err;
539 }
540
541 unsigned char *
542 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
543 {
544         void *ret;
545         char *buffer = 0;
546         uLongf destLen=size_uncomp;
547
548         if (file->cache) {
549                 struct file_cache_id id={offset,size,file->name_id,1};
550                 ret=cache_lookup(file_cache,&id); 
551                 if (ret)
552                         return ret;
553                 ret=cache_insert_new(file_cache,&id,size_uncomp);
554         } else 
555                 ret=g_malloc(size_uncomp);
556         lseek(file->fd, offset, SEEK_SET);
557
558         buffer = (char *)g_malloc(size);
559         if (read(file->fd, buffer, size) != size) {
560                 g_free(ret);
561                 ret=NULL;
562         } else {
563                 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
564                         dbg(0,"uncompress failed\n");
565                         g_free(ret);
566                         ret=NULL;
567                 }
568         }
569         g_free(buffer);
570
571         return ret;
572 }
573
574 unsigned char *
575 file_data_read_encrypted(struct file *file, long long offset, int size, int size_uncomp, int compressed, char *passwd)
576 {
577 #ifdef HAVE_LIBCRYPTO
578         void *ret;
579         unsigned char *buffer = 0;
580         uLongf destLen=size_uncomp;
581
582         if (file->cache) {
583                 struct file_cache_id id={offset,size,file->name_id,1};
584                 ret=cache_lookup(file_cache,&id); 
585                 if (ret)
586                         return ret;
587                 ret=cache_insert_new(file_cache,&id,size_uncomp);
588         } else 
589                 ret=g_malloc(size_uncomp);
590         lseek(file->fd, offset, SEEK_SET);
591
592         buffer = (unsigned char *)g_malloc(size);
593         if (read(file->fd, buffer, size) != size) {
594                 g_free(ret);
595                 ret=NULL;
596         } else {
597                 unsigned char key[34], salt[8], verify[2], counter[16], xor[16], mac[10], *datap;
598                 int overhead=sizeof(salt)+sizeof(verify)+sizeof(mac);
599                 int esize=size-overhead;
600                 PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), (unsigned char *)buffer, 8, 1000, 34, key);
601                 if (key[32] == buffer[8] && key[33] == buffer[9] && esize >= 0) {
602                         AES_KEY aeskey;
603                         AES_set_encrypt_key(key, 128, &aeskey);
604                         datap=buffer+sizeof(salt)+sizeof(verify);
605                         memset(counter, 0, sizeof(counter));
606                         while (esize > 0) {
607                                 int i,curr_size,idx=0;
608                                 do {
609                                         counter[idx]++;
610                                 } while (!counter[idx++]);
611                                 AES_encrypt(counter, xor, &aeskey);
612                                 curr_size=esize;
613                                 if (curr_size > sizeof(xor))
614                                         curr_size=sizeof(xor);
615                                 for (i = 0 ; i < curr_size ; i++) 
616                                         *datap++^=xor[i];
617                                 esize-=curr_size;
618                         }
619                         size-=overhead;
620                         datap=buffer+sizeof(salt)+sizeof(verify);
621                         if (compressed) {
622                                 if (uncompress_int(ret, &destLen, (Bytef *)datap, size) != Z_OK) {
623                                         dbg(0,"uncompress failed\n");
624                                         g_free(ret);
625                                         ret=NULL;
626                                 }
627                         } else {
628                                 if (size == destLen) 
629                                         memcpy(ret, buffer, destLen);
630                                 else {
631                                         dbg(0,"memcpy failed\n");
632                                         g_free(ret);
633                                         ret=NULL;
634                                 }
635                         }
636                 } else {
637                         g_free(ret);
638                         ret=NULL;
639                 }
640         }
641         g_free(buffer);
642
643         return ret;
644 #else
645         return NULL;
646 #endif
647 }
648
649 void
650 file_data_free(struct file *file, unsigned char *data)
651 {
652         if (file->begin) {
653                 if (data == file->begin)
654                         return;
655                 if (data >= file->begin && data < file->end)
656                         return;
657         }
658         if (file->cache && data) {
659                 cache_entry_destroy(file_cache, data);
660         } else
661                 g_free(data);
662 }
663
664 void
665 file_data_remove(struct file *file, unsigned char *data)
666 {
667         if (file->begin) {
668                 if (data == file->begin)
669                         return;
670                 if (data >= file->begin && data < file->end)
671                         return;
672         }
673         if (file->cache && data) {
674                 cache_flush_data(file_cache, data);
675         } else
676                 g_free(data);
677 }
678
679 int
680 file_exists(char const *name)
681 {
682         struct stat buf;
683         if (! stat(name, &buf))
684                 return 1;
685         return 0;
686 }
687
688 void
689 file_remap_readonly(struct file *f)
690 {
691 #if defined(_WIN32) || defined(__CEGCC__)
692 #else
693         void *begin;
694         munmap(f->begin, f->size);
695         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
696         if (f->begin != begin)
697                 printf("remap failed\n");
698 #endif
699 }
700
701 void
702 file_unmap(struct file *f)
703 {
704 #if defined(_WIN32) || defined(__CEGCC__)
705     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
706 #else
707         munmap(f->begin, f->size);
708 #endif
709 }
710
711 #ifndef _MSC_VER
712 void *
713 file_opendir(char *dir)
714 {
715         return opendir(dir);
716 }
717 #else 
718 void *
719 file_opendir(char *dir)
720 {
721         WIN32_FIND_DATAA FindFileData;
722         HANDLE hFind = INVALID_HANDLE_VALUE;
723 #undef UNICODE         // we need FindFirstFileA() which takes an 8-bit c-string
724         char* fname=g_alloca(sizeof(char)*(strlen(dir)+4));
725         sprintf(fname,"%s\\*",dir);
726         hFind = FindFirstFileA(fname, &FindFileData);
727         return hFind;
728 }
729 #endif
730
731 #ifndef _MSC_VER
732 char *
733 file_readdir(void *hnd)
734 {
735         struct dirent *ent;
736
737         ent=readdir(hnd);
738         if (! ent)
739                 return NULL;
740         return ent->d_name;
741 }
742 #else
743 char *
744 file_readdir(void *hnd)
745 {
746         WIN32_FIND_DATA FindFileData;
747
748         if (FindNextFile(hnd, &FindFileData) ) {
749                 return FindFileData.cFileName;
750         } else {
751                 return NULL;
752         }
753 }
754 #endif /* _MSC_VER */
755
756 #ifndef _MSC_VER
757 void
758 file_closedir(void *hnd)
759 {
760         closedir(hnd);
761 }
762 #else
763 void
764 file_closedir(void *hnd)
765 {
766         FindClose(hnd);
767 }
768 #endif /* _MSC_VER */
769
770 struct file *
771 file_create_caseinsensitive(char *name, struct attr **options)
772 {
773         char *dirname=g_alloca(sizeof(char)*(strlen(name)+1));
774         char *filename;
775         char *p;
776         void *d;
777         struct file *ret;
778
779         ret=file_create(name, options);
780         if (ret)
781                 return ret;
782
783         strcpy(dirname, name);
784         p=dirname+strlen(name);
785         while (p > dirname) {
786                 if (*p == '/')
787                         break;
788                 p--;
789         }
790         *p=0;
791         d=file_opendir(dirname);
792         if (d) {
793                 *p++='/';
794                 while ((filename=file_readdir(d))) {
795                         if (!g_strcasecmp(filename, p)) {
796                                 strcpy(p, filename);
797                                 ret=file_create(dirname, options);
798                                 if (ret)
799                                         break;
800                         }
801                 }
802                 file_closedir(d);
803         }
804         return ret;
805 }
806
807 void
808 file_destroy(struct file *f)
809 {
810         if (f->headers)
811                 g_hash_table_destroy(f->headers);
812         switch (f->special) {
813         case 0:
814         case 1:
815                 close(f->fd);
816                 break;
817         }
818
819     if ( f->begin != NULL )
820     {
821         file_unmap( f );
822     }
823
824         g_free(f->buffer);
825         g_free(f->name);
826         g_free(f);
827 }
828
829 struct file_wordexp {
830         int err;
831         char *pattern;
832         wordexp_t we;
833 };
834
835 struct file_wordexp *
836 file_wordexp_new(const char *pattern)
837 {
838         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
839
840         ret->pattern=g_strdup(pattern);
841         ret->err=wordexp(pattern, &ret->we, 0);
842         if (ret->err)
843                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
844         return ret;
845 }
846
847 int
848 file_wordexp_get_count(struct file_wordexp *wexp)
849 {
850         if (wexp->err)
851                 return 1;
852         return wexp->we.we_wordc;
853 }
854
855 char **
856 file_wordexp_get_array(struct file_wordexp *wexp)
857 {
858         if (wexp->err)
859                 return &wexp->pattern;
860         return wexp->we.we_wordv;
861 }
862
863 void
864 file_wordexp_destroy(struct file_wordexp *wexp)
865 {
866         if (! wexp->err)
867                 wordfree(&wexp->we);
868         g_free(wexp->pattern);
869         g_free(wexp);
870 }
871
872
873 int
874 file_get_param(struct file *file, struct param_list *param, int count)
875 {
876         int i=count;
877         param_add_string("Filename", file->name, &param, &count);
878         param_add_hex("Size", file->size, &param, &count);
879         return i-count;
880 }
881
882 int
883 file_version(struct file *file, int mode)
884 {
885 #ifndef HAVE_API_WIN32_BASE
886         struct stat st;
887         int error;
888         if (mode == 3) {
889                 long long size=lseek(file->fd, 0, SEEK_END);
890                 if (file->begin && file->begin+size > file->mmap_end) {
891                         file->version++;
892                 } else {
893                         file->size=size;
894                         if (file->begin)
895                                 file->end=file->begin+file->size;
896                 }
897         } else {
898                 if (mode == 2)
899                         error=stat(file->name, &st);
900                 else
901                         error=fstat(file->fd, &st);
902                 if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
903                         file->mtime=st.st_mtime;
904                         file->ctime=st.st_ctime;
905                         file->version++;
906                         dbg(1,"%s now version %d\n", file->name, file->version);
907                 }
908         }
909         return file->version;
910 #else
911         return 0;
912 #endif
913 }
914
915 void *
916 file_get_os_handle(struct file *file)
917 {
918         return GINT_TO_POINTER(file->fd);
919 }
920
921 void
922 file_init(void)
923 {
924 #ifdef CACHE_SIZE
925         file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
926         file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
927 #endif
928 }
929