source: tags/arb_5.5/ARBDB/ad_load.c

Last change on this file was 7590, checked in by westram, 13 years ago
  • if ARB can't write to /tmp, it terminated with 'unknown error'
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.5 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <errno.h>
4#include <string.h>
5/* #include <malloc.h> */
6#include <ctype.h>
7#include <sys/stat.h>
8#include <time.h>
9#include <netinet/in.h>
10
11/*#include "arbdb.h"*/
12#include "adlocal.h"
13#include "admap.h"
14#include "arbdbt.h"
15
16#define READING_BUFFER_SIZE (1024*32)
17
18/* ------------------------------------------ */
19/* helper code to read ascii file in portions */
20
21/* ----------------------- */
22/*      ReadingBuffer      */
23/* ----------------------- */
24
25typedef struct reading_buffer_S {
26    char                    *data;
27    struct reading_buffer_S *next;
28    int                      read_bytes;
29} *ReadingBuffer;
30
31static ReadingBuffer unused_reading_buffers = 0;
32
33#if defined(DEBUG)
34/* #define CHECK_RELEASED_BUFFERS */
35#endif /* DEBUG */
36
37#if defined(CHECK_RELEASED_BUFFERS)
38static int is_a_unused_reading_buffer(ReadingBuffer rb) {
39    if (unused_reading_buffers) {
40        ReadingBuffer check = unused_reading_buffers;
41        for (; check; check = check->next) {
42            if (check == rb) return 1;
43        }
44    }
45    return 0;
46}
47#endif /* CHECK_RELEASED_BUFFERS */
48
49static ReadingBuffer allocate_ReadingBuffer() {
50    ReadingBuffer rb = malloc(sizeof(*rb)+READING_BUFFER_SIZE);
51    rb->data         = ((char*)rb)+sizeof(*rb);
52    rb->next         = 0;
53    rb->read_bytes   = 0;
54    return rb;
55}
56
57static void release_ReadingBuffers(ReadingBuffer rb) {
58    ReadingBuffer last = rb;
59
60#if defined(CHECK_RELEASED_BUFFERS)
61    gb_assert(!is_a_unused_reading_buffer(rb));
62#endif /* CHECK_RELEASED_BUFFERS */
63    while (last->next) {
64        last = last->next;
65#if defined(CHECK_RELEASED_BUFFERS)
66        gb_assert(!is_a_unused_reading_buffer(last));
67#endif /* CHECK_RELEASED_BUFFERS */
68    }
69    gb_assert(last && !last->next);
70    last->next              = unused_reading_buffers;
71    unused_reading_buffers  = rb;
72}
73static void free_ReadingBuffer(ReadingBuffer rb) {
74    if (rb) {
75        if (rb->next) free_ReadingBuffer(rb->next);
76        free(rb);
77    }
78}
79
80static ReadingBuffer read_another_block(FILE *in) {
81    ReadingBuffer buf = 0;
82    if (unused_reading_buffers) {
83        buf                    = unused_reading_buffers;
84        unused_reading_buffers = buf->next;
85        buf->next              = 0;
86        buf->read_bytes        = 0;
87    }
88    else {
89        buf = allocate_ReadingBuffer();
90    }
91
92    buf->read_bytes = fread(buf->data, 1, READING_BUFFER_SIZE, in);
93
94    return buf;
95}
96
97/* ---------------- */
98/*      Reader      */
99/* ---------------- */
100
101typedef struct reader_S {
102    FILE          *in;
103    ReadingBuffer  first; // allocated
104    GB_ERROR       error;
105
106    ReadingBuffer current;      // only reference
107    size_t        current_offset; // into 'current->data'
108
109    char   *current_line;
110    int     current_line_allocated; // whether 'current_line' was allocated
111    size_t  current_line_size;  // size of 'current_line' (valid if current_line_allocated == 1)
112    size_t  line_number;
113
114} *Reader;
115
116typedef unsigned long ReaderPos; // absolute position (relative to ReadingBuffer 'first')
117#define NOPOS (-1UL)
118
119
120static Reader openReader(FILE *in) {
121    Reader r = malloc(sizeof(*r));
122
123    gb_assert(unused_reading_buffers == 0);
124
125    r->in    = in;
126    r->error = 0;
127    r->first = read_another_block(r->in);
128
129    r->current_offset = 0;
130    r->current        = r->first;
131
132    r->current_line           = 0;
133    r->current_line_allocated = 0;
134    r->line_number            = 0;
135
136    return r;
137}
138
139static void freeCurrentLine(Reader r) {
140    if (r->current_line_allocated && r->current_line) {
141        free(r->current_line);
142        r->current_line_allocated = 0;
143    }
144}
145
146static GB_ERROR closeReader(Reader r) {
147    GB_ERROR error = r->error;
148
149    free_ReadingBuffer(r->first);
150    free_ReadingBuffer(unused_reading_buffers);
151    unused_reading_buffers = 0;
152
153    freeCurrentLine(r);
154    free(r);
155
156    return error;
157}
158
159static void releasePreviousBuffers(Reader r) {
160    /* Release all buffers before current position.
161     * Warning: This invalidates all offsets!
162     */
163    ReadingBuffer last_rel  = 0;
164    ReadingBuffer old_first = r->first;
165
166    while (r->first != r->current) {
167        last_rel = r->first;
168        r->first = r->first->next;
169    }
170
171    if (last_rel) {
172        last_rel->next = 0;     // avoid to release 'current'
173        release_ReadingBuffers(old_first);
174        r->first       = r->current;
175    }
176}
177
178static char *getPointer(const Reader r) {
179    return r->current->data + r->current_offset;
180}
181
182static ReaderPos getPosition(const Reader r) {
183    ReaderPos     p = 0;
184    ReadingBuffer b = r->first;
185    while (b != r->current) {
186        ad_assert(b);
187        p += b->read_bytes;
188        b  = b->next;
189    }
190    p += r->current_offset;
191    return p;
192}
193
194static int gotoNextBuffer(Reader r) {
195    if (!r->current->next) {
196        if (r->current->read_bytes < READING_BUFFER_SIZE) { // eof
197            return 0;
198        }
199        r->current->next = read_another_block(r->in);
200    }
201
202    r->current        = r->current->next;
203    r->current_offset = 0;
204
205    return r->current != 0;
206}
207
208static int movePosition(Reader r, int offset) {
209    int rest = r->current->read_bytes - r->current_offset - 1;
210
211    gb_assert(offset >= 0);     // not implemented for negative offsets
212    if (rest >= offset) {
213        r->current_offset += offset;
214        return 1;
215    }
216
217    if (gotoNextBuffer(r)) {
218        offset -= rest+1;
219        return offset == 0 ? 1 : movePosition(r, offset);
220    }
221
222    // in last buffer and position behind end -> position after last element
223    // (Note: last buffer cannot be full - only empty)
224    r->current_offset = r->current->read_bytes;
225    return 0;
226}
227
228static int gotoChar(Reader r, char lookfor) {
229    const char *data  = r->current->data + r->current_offset;
230    size_t      size  = r->current->read_bytes-r->current_offset;
231    char       *found = memchr(data, lookfor, size);
232
233    if (found) {
234        r->current_offset += (found-data);
235        return 1;
236    }
237
238    if (gotoNextBuffer(r)) {
239        return gotoChar(r, lookfor);
240    }
241
242    // in last buffer and char not found -> position after last element
243    // (Note: last buffer cannot be full - only empty)
244    r->current_offset = r->current->read_bytes;
245    return 0;
246}
247
248char *getLine(Reader r) {
249    releasePreviousBuffers(r);
250
251    {
252        ReaderPos      start        = getPosition(r);
253        ReadingBuffer  start_buffer = r->current;
254        char          *start_ptr    = getPointer(r);
255        int            eol_found    = gotoChar(r, '\n');
256
257        // now current position is on EOL or EOF
258
259        ReaderPos      eol        = getPosition(r);
260        ReadingBuffer  eol_buffer = r->current;
261        char          *eol_ptr    = getPointer(r);
262
263        movePosition(r, 1);
264
265        if (start_buffer == eol_buffer) { // start and eol in one ReadingBuffer -> no copy
266            freeCurrentLine(r);
267            r->current_line           = start_ptr;
268            r->current_line_allocated = 0;
269            eol_ptr[0]                = 0; // eos
270        }
271        else { // otherwise build a copy of the string
272            size_t  line_length = eol-start+1;
273            char   *bp;
274            size_t  len;
275
276            if (r->current_line_allocated == 0 || r->current_line_size < line_length) { // need alloc
277                freeCurrentLine(r);
278                r->current_line           = malloc(line_length);
279                r->current_line_size      = line_length;
280                r->current_line_allocated = 1;
281
282                gb_assert(r->current_line);
283            }
284
285            // copy contents of first buffer
286            bp            = r->current_line;
287            len           = start_buffer->read_bytes - (start_ptr-start_buffer->data);
288            memcpy(bp, start_ptr, len);
289            bp           += len;
290            start_buffer  = start_buffer->next;
291
292            // copy contents of middle buffers
293            while (start_buffer != eol_buffer) {
294                memcpy(bp, start_buffer->data, start_buffer->read_bytes);
295                bp           += start_buffer->read_bytes;
296                start_buffer  = start_buffer->next;
297            }
298
299            // copy contents from last buffer
300            len        = eol_ptr-start_buffer->data;
301            memcpy(bp, start_buffer->data, len);
302            bp        += len;
303            bp[0]  = 0; // eos
304        }
305
306        if (!eol_found && r->current_line[0] == 0)
307            return 0;               // signal eof
308
309    }
310
311    ++r->line_number;
312    return r->current_line;
313}
314
315/********************************************************************************************
316            Versions:
317        ASCII
318
319        V0  - 20.6.95
320        V1  Full save
321        V2  Differential save
322        V3  May read from stdin. Skipped support for old ASCII format.
323********************************************************************************************/
324
325static char *getToken(char **line) {
326    char *token  = *line;
327    (*line)     += strcspn(*line, " \t");
328
329    if ((*line)[0]) { // sth follows behind token
330        (*line)[0]  = 0;        // terminate token
331        (*line)++;
332        (*line)    += strspn(*line, " \t"); // goto next token
333    }
334
335    return token;
336}
337
338static GB_ERROR set_protection_level(GB_MAIN_TYPE *Main, GBDATA *gbd, const char *p) {
339    int      secr, secw, secd, lu;
340    GB_ERROR error = 0;
341
342    secr = secw = secd = 0;
343    lu   = 0;
344
345    if (p && p[0] == ':') {
346        long i;
347
348        secd = p[1]; A_TO_I(secd);
349        secw = p[2]; A_TO_I(secw);
350        secr = p[3]; A_TO_I(secr);
351
352        if (secd<0 || secd>7) error = GBS_global_string("Illegal protection level %i", secd);
353        else if (secw<0 || secw>7) error = GBS_global_string("Illegal protection level %i", secw);
354        else if (secr<0 || secr>7) error = GBS_global_string("Illegal protection level %i", secr);
355
356        lu = atoi(p+4);
357
358        for (i=Main->last_updated; i<=lu; ++i) {
359            Main->dates[i] = strdup("unknown date");
360            Main->last_updated = lu+1;
361        }
362    }
363
364    if (!error) {
365        gbd->flags.security_delete = secd;
366        gbd->flags.security_write  = secw;
367        gbd->flags.security_read   = secr;
368        gbd->flags2.last_updated   = lu;
369    }
370
371    return error;
372}
373
374static GB_ERROR gb_parse_ascii_rek(Reader r, GBCONTAINER *gb_parent, const char *parent_name) {
375    /* if parent_name == 0 -> we are parsing at root-level */
376    GB_ERROR      error = 0;
377    int           done  = 0;
378    GB_MAIN_TYPE *Main  = GBCONTAINER_MAIN(gb_parent);
379
380    while (!error && !done) {
381        char *line = getLine(r);
382        if (!line) break;
383
384    rest:
385        line += strspn(line, " \t"); // goto first non-whitespace
386
387        if (line[0]) {          // not empty
388            if (line[0] == '/' && line[1] == '*') { // comment
389                char *eoc = strstr(line+2, "*/");
390                if (eoc) {
391                    line = eoc+2;
392                    goto rest;
393                }
394                error = "expected '*/'";
395            }
396            else { // real content
397                char *name = getToken(&line);
398
399                if (name[0] == '%' && name[1] == ')' && !name[2]) { // close container
400                    if (!parent_name) {
401                        error = "Unexpected '%)' (not allowed outside container)";
402                    }
403                    else {
404                        if (line[0] == '/' && line[1] == '*') { // comment at container-end
405                            char *eoc  = strstr(line+2, "*/");
406                            if (!eoc) {
407                                error = "expected '*/'";
408                            }
409                            else {
410                                line += 2;
411                                *eoc  = 0;
412                                if (strcmp(line, parent_name) != 0) {
413                                    fprintf(stderr,
414                                            "Warning: comment at end of container ('%s') does not match name of container ('%s').\n"
415                                            "         (might be harmless if you've edited the file and did not care about these comments)\n",
416                                            line, parent_name);
417                                }
418                                line = eoc+2;
419                            }
420                        }
421                        done = 1;
422                    }
423                }
424                else {
425                    char *protection = 0;
426                    if (line[0] == ':') { // protection level
427                        protection = getToken(&line);
428                    }
429
430                    if (line[0] == '%') {
431                        char *type = getToken(&line);
432
433                        if (type[1] == 0 || type[2] != 0) {
434                            error = GBS_global_string("Syntax error in type '%s' (expected %% and 1 more character)", type);
435                        }
436                        else {
437                            if (type[1] == '%') { // container
438                                if (line[0] == '(' && line[1] == '%') {
439                                    char        *cont_name = strdup(name);
440                                    GBCONTAINER *gbc       = gb_make_container(gb_parent, cont_name, -1, 0);
441
442                                    protection = protection ? strdup(protection) : 0;
443                                    error      = gb_parse_ascii_rek(r, gbc, cont_name);
444                                    // caution: most buffer variables are invalidated NOW!
445
446                                    if (!error) error = set_protection_level(Main, (GBDATA*)gbc, protection);
447
448                                    free(protection);
449                                    free(cont_name);
450                                }
451                                else {
452                                    error = "Expected '(%' after '%%'";
453                                }
454                            }
455                            else {
456                                GB_TYPES gb_type = GB_NONE;
457
458                                switch (type[1]) {
459                                    case 'i': gb_type = GB_INT; break;
460                                    case 'l': gb_type = GB_LINK; break;
461                                    case 'y': gb_type = GB_BYTE; break;
462                                    case 'f': gb_type = GB_FLOAT; break;
463                                    case 'I': gb_type = GB_BITS; break;
464
465                                    case 'Y': gb_type = GB_BYTES; break;
466                                    case 'N': gb_type = GB_INTS; break;
467                                    case 'F': gb_type = GB_FLOATS; break;
468
469                                    default:
470                                        error = GBS_global_string("Unknown type '%s'", type);
471                                        break;
472                                }
473
474                                if (!error) {
475                                    GBDATA *gb_new;
476
477                                    gb_assert(gb_type != GB_NONE);
478                                    gb_new = gb_make_entry(gb_parent, name, -1, 0, gb_type);
479                                    if (!gb_new) error = GB_await_error();
480                                    else {
481                                        switch (type[1]) {
482                                            case 'i': error = GB_write_int(gb_new, atoi(line)); break;
483                                            case 'l': error = GB_write_link(gb_new, line); break;
484                                            case 'y': error = GB_write_byte(gb_new, atoi(line)); break;
485                                            case 'f': error = GB_write_float(gb_new, GB_atof(line)); break;
486                                            case 'I': {
487                                                int len = strlen(line);
488                                                gb_assert(line[0] == '\"');
489                                                gb_assert(line[len-1] == '\"');
490                                                error   = GB_write_bits(gb_new, line+1, len-2, "-"); break;
491                                            }
492
493                                            case 'Y': if (gb_ascii_2_bin(line, gb_new)) error = "syntax error in byte-array"; break;
494                                            case 'N': if (gb_ascii_2_bin(line, gb_new)) error = "syntax error in int-array"; break;
495                                            case 'F': if (gb_ascii_2_bin(line, gb_new)) error = "syntax error in float-array"; break;
496
497                                            default : gb_assert(0); // forgot a case ?
498                                        }
499
500                                        if (!error) error = set_protection_level(Main, gb_new, protection);
501                                    }
502                                }
503                            }
504                        }
505                    }
506                    else {
507                        if (line[0] != '\"') {
508                            error = GBS_global_string("Unexpected content '%s'", line);
509                        }
510                        else {  // string entry
511                            char *string_start = line+1;
512                            char *end          = GBS_fconvert_string(string_start);
513
514                            if (!end) error = "Cannot convert string (contains zero char)";
515                            else {
516                                GBDATA *gb_string     = gb_make_entry(gb_parent, name, -1, 0, GB_STRING);
517                                if (!gb_string) error = GB_await_error();
518                                else {
519                                    error             = GB_write_string(gb_string, string_start);
520                                    if (!error) error = set_protection_level(Main, gb_string, protection);
521                                }
522                            }
523                        }
524                    }
525                }
526            }
527        }
528    }
529
530    return error;
531}
532
533static GB_ERROR gb_parse_ascii(Reader r, GBCONTAINER *gb_parent) {
534    GB_ERROR error = gb_parse_ascii_rek(r, gb_parent, 0);
535    if (error) {
536        error = GBS_global_string("%s in line %zu", error, r->line_number);
537    }
538    return error;
539}
540
541GB_ERROR gb_read_ascii(const char *path, GBCONTAINER *gbd) {
542    /* This loads an ACSII database
543     * if path == "-" -> read from stdin
544     */
545
546    FILE     *in         = 0;
547    GB_ERROR  error      = 0;
548    int       close_file = 0;
549
550    if (strcmp(path, "-") == 0) {
551        in = stdin;
552    }
553    else {
554        in              = fopen(path, "rt");
555        if (!in) error  = GBS_global_string("Can't open '%s'", path);
556        else close_file = 1;
557    }
558
559    if (!error) {
560        Reader   r        = openReader(in);
561        GB_ERROR cl_error = 0;
562
563        GB_search((GBDATA *)gbd,GB_SYSTEM_FOLDER,GB_CREATE_CONTAINER); /* Switch to Version 3 */
564
565        error = gb_parse_ascii(r, gbd);
566
567        cl_error = closeReader(r);
568        if (!error) error = cl_error;
569    }
570
571    if (close_file) fclose(in);
572    return error;
573}
574
575/********************************************************************************************
576                    Read binary files
577********************************************************************************************/
578
579long gb_read_bin_rek(FILE *in,GBCONTAINER *gbd,long nitems,long version,long reversed)
580{
581    long          item;
582    long          type,type2;
583    GBQUARK       key;
584    char         *p;
585    long          i;
586    int           c;
587    long          size;
588    long          memsize;
589    GBDATA       *gb2;
590    GBCONTAINER  *gbc  = 0;
591    long          security;
592    char         *buff;
593    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
594
595    gb_create_header_array(gbd,(int)nitems);
596
597    for (item = 0;item<nitems;item++) {
598        type = getc(in);
599        security = getc(in);
600        type2 = (type>>4)&0xf;
601        key = getc(in);
602        if (!key) {
603            p = buff = GB_give_buffer(256);
604            for (i=0;i<256;i++) {
605                c = getc(in);
606                *(p++) = c;
607                if (!c) break;
608                if (c==EOF) {
609                    gb_read_bin_error(in,(GBDATA *)gbd,"Unexpected EOF found");
610                    return -1;
611                }
612            }
613            if (i>GB_KEY_LEN_MAX*2) {
614                gb_read_bin_error(in,(GBDATA *)gbd,"Key to long");
615                return -1;
616            }
617            if (type2 == (long)GB_DB){
618                gbc = gb_make_container(gbd, buff, -1, 0);
619                gb2 = (GBDATA *)gbc;
620            }else{
621                gb2 = gb_make_entry(gbd, buff, -1, 0, (GB_TYPES)type2);
622            }
623        }else{
624            if (type2 == (long)GB_DB){
625                gbc = gb_make_container(gbd,NULL,-1,key);
626                gb2 = (GBDATA *)gbc;
627            }else{
628                gb2 = gb_make_entry(gbd,NULL,-1,(GBQUARK)key,(GB_TYPES)type2);
629            }
630            if (!Main->keys[key].key) {
631                GB_internal_error("Some database fields have no field identifier -> setting to 'main'");
632                gb_write_index_key(GB_FATHER(gbd),gbd->index,0);
633            }
634        }
635        gb2->flags.security_delete  = type >> 1;
636        gb2->flags.security_write   = ((type&1) << 2 ) + (security >>6);
637        gb2->flags.security_read    = security >> 3;
638        gb2->flags.compressed_data  = security >> 2;
639        GB_ARRAY_FLAGS(((GBCONTAINER*)gb2)).flags = (int)((security >> 1) & 1);
640        gb2->flags.unused       = security >> 0;
641        gb2->flags2.last_updated = getc(in);
642
643        switch (type2) {
644            case GB_INT:
645                {
646                    GB_UINT4 buffer;
647                    if (!fread((char*)&buffer,sizeof(GB_UINT4),1,in) ) {
648                        GB_export_error("File too short, seems truncated");
649                        return -1;
650                    }
651                    gb2->info.i = ntohl(buffer);
652                    break;
653                }
654            case GB_FLOAT:
655                gb2->info.i = 0;
656                if (!fread((char*)&gb2->info.i,sizeof(float),1,in) ) {
657                    return -1;
658                }
659                break;
660            case GB_STRING_SHRT:
661                p = buff = GB_give_buffer(GBTUM_SHORT_STRING_SIZE+2);
662                for (size=0;size<=GBTUM_SHORT_STRING_SIZE;size++) {
663                    if (!(*(p++) = getc(in) )) break;
664                }
665                *p=0;
666                GB_SETSMDMALLOC(gb2,size,size+1,buff);
667                break;
668            case GB_STRING:
669            case GB_LINK:
670            case GB_BITS:
671            case GB_BYTES:
672            case GB_INTS:
673            case GB_FLOATS:
674                size = gb_read_in_long(in, reversed);
675                memsize =  gb_read_in_long(in, reversed);
676                if (GB_CHECKINTERN(size,memsize) ){
677                    GB_SETINTERN(gb2);
678                    p = &(gb2->info.istr.data[0]);
679                }else{
680                    GB_SETEXTERN(gb2);
681                    p = GB_give_buffer(memsize);
682                }
683                i = fread(p,1,(size_t)memsize,in);
684                if (i!=memsize) {
685                    gb_read_bin_error(in,gb2,"Unexpected EOF found");
686                    return -1;
687                }
688                GB_SETSMDMALLOC(gb2,size,memsize,p);
689                break;
690            case GB_DB:
691                size = gb_read_in_long(in, reversed);
692                /* gbc->d.size  is automatically incremented */
693                memsize = gb_read_in_long(in, reversed);
694                if (gb_read_bin_rek(in,gbc,size,version,reversed)) return -1;
695                break;
696            case GB_BYTE:
697                gb2->info.i = getc(in);
698                break;
699            default:
700                gb_read_bin_error(in,gb2,"Unknown type");
701                return -1;
702        }
703    }
704    return 0;
705}
706
707
708long gb_recover_corrupt_file(GBCONTAINER *gbd,FILE *in, GB_ERROR recovery_reason){
709    /* search pattern dx xx xx xx string 0 */
710    static FILE *old_in = 0;
711    static unsigned char *file = 0;
712    static long size = 0;
713    long pos = ftell(in);
714    if (!GBCONTAINER_MAIN(gbd)->allow_corrupt_file_recovery) {
715        if (!recovery_reason) { recovery_reason = GB_await_error(); }
716        GB_export_errorf("Aborting recovery (because recovery mode is disabled)\n"
717                         "Error causing recovery: '%s'\n"
718                         "Part of data may be recovered using 'arb_repair yourDB.arb newName.arb'\n"
719                         "(Note: Recovery doesn't work if the error occurs while loading a quick save file)",
720                         recovery_reason);
721        return -1;
722    }
723    pos = ftell(in);
724    if (old_in != in) {
725        file = (unsigned char *)GB_map_FILE(in,0);
726        old_in = in;
727        size = GB_size_of_FILE(in);
728    }
729    for (;pos<size-10;pos ++){
730        if ( ( file[pos] & 0xf0) == (GB_STRING_SHRT<<4)) {
731            long s;
732            int c;
733            for ( s= pos +4; s<size && file[s]; s++ ){
734                c = file[s];
735                if (! (isalnum(c) || isspace(c) || strchr("._;:,",c) ) ) break;
736            }
737            if ( s< size && s > pos+11 && !file[s]) {   /* we found something */
738                gb_local->search_system_folder = 1;
739                return fseek(in,pos,0);
740            }
741        }
742    }
743    return -1;          /* no short string found */
744}
745
746/* #define DEBUG_READ */
747#if defined(DEBUG_READ)
748
749static void DEBUG_DUMP_INDENTED(long deep, const char *s) {
750    printf("%*s%s\n", (int)deep, "", s);
751}
752
753#else
754
755#define DEBUG_DUMP_INDENTED(d, s)
756
757#endif /* DEBUG_READ */
758
759
760long gb_read_bin_rek_V2(FILE *in,GBCONTAINER *gbd,long nitems,long version,long reversed,long deep)
761{
762    long          item;
763    long          type,type2;
764    GBQUARK       key;
765    char         *p;
766    long          i;
767    long          size;
768    long          memsize;
769    int           index;
770    GBDATA       *gb2;
771    GBCONTAINER  *gbc;
772    long          security;
773    char         *buff;
774    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
775   
776    struct gb_header_list_struct *header;
777
778    DEBUG_DUMP_INDENTED(deep, GBS_global_string("Reading container with %li items", nitems));
779
780    gb_create_header_array(gbd,(int)nitems);
781    header = GB_DATA_LIST_HEADER(gbd->d);
782    if (deep == 0 && GBCONTAINER_MAIN(gbd)->allow_corrupt_file_recovery) {
783        GB_warning("Read to end of file in recovery mode");
784        nitems = 10000000; /* read forever at highest level */
785    }
786
787    for (item = 0;item<nitems;item++)
788    {
789        type = getc(in);
790        DEBUG_DUMP_INDENTED(deep, GBS_global_string("Item #%li/%li type=%02lx (filepos=%08lx)", item+1, nitems, type, ftell(in)-1));
791        if (type == EOF){
792            GB_export_error("Unexpected end of file seen");
793            return -1;
794        }
795        if (!type) {
796            int func;
797            if (version == 1) { /* master file */
798                if (gb_recover_corrupt_file(gbd,in, "Unknown DB type 0 (DB version=1)")) return -1;
799                continue;
800            }
801            func = getc(in);
802            switch (func) {
803                case 1:     /*  delete entry    */
804                    index = (int)gb_read_number(in);
805                    if (index >= gbd->d.nheader ){
806                        gb_create_header_array(gbd,index+1);
807                        header = GB_DATA_LIST_HEADER(gbd->d);
808                    }
809                    if ((gb2 = GB_HEADER_LIST_GBD(header[index]))!=NULL) {
810                        gb_delete_entry(&gb2);
811                    }
812                    else {
813                        header[index].flags.ever_changed = 1;
814                        header[index].flags.changed = gb_deleted;
815                    }
816
817                    break;
818                default:
819                    if (gb_recover_corrupt_file(gbd,in, GBS_global_string("Unknown func=%i", func))) return -1;
820                    continue;
821            }
822            continue;
823        }
824
825        security = getc(in);
826        type2 = (type>>4)&0xf;
827        key = (GBQUARK)gb_read_number(in);
828
829        if (key >= Main->keycnt || !Main->keys[key].key ){
830            GB_export_error("Inconsistent Database: Changing field identifier to 'main'");
831            key = 0;
832        }
833
834        DEBUG_DUMP_INDENTED(deep, GBS_global_string("key='%s' type2=%li", Main->keys[key].key, type2));
835
836        gb2 = NULL;
837        gbc = NULL;
838        if (version == 2) {
839            index = (int)gb_read_number(in);
840            if (index >= gbd->d.nheader ) {
841                gb_create_header_array(gbd,index+1);
842                header = GB_DATA_LIST_HEADER(gbd->d);
843            }
844
845            if (index >= 0 && (gb2 = GB_HEADER_LIST_GBD(header[index]))!=NULL) {
846                if ( (GB_TYPE(gb2) == GB_DB ) != (type2 == GB_DB)) {
847                    GB_internal_error("Type changed, you may loose data");
848                    gb_delete_entry(&gb2);
849                    SET_GB_HEADER_LIST_GBD(header[index],NULL);
850                }
851                else {
852                    if (type2 == GB_DB) gbc = (GBCONTAINER *)gb2;
853                    else GB_FREEDATA(gb2);
854                }
855            }
856        }
857        else index = -1;
858
859        if (!gb2) {
860            if (type2 == (long)GB_DB){
861                gbc = gb_make_container(gbd,NULL,index, key);
862                gb2 = (GBDATA *)gbc;
863            }
864            else {
865                gb2 = gb_make_entry(gbd,NULL,index, key, (GB_TYPES)type2);
866                GB_INDEX_CHECK_OUT(gb2);
867            }
868        }
869
870        if (version == 2) {
871            GB_CREATE_EXT(gb2);
872            gb2->ext->update_date = gb2->ext->creation_date = Main->clock;
873            header[gb2->index].flags.ever_changed = 1;
874        }else{
875            Main->keys[key].nref_last_saved++;
876        }
877
878        gb2->flags.security_delete  = type >> 1;
879        gb2->flags.security_write   = ((type&1) << 2 ) + (security >>6);
880        gb2->flags.security_read    = security >> 3;
881        gb2->flags.compressed_data  = security >> 2;
882        header[gb2->index].flags.flags  = (int)((security >> 1) & 1);
883        gb2->flags.unused       = security >> 0;
884        gb2->flags2.last_updated = getc(in);
885
886        switch (type2) {
887            case GB_INT:
888                {
889                    GB_UINT4 buffer;
890                    if (!fread((char*)&buffer,sizeof(GB_UINT4),1,in) ) {
891                        GB_export_error("File too short, seems truncated");
892                        return -1;
893                    }
894                    gb2->info.i = ntohl(buffer);
895                    break;
896                }
897
898            case GB_FLOAT:
899                if (!fread((char*)&gb2->info.i,sizeof(float),1,in) ) {
900                    GB_export_error("File too short, seems truncated");
901                    return -1;
902                }
903                break;
904            case GB_STRING_SHRT:
905                i = GB_give_buffer_size();
906                p = buff = GB_give_buffer(GBTUM_SHORT_STRING_SIZE+2);
907                size = 0;
908                while(1){
909                    for (;size<i;size++) {
910                        if (!(*(p++) = getc(in) )) goto shrtstring_fully_loaded;
911                    }
912                    i = i*3/2;
913                    buff = GB_increase_buffer(i);
914                    p = buff + size;
915                }
916        shrtstring_fully_loaded:
917                GB_SETSMDMALLOC(gb2,size,size+1,buff);
918                break;
919            case GB_STRING:
920            case GB_LINK:
921            case GB_BITS:
922            case GB_BYTES:
923            case GB_INTS:
924            case GB_FLOATS:
925                size = gb_read_number(in);
926                memsize =  gb_read_number(in);
927                DEBUG_DUMP_INDENTED(deep, GBS_global_string("size=%li memsize=%li", size, memsize));
928                if (GB_CHECKINTERN(size,memsize) ){
929                    GB_SETINTERN(gb2);
930                    p = &(gb2->info.istr.data[0]);
931                }else{
932                    GB_SETEXTERN(gb2);
933                    p = gbm_get_mem((size_t)memsize+1,GB_GBM_INDEX(gb2)); // ralf: added +1 because decompress ran out of this block
934                }
935                i = fread(p,1,(size_t)memsize,in);
936                if (i!=memsize) {
937                    gb_read_bin_error(in,gb2,"Unexpected EOF found");
938                    return -1;
939                }
940                GB_SETSMD(gb2,size,memsize,p);
941                break;
942            case GB_DB:
943                size = gb_read_number(in);
944                /* gbc->d.size  is automatically incremented */
945                if (gb_read_bin_rek_V2(in,gbc,size,version,reversed,deep+1)){
946                    if (!GBCONTAINER_MAIN(gbd)->allow_corrupt_file_recovery) {
947                        return -1;
948                    }
949                }
950                break;
951            case GB_BYTE:
952                gb2->info.i = getc(in);
953                break;
954            default:
955                gb_read_bin_error(in,gb2,"Unknown type");
956                if (gb_recover_corrupt_file(gbd,in, NULL)){
957                    if (GBCONTAINER_MAIN(gbd)->allow_corrupt_file_recovery){
958                        return 0;       /* loading stopped */
959                    }else{
960                        return -1;
961                    }
962                }
963
964                continue;
965        }
966    }
967    return 0;
968}
969
970GBDATA *gb_search_system_folder_rek(GBDATA *gbd) {
971    GBDATA *gb2;
972    GBDATA *gb_result = 0;
973    for (gb2 = GB_child(gbd); gb2; gb2 = GB_nextChild(gb2)) {
974        int type = GB_read_type(gb2);
975        if (type != GB_DB) continue;
976        if (!strcmp(GB_SYSTEM_FOLDER, GB_read_key_pntr(gb2))){
977            gb_result = gb2;
978            break;
979        }
980    }
981    return gb_result;
982}
983
984
985void gb_search_system_folder(GBDATA *gb_main){
986    /* Search a system folder within the database tree
987     *  and copy it to main level */
988    GBDATA *gb_oldsystem;
989    GB_ERROR error;
990    GBDATA *gb_system = GB_entry(gb_main,GB_SYSTEM_FOLDER);
991    if (gb_system) return;
992
993    GB_warning("Searching system information");
994    gb_oldsystem = gb_search_system_folder_rek(gb_main);
995    if (!gb_oldsystem){
996        GB_warning("!!!!! not found (bad)");
997        return;
998    }
999    gb_system = GB_search(gb_main,GB_SYSTEM_FOLDER,GB_CREATE_CONTAINER);
1000    error = GB_copy(gb_system,gb_oldsystem);
1001    if (!error) error = GB_delete(gb_oldsystem);
1002    if (error) GB_warning(error);
1003    GB_warning("***** found (good)");
1004}
1005
1006long gb_read_bin(FILE *in,GBCONTAINER *gbd, int diff_file_allowed)
1007{
1008    int   c = 1;
1009    long  i;
1010    long  error;
1011    long  j,k;
1012    long  version;
1013    long  reversed;
1014    long  nodecnt;
1015    long  first_free_key;
1016    char *buffer,*p;
1017   
1018    GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gbd);
1019
1020    while ( c && c!= EOF ) {
1021        c = getc(in);
1022    }
1023    if (c==EOF){
1024        gb_read_bin_error(in,(GBDATA *)gbd,"First zero not found");
1025        return 1;
1026    }
1027
1028    i = gb_read_in_long(in,0);
1029    if ( strncmp((char *)&i,"vers",4) ) {
1030        gb_read_bin_error(in,(GBDATA *)gbd,"keyword 'vers' not found");
1031        return 1;
1032    }
1033    i = gb_read_in_long(in,0);
1034    switch (i) {
1035        case 0x01020304:
1036            reversed = 0;
1037            break;
1038        case 0x04030201:
1039            reversed = 1;
1040            break;
1041        default:
1042            gb_read_bin_error(in,(GBDATA *)gbd,"keyword '^A^B^C^D' not found");
1043            return 1;
1044    }
1045    version = gb_read_in_long(in,reversed);
1046    if (version >2 ) {
1047        gb_read_bin_error(in,(GBDATA *)gbd,"ARB Database version > '2'");
1048        return 1;
1049    }
1050
1051    if (version == 2 && !diff_file_allowed) {
1052        GB_export_error("This is not a primary arb file, please select the master"
1053                        " file xxx.arb");
1054        return 1;
1055    }
1056
1057    buffer = GB_give_buffer(256);
1058    i = gb_read_in_long(in,0);
1059    if ( strncmp((char *)&i,"keys",4) ) {
1060        gb_read_bin_error(in,(GBDATA *)gbd,"keyword 'keys' not found");
1061        return 1;
1062    }
1063
1064    if (!Main->key_2_index_hash) Main->key_2_index_hash = GBS_create_hash(30000, GB_MIND_CASE);
1065
1066    first_free_key = 0;
1067    gb_free_all_keys(Main);
1068
1069    while(1) {          /* read keys */
1070        long nrefs = 0;
1071        if (version) {
1072            nrefs = gb_read_number(in);
1073        }
1074        p = buffer;
1075        for (k=0;;k++) {
1076            c = getc(in);
1077            if (!c) break;
1078            if (c==EOF) {
1079                gb_read_bin_error(in,(GBDATA *)gbd,"unexpected EOF while reading keys");
1080                return 1;
1081            }
1082            *(p++) = c;
1083        }
1084        *p = 0;
1085
1086        if (k > GB_KEY_LEN_MAX) {
1087            printf("Warning: Key '%s' exceeds maximum keylength (%i)\n"
1088                   "         Please do NOT create such long keys!\n", 
1089                   buffer, GB_KEY_LEN_MAX);
1090        }
1091        if (p == buffer) break;
1092
1093        if (*buffer == 1) {                                                   /* empty key */
1094            long index = gb_create_key(Main,0,GB_FALSE);
1095
1096            Main->keys[index].key           = 0;
1097            Main->keys[index].nref          = 0;
1098            Main->keys[index].next_free_key = first_free_key;
1099           
1100            first_free_key = index;
1101        }
1102        else {
1103            long index = gb_create_key(Main,buffer,GB_FALSE);
1104           
1105            Main->keys[index].nref = nrefs;
1106        }
1107    }
1108
1109    Main->first_free_key = first_free_key;
1110
1111    i = gb_read_in_long(in,0);
1112    if ( strncmp((char *)&i,"time",4) ) {
1113        gb_read_bin_error(in,(GBDATA *)gbd,"keyword 'time' not found");
1114        return 1;
1115    }
1116    for (j=0;j<255;j++) {           /* read times */
1117        p = buffer;
1118        for (k=0;k<256;k++) {
1119            c = getc(in);
1120            if (!c) break;
1121            if (c==EOF) {
1122                gb_read_bin_error(in,(GBDATA *)gbd,"unexpected EOF while reading times");
1123                return 1;
1124            }
1125            *(p++) = c;
1126        }
1127        *p = 0;
1128        if (p == buffer) break;
1129        freedup(Main->dates[j], buffer);
1130    }
1131    if (j>=255) {
1132        gb_read_bin_error(in,(GBDATA *)gbd,"more than 255 dates are not allowed");
1133        return 1;
1134    }
1135    Main->last_updated = (unsigned int)j;
1136
1137    i = gb_read_in_long(in,0);
1138    if ( strncmp((char *)&i,"data",4) ) {
1139        gb_read_bin_error(in,(GBDATA *)gbd,"keyword 'data' not found");
1140        return 0;
1141    }
1142    nodecnt = gb_read_in_long(in,reversed);
1143    GB_give_buffer(256);
1144
1145    if (version==1)         /* teste auf map file falls version == 1 */
1146    {
1147        GB_CSTR map_path;
1148        int merror;
1149        struct gb_map_header mheader;
1150        long    mode;
1151        int ok=0;
1152        mode = GB_mode_of_link(Main->path); /* old master */
1153        if (S_ISLNK(mode)){
1154            char *path2 = GB_follow_unix_link(Main->path);
1155            map_path = gb_mapfile_name(path2);
1156            free(path2);
1157        }else{
1158            map_path = gb_mapfile_name(Main->path);
1159        }
1160        merror = gb_is_valid_mapfile(map_path,&mheader, 0);
1161        if (merror>0)
1162        {
1163            if (gb_main_array[mheader.main_idx]==NULL)
1164            {
1165                GBCONTAINER *newGbd = (GBCONTAINER*)gb_map_mapfile(map_path);
1166
1167                if (newGbd)
1168                {
1169                    GBCONTAINER     *father = GB_FATHER(gbd);
1170                    GB_MAIN_IDX     new_idx = mheader.main_idx,
1171                        old_idx = father->main_idx;
1172
1173                    GB_commit_transaction((GBDATA*)gbd);
1174
1175                    ad_assert(newGbd->main_idx == new_idx);
1176                    ad_assert((new_idx % GB_MAIN_ARRAY_SIZE) == new_idx);
1177
1178                    gb_main_array[new_idx] = Main;
1179                    Main->data = newGbd;
1180                    father->main_idx = new_idx;
1181
1182                    gbd = newGbd;
1183                    SET_GB_FATHER(gbd,father);
1184
1185                    gb_main_array[old_idx]    = NULL;
1186
1187                    GB_begin_transaction((GBDATA*)gbd);
1188                    ok=1;
1189                }
1190            }
1191            else {
1192                GB_export_errorf("FastLoad-File index conflict (%s)", map_path);
1193            }
1194        }
1195        else {
1196            if (!merror) {
1197                GB_warning(GB_await_error());
1198            }
1199            else {
1200                GB_informationf("ARB: no FastLoad File '%s' found: loading entire database",map_path);
1201            }
1202        }
1203        if (ok) return 0;
1204    }
1205
1206    switch(version) {
1207        case 0:
1208            error = gb_read_bin_rek(in,gbd,nodecnt,version,reversed);
1209            break;
1210        case 2:
1211            for (i=1; i < Main->keycnt;i++) {
1212                if (Main->keys[i].key) {
1213                    Main->keys[i].nref_last_saved = Main->keys[i].nref;
1214                }
1215            }
1216
1217            if (Main->clock<=0) Main->clock++;
1218        case 1:
1219            error = gb_read_bin_rek_V2(in,gbd,nodecnt,version,reversed,0);
1220            break;
1221        default:
1222            GB_internal_errorf("Sorry: This ARB Version does not support database format V%li",version);
1223            error = 1;
1224    }
1225
1226    if (gb_local->search_system_folder){
1227        gb_search_system_folder((GBDATA *)gbd);
1228    }
1229
1230    switch(version) {
1231        case 2:
1232        case 1:
1233            for (i=1; i < Main->keycnt;i++) {
1234                if (Main->keys[i].key) {
1235                    Main->keys[i].nref = Main->keys[i].nref_last_saved;
1236                }
1237            }
1238            break;
1239        default:
1240            break;
1241    }
1242
1243    return error;
1244}
1245
1246/********************************************************************************************
1247                    OPEN DATABASE
1248********************************************************************************************/
1249
1250long    gb_next_main_idx_for_mapfile;
1251
1252void GB_set_next_main_idx(long idx){
1253    gb_next_main_idx_for_mapfile = idx;
1254}
1255
1256GB_MAIN_IDX gb_make_main_idx(GB_MAIN_TYPE *Main)
1257{
1258    static int initialized = 0;
1259    GB_MAIN_IDX idx;
1260
1261    if (!initialized)
1262    {
1263        for (idx=0; idx<GB_MAIN_ARRAY_SIZE; idx++)
1264            gb_main_array[idx] = NULL;
1265        initialized = 1;
1266    }
1267    if (gb_next_main_idx_for_mapfile<=0){
1268        while (1)   /* search for unused array index */
1269        {
1270            idx = (short)(time(NULL) % GB_MAIN_ARRAY_SIZE);
1271            if (gb_main_array[idx]==NULL)
1272                break;
1273        }
1274    }else{
1275        idx = (short)gb_next_main_idx_for_mapfile;
1276        gb_next_main_idx_for_mapfile = 0;
1277    }
1278
1279    ad_assert((idx%GB_MAIN_ARRAY_SIZE) == idx);
1280   
1281    gb_main_array[idx] = Main;
1282
1283    return idx;
1284}
1285
1286GB_ERROR gb_login_remote(struct gb_main_type *gb_main,const char *path,const char *opent) {
1287    GBCONTAINER *gbd   = gb_main->data;
1288    GB_ERROR     error = NULL;
1289
1290    gb_main->local_mode = GB_FALSE;
1291    gb_main->c_link     = gbcmc_open(path);
1292
1293    if (!gb_main->c_link) {
1294        error = GBS_global_string("There is no ARBDB server '%s', please start one or add a filename", path);
1295    }
1296    else {
1297        gbd->server_id       = 0;
1298        gb_main->remote_hash = GBS_create_hashi(GB_REMOTE_HASH_SIZE);
1299        error                = gb_init_transaction(gbd); /* login in server */
1300       
1301        if (!error) {
1302            gbd->flags2.folded_container = 1;
1303
1304            if (    strchr(opent, 't')  ) error = gb_unfold(gbd, 0,-2); /* tiny */
1305            else if (strchr(opent, 'm') ) error = gb_unfold(gbd, 1,-2); /* medium (no sequence)*/
1306            else if (strchr(opent, 'b') ) error = gb_unfold(gbd, 2,-2); /* big (no tree)*/
1307            else if (strchr(opent, 'h') ) error = gb_unfold(gbd,-1,-2); /* huge (all)*/
1308            else error                          = gb_unfold(gbd, 0,-2); /* tiny */
1309        }
1310    }
1311    return error;
1312}
1313
1314GBDATA *GB_login(const char *cpath,const char *opent,const char *user)
1315     /* opent char :
1316        'r' read
1317        'w' write (w/o 'r' it overwrites existing database)
1318        'c' create (if not found)
1319        's'     read only ???
1320        'd' look for default (if create) in $ARBHOME/lib (any leading '.' is removed )
1321        'D' look for default (if create) in $ARBHOME/lib/arb_default (any leading '.' is removed )
1322
1323        't' small memory usage
1324        'm' medium
1325        'b' big
1326        'h' huge
1327
1328        'R' allow corrupt file recovery + opening quicks with no master
1329
1330        'N' assume new database format (do not check whether to convert old->new compression)
1331     */
1332{
1333    GBCONTAINER         *gbd;
1334    FILE                *input;
1335    long                 i;
1336    struct gb_main_type *Main;
1337    enum gb_open_types   opentype;
1338    GB_CSTR              quickFile           = NULL;
1339    int                  ignoreMissingMaster = 0;
1340    int                  loadedQuickIndex    = -1;
1341    GB_ERROR             error               = 0;
1342    char                *path                = strdup(cpath);
1343    GB_BOOL              dbCreated           = GB_FALSE;
1344
1345    GBK_install_SIGSEGV_handler(GB_TRUE);
1346
1347    if (!opent) opentype = gb_open_all;
1348    else if (strchr(opent, 'w')) opentype = gb_open_all;
1349    else if (strchr(opent, 's')) opentype = gb_open_read_only_all;
1350    else opentype = gb_open_read_only_all;
1351
1352    if (strchr(path,':')){
1353        ; /* remote access */
1354    }else if (GBS_string_matches(path,"*.quick?",GB_MIND_CASE)){
1355        char *ext = gb_findExtension(path);
1356        ad_assert(ext!=0);
1357        if (isdigit(ext[6]))
1358        {
1359            loadedQuickIndex = atoi(ext+6);
1360            strcpy(ext, ".arb");
1361            quickFile = gb_oldQuicksaveName(path, loadedQuickIndex);
1362            if (strchr(opent,'R'))      ignoreMissingMaster = 1;
1363        }
1364    }else if (GBS_string_matches(path,"*.a??",GB_MIND_CASE)){
1365
1366        char *extension = gb_findExtension(path);
1367
1368        if (isdigit(extension[2]) && isdigit(extension[3]))
1369        {
1370            loadedQuickIndex = atoi(extension+2);
1371            strcpy(extension,".arb");
1372            quickFile = gb_quicksaveName(path, loadedQuickIndex);
1373            if (strchr(opent,'R'))      ignoreMissingMaster = 1;
1374        }else {
1375            char *base = strdup(path);
1376            char *ext = gb_findExtension(base);
1377            {
1378                struct gb_scandir dir;
1379                ext[0] = 0;
1380                gb_scan_directory(base,&dir);
1381
1382                loadedQuickIndex = dir.highest_quick_index;
1383
1384                if (dir.highest_quick_index!=dir.newest_quick_index)
1385                {
1386                    GB_warning("The QuickSave-File with the highest index-number\n"
1387                               "is not the NEWEST of your QuickSave-Files.\n"
1388                               "If you didn't restore old QuickSave-File from a backup\n"
1389                               "please inform your system-administrator - \n"
1390                               "this may be a serious bug and you may loose your data.");
1391                }
1392
1393                switch(dir.type)
1394                {
1395                    case GB_SCAN_NO_QUICK:
1396                        break;
1397                    case GB_SCAN_NEW_QUICK:
1398                        quickFile = gb_quicksaveName(path,dir.highest_quick_index);
1399                        break;
1400                    case GB_SCAN_OLD_QUICK:
1401                        quickFile = gb_oldQuicksaveName(path,dir.newest_quick_index);
1402
1403                        break;
1404                }
1405            }
1406
1407            free(base);
1408        }
1409    }
1410
1411    if (gb_verbose_mode){
1412        GB_informationf("ARB: Loading '%s'%s%s", path, quickFile ? " + Changes-File ":"", quickFile ? quickFile :"");
1413    }
1414
1415    gbm_init_mem();
1416    GB_init_gb();
1417
1418    error = GB_install_pid(1);
1419    if (error) {
1420        GB_export_error(error);
1421        return 0;
1422    }
1423
1424    Main = gb_make_gb_main_type(path);
1425    Main->local_mode = GB_TRUE;
1426
1427    if (strchr(opent,'R')) Main->allow_corrupt_file_recovery = 1;
1428
1429    gb_create_key(Main,"main",GB_FALSE);
1430
1431    Main->dummy_father = gb_make_container(NULL, 0, -1,0);  /* create "main" */
1432    Main->dummy_father->main_idx = gb_make_main_idx(Main);
1433    Main->dummy_father->server_id = GBTUM_MAGIC_NUMBER;
1434    gbd = gb_make_container(Main->dummy_father, 0, -1,0 );  /* create "main" */
1435
1436    Main->data = gbd;
1437    gbcm_login(gbd,user);
1438    Main->opentype = opentype;
1439    Main->security_level = 7;
1440
1441    if (path && (strchr(opent, 'r')) ){
1442        if (strchr(path, ':')){
1443            error = gb_login_remote(Main,path,opent);
1444        }
1445        else {
1446            int read_from_stdin = strcmp(path, "-") == 0;
1447
1448            GB_ULONG time_of_main_file  = 0;
1449            GB_ULONG time_of_quick_file = 0;
1450            Main->local_mode            = GB_TRUE;
1451            GB_begin_transaction((GBDATA *)gbd);
1452            Main->clock                 = 0; /* start clock */
1453
1454            if (read_from_stdin) input = stdin;
1455            else input                 = fopen(path, "rb");
1456
1457            if (!input && ignoreMissingMaster) {
1458                goto load_quick_save_file_only;
1459            }
1460
1461            if (!input ) {
1462                if (strchr(opent, 'c') ) {
1463                    GB_disable_quicksave((GBDATA *)gbd,"Database Created");
1464
1465                    if (strchr(opent, 'd')||strchr(opent, 'D')) {
1466                        /* use default settings */
1467                        const char *pre;
1468                        char       *found_path;
1469                       
1470                        GB_clear_error(); // with default-files gb_scan_directory (used above)
1471                        // creates an error, cause the path is a fake path
1472
1473                        if (strchr(opent, 'd')) pre = "";
1474                        else                    pre = "arb_default/";
1475
1476                        found_path = GBS_find_lib_file(path,pre, 0);
1477                        if (!found_path) {
1478                            fprintf(stderr,"file %s not found\n", path);
1479                            dbCreated = GB_TRUE;
1480                        }
1481                        else {
1482#if defined(DEBUG)
1483                            fprintf(stderr, "Using properties from %s\n", found_path);
1484#endif /* DEBUG */
1485                            freeset(path, found_path);
1486                            input = fopen(path, "rb");
1487                        }
1488                    }
1489                    else {
1490                        dbCreated = GB_TRUE;
1491                    }
1492
1493                    if (dbCreated) printf(" database %s created\n", path);
1494                }
1495                else {
1496                    error = GBS_global_string("Database '%s' not found",path);
1497                    gbd   = 0;
1498                }
1499            }
1500            if (input) {
1501                time_of_main_file = GB_time_of_file(path);
1502
1503                if (input != stdin) i = gb_read_in_long(input, 0);
1504                else i                = 0;
1505
1506                if ((i== 0x56430176) || (i == GBTUM_MAGIC_NUMBER) || (i == GBTUM_MAGIC_REVERSED))    {
1507                    i = gb_read_bin(input, gbd,0);      /* read or map whole db */
1508                    gbd = Main->data;
1509                    fclose(input);
1510
1511                    if (i) {
1512                        if (Main->allow_corrupt_file_recovery) {
1513                            GB_print_error();
1514                        }
1515                        else {
1516                            gbd   = 0;
1517                            error = GB_await_error();
1518                        }
1519                    }
1520
1521                    if (gbd && quickFile) {
1522                        long     err;
1523                        GB_ERROR err_msg;
1524                    load_quick_save_file_only:
1525                        err     = 0;
1526                        err_msg = 0;
1527
1528                        input = fopen(quickFile,"rb");
1529
1530                        if (input){
1531                            time_of_quick_file = GB_time_of_file(quickFile);
1532                            if (time_of_main_file && time_of_quick_file < time_of_main_file){
1533                                const char *warning = GBS_global_string("Your main database file '%s' is newer than\n"
1534                                                                        "   the changes file '%s'\n"
1535                                                                        "   That is very strange and happens only if files where\n"
1536                                                                        "   moved/copied by hand\n"
1537                                                                        "   Your file '%s' may be an old relict,\n"
1538                                                                        "   if you ran into problems now,delete it",
1539                                                                        path, quickFile, quickFile);
1540                                GB_warning(warning);
1541                            }
1542                            i = gb_read_in_long(input, 0);
1543                            if ((i== 0x56430176) || (i == GBTUM_MAGIC_NUMBER) || (i == GBTUM_MAGIC_REVERSED))
1544                            {
1545                                err = gb_read_bin(input, gbd, 1);
1546                                fclose (input);
1547
1548                                if (err) {
1549                                    err_msg = GBS_global_string("Loading failed (file corrupt?)\n"
1550                                                                "[Fail-Reason: '%s']\n",
1551                                                                GB_await_error());
1552                                }
1553                            }
1554                            else {
1555                                err_msg = "Wrong file format (not a quicksave file)";
1556                                err     = 1;
1557                            }
1558                        }
1559                        else  {
1560                            err_msg = "Can't open file";
1561                            err     = 1;
1562                        }
1563
1564                        if (err){
1565                            error = GBS_global_string("I cannot load your quick file '%s'\n"
1566                                                      "Reason: %s\n"
1567                                                      "\n"
1568                                                      "Note: you MAY restore an older version by running arb with:\n"
1569                                                      "      arb <name of quicksave-file>",
1570                                                      quickFile, err_msg);
1571
1572                            if (!Main->allow_corrupt_file_recovery) {
1573                                gbd = 0;
1574                            }
1575                            else {
1576                                GB_export_error(error);
1577                                GB_print_error();
1578                                GB_clear_error();
1579                                error = 0;
1580                                GB_disable_quicksave((GBDATA*)gbd, "Couldn't load last quicksave (your latest changes are NOT included)");
1581                            }
1582                        }
1583                    }
1584                    Main->qs.last_index = loadedQuickIndex; /* determines which # will be saved next */
1585                }
1586                else {
1587                    if (input != stdin) fclose(input);
1588                    error = gb_read_ascii(path, gbd);
1589                    if (error) GB_warning(error);
1590                    GB_disable_quicksave((GBDATA *)gbd,"Sorry, I cannot save differences to ascii files\n"
1591                                         "  Save whole database in binary mode first");
1592                }
1593            }
1594        }
1595    }
1596    else {
1597        GB_disable_quicksave((GBDATA *)gbd,"Database not part of this process");
1598        Main->local_mode = GB_TRUE;
1599        GB_begin_transaction((GBDATA *)gbd);
1600    }
1601
1602    gb_assert(error || gbd);
1603   
1604    if (error) {
1605        GB_export_error(error);
1606        gbd = 0;
1607    }
1608    else {
1609        GB_commit_transaction((GBDATA *)gbd);
1610        {               /* New Transaction, should be quicksaveable */
1611            GB_begin_transaction((GBDATA *)gbd);
1612            if (!strchr(opent,'N')){    /* new format */
1613                gb_convert_V2_to_V3((GBDATA *)gbd);     /* Compression conversion */
1614            }
1615            error = gb_load_key_data_and_dictionaries((GBDATA *)Main->data);
1616            if (!error) error = GB_resort_system_folder_to_top((GBDATA *)Main->data);
1617            GB_commit_transaction((GBDATA *)gbd);
1618        }
1619        Main->security_level = 0;
1620        gbl_install_standard_commands((GBDATA *)gbd);
1621   
1622        if (Main->local_mode == GB_TRUE) { // i am the server
1623            GBT_install_message_handler((GBDATA *)gbd);
1624        }
1625        if (gb_verbose_mode && !dbCreated) GB_informationf("ARB: Loading '%s' done\n", path);
1626    }
1627    free(path);
1628    return (GBDATA *)gbd;
1629}
1630
1631GBDATA *GB_open(const char *path, const char *opent)
1632{
1633    const char *user;
1634    user = GB_getenvUSER();
1635    return GB_login(path,opent,user);
1636}
1637
1638int gb_verbose_mode = 0;
1639
1640void GB_set_verbose(){
1641    gb_verbose_mode = 1;
1642}
Note: See TracBrowser for help on using the repository browser.