2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2011 Navit Team
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.
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.
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.
20 #define _FILE_OFFSET_BITS 64
21 #define _LARGEFILE_SOURCE
22 #define _LARGEFILE64_SOURCE
50 #include <sys/socket.h>
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>
64 #ifdef HAVE_API_ANDROID
77 static GHashTable *file_name_hash;
80 static struct cache *file_cache;
82 #ifdef HAVE_PRAGMA_PACK
87 struct file_cache_id {
94 #ifdef HAVE_PRAGMA_PACK
100 file_socket_connect(char *host, char *service)
102 struct addrinfo hints;
103 struct addrinfo *result, *rp;
106 memset(&hints, 0, sizeof(struct addrinfo));
107 hints.ai_family = AF_UNSPEC;
108 hints.ai_socktype = SOCK_STREAM;
110 hints.ai_protocol = 0;
111 s = getaddrinfo(host, service, &hints, &result);
113 dbg(0,"getaddrinfo error %s\n",gai_strerror(s));
116 for (rp = result; rp != NULL; rp = rp->ai_next) {
117 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
119 if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
125 freeaddrinfo(result);
130 file_http_request(struct file *file, char *method, char *host, char *path, char *header, int persistent)
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);
139 file_request_do(struct file *file, struct attr **options, int connect)
146 attr=attr_search(options, NULL, attr_url);
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,'/');
161 if ((attr=attr_search(options, NULL, attr_http_method)) && attr->u.str)
163 if ((attr=attr_search(options, NULL, attr_http_header)) && attr->u.str)
165 if ((attr=attr_search(options, NULL, attr_persistent)))
166 persistent=attr->u.num;
168 host[path-name-7]='\0';
171 dbg(1,"host=%s path=%s\n",host,path);
173 file->fd=file_socket_connect(host,port?port:"80");
174 file_http_request(file,method,host,path,header,persistent);
182 static unsigned char *
183 file_http_header_end(unsigned char *str, int len)
186 for (i=0; i+1<len; i+=2) {
187 if (str[i+1]=='\n') {
190 else if (str[i]=='\r' && i+3<len && str[i+2]=='\r' && str[i+3]=='\n')
193 } else if (str[i+1]=='\r') {
194 if (i+4<len && str[i+2]=='\n' && str[i+3]=='\r' && str[i+4]=='\n')
203 file_request(struct file *f, struct attr **options)
206 return file_request_do(f, options, 0);
213 file_http_header(struct file *f, char *header)
217 return g_hash_table_lookup(f->headers, header);
221 file_create(char *name, struct attr **options)
224 struct file *file= g_new0(struct file,1);
226 int open_flags=O_LARGEFILE|O_BINARY;
228 if (options && (attr=attr_search(options, NULL, attr_url))) {
230 file_request_do(file, options, 1);
233 if (options && (attr=attr_search(options, NULL, attr_readwrite)) && attr->u.num) {
234 open_flags |= O_RDWR;
235 if ((attr=attr_search(options, NULL, attr_create)) && attr->u.num)
236 open_flags |= O_CREAT;
238 open_flags |= O_RDONLY;
239 file->name = g_strdup(name);
240 file->fd=open(name, open_flags, 0666);
241 if (file->fd == -1) {
245 dbg(1,"fd=%d\n", file->fd);
246 file->size=lseek(file->fd, 0, SEEK_END);
247 dbg(1,"size="LONGLONG_FMT"\n", file->size);
248 file->name_id = (long)atom(name);
251 if (!options || !(attr=attr_search(options, NULL, attr_cache)) || attr->u.num)
254 dbg_assert(file != NULL);
260 file_create_url(char *url)
266 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
269 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
272 int file_is_dir(char *name)
275 if (! stat(name, &buf)) {
276 return S_ISDIR(buf.st_mode);
282 int file_is_reg(char *name)
285 if (! stat(name, &buf)) {
286 return S_ISREG(buf.st_mode);
292 file_size(struct file *file)
297 int file_mkdir(char *name, int pflag)
299 char *buffer=g_alloca(sizeof(char)*(strlen(name)+1));
302 dbg(1,"enter %s %d\n",name,pflag);
304 if (file_is_dir(name))
306 #if defined HAVE_API_WIN32_BASE || defined _MSC_VER
309 return mkdir(name, 0777);
312 strcpy(buffer, name);
314 while ((next=strchr(next, '/'))) {
317 ret=file_mkdir(buffer, 0);
325 return file_mkdir(buffer, 0);
329 file_mmap(struct file *file)
332 int mmap_size=file->size+1024*1024;
334 int mmap_size=file->size;
336 #ifdef HAVE_API_WIN32_BASE
337 file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
339 file->begin=mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
340 dbg_assert(file->begin != NULL);
341 if (file->begin == (void *)0xffffffff) {
346 dbg_assert(file->begin != (void *)0xffffffff);
347 file->mmap_end=file->begin+mmap_size;
348 file->end=file->begin+file->size;
354 file_data_read(struct file *file, long long offset, int size)
360 return file->begin+offset;
362 struct file_cache_id id={offset,size,file->name_id,0};
363 ret=cache_lookup(file_cache,&id);
366 ret=cache_insert_new(file_cache,&id,size);
369 lseek(file->fd, offset, SEEK_SET);
370 if (read(file->fd, ret, size) != size) {
371 file_data_free(file, ret);
379 file_process_headers(struct file *file, unsigned char *headers)
384 g_hash_table_destroy(file->headers);
385 file->headers=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
386 while ((tok=strtok((char*)headers, "\r\n"))) {
399 strtolower(tok, tok);
400 dbg(1,"header '%s'='%s'\n",tok,sep);
401 g_hash_table_insert(file->headers, tok, sep);
404 cl=g_hash_table_lookup(file->headers, "content-length");
407 file->size=_atoi64(cl);
409 file->size=atoll(cl);
414 file_shift_buffer(struct file *file, int amount)
416 memmove(file->buffer, file->buffer+amount, file->buffer_len-amount);
417 file->buffer_len-=amount;
421 file_data_read_special(struct file *file, int size, int *size_ret)
423 unsigned char *ret,*hdr;
425 int buffer_size=8192;
430 file->buffer=g_malloc(buffer_size);
432 while ((size > 0 || file->requests) && (!eof || file->buffer_len)) {
433 int toread=buffer_size-file->buffer_len;
434 if (toread >= 4096 && !eof) {
435 if (!file->requests && toread > size)
437 rd=read(file->fd, file->buffer+file->buffer_len, toread);
439 file->buffer_len+=rd;
443 if (file->requests) {
444 dbg(1,"checking header\n");
445 if ((hdr=file_http_header_end(file->buffer, file->buffer_len))) {
447 dbg(1,"found %s (%d bytes)\n",file->buffer,sizeof(file->buffer));
448 file_process_headers(file, file->buffer);
449 file_shift_buffer(file, hdr-file->buffer);
451 if (file_http_header(file, "location"))
455 if (!file->requests) {
459 memcpy(ret+rets, file->buffer, rd);
460 file_shift_buffer(file, rd);
470 file_data_read_all(struct file *file)
472 return file_data_read(file, 0, file->size);
476 file_data_flush(struct file *file, long long offset, int size)
479 struct file_cache_id id={offset,size,file->name_id,0};
480 cache_flush(file_cache,&id);
481 dbg(1,"Flushing "LONGLONG_FMT" %d bytes\n",offset,size);
486 file_data_write(struct file *file, long long offset, int size, unsigned char *data)
488 file_data_flush(file, offset, size);
489 lseek(file->fd, offset, SEEK_SET);
490 if (write(file->fd, data, size) != size)
492 if (file->size < offset+size)
493 file->size=offset+size;
498 file_get_contents(char *name, unsigned char **buffer, int *size)
501 file=file_create(name, 0);
505 *size=file_size(file);
506 *buffer=file_data_read_all(file);
513 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
518 stream.next_in = (Bytef*)source;
519 stream.avail_in = (uInt)sourceLen;
520 stream.next_out = dest;
521 stream.avail_out = (uInt)*destLen;
523 stream.zalloc = (alloc_func)0;
524 stream.zfree = (free_func)0;
526 err = inflateInit2(&stream, -MAX_WBITS);
527 if (err != Z_OK) return err;
529 err = inflate(&stream, Z_FINISH);
530 if (err != Z_STREAM_END) {
532 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
536 *destLen = stream.total_out;
538 err = inflateEnd(&stream);
543 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
547 uLongf destLen=size_uncomp;
550 struct file_cache_id id={offset,size,file->name_id,1};
551 ret=cache_lookup(file_cache,&id);
554 ret=cache_insert_new(file_cache,&id,size_uncomp);
556 ret=g_malloc(size_uncomp);
557 lseek(file->fd, offset, SEEK_SET);
559 buffer = (char *)g_malloc(size);
560 if (read(file->fd, buffer, size) != size) {
564 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
565 dbg(0,"uncompress failed\n");
576 file_data_read_encrypted(struct file *file, long long offset, int size, int size_uncomp, int compressed, char *passwd)
578 #ifdef HAVE_LIBCRYPTO
580 unsigned char *buffer = 0;
581 uLongf destLen=size_uncomp;
584 struct file_cache_id id={offset,size,file->name_id,1};
585 ret=cache_lookup(file_cache,&id);
588 ret=cache_insert_new(file_cache,&id,size_uncomp);
590 ret=g_malloc(size_uncomp);
591 lseek(file->fd, offset, SEEK_SET);
593 buffer = (unsigned char *)g_malloc(size);
594 if (read(file->fd, buffer, size) != size) {
598 unsigned char key[34], salt[8], verify[2], counter[16], xor[16], mac[10], *datap;
599 int overhead=sizeof(salt)+sizeof(verify)+sizeof(mac);
600 int esize=size-overhead;
601 PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), (unsigned char *)buffer, 8, 1000, 34, key);
602 if (key[32] == buffer[8] && key[33] == buffer[9] && esize >= 0) {
604 AES_set_encrypt_key(key, 128, &aeskey);
605 datap=buffer+sizeof(salt)+sizeof(verify);
606 memset(counter, 0, sizeof(counter));
608 int i,curr_size,idx=0;
611 } while (!counter[idx++]);
612 AES_encrypt(counter, xor, &aeskey);
614 if (curr_size > sizeof(xor))
615 curr_size=sizeof(xor);
616 for (i = 0 ; i < curr_size ; i++)
621 datap=buffer+sizeof(salt)+sizeof(verify);
623 if (uncompress_int(ret, &destLen, (Bytef *)datap, size) != Z_OK) {
624 dbg(0,"uncompress failed\n");
630 memcpy(ret, buffer, destLen);
632 dbg(0,"memcpy failed\n");
651 file_data_free(struct file *file, unsigned char *data)
654 if (data == file->begin)
656 if (data >= file->begin && data < file->end)
659 if (file->cache && data) {
660 cache_entry_destroy(file_cache, data);
666 file_data_remove(struct file *file, unsigned char *data)
669 if (data == file->begin)
671 if (data >= file->begin && data < file->end)
674 if (file->cache && data) {
675 cache_flush_data(file_cache, data);
681 file_exists(char const *name)
684 if (! stat(name, &buf))
690 file_remap_readonly(struct file *f)
692 #if defined(_WIN32) || defined(__CEGCC__)
695 munmap(f->begin, f->size);
696 begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
697 if (f->begin != begin)
698 printf("remap failed\n");
703 file_unmap(struct file *f)
705 #if defined(_WIN32) || defined(__CEGCC__)
706 mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
708 munmap(f->begin, f->size);
714 file_opendir(char *dir)
720 file_opendir(char *dir)
722 WIN32_FIND_DATAA FindFileData;
723 HANDLE hFind = INVALID_HANDLE_VALUE;
724 #undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string
725 char* fname=g_alloca(sizeof(char)*(strlen(dir)+4));
726 sprintf(fname,"%s\\*",dir);
727 hFind = FindFirstFileA(fname, &FindFileData);
734 file_readdir(void *hnd)
745 file_readdir(void *hnd)
747 WIN32_FIND_DATA FindFileData;
749 if (FindNextFile(hnd, &FindFileData) ) {
750 return FindFileData.cFileName;
755 #endif /* _MSC_VER */
759 file_closedir(void *hnd)
765 file_closedir(void *hnd)
769 #endif /* _MSC_VER */
772 file_create_caseinsensitive(char *name, struct attr **options)
774 char *dirname=g_alloca(sizeof(char)*(strlen(name)+1));
780 ret=file_create(name, options);
784 strcpy(dirname, name);
785 p=dirname+strlen(name);
786 while (p > dirname) {
792 d=file_opendir(dirname);
795 while ((filename=file_readdir(d))) {
796 if (!g_strcasecmp(filename, p)) {
798 ret=file_create(dirname, options);
809 file_destroy(struct file *f)
812 g_hash_table_destroy(f->headers);
813 switch (f->special) {
820 if ( f->begin != NULL )
830 struct file_wordexp {
836 struct file_wordexp *
837 file_wordexp_new(const char *pattern)
839 struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
841 ret->pattern=g_strdup(pattern);
842 ret->err=wordexp(pattern, &ret->we, 0);
844 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
849 file_wordexp_get_count(struct file_wordexp *wexp)
853 return wexp->we.we_wordc;
857 file_wordexp_get_array(struct file_wordexp *wexp)
860 return &wexp->pattern;
861 return wexp->we.we_wordv;
865 file_wordexp_destroy(struct file_wordexp *wexp)
869 g_free(wexp->pattern);
875 file_get_param(struct file *file, struct param_list *param, int count)
878 param_add_string("Filename", file->name, ¶m, &count);
879 param_add_hex("Size", file->size, ¶m, &count);
884 file_version(struct file *file, int mode)
886 #ifndef HAVE_API_WIN32_BASE
890 long long size=lseek(file->fd, 0, SEEK_END);
891 if (file->begin && file->begin+size > file->mmap_end) {
896 file->end=file->begin+file->size;
900 error=stat(file->name, &st);
902 error=fstat(file->fd, &st);
903 if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
904 file->mtime=st.st_mtime;
905 file->ctime=st.st_ctime;
907 dbg(1,"%s now version %d\n", file->name, file->version);
910 return file->version;
917 file_get_os_handle(struct file *file)
919 return GINT_TO_POINTER(file->fd);
926 file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
927 file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);