root/branches/stable_5.0/ARBDB/ad_save_load.c

Revision 6519, 38.7 KB (checked in by westram, 2 years ago)
  • quick save errors were dropped (no quicksave happened)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <errno.h>
4#include <string.h>
5#include <unistd.h>
6/* #include <malloc.h> */
7#include <ctype.h>
8#include <sys/stat.h>
9#include <arpa/inet.h>
10#include <netinet/in.h>
11
12/*#include "arbdb.h"*/
13#include "adlocal.h"
14#include "admap.h"
15
16GB_MAIN_TYPE *gb_main_array[GB_MAIN_ARRAY_SIZE];
17
18/********************************************************************************************
19            Versions:
20        ASCII
21
22        V0  - 20.6.95
23        V1  Full save
24        V2  Differential save
25********************************************************************************************/
26
27char *gb_findExtension(char *path) {
28    char *punkt = strrchr(path, '.');
29    if (punkt) {
30        char *slash = strchr(punkt,'/');
31        if (slash) punkt = 0;   //  slash after '.' -> no extension
32    }
33    return punkt;
34}
35
36
37/*
38 * CAUTION!!!
39 *
40 * The following functions (quicksaveName, oldQuicksaveName, mapfile_name, gb_overwriteName)
41 * use static buffers for the created filenames.
42 *
43 * So you have to make sure, to use only one instance of every of these
44 * functions or to dup the string before using the second instance
45 *
46 */
47
48GB_CSTR gb_oldQuicksaveName(GB_CSTR path, int nr)
49{
50    static char *qname = 0;
51    char        *ext;
52    size_t       len   = strlen(path);
53
54    STATIC_BUFFER(qname,len+15);
55
56    strcpy(qname,path);
57    ext = gb_findExtension(qname);
58    if (!ext) ext = qname + len;
59
60    if (nr==-1) sprintf(ext,".arb.quick?");
61    else    sprintf(ext,".arb.quick%i", nr);
62
63    return qname;
64}
65
66GB_CSTR gb_quicksaveName(GB_CSTR path,int nr) {
67    static char *qname = 0;
68    char *ext;
69
70    STATIC_BUFFER(qname,strlen(path)+4);
71
72    strcpy(qname,path);
73    ext = gb_findExtension(qname);
74    if (!ext){
75        ext = qname + strlen(qname);
76    }
77
78    if (nr==-1) sprintf(ext,".a??");
79    else    sprintf(ext,".a%02i", nr);
80
81    return qname;
82}
83
84GB_CSTR gb_mapfile_name(GB_CSTR path) {
85    static char *mapname = 0;
86    char *ext;
87
88    STATIC_BUFFER(mapname,strlen(path)+4+1);
89
90    strcpy(mapname,path);
91    ext = gb_findExtension(mapname);
92    if (!ext) ext = mapname + strlen(mapname);
93
94    strcpy(ext,".ARM");
95
96    return mapname;
97}
98
99GB_CSTR gb_overwriteName(GB_CSTR path) {
100    static char *oname = 0;
101    int          len   = strlen(path);
102
103    STATIC_BUFFER(oname, len+2);
104    strcpy(oname,path);
105    strcpy(oname+len, "~");     // append ~
106
107    return oname;
108}
109
110GB_CSTR gb_reffile_name(GB_CSTR path) {
111    static char *refname;
112    size_t       len = strlen(path);
113    const char  *ext;
114    size_t       ext_offset;
115
116    STATIC_BUFFER(refname, len+4+1);
117    memcpy(refname, path, len+1);
118
119    ext        = gb_findExtension(refname);
120    ext_offset = ext ? (size_t)(ext-refname) : len;
121
122    strcpy(refname+ext_offset, ".ARF");
123
124    return refname;
125}
126
127GB_ERROR gb_delete_reference(const char *master) {
128    GB_ERROR    error      = 0;
129    char       *fullmaster = gb_full_path(master);
130    const char *fullref    = gb_reffile_name(fullmaster);
131
132    GB_unlink_or_warn(fullref, &error);
133
134    free(fullmaster);
135    return error;
136}
137
138GB_ERROR gb_create_reference(const char *master){
139    char       *fullmaster = gb_full_path(master);
140    const char *fullref    = gb_reffile_name(fullmaster);
141    GB_ERROR    error      = 0;
142    FILE       *out        = fopen(fullref,"w");
143   
144    if (out) {
145        fprintf(out,"***** The following files may be a link to %s ********\n",fullmaster);
146        fclose(out);
147        GB_set_mode_of_file(fullref,00666);
148    }
149    else {
150        error = GB_export_errorf("WARNING: Cannot create file '%s'\n"
151                                 "   Your database is saved, but you should check write permissions\n"
152                                 "   in the destination directory",
153                                 fullref);
154    }
155
156    free(fullmaster);
157    return error;
158}
159
160GB_ERROR gb_add_reference(char *master, char *changes){
161    char       *fullmaster  = gb_full_path(master);
162    char       *fullchanges = gb_full_path(changes);
163    const char *fullref     = gb_reffile_name(fullmaster);
164    GB_ERROR    error       = 0;
165    FILE       *out         = fopen(fullref,"a");
166
167    if (out) {
168        fprintf(out,"%s\n",fullchanges);
169        fclose(out);
170        GB_set_mode_of_file(fullref,00666);
171    }
172    else {
173        error = GB_export_errorf("Cannot add your file '%s'\n"
174                                 "   to the list of references of '%s'\n"
175                                 "   Please ask the owner of that file not to delete it\n"
176                                 "   or save the entire database (that's recommended!)",
177                                 fullchanges,fullref);
178    }
179
180    free(fullchanges);
181    free(fullmaster);
182   
183    return error;
184}
185
186static GB_ERROR gb_remove_quick_saved(GB_MAIN_TYPE *Main, const char *path) {
187    int i;
188    GB_ERROR error = 0;
189
190    for (i=0; i<GB_MAX_QUICK_SAVE_INDEX && !error; i++) GB_unlink_or_warn(gb_quicksaveName(path,i), &error);
191    for (i=0; i<10 && !error; i++) GB_unlink_or_warn(gb_oldQuicksaveName(path,i), &error);
192    if (Main) Main->qs.last_index = -1;
193
194    return error;
195}
196
197GB_ERROR gb_remove_all_but_main(GB_MAIN_TYPE *Main, const char *path){
198    GB_ERROR error = 0;
199    error = gb_remove_quick_saved(Main,path);
200    if (!error) GB_unlink_or_warn(gb_mapfile_name(path), &error); /* delete old mapfile */
201    return error;
202}
203
204/*
205 *  If we did a hundred quicksaves, we rename the quicksave-files to a00...a09
206 *  to keep MS-DOS-compatibility
207 */
208static GB_ERROR renameQuicksaves(GB_MAIN_TYPE *Main)
209{
210    int i,
211        j;
212    GB_ERROR error = NULL;
213    const char *path = Main->path;
214
215    while(1)
216    {
217        for (i=0,j=0; i<GB_MAX_QUICK_SAVE_INDEX; i++)
218        {
219            GB_CSTR qsave = gb_quicksaveName(path,i);
220
221            if (GB_is_regularfile(qsave))
222            {
223                if (i!=j)         /* otherwise the filename is correct */
224                {
225                    char    *qdup = strdup(qsave);
226                    GB_CSTR  qnew = gb_quicksaveName(path,j);
227
228                    GB_rename_file(qdup,qnew);
229                    free(qdup);
230                }
231
232                j++;
233            }
234        }
235
236        if (j<=GB_MAX_QUICK_SAVES) break; /* less or equal than GB_MAX_QUICK_SAVES files -> ok */
237
238        i = 0;
239        while (j>GB_MAX_QUICK_SAVES) /* otherwise delete files from lower numbers till there
240                                      * are only GB_MAX_QUICK_SAVES left */
241        {
242            GB_CSTR qsave = gb_quicksaveName(path,i);
243
244            if (GB_is_regularfile(qsave)) remove(qsave);
245            j--;
246            i++;
247        }
248    }
249
250    Main->qs.last_index = j-1;
251
252    return error;
253}
254
255static GB_ERROR deleteSuperfluousQuicksaves(GB_MAIN_TYPE *Main) {
256    int       cnt   = 0;
257    int       i;
258    char     *path  = Main->path;
259    GB_ERROR  error = 0;
260
261    for (i=0; i<GB_MAX_QUICK_SAVE_INDEX; i++) {
262        GB_CSTR qsave = gb_quicksaveName(path, i);
263        if (GB_is_regularfile(qsave)) cnt++;
264    }
265
266    for (i=0; cnt>GB_MAX_QUICK_SAVES && i<GB_MAX_QUICK_SAVE_INDEX && !error; i++) {
267        GB_CSTR qsave = gb_quicksaveName(path, i);
268        if (GB_is_regularfile(qsave)) {
269            if (GB_unlink(qsave)<0) error = GB_await_error();
270            else cnt--;
271        }
272    }
273
274    return error;
275}
276
277
278
279
280/********************************************************************************************
281                    Ascii to  Binary
282********************************************************************************************/
283
284
285long gb_ascii_2_bin(const char *source,GBDATA *gbd)
286{
287    const char *s = source;
288   
289    long len = 0;
290    char c   = *(s++);
291
292    long  size;
293    long  memsize;
294    char *d;
295    long  k;
296    long  i;
297
298    A_TO_I(c);
299    gbd->flags.compressed_data = c;
300
301    if (*s == ':') {
302        size = 0;
303        s++;
304    }else{
305        for (i=0,k = 8;k && (c = *(s++));k--) {
306            A_TO_I(c);
307            i = (i<<4)+c;
308        }
309        size = i;
310    }
311    source = s;
312
313    while ( (c = *(s++)) ) {
314        if ((c == '.') || (c=='-')) {
315            len++;
316            continue;
317        }
318        if ((c == ':') || (c=='=')) {
319            len += 2;
320            continue;
321        }
322        if (!(c = *(s++))) {
323            return 1;
324        };
325        len++;
326    }
327
328    memsize = len;
329
330    GB_SETSMDMALLOC_UNINITIALIZED(gbd,size,memsize);
331    d = GB_GETDATA(gbd);
332    s = source;
333    while ( (c = *(s++)) ) {
334        if (c == '.') {
335            *(d++)=0;
336            continue;
337        }
338        if (c == ':') {
339            *(d++)=0;
340            *(d++)=0;
341            continue;
342        }
343        if (c == '-') {
344            *(d++)= 0xff;
345            continue;
346        }
347        if (c == '=') {
348            *(d++)= 0xff;
349            *(d++)= 0xff;
350            continue;
351        }
352        A_TO_I(c);
353        i = c << 4;
354        c = *(s++);
355        A_TO_I(c);
356        *(d++) = (char)(i + c);
357    }
358    return 0;
359}
360/********************************************************************************************
361                    Binary to  Ascii
362********************************************************************************************/
363
364#define GB_PUT(c,out) if(c>=10) c+='A'-10; else c+= '0'; *(out++) = (char)c;
365
366GB_BUFFER gb_bin_2_ascii(GBDATA *gbd)
367{
368    signed char   *s, *out, c, mo;
369    unsigned long  i;
370    int            j;
371    char          *buffer;
372    int            k;
373
374    char *source = GB_GETDATA(gbd);
375    long len = GB_GETMEMSIZE(gbd);
376    long xtended = GB_GETSIZE(gbd);
377    int compressed = gbd->flags.compressed_data;
378
379    buffer = GB_give_buffer(len * 2 + 10);
380    out = (signed char * )buffer;
381    s = (signed char *)source, mo = -1;
382
383    GB_PUT(compressed,out);
384    if (!xtended) {
385        *(out++) = ':';
386    }else{
387        for (i = 0xf0000000,j=28;j>=0;j-=4,i=i>>4) {
388            k = (int)((xtended & i)>>j);
389            GB_PUT(k, out);
390        }
391    }
392    for (i = len; i; i--) {
393        if (!(c = *(s++))) {
394            if ((i > 1) && !*s) {
395                *(out++) = ':';
396                s ++;
397                i--;
398                continue;
399            }
400            *(out++) = '.';
401            continue;
402        }
403        if (c == mo) {
404            if ((i > 1) && (*s == -1)) {
405                *(out++) = '=';
406                s ++;
407                i--;
408                continue;
409            }
410            *(out++) = '-';
411            continue;
412        }
413        j = ((unsigned char) c) >> 4;
414        GB_PUT(j, out);
415        j = c & 15;
416        GB_PUT(j, out);
417    }
418    *(out++) = 0;
419    return buffer;
420}
421
422
423
424
425
426
427/********************************************************************************************
428                    Write Ascii File
429********************************************************************************************/
430#define GB_PUT_OUT(c,out) if(c>=10) c+='A'-10; else c+= '0'; putc(c,out);
431
432long gb_test_sub(GBDATA *gbd)
433{
434    gbd = gbd;
435    return 0;
436}
437
438/* only used for saving ASCII database */
439static long gb_write_rek(FILE *out,GBCONTAINER *gbc,long deep,long big_hunk)
440{
441    long     i;
442    char    *s;
443    char     c;
444    GBDATA  *gb;
445    GB_CSTR  strng;
446    char    *key;
447   
448    for (gb = GB_child((GBDATA *)gbc); gb; gb = GB_nextChild(gb)) {
449        if (gb->flags.temporary) continue;
450        key = GB_KEY(gb);
451        if (!strcmp(key,GB_SYSTEM_FOLDER)) continue;    /* do not save system folder */
452        for (i=deep;i--;) putc('\t',out);
453        fprintf(out,"%s\t",key);
454        if ((int)strlen(key) < 8){
455            putc('\t',out);
456        }
457        if (    gb->flags.security_delete ||
458                gb->flags.security_write ||
459                gb->flags.security_read ||
460                gb->flags2.last_updated ){
461            putc(':',out);
462            c = gb->flags.security_delete;
463            GB_PUT_OUT(c,out);
464            c = gb->flags.security_write;
465            GB_PUT_OUT(c,out);
466            c = gb->flags.security_read;
467            GB_PUT_OUT(c,out);
468            fprintf(out,"%i\t",gb->flags2.last_updated);
469        }else{
470            putc('\t',out);
471        }
472        switch (GB_TYPE(gb)) {
473            case    GB_STRING:
474                strng = GB_read_char_pntr(gb);
475                if (!strng) {
476                    strng = "<entry was broken - replaced during ASCIIsave/arb_repair>";
477                    GB_warningf("- replaced broken DB entry %s (data lost)\n", GB_get_db_path(gb));
478                }
479                if (*strng == '%') {
480                    putc('%',out);
481                    putc('s',out);
482                    putc('\t',out);
483                }
484                GBS_fwrite_string(strng,out);
485                putc('\n',out);
486                break;
487            case    GB_LINK:
488                strng = GB_read_link_pntr(gb);
489                if (*strng == '%') {
490                    putc('%',out);
491                    putc('l',out);
492                    putc('\t',out);
493                }
494                GBS_fwrite_string(strng,out);
495                putc('\n',out);
496                break;
497            case GB_INT:
498                fprintf(out,"%%i %li\n",GB_read_int(gb));
499                break;
500            case GB_FLOAT:
501                fprintf(out,"%%f %g\n",GB_read_float(gb));
502                break;
503            case GB_BITS:
504                fprintf(out,"%%I\t\"%s\"\n",
505                        GB_read_bits_pntr(gb,'-','+'));
506                break;
507            case GB_BYTES:
508                s = gb_bin_2_ascii(gb);
509                fprintf(out,"%%Y\t%s\n",s);
510                break;
511            case GB_INTS:
512                s = gb_bin_2_ascii(gb);
513                fprintf(out,"%%N\t%s\n",s);
514                break;
515            case GB_FLOATS:
516                s = gb_bin_2_ascii(gb);
517                fprintf(out,"%%F\t%s\n",s);
518                break;
519            case GB_DB:
520                fprintf(out, "%%%% (%%\n");
521                gb_write_rek(out, (GBCONTAINER *)gb, deep + 1, big_hunk);
522                for (i=deep+1;i--;) putc('\t',out);
523                fprintf(out, "%%) /*%s*/\n\n", GB_KEY(gb));
524                break;
525            case GB_BYTE:
526                fprintf(out,"%%y %i\n",GB_read_byte(gb));
527                break;
528            default:
529                fprintf(stderr,
530                        "ARBDB ERROR Key \'%s\' is of unknown type\n",
531                        GB_KEY(gb));
532                fprintf(out, "%%%% (%% %%) /* unknown type */\n");
533                break;
534        }
535    }/*while*/
536    return 0;
537}
538
539
540
541
542/********************************************************************************************
543                    Read Binary File
544********************************************************************************************/
545
546long    gb_read_in_long(FILE *in,long reversed)
547{
548    long  sdata = 0;
549    char *p     = (char *)&sdata;
550
551    if (!reversed) {
552        *(p++) = getc(in);
553        *(p++) = getc(in);
554        *(p++) = getc(in);
555        *(p) = getc(in);
556    }
557    else {
558        p[3] = getc(in);
559        p[2] = getc(in);
560        p[1] = getc(in);
561        p[0] = getc(in);
562    }
563    return sdata;
564}
565
566
567long gb_read_number(FILE *in) {
568    unsigned int c0,c1,c2,c3,c4;
569    c0 = getc(in);
570    if (c0 & 0x80){
571        c1 = getc(in);
572        if (c0 & 0x40) {
573            c2 = getc(in);
574            if (c0 & 0x20) {
575                c3 = getc(in);
576                if (c0 &0x10) {
577                    c4 = getc(in);
578                    return c4 | (c3<<8) | (c2<<16) | (c1<<8);
579                }else{
580                    return (c3) | (c2<<8 ) | (c1<<16) | ((c0 & 0x0f)<<24);
581                }
582            }else{
583                return (c2) | (c1<<8) | ((c0 & 0x1f)<<16);
584            }
585        }else{
586            return (c1) | ((c0 & 0x3f)<<8);
587        }
588    }else{
589        return c0;
590    }
591}
592
593void gb_put_number(long i, FILE *out) {
594    long j;
595    if (i< 0x80 ){ putc((int)i,out);return; }
596    if (i<0x4000) {
597        j = (i>>8) | 0x80;
598        putc((int)j,out);
599        putc((int)i,out);
600        return;
601    }
602    if (i<0x200000) {
603        j = (i>>16) | 0xC0;
604        putc((int)j,out);
605        j = (i>>8);
606        putc((int)j,out);
607        putc((int)i,out);
608        return;
609    }
610    if (i<0x10000000) {
611        j = (i>>24) | 0xE0;
612        putc((int)j,out);
613        j = (i>>16);
614        putc((int)j,out);
615        j = (i>>8);
616        putc((int)j,out);
617        putc((int)i,out);
618        return;
619    }
620}
621
622long gb_read_bin_error(FILE *in,GBDATA *gbd,const char *text)
623{
624    long p = (long)ftell(in);
625    GB_export_errorf("%s in reading GB_file (loc %li=%lX) reading %s\n",
626                    text,p,p,GB_KEY(gbd));
627    GB_print_error();
628    return 0;
629}
630
631
632
633
634/********************************************************************************************
635                    Write Binary File
636********************************************************************************************/
637
638long    gb_write_out_long(long data, FILE *out)
639{
640    long sdata[1];
641    char *p = (char *)sdata,c;
642    sdata[0] = data;
643    c = *(p++);
644    putc(c,out);
645    c = *(p++);
646    putc(c,out);
647    c = *(p++);
648    putc(c,out);
649    c = *(p);
650    putc(c,out);
651    return 0;
652}
653/** Test whether to write any data to disc.
654    version 1       write only latest data
655    version 2       write deleted entries two (which are not already stored to master file !!!
656    try to avoid to access gbd, keep it swap out
657*/
658
659
660int gb_is_writeable(struct gb_header_list_struct *header, GBDATA *gbd, long version, long diff_save)
661{
662    if (version == 2 && header->flags.changed==gb_deleted) return 1;    /* save delete flag */
663    if (!gbd) return 0;
664    if (diff_save) {
665        if (!header->flags.ever_changed) return 0;
666        if (!gbd->ext || (gbd->ext->update_date<diff_save && gbd->ext->creation_date < diff_save))
667            return 0;
668    }
669    if (gbd->flags.temporary) return 0;
670    return 1;
671}
672
673int gb_write_bin_sub_containers(FILE *out,GBCONTAINER *gbc,long version,long diff_save, int is_root){
674    struct gb_header_list_struct *header;
675    int i,index;
676    int counter;
677    header = GB_DATA_LIST_HEADER(gbc->d);
678    for (i=0, index = 0; index < gbc->d.nheader; index++) {
679        if (gb_is_writeable(&(header[index]),GB_HEADER_LIST_GBD(header[index]),version,diff_save)) i++;
680    }
681
682    if (!is_root){
683        gb_put_number(i,out);
684    }else{
685        gb_write_out_long(i,out);
686    }
687
688    counter = 0;
689    for (index = 0; index < gbc->d.nheader; index++){
690        GBDATA *h_gbd;
691
692        if (header[index].flags.changed == gb_deleted_in_master){   /* count deleted items in master, because of index renaming */
693            counter ++;
694            continue;
695        }
696
697        h_gbd = GB_HEADER_LIST_GBD(header[index]);
698
699        if(!gb_is_writeable(&(header[index]),h_gbd,version,diff_save))
700        {   /* mark deleted in master */
701            if (version <= 1 && header[index].flags.changed == gb_deleted) {
702                header[index].flags.changed = gb_deleted_in_master;
703            }
704            continue;
705        }
706
707        if (h_gbd) {
708            i = (int)gb_write_bin_rek(out,h_gbd,version,diff_save,index-counter);
709            if (i) return i;
710        }else{
711            if (header[index].flags.changed == gb_deleted ) {
712                putc(0,out);
713                putc(1,out);
714                gb_put_number(index - counter,out);
715            }
716        }
717    }
718    return 0;
719}
720
721long gb_write_bin_rek(FILE *out,GBDATA *gbd,long version, long diff_save, long index_of_master_file)
722{
723    int          i;
724    GBCONTAINER *gbc     = 0;
725    long         size    = 0;
726    int          type    = GB_TYPE(gbd);
727
728    if (type == GB_DB) {
729        gbc = (GBCONTAINER *)gbd;
730    }
731    else if (type == GB_STRING || type == GB_STRING_SHRT) {
732        size = GB_GETSIZE(gbd);
733        if (!gbd->flags.compressed_data && size < GBTUM_SHORT_STRING_SIZE) {
734            type = GB_STRING_SHRT;
735        }
736        else {
737            type = GB_STRING;
738        }
739    }
740
741    i =     (type<<4)
742        +   (gbd->flags.security_delete<<1)
743        +   (gbd->flags.security_write>>2);
744    putc(i,out);
745
746    i =     ((gbd->flags.security_write &3) <<6)
747        +   (gbd->flags.security_read<<3)
748        +   (gbd->flags.compressed_data<<2)
749        +   ((GB_ARRAY_FLAGS(gbd).flags&1)<<1)
750        +   (gbd->flags.unused);
751    putc(i,out);
752
753    gb_put_number(GB_ARRAY_FLAGS(gbd).key_quark,out);
754
755    if (diff_save) {
756        gb_put_number(index_of_master_file,out);
757    }
758
759    i = gbd->flags2.last_updated;
760    putc(i,out);
761
762    if (type == GB_STRING_SHRT) {
763        const char *data = GB_GETDATA(gbd);
764        size_t      len  = strlen(data); // w/o zero-byte!
765
766        if ((long)len == size) {
767            i = fwrite(data, len+1, 1, out);
768
769            return i <= 0 ? -1 : 0;
770        }
771        // string contains zero-byte inside data or misses trailing zero-byte
772        type = GB_STRING; // fallback to safer type
773    }
774
775    switch(type) {
776        case GB_DB:
777            i = gb_write_bin_sub_containers(out,gbc,version,diff_save,0);
778            return i;
779
780        case GB_INT:{
781            GB_UINT4 buffer = (GB_UINT4)htonl(gbd->info.i);
782            if (!fwrite((char *)&buffer,sizeof(float),1,out)) return -1;
783            return 0;
784        }
785        case GB_FLOAT:
786            if (!fwrite((char *)&gbd->info.i,sizeof(float),1,out)) return -1;
787            return 0;
788        case GB_LINK:
789        case GB_BITS:
790        case GB_BYTES:
791        case GB_INTS:
792        case GB_FLOATS:
793            size = GB_GETSIZE(gbd);
794            // fall-through
795        case GB_STRING: {
796            long memsize = GB_GETMEMSIZE(gbd);
797            gb_put_number(size,out);
798            gb_put_number(memsize,out);
799            i = fwrite(GB_GETDATA(gbd),(size_t)memsize,1,out);
800            if (memsize && !i) return -1;
801            return 0;
802        }
803        case GB_BYTE:
804            putc((int)(gbd->info.i),out);
805            return 0;
806        default:
807            gb_assert(0); // unknown type
808            return -1;
809    }
810}
811
812
813/**     version 1 write master arb file
814        version 2 write slave arb file */
815int gb_write_bin(FILE *out,GBDATA *gbd,long version){
816    long i;
817    GBCONTAINER *gbc = (GBCONTAINER *)gbd;
818    int diff_save = 0;
819    GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gbc);
820
821    gb_write_out_long(GBTUM_MAGIC_NUMBER,out);
822    fprintf(out,"\n this is the binary version of the gbtum data file version %li\n",version);
823    putc(0,out);
824    fwrite("vers",4,1,out);
825    gb_write_out_long(0x01020304,out);
826    gb_write_out_long(version,out);
827    fwrite("keys",4,1,out);
828
829    for (i=1;i<Main->keycnt;i++) {
830        if (Main->keys[i].nref>0) {
831            gb_put_number(Main->keys[i].nref,out);
832            fprintf(out,"%s",Main->keys[i].key);
833        }else{
834            putc(0,out);        /* 0 nref */
835            putc(1,out);        /* empty key */
836        }
837        putc(0,out);
838
839    }
840    putc(0,out);
841    putc(0,out);
842    fwrite("time",4,1,out);{
843        unsigned int k;
844        for (k=0;k<Main->last_updated;k++) {
845            fprintf(out,"%s",Main->dates[k]);
846            putc(0,out);
847        }
848    }
849    putc(0,out);
850    fwrite("data",4,1,out);
851    if (version == 2) diff_save = (int)Main->last_main_saved_transaction+1;
852
853    return gb_write_bin_sub_containers(out,gbc,version,diff_save,1);
854}
855
856/********************************************************************************************
857                    SAVE DATABASE
858********************************************************************************************/
859
860
861GB_ERROR GB_save(GBDATA *gb,const char *path,const char *savetype)
862     /*
863      * savetype 'a'    ascii
864      *          'aS'   dump to stdout
865      *          'b'    binary
866      *          'bm'   binary + mapfile
867      *          0      ascii
868      */
869{
870    if (path && strchr(savetype, 'S') == 0) // 'S' dumps to stdout -> do not change path
871    {
872        freedup(GB_MAIN(gb)->path, path);
873    }
874    return GB_save_as(gb,path,savetype);
875}
876
877GB_ERROR GB_create_directory(const char *path) {
878    GB_ERROR error = 0;
879    if (!GB_is_directory(path)) {
880        char *parent;
881        GB_split_full_path(path, &parent, NULL, NULL, NULL);
882        if (parent) {
883            if (!GB_is_directory(parent)) error = GB_create_directory(parent);
884            free(parent);
885        }
886
887        if (!error && !GB_is_directory(path)) {
888            int res = mkdir(path, ACCESSPERMS);
889            if (res) error = GB_export_IO_error("creating directory", path);
890        }
891
892        gb_assert(error || GB_is_directory(path));
893
894        error = GB_failedTo_error("GB_create_directory", path, error);
895    }
896    return error;
897}
898
899GB_ERROR GB_save_in_home(GBDATA *gb,const char *path,const char *savetype)
900     /*
901      * savetype 'a'    ascii
902      *      'b'    binary
903      *      'bm'   binary + mapfile
904      *      0=ascii
905      *
906      *      creates subdirectories too
907      */
908{
909    GB_ERROR error = 0;
910    char *buffer;
911    const char *env;
912    char *slash;
913    /*     char *buf2; */
914
915    env = GB_getenvHOME();
916    if(!path) path = GB_MAIN(gb)->path;
917
918    buffer = (char *)GB_calloc(sizeof(char),strlen(env)+ strlen(path) + 2);
919
920    sprintf(buffer,"%s/%s",env,path);
921    slash             = strrchr(buffer,'/');
922    *slash            = 0;
923    error             = GB_create_directory(buffer);
924    *slash            = '/';
925    if (!error) error = GB_save_as(gb,buffer,savetype);
926    if (buffer) free(buffer);
927    return error;
928}
929
930#if defined(DEVEL_RALF)
931#warning rewrite error handling in GB_save_as, GB_save_quick_as, GB_save_quick, gb_check_saveable
932#endif /* DEVEL_RALF */
933
934/** Save whole database */
935GB_ERROR GB_save_as(GBDATA *gb,const char *path,const char *savetype)
936     /*
937      * savetype    'a' ascii
938      *         'b' binary
939      *         'm' save mapfile too (only with binary)
940      *         'f' force saving even in disabled path to a different directory (out of order save)
941      *                      'S' save to stdout (for debugging)
942      *          0=ascii
943      *
944      */
945{
946    FILE *out;
947    long erg =0;
948    int slevel;
949    int translevel;
950    char    *sec_path = NULL;
951    GB_CSTR map_path = NULL;
952    GB_MAIN_TYPE *Main = GB_MAIN(gb);
953    int deleteQuickAllowed = savetype==NULL || strchr(savetype, 'f')==NULL;
954    int dump_to_stdout = 0;
955
956    if (gb == NULL) return NULL;
957    gb = (GBDATA *)Main->data;
958
959    if (path == NULL) path = Main->path;
960
961    if (!path || !strlen(path) )
962    {
963        GB_export_error("Please specify a file name");
964        goto error;
965    }
966
967    if (gb_check_saveable(gb,path,savetype)) goto error;
968
969    sec_path = strdup(gb_overwriteName(path));
970
971    if (strchr(savetype,'S')) {
972        out = stdout;
973        dump_to_stdout = 1;
974    }
975    else if ((out = fopen(sec_path, "w")) == NULL)
976    {
977        GB_export_IO_error("saving",sec_path);
978/*         printf(" file %s could not be opened for writing \n", sec_path); */
979/*         GB_export_error("ARBDB ERROR: Cannot save file to '%s'",sec_path); */
980        goto error;
981    }
982
983    slevel = Main->security_level;
984    translevel = Main->transaction;
985
986    if (!translevel) Main->transaction = 1;
987    else
988    {
989        if (translevel> 0 )
990        {
991            GB_commit_transaction(gb);
992            GB_begin_transaction(gb);
993        }
994    }
995
996    Main->security_level = 7;
997
998    if (!savetype || strchr(savetype,'a'))          /* ASCII */
999    {
1000        fprintf(out,"/*ARBDB ASCII*/\n");
1001        erg = gb_write_rek(out,(GBCONTAINER *)gb,0,1);
1002        if (erg==0) {
1003            freedup(Main->qs.quick_save_disabled, "Database saved in ASCII mode");
1004            if (deleteQuickAllowed && gb_remove_all_but_main(Main,path)) goto error;
1005        }
1006    }
1007    else if (strchr(savetype,'b'))              /* binary */
1008    {
1009        /* it's necessary to save the mapfile FIRST, cause this re-orders all GB_CONTAINERs
1010         * containing NULL-entries in their header */
1011
1012        erg = 0;
1013        if (strchr(savetype,'m')) {
1014            map_path  = gb_mapfile_name(path);
1015            erg      |= gb_save_mapfile(Main,map_path); /* save mapfile */
1016            erg      |= gb_write_bin(out,gb,1);     /* save binary */
1017        }
1018        else {
1019            GB_unlink_or_warn(gb_mapfile_name(path), NULL); /* delete old mapfile */
1020            erg |= gb_write_bin(out,gb,1);          /* save binary */
1021        }
1022
1023        if (erg==0){
1024            if (!strchr(savetype,'f')){             /* allow quick saving unless saved in 'f' mode */
1025                freeset(Main->qs.quick_save_disabled, NULL); /* delete reason, why quicksaving is disallowed */
1026            }
1027            if (deleteQuickAllowed && gb_remove_quick_saved(Main,path)) goto error;
1028        }
1029    }
1030
1031    Main->security_level = slevel;
1032    Main->transaction = translevel;
1033    erg |= fclose(out);
1034
1035    if (erg) {
1036        GB_export_IO_error("writing", sec_path);
1037/*         GB_export_error("ARBDB: Write Error, system errno = '%i', see console", errno); */
1038/*         perror("Write Error"); */
1039        goto error;
1040    }
1041
1042
1043    if (!dump_to_stdout) {
1044        if (GB_rename_file(sec_path, path)==0){
1045            if (map_path){
1046                GB_CSTR overwrite_map_path = gb_overwriteName(map_path);
1047                long path_mode = GB_mode_of_file(path);
1048
1049                if (GB_rename_file(overwrite_map_path, map_path)==0)
1050                {
1051                    GB_set_mode_of_file(map_path,path_mode);        /* set mapfile to same mode as binary file */
1052                }
1053                else /* if we cannot rename the mapfile, then we delete it */
1054                {
1055                    GB_unlink_or_warn(overwrite_map_path, NULL);
1056                    goto error;
1057                }
1058            }
1059            if (Main->qs.quick_save_disabled == 0){     /* do we need an ARF file ?? */
1060                gb_create_reference(path);
1061            }else{
1062                gb_delete_reference(path);              /* delete old ARF file */
1063            }
1064        }else{
1065            goto error;
1066        }
1067    }
1068    freeset(sec_path, NULL);
1069    if (!strchr(savetype,'f')){ /* reset values unless out of order save */
1070        Main->last_saved_transaction = GB_read_clock(gb);
1071        Main->last_main_saved_transaction = GB_read_clock(gb);
1072        Main->last_saved_time = GB_time_of_day();
1073    }
1074    return NULL;
1075
1076 error:
1077
1078    if (sec_path) free(sec_path);
1079    return GB_get_error();
1080}
1081
1082static GB_ERROR gb_check_quick_save(GBDATA *gb_main) {
1083    /* is quick save allowed?
1084     * return NULL if allowed, error why disallowed otherwise.
1085     */
1086
1087    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
1088    if (Main->qs.quick_save_disabled) {
1089        return GBS_global_string("Save Changes Disabled, because\n"
1090                                 "    '%s'\n"
1091                                 "    Save whole database using binary mode first",
1092                                 Main->qs.quick_save_disabled);
1093    }
1094
1095    return NULL;
1096}
1097
1098GB_ERROR GB_delete_database(GB_CSTR filename) {
1099    GB_ERROR error = 0;
1100
1101    if (GB_unlink(filename)<0) error = GB_await_error();
1102    else error                       = gb_remove_all_but_main(0, filename);
1103
1104    return error;
1105}
1106
1107GB_ERROR GB_save_quick_as(GBDATA *gb_main, char *path)
1108{
1109    FILE *fmaster;
1110    long mode;
1111    char *org_master;
1112    char *full_path_of_source;
1113    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
1114
1115    gb_main = (GBDATA *)Main->data;
1116
1117    if (!path || !strlen(path) ) {
1118        return GB_export_error("Please specify a file name");
1119    }
1120
1121    if (!strcmp(path,Main->path)) return GB_save_quick(gb_main,path); /* No rename */
1122    {
1123        GB_ERROR error = gb_check_quick_save(gb_main);
1124        if (error) return error;
1125    }
1126    if (gb_check_saveable(gb_main,path,"bn")) return GB_get_error();
1127
1128    fmaster = fopen( Main->path, "r" ); /* old master !!!! */
1129    if (!fmaster){      /* Oh no, where is my old master */
1130        return GB_export_errorf("Save Changes is missing master ARB file '%s',\n"
1131                                "    save database first", Main->path);
1132    }
1133    fclose(fmaster);
1134    if (GB_unlink(path)<0){
1135        return GB_export_errorf("File '%s' already exists and cannot be deleted\n(Reason: %s)",path, GB_await_error());
1136    };      /* delete old file */
1137
1138    mode = GB_mode_of_link(Main->path); /* old master */
1139    if (S_ISLNK(mode)){
1140        org_master = GB_follow_unix_link(Main->path);
1141    }else{
1142        org_master = strdup(Main->path);
1143    }
1144
1145    if( gb_remove_all_but_main(Main,path))
1146    {
1147        free(org_master);
1148        return GB_get_error();
1149    }
1150
1151    mode = GB_mode_of_file(org_master);
1152    if (mode & S_IWUSR) {
1153        if (GB_set_mode_of_file(org_master,mode & ~(S_IWUSR | S_IWGRP | S_IWOTH))){
1154            GB_warningf("!!!!!!!!! WARNING !!!!!!!\n"
1155                        "   Cannot set mode of file '%s'\n"
1156                        "   NEVER, NEVER delete or change file\n"
1157                        "        '%s'\n"
1158                        "   Best: Ask your system administrator\n"
1159                        "   to remove write permissions.",
1160                        org_master,org_master);
1161        }
1162    }
1163    if (strchr(path,'/') || strchr(org_master,'/') ){
1164        /* dest or source in different directory */
1165        full_path_of_source = gb_full_path(org_master);
1166    }else{
1167        full_path_of_source = strdup(org_master);
1168    }
1169
1170    if (GB_symlink(full_path_of_source,path)){
1171        free(org_master);
1172        free(full_path_of_source);
1173        return GB_get_error();
1174    }
1175    if ((uid_t)GB_getuid_of_file(full_path_of_source) != getuid()){
1176        GB_warningf("**** WARNING ******\n"
1177                    "   You now using a file '%s'\n"
1178                    "   which is owned by another user\n"
1179                    "   Please ask him not to delete this file\n"
1180                    "   If you don't trust him, don't save changes but\n"
1181                    "   the WHOLE database",full_path_of_source);
1182    }
1183    if (gb_add_reference(full_path_of_source,path)){
1184        GB_warning(GB_get_error());
1185    }
1186
1187    freedup(Main->path, path); /* Symlink created -> rename allowed */
1188
1189    free(full_path_of_source);
1190    free(org_master);
1191
1192    Main->qs.last_index = 0;        /* Start with new quicks */
1193    return GB_save_quick(gb_main,path);
1194}
1195
1196
1197GB_ERROR GB_save_quick(GBDATA *gb, char *refpath)
1198{
1199    FILE *out;
1200    GB_CSTR path;
1201    GB_CSTR sec_path;
1202    long erg;
1203    int slevel;
1204    int translevel;
1205    FILE *fmaster;
1206    GB_MAIN_TYPE *Main = GB_MAIN(gb);
1207
1208    gb = (GBDATA *)Main->data;
1209    {
1210        GB_ERROR error = gb_check_quick_save(gb);
1211        if (error) return error;
1212    }
1213    if (gb_check_saveable(gb,refpath,"q")) return GB_get_error();
1214
1215    if (refpath && strcmp(refpath, Main->path) )
1216    {
1217        return GB_export_errorf("Internal ARB Error, master file rename '%s'!= '%s',\n"
1218                                "    save database first", refpath,Main->path);
1219    }
1220
1221    fmaster = fopen( Main->path, "r");
1222
1223    if (!fmaster) /* Oh no, where is my old master */
1224    {
1225        return GB_export_errorf("Quick save is missing master ARB file '%s',\n"
1226                                "    save database first", refpath);
1227    }
1228    fclose(fmaster);
1229
1230    if (Main->local_mode == GB_FALSE)
1231    {
1232        GB_export_error("You cannot save a remote database");
1233        GB_print_error();
1234        return GB_get_error();
1235    }
1236
1237    Main->qs.last_index++;
1238    if (Main->qs.last_index >= GB_MAX_QUICK_SAVE_INDEX) renameQuicksaves(Main);
1239
1240    path = gb_quicksaveName(Main->path, Main->qs.last_index);
1241    sec_path = gb_overwriteName(path);
1242
1243    if ((out = fopen(sec_path, "w")) == NULL) return GB_export_errorf("ARBDB ERROR: Cannot save file to '%s'",sec_path);
1244
1245    slevel = Main->security_level;
1246    translevel = Main->transaction;
1247
1248    if (!translevel)
1249        Main->transaction = 1;
1250    else
1251    {
1252        if (translevel> 0 )
1253        {
1254            GB_commit_transaction(gb);
1255            GB_begin_transaction(gb);
1256        }
1257    }
1258
1259    Main->security_level = 7;
1260    erg = gb_write_bin(out,gb,2);
1261
1262    Main->security_level = slevel;
1263    Main->transaction = translevel;
1264    erg |= fclose(out);
1265    if (erg!=0) return GB_export_errorf("Cannot write to '%s'",sec_path); /* was: '%s%%'",path);*/
1266
1267    if (GB_rename_file(sec_path,path)) return GB_get_error();
1268
1269    Main->last_saved_transaction = GB_read_clock(gb);
1270    Main->last_saved_time = GB_time_of_day();
1271
1272    return deleteSuperfluousQuicksaves(Main);
1273}
1274
1275/********************************************************************************************
1276                    DISABLE DIRECTORIES
1277********************************************************************************************/
1278
1279/** returns 0 if user is allowed to save */
1280
1281char *gb_full_path(const char *path) {
1282    char *res = 0;
1283   
1284    if (path[0] == '/') res = strdup(path);
1285    else {
1286        const char *cwd = GB_getcwd();
1287
1288        if (path[0] == 0) res = strdup(cwd);
1289        else res              = GBS_global_string_copy("%s/%s",cwd,path);
1290    }
1291    return res;
1292}
1293
1294
1295/* Check wether file can be stored at destination
1296 * a 'f' in flags means 'force', disables main->disabled_path
1297 * a 'q' in flags means 'quick save'
1298 * a 'n' in flags means destination must be empty */
1299
1300GB_ERROR gb_check_saveable(GBDATA *gbd,const char *path,const char *flags){
1301    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1302    char *fullpath;
1303    long mode;
1304    if (Main->local_mode == GB_FALSE) {
1305        GB_export_error("You cannot save a remote database, please use save button in master program");
1306        GB_print_error();
1307        return GB_get_error();
1308    }
1309    if (Main->opentype == gb_open_read_only_all) {
1310        GB_export_error("Database is read only");
1311        GB_print_error();
1312        return GB_get_error();
1313    }
1314    if (strchr(path,':')){
1315        return GB_export_error( "Your database name must not contain a ':' character\n"
1316                                "   Choose a different name");
1317    }
1318
1319    fullpath = gb_full_path(path);
1320    if (Main->disabled_path && !strchr(flags,'f') ) {
1321        if (GBS_string_matches(fullpath,Main->disabled_path,GB_MIND_CASE)) {
1322            free(fullpath);
1323            return GB_export_error(
1324                                   "You are not allowed to save your database in this directory,\n"
1325                                   "    Please select 'save as' and save your data to a different location");
1326        }
1327    }
1328
1329    // check whether destination directory exists
1330    {
1331        char *lslash = strrchr(fullpath, '/');
1332        if (lslash) {
1333            GB_ERROR err = 0;
1334
1335            lslash[0] = 0;
1336            if (!GB_is_directory(fullpath)) {
1337                err = GB_export_errorf("Directory '%s' doesn't exist", fullpath);
1338            }
1339            lslash[0] = '/';
1340
1341            if (err) return err;
1342        }
1343    }
1344
1345    free(fullpath);
1346
1347    if ( !strchr(flags,'q')){
1348        mode = GB_mode_of_link(path);
1349        if (mode >=0 && !(mode & S_IWUSR)){ /* no write access -> lookes like a master file */
1350            return GB_export_errorf(
1351                                    "Your selected file '%s' already exists and is write protected\n"
1352                                    "    It looks like that your file is a master arb file which is\n"
1353                                    "    used by some xxx.a?? quicksave databases\n"
1354                                    "    If you want to save it nevertheless, delete it first !!!",
1355                                    path);
1356        }
1357    }
1358    if ( strchr(flags,'n')){
1359        if (GB_time_of_file(path)){
1360            return GB_export_errorf("Your destination file '%s' already exists.\n"
1361                                    "\tDelete it by hand first",path );
1362        }
1363    }
1364    return 0;
1365}
1366
1367void GB_disable_path(GBDATA *gbd, const char *path) {
1368    freeset(GB_MAIN(gbd)->disabled_path, path ? GBS_eval_env(path) : NULL);
1369}
1370
1371
1372
Note: See TracBrowser for help on using the browser.