/[zanavi_public1]/navit/navit/file.c
ZANavi

Contents of /navit/navit/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (12 years, 5 months ago) by zoff99
File MIME type: text/plain
File size: 19345 byte(s)
import files
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 #ifdef HAVE_SOCKET
49 #include <sys/socket.h>
50 #include <netdb.h>
51 #endif
52
53 extern char *version;
54
55 #ifdef HAVE_LIBCRYPTO
56 #include <openssl/sha.h>
57 #include <openssl/hmac.h>
58 #include <openssl/aes.h>
59 #include <openssl/evp.h>
60 #include <openssl/rand.h>
61 #endif
62
63 #ifdef HAVE_API_ANDROID
64 #define lseek lseek64
65 #endif
66
67 #ifndef O_LARGEFILE
68 #define O_LARGEFILE 0
69 #endif
70
71 #ifndef O_BINARY
72 #define O_BINARY 0
73 #endif
74
75 #ifdef CACHE_SIZE
76 static GHashTable *file_name_hash;
77 #endif
78
79 static struct cache *file_cache;
80
81 #ifdef _MSC_VER
82 #pragma pack(push,1)
83 #endif /* _MSC_VER */
84 struct file_cache_id {
85 long long offset;
86 int size;
87 int file_name_id;
88 int method;
89 #ifndef _MSC_VER
90 }__attribute__ ((packed));
91 #else /* _MSC_VER */
92 };
93 #pragma pack(pop)
94 #endif /* _MSC_VER */
95
96 #ifdef HAVE_SOCKET
97 static int
98 file_socket_connect(char *host, char *service)
99 {
100 struct addrinfo hints;
101 struct addrinfo *result, *rp;
102 int fd=-1,s;
103
104 memset(&hints, 0, sizeof(struct addrinfo));
105 hints.ai_family = AF_UNSPEC;
106 hints.ai_socktype = SOCK_STREAM;
107 hints.ai_flags = 0;
108 hints.ai_protocol = 0;
109 s = getaddrinfo(host, service, &hints, &result);
110 if (s != 0) {
111 dbg(0,"getaddrinfo error %s\n",gai_strerror(s));
112 return -1;
113 }
114 for (rp = result; rp != NULL; rp = rp->ai_next) {
115 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
116 if (fd != -1) {
117 if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
118 break;
119 close(fd);
120 fd=-1;
121 }
122 }
123 freeaddrinfo(result);
124 return fd;
125 }
126
127 static void
128 file_http_request(struct file *file, char *method, char *host, char *path, char *header, int persistent)
129 {
130 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":"");
131 write(file->fd, request, strlen(request));
132 dbg(1,"%s\n",request);
133 file->requests++;
134 }
135
136 static int
137 file_request_do(struct file *file, struct attr **options, int connect)
138 {
139 struct attr *attr;
140 char *name;
141
142 if (!options)
143 return 0;
144 attr=attr_search(options, NULL, attr_url);
145 if (!attr)
146 return 0;
147 name=attr->u.str;
148 if (!name)
149 return 0;
150 g_free(file->name);
151 file->name = g_strdup(name);
152 if (!strncmp(name,"http://",7)) {
153 char *host=g_strdup(name+7);
154 char *port=strchr(host,':');
155 char *path=strchr(name+7,'/');
156 char *method="GET";
157 char *header=NULL;
158 int persistent=0;
159 if ((attr=attr_search(options, NULL, attr_http_method)) && attr->u.str)
160 method=attr->u.str;
161 if ((attr=attr_search(options, NULL, attr_http_header)) && attr->u.str)
162 header=attr->u.str;
163 if ((attr=attr_search(options, NULL, attr_persistent)))
164 persistent=attr->u.num;
165 if (path)
166 host[path-name-7]='\0';
167 if (port)
168 *port++='\0';
169 dbg(1,"host=%s path=%s\n",host,path);
170 if (connect)
171 file->fd=file_socket_connect(host,port?port:"80");
172 file_http_request(file,method,host,path,header,persistent);
173 file->special=1;
174 g_free(host);
175 }
176 return 1;
177 }
178 #endif
179
180 static unsigned char *
181 file_http_header_end(unsigned char *str, int len)
182 {
183 int i;
184 for (i=0; i+1<len; i+=2) {
185 if (str[i+1]=='\n') {
186 if (str[i]=='\n')
187 return str+i+2;
188 else if (str[i]=='\r' && i+3<len && str[i+2]=='\r' && str[i+3]=='\n')
189 return str+i+4;
190 --i;
191 } else if (str[i+1]=='\r') {
192 if (i+4<len && str[i+2]=='\n' && str[i+3]=='\r' && str[i+4]=='\n')
193 return str+i+5;
194 --i;
195 }
196 }
197 return NULL;
198 }
199
200 int
201 file_request(struct file *f, struct attr **options)
202 {
203 #ifdef HAVE_SOCKET
204 return file_request_do(f, options, 0);
205 #else
206 return 0;
207 #endif
208 }
209
210 char *
211 file_http_header(struct file *f, char *header)
212 {
213 if (!f->headers)
214 return NULL;
215 return g_hash_table_lookup(f->headers, header);
216 }
217
218 struct file *
219 file_create(char *name, struct attr **options)
220 {
221 struct stat stat;
222 struct file *file= g_new0(struct file,1);
223 struct attr *attr;
224 int open_flags=O_LARGEFILE|O_BINARY;
225
226 if (options && (attr=attr_search(options, NULL, attr_url))) {
227 #ifdef HAVE_SOCKET
228 file_request_do(file, options, 1);
229 #endif
230 } else {
231 if (options && (attr=attr_search(options, NULL, attr_readwrite)) && attr->u.num) {
232 open_flags |= O_RDWR;
233 if ((attr=attr_search(options, NULL, attr_create)) && attr->u.num)
234 open_flags |= O_CREAT;
235 } else
236 open_flags |= O_RDONLY;
237 file->name = g_strdup(name);
238 file->fd=open(name, open_flags, 0666);
239 if (file->fd == -1) {
240 g_free(file);
241 return NULL;
242 }
243 dbg(1,"fd=%d\n", file->fd);
244 fstat(file->fd, &stat);
245 file->size=stat.st_size;
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 = (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 *size=file_size(file);
504 *buffer=file_data_read_all(file);
505 file_destroy(file);
506 return 1;
507 }
508
509
510 static int
511 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
512 {
513 z_stream stream;
514 int err;
515
516 stream.next_in = (Bytef*)source;
517 stream.avail_in = (uInt)sourceLen;
518 stream.next_out = dest;
519 stream.avail_out = (uInt)*destLen;
520
521 stream.zalloc = (alloc_func)0;
522 stream.zfree = (free_func)0;
523
524 err = inflateInit2(&stream, -MAX_WBITS);
525 if (err != Z_OK) return err;
526
527 err = inflate(&stream, Z_FINISH);
528 if (err != Z_STREAM_END) {
529 inflateEnd(&stream);
530 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
531 return Z_DATA_ERROR;
532 return err;
533 }
534 *destLen = stream.total_out;
535
536 err = inflateEnd(&stream);
537 return err;
538 }
539
540 unsigned char *
541 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
542 {
543 void *ret;
544 char *buffer = 0;
545 uLongf destLen=size_uncomp;
546
547 if (file_cache) {
548 struct file_cache_id id={offset,size,file->name_id,1};
549 ret=cache_lookup(file_cache,&id);
550 if (ret)
551 return ret;
552 ret=cache_insert_new(file_cache,&id,size_uncomp);
553 } else
554 ret=g_malloc(size_uncomp);
555 lseek(file->fd, offset, SEEK_SET);
556
557 buffer = (char *)g_malloc(size);
558 if (read(file->fd, buffer, size) != size) {
559 g_free(ret);
560 ret=NULL;
561 } else {
562 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
563 dbg(0,"uncompress failed\n");
564 g_free(ret);
565 ret=NULL;
566 }
567 }
568 g_free(buffer);
569
570 return ret;
571 }
572
573 unsigned char *
574 file_data_read_encrypted(struct file *file, long long offset, int size, int size_uncomp, int compressed, char *passwd)
575 {
576 #ifdef HAVE_LIBCRYPTO
577 void *ret;
578 unsigned char *buffer = 0;
579 uLongf destLen=size_uncomp;
580
581 if (file_cache) {
582 struct file_cache_id id={offset,size,file->name_id,1};
583 ret=cache_lookup(file_cache,&id);
584 if (ret)
585 return ret;
586 ret=cache_insert_new(file_cache,&id,size_uncomp);
587 } else
588 ret=g_malloc(size_uncomp);
589 lseek(file->fd, offset, SEEK_SET);
590
591 buffer = (unsigned char *)g_malloc(size);
592 if (read(file->fd, buffer, size) != size) {
593 g_free(ret);
594 ret=NULL;
595 } else {
596 unsigned char key[34], salt[8], verify[2], counter[16], xor[16], mac[10], *datap;
597 int overhead=sizeof(salt)+sizeof(verify)+sizeof(mac);
598 int esize=size-overhead;
599 PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), (unsigned char *)buffer, 8, 1000, 34, key);
600 if (key[32] == buffer[8] && key[33] == buffer[9] && esize >= 0) {
601 AES_KEY aeskey;
602 AES_set_encrypt_key(key, 128, &aeskey);
603 datap=buffer+sizeof(salt)+sizeof(verify);
604 memset(counter, 0, sizeof(counter));
605 while (esize > 0) {
606 int i,curr_size,idx=0;
607 do {
608 counter[idx]++;
609 } while (!counter[idx++]);
610 AES_encrypt(counter, xor, &aeskey);
611 curr_size=esize;
612 if (curr_size > sizeof(xor))
613 curr_size=sizeof(xor);
614 for (i = 0 ; i < curr_size ; i++)
615 *datap++^=xor[i];
616 esize-=curr_size;
617 }
618 size-=overhead;
619 datap=buffer+sizeof(salt)+sizeof(verify);
620 if (compressed) {
621 if (uncompress_int(ret, &destLen, (Bytef *)datap, size) != Z_OK) {
622 dbg(0,"uncompress failed\n");
623 g_free(ret);
624 ret=NULL;
625 }
626 } else {
627 if (size == destLen)
628 memcpy(ret, buffer, destLen);
629 else {
630 dbg(0,"memcpy failed\n");
631 g_free(ret);
632 ret=NULL;
633 }
634 }
635 } else {
636 g_free(ret);
637 ret=NULL;
638 }
639 }
640 g_free(buffer);
641
642 return ret;
643 #else
644 return NULL;
645 #endif
646 }
647
648 void
649 file_data_free(struct file *file, unsigned char *data)
650 {
651 if (file->begin) {
652 if (data == file->begin)
653 return;
654 if (data >= file->begin && data < file->end)
655 return;
656 }
657 if (file->cache && data) {
658 cache_entry_destroy(file_cache, data);
659 } else
660 g_free(data);
661 }
662
663 void
664 file_data_remove(struct file *file, unsigned char *data)
665 {
666 if (file->begin) {
667 if (data == file->begin)
668 return;
669 if (data >= file->begin && data < file->end)
670 return;
671 }
672 if (file->cache && data) {
673 cache_flush_data(file_cache, data);
674 } else
675 g_free(data);
676 }
677
678 int
679 file_exists(char const *name)
680 {
681 struct stat buf;
682 if (! stat(name, &buf))
683 return 1;
684 return 0;
685 }
686
687 void
688 file_remap_readonly(struct file *f)
689 {
690 #if defined(_WIN32) || defined(__CEGCC__)
691 #else
692 void *begin;
693 munmap(f->begin, f->size);
694 begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
695 if (f->begin != begin)
696 printf("remap failed\n");
697 #endif
698 }
699
700 void
701 file_unmap(struct file *f)
702 {
703 #if defined(_WIN32) || defined(__CEGCC__)
704 mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
705 #else
706 munmap(f->begin, f->size);
707 #endif
708 }
709
710 #ifndef _MSC_VER
711 void *
712 file_opendir(char *dir)
713 {
714 return opendir(dir);
715 }
716 #else
717 void *
718 file_opendir(char *dir)
719 {
720 WIN32_FIND_DATAA FindFileData;
721 HANDLE hFind = INVALID_HANDLE_VALUE;
722 #undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string
723 char* fname=g_alloca(sizeof(char)*(strlen(dir)+4));
724 sprintf(fname,"%s\\*",dir);
725 hFind = FindFirstFileA(fname, &FindFileData);
726 return hFind;
727 }
728 #endif
729
730 #ifndef _MSC_VER
731 char *
732 file_readdir(void *hnd)
733 {
734 struct dirent *ent;
735
736 ent=readdir(hnd);
737 if (! ent)
738 return NULL;
739 return ent->d_name;
740 }
741 #else
742 char *
743 file_readdir(void *hnd)
744 {
745 WIN32_FIND_DATA FindFileData;
746
747 if (FindNextFile(hnd, &FindFileData) ) {
748 return FindFileData.cFileName;
749 } else {
750 return NULL;
751 }
752 }
753 #endif /* _MSC_VER */
754
755 #ifndef _MSC_VER
756 void
757 file_closedir(void *hnd)
758 {
759 closedir(hnd);
760 }
761 #else
762 void
763 file_closedir(void *hnd)
764 {
765 FindClose(hnd);
766 }
767 #endif /* _MSC_VER */
768
769 struct file *
770 file_create_caseinsensitive(char *name, struct attr **options)
771 {
772 char *dirname=g_alloca(sizeof(char)*(strlen(name)+1));
773 char *filename;
774 char *p;
775 void *d;
776 struct file *ret;
777
778 ret=file_create(name, options);
779 if (ret)
780 return ret;
781
782 strcpy(dirname, name);
783 p=dirname+strlen(name);
784 while (p > dirname) {
785 if (*p == '/')
786 break;
787 p--;
788 }
789 *p=0;
790 d=file_opendir(dirname);
791 if (d) {
792 *p++='/';
793 while ((filename=file_readdir(d))) {
794 if (!g_strcasecmp(filename, p)) {
795 strcpy(p, filename);
796 ret=file_create(dirname, options);
797 if (ret)
798 break;
799 }
800 }
801 file_closedir(d);
802 }
803 return ret;
804 }
805
806 void
807 file_destroy(struct file *f)
808 {
809 if (f->headers)
810 g_hash_table_destroy(f->headers);
811 switch (f->special) {
812 case 0:
813 case 1:
814 close(f->fd);
815 break;
816 }
817
818 if ( f->begin != NULL )
819 {
820 file_unmap( f );
821 }
822
823 g_free(f->buffer);
824 g_free(f->name);
825 g_free(f);
826 }
827
828 struct file_wordexp {
829 int err;
830 char *pattern;
831 wordexp_t we;
832 };
833
834 struct file_wordexp *
835 file_wordexp_new(const char *pattern)
836 {
837 struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
838
839 ret->pattern=g_strdup(pattern);
840 ret->err=wordexp(pattern, &ret->we, 0);
841 if (ret->err)
842 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
843 return ret;
844 }
845
846 int
847 file_wordexp_get_count(struct file_wordexp *wexp)
848 {
849 if (wexp->err)
850 return 1;
851 return wexp->we.we_wordc;
852 }
853
854 char **
855 file_wordexp_get_array(struct file_wordexp *wexp)
856 {
857 if (wexp->err)
858 return &wexp->pattern;
859 return wexp->we.we_wordv;
860 }
861
862 void
863 file_wordexp_destroy(struct file_wordexp *wexp)
864 {
865 if (! wexp->err)
866 wordfree(&wexp->we);
867 g_free(wexp->pattern);
868 g_free(wexp);
869 }
870
871
872 int
873 file_get_param(struct file *file, struct param_list *param, int count)
874 {
875 int i=count;
876 param_add_string("Filename", file->name, &param, &count);
877 param_add_hex("Size", file->size, &param, &count);
878 return i-count;
879 }
880
881 int
882 file_version(struct file *file, int mode)
883 {
884 #ifndef HAVE_API_WIN32_BASE
885 struct stat st;
886 int error;
887 if (mode == 3) {
888 long long size=lseek(file->fd, 0, SEEK_END);
889 if (file->begin && file->begin+size > file->mmap_end) {
890 file->version++;
891 } else {
892 file->size=size;
893 if (file->begin)
894 file->end=file->begin+file->size;
895 }
896 } else {
897 if (mode == 2)
898 error=stat(file->name, &st);
899 else
900 error=fstat(file->fd, &st);
901 if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
902 file->mtime=st.st_mtime;
903 file->ctime=st.st_ctime;
904 file->version++;
905 dbg(1,"%s now version %d\n", file->name, file->version);
906 }
907 }
908 return file->version;
909 #else
910 return 0;
911 #endif
912 }
913
914 void *
915 file_get_os_handle(struct file *file)
916 {
917 return GINT_TO_POINTER(file->fd);
918 }
919
920 void
921 file_init(void)
922 {
923 #ifdef CACHE_SIZE
924 file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
925 file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
926 #endif
927 }
928

   
Visit the ZANavi Wiki