13 #include <netinet/in.h>
31 char *punkt = strrchr(path,
'.');
33 char *slash = strchr(punkt,
'/');
34 if (slash) punkt =
NULp;
51 if (strvar.isNull() || (strlen(&*strvar) < (
size_t)(minlen-1))) {
52 strvar = ARB_calloc<char>(minlen);
58 static SmartCharPtr Qname;
60 size_t len = strlen(path);
65 if (!ext) ext = qname + len;
67 if (nr==-1) sprintf(ext,
".arb.quick?");
68 else sprintf(ext,
".arb.quick%i", nr);
74 static SmartCharPtr Qname;
80 if (!ext) ext = qname + strlen(qname);
82 if (nr==-1) sprintf(ext,
".a??");
83 else sprintf(ext,
".a%02i", nr);
89 static SmartCharPtr Mapname;
92 strcpy(mapname, path);
95 if (!ext) ext = mapname + strlen(mapname);
108 static SmartCharPtr Oname;
110 int len = strlen(path);
114 strcpy(oname+len,
"~");
120 static SmartCharPtr Refname;
122 size_t len = strlen(path);
124 memcpy(refname, path, len+1);
127 size_t ext_offset = ext ? (
size_t)(ext-refname) : len;
129 strcpy(refname+ext_offset,
".ARF");
162 FILE *out = fopen(fullref,
"w");
165 fprintf(out,
"***** The following files may be a link to %s ********\n", fullmaster);
171 "Your database was saved, but you should check "
172 "write permissions in the destination directory!", fullref);
184 FILE *out = fopen(fullref,
"a");
187 fprintf(out,
"%s\n", fullchanges);
193 "to the list of references of '%s'.\n"
194 "Please ask the owner of that file not to delete it\n"
195 "or save the entire database (that's recommended!)",
196 fullchanges, fullref);
226 char *path = Main->
path;
253 const char *path = Main->
path;
285 const char *
s = source;
298 for (i = 0, k = 8; k && (c = *(s++)); k--) {
307 while ((c = *(s++))) {
308 if ((c ==
'.') || (c==
'-')) {
312 if ((c ==
':') || (c==
'=')) {
327 while ((c = *(s++))) {
350 *(d++) = (
char)(i + c);
358 #define GB_PUT(c, out) do { if (c>=10) c+='A'-10; else c += '0'; *(out++) = (char)c; } while (0)
361 signed char *
s, *out, c, mo;
367 const char *source = gbe->
data();
369 long xtended = gbe->
size();
373 out = (
signed char *)buffer;
374 s = (
signed char *)source, mo = -1;
381 for (i = 0xf0000000, j=28; j>=0; j-=4, i=i>>4) {
382 k = (
int)((xtended & i)>>j);
386 for (i = len; i; i--) {
388 if ((i > 1) && !*s) {
398 if ((i > 1) && (*s == -1)) {
407 j = ((
unsigned char) c) >> 4;
419 #define GB_PUT_OUT(c, out) do { if (c>=10) c+='A'-10; else c += '0'; putc(c, out); } while (0)
430 const char *key =
GB_KEY(gb);
434 for (
int i=indent; i--;) putc(
'\t', out);
435 fprintf(out,
"%s\t", key);
436 const int klen = strlen(key);
439 if (klen < 8) putc(
'\t', out);
464 fprintf(out,
"%%%c (%%\n",
GB_read_flag(gb) ?
'$' :
'%');
466 if (!closeTags)
return false;
468 if (gb_writeFrom && gb_writeFrom == gb->
as_container()) gb_writeFrom =
NULp;
469 if (gb_writeTill && gb_writeTill == gb->
as_container()) {
473 for (
int i=indent+1; i--;) putc(
'\t', out);
474 fprintf(out,
"%%) /*%s*/\n\n",
GB_KEY(gb));
479 switch (gbe->
type()) {
483 strng =
"<entry was broken - replaced during ASCIIsave/arb_repair>";
506 fprintf(out,
"%%I\t\"%s\"\n",
511 fprintf(out,
"%%Y\t%s\n", s);
516 fprintf(out,
"%%N\t%s\n", s);
521 fprintf(out,
"%%F\t%s\n", s);
532 "ARBDB ERROR Key \'%s\' is of unknown type\n",
534 fprintf(out,
"%%%% (%% %%) /* unknown type */\n");
552 gb_assert(!gb_writeFrom || !gb_writeTill);
555 if (gb->flags.temporary)
continue;
558 if (!closeTags)
return false;
568 long p = (
long)ftell(in);
616 const char *data = gbe->
data();
617 size_t len = strlen(data);
619 if ((
long)len == size) {
661 const char *data = gbe->
data();
664 i = fwrite(data, size+1, 1, out);
665 return i <= 0 ? -1 : 0;
675 if (!fwrite((
char *)&buffer,
sizeof(
float), 1, out))
return -1;
679 if (!fwrite((
char *)&gbe->
info.
i,
sizeof(
float), 1, out))
return -1;
691 i = fwrite(gbe->
data(), (
size_t)memsize, 1, out);
692 if (memsize && !i)
return -1;
696 putc((
int)(gbe->
info.
i), out);
710 for (i=0, index = 0; index < (uint32_t)gbc->
d.
nheader; index++) {
722 for (index = 0; index < (uint32_t)gbc->
d.
nheader; index++) {
765 fprintf(out,
"\n this is the binary version of the gbtum data file version %li\n", (
long)version);
767 fwrite(
"vers", 4, 1, out);
770 fwrite(
"keys", 4, 1, out);
772 for (
long i=1; i<Main->
keycnt; i++) {
787 fwrite(
"time", 4, 1, out); {
790 fprintf(out,
"%s", Main->
dates[k]);
795 fwrite(
"data", 4, 1, out);
810 if (path && !strchr(savetype,
'S')) {
811 freedup(
GB_MAIN(gb)->path, path);
832 int res = mkdir(path, ACCESSPERMS);
833 if (res) error =
GB_IO_error(
"creating directory", path);
850 if (!error) error =
GB_save_as(gb, fullname, savetype);
856 GB_ERROR GB_MAIN_TYPE::check_saveable(
const char *new_path,
const char *
flags)
const {
865 error =
"You cannot save a remote database,\nplease use save button in master program";
868 error =
"Database is read only";
870 else if (strchr(new_path,
':')) {
871 error =
"Your database name may not contain a ':' character\nChoose a different name";
877 error =
GBS_global_string(
"You are not allowed to save your database in this directory,\n"
878 "Please select 'save as' and save your data to a different location");
884 char *lslash = strrchr(fullpath,
'/');
896 if (!error && !strchr(flags,
'q')) {
898 if (mode >= 0 && !(mode & S_IWUSR)) {
900 "already exists and is write protected!\n"
901 "This happens e.g. if your file is a MASTER ARB FILE which is\n"
902 "used by multiple quicksaved databases.\n"
903 "If you want to save it nevertheless, delete it first, but\n"
904 "note that doing this will render all these quicksaves useless!",
911 "Delete it manually!", new_path);
915 if (!error && strchr(flags,
'm')) {
916 error =
"It's impossible to save mapfiles (ARBDB is MEMORY_TEST mode 1)";
926 if (!strstr(savepath,
"CORRUPTED")) {
927 error =
"Severe error: Corrupted data detected during save\n"
928 "ARB did NOT save your database!\n"
930 "* If your previous (quick)save was not long ago, your savest\n"
931 " option is to drop the changes since then, by reloading the not\n"
932 " corrupted database and redo your changes. If you can reproduce\n"
933 " the bug that corrupted the entries, please report it!\n"
934 "* If that is no option (because too much work would be lost)\n"
935 " you can force saving the corrupted database by adding the text\n"
936 " 'CORRUPTED' to the database name. After doing that, do NOT\n"
937 " quit ARB, instead try to find and fix all corrupted entries\n"
938 " that were listed below. Manually enter their original values\n"
939 " (in case you want to lookup or copy&paste some values, you may\n"
940 " open the last saved version of this database using\n"
941 " 'Start second database').\n"
942 " Saving the database again will show all remaining unfixed\n"
943 " entries. If no more corrupted entries show up, you can safely\n"
944 " continue to work with that database.";
947 GB_warning(
"Warning: Saved corrupt database");
953 #define SUPPORTED_COMPRESSION_FLAGS "zBx"
959 if (f) doc.
cat(
", ");
962 case 'z': doc.
cat(
"z=gzip");
break;
963 case 'B': doc.
cat(
"B=bzip2");
break;
964 case 'x': doc.
cat(
"x=xz");
break;
1003 if (main->transaction_level>0) {
1009 gb_assert(main->transaction_level == transaction || main->transaction_level == -1);
1022 bool dump_to_stdout;
1023 bool outOfOrderSave;
1024 bool deleteQuickAllowed;
1038 dump_to_stdout(
false),
1039 outOfOrderSave(
false),
1040 deleteQuickAllowed(
false)
1060 given_path = nulldup(given_path_);
1061 as_path = given_path;
1063 if (strchr(savetype,
'a')) saveASCII =
true;
1064 else if (strchr(savetype,
'b')) saveASCII =
false;
1065 else error =
GBS_global_string(
"Invalid savetype '%s' (expected 'a' or 'b')", savetype);
1068 if (!as_path) as_path = Main->
path;
1069 if (!as_path || !as_path[0]) error =
"Please specify a savename";
1070 else error = Main->check_saveable(as_path, savetype);
1087 for (
size_t comp = 0; !error && comp<
ARRAY_ELEMS(supported); ++comp) {
1088 if (strchr(savetype, supported[comp].
flag)) {
1090 compressMode = supported[comp].mode;
1093 error =
"Multiple compression modes specified";
1100 if (!error && Main->transaction_level>0) {
1101 error =
"Cannot save while inside transaction";
1104 save.readFrom(Main);
1109 dump_to_stdout = strchr(savetype,
'S');
1110 out = dump_to_stdout ? stdout :
ARB_zfopen(sec_path,
"w", compressMode, error,
false);
1118 save.transaction = 1;
1122 outOfOrderSave = strchr(savetype,
'f');
1123 deleteQuickAllowed = !outOfOrderSave && !dump_to_stdout;
1126 fprintf(out,
"/*ARBDB ASCII*/\n");
1129 saveMapfile = strchr(savetype,
'm');
1144 int root_indent = 0;
1164 Levels org; org.readFrom(Main);
1168 if (gb_from == gb_till) {
1169 writeContainerOrChilds(gb_from,
NULp,
NULp);
1172 bool from_is_ancestor =
false;
1173 bool till_is_ancestor =
false;
1178 while (gb_from_ancestor || gb_till_ancestor) {
1179 if (gb_from_ancestor && gb_from_ancestor == gb_till) till_is_ancestor =
true;
1180 if (gb_till_ancestor && gb_till_ancestor == gb_from) from_is_ancestor =
true;
1182 if (gb_from_ancestor) gb_from_ancestor = gb_from_ancestor->
get_father();
1183 if (gb_till_ancestor) gb_till_ancestor = gb_till_ancestor->
get_father();
1186 if (from_is_ancestor) {
1187 writeContainerOrChilds(gb_from,
NULp, gb_till);
1189 else if (till_is_ancestor) {
1190 writeContainerOrChilds(gb_till, gb_from,
NULp);
1193 error =
"Invalid use (one container has to be an ancestor of the other)";
1199 error =
"streamed saving only supported for ascii database format";
1210 Levels org; org.readFrom(Main);
1235 if (result != 0 && !error) {
1237 if (!dump_to_stdout) {
1239 if (close_error) error =
GBS_global_string(
"%s\n(close reports: %s)", error, close_error);
1243 if (!dump_to_stdout) {
1245 if (!error) error = close_error;
1253 if (!error && !saveASCII) {
1258 if (!dump_to_stdout) {
1264 bool unlinkMapfiles =
false;
1265 if (strcmp(sec_path, as_path) != 0) {
1270 unlinkMapfiles =
true;
1272 else if (sec_mappath) {
1277 GB_warningf(
"Error: %s\n[Falling back to non-fastload-save]", error);
1279 unlinkMapfiles =
true;
1283 if (unlinkMapfiles) {
1296 if (!error && !outOfOrderSave) {
1354 error =
"Invalid use of GB_stream_save_part: need to pass 2 containers";
1395 error =
"got no DB";
1404 GB_ERROR GB_MAIN_TYPE::check_quick_save()
const {
1412 " Save whole database using binary mode first",
1429 if (!as_path || !strlen(as_path)) {
1430 error =
"Please specify a file name";
1432 else if (strcmp(as_path,
path) == 0) {
1436 error = check_quick_saveable(as_path,
"bn");
1439 FILE *fmaster = fopen(
path,
"r");
1442 " save database first",
path);
1463 if (mode & S_IWUSR) {
1467 "Ask the owner to remove write permissions from that master file.\n"
1468 "NEVER delete or change it, otherwise your quicksaves will be rendered useless!",
1472 char *full_path_of_source;
1473 if (strchr(as_path,
'/') || strchr(org_master,
'/')) {
1478 full_path_of_source =
ARB_strdup(org_master);
1481 error =
GB_symlink(full_path_of_source, as_path);
1485 " You are using the file '%s' \n"
1486 " as reference for your saved changes.\n"
1487 " That file is owned by ANOTHER USER.\n"
1488 " If that user deletes or overwrites that file, your saved\n"
1489 " changes will get useless (=they will be lost)!\n"
1490 " You should only 'save changes as' if you understand what that means.\n"
1491 " Otherwise use 'Save whole database as' NOW!", full_path_of_source);
1497 freedup(
path, as_path);
1502 free(full_path_of_source);
1516 GB_ERROR error = check_quick_saveable(refpath,
"q");
1518 if (!error && refpath && strcmp(refpath,
path) != 0) {
1520 "save database first", refpath,
path);
1523 FILE *fmaster = fopen(
path,
"r");
1527 "save database first", refpath);
1533 if (!error &&
is_client()) error =
"Cannot save a remote database";
1534 if (!error && transaction_level>0) error =
"Cannot save while inside transaction";
1542 FILE *out = fopen(sec_path,
"w");
1550 if (!org_transaction_level) transaction_level = 1;
1552 if (org_transaction_level> 0) {
1565 transaction_level = org_transaction_level;
1619 #if defined(TEST_AUTO_UPDATE)
1620 #define TEST_UPDATE_OR_EXPECT_TEXTFILES_EQUAL(src,dest) TEST_COPY_FILE(src,dest)
1622 #define TEST_UPDATE_OR_EXPECT_TEXTFILES_EQUAL(src,dest) TEST_EXPECT_TEXTFILES_EQUAL(src,dest)
1625 #define SAVE_AND_COMPARE(gbd, save_as, savetype, compare_with) \
1626 TEST_EXPECT_NO_ERROR(GB_save_as(gbd, save_as, savetype)); \
1627 TEST_UPDATE_OR_EXPECT_TEXTFILES_EQUAL(save_as, compare_with)
1629 #define SAVE_AND_COMPARE__BROKEN(gbd, save_as, savetype, compare_with) \
1630 TEST_EXPECT_NO_ERROR(GB_save_as(gbd, save_as, savetype)); \
1631 TEST_EXPECT_FILES_EQUAL__BROKEN(save_as, compare_with)
1648 #define TEST_loadsave_CLEANUP() TEST_EXPECT_ZERO(system("rm -f [abr]2[ab]*.* master.* slave.* renamed.* fast.* fast2a.* TEST_loadsave.ARF"))
1650 void TEST_SLOW_loadsave() {
1652 TEST_loadsave_CLEANUP();
1655 TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(
GB_open(
"nonexisting.arb",
"r"),
"'nonexisting.arb' not found");
1656 TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(
GB_open(
"nonexisting.arb",
"rw"),
"'nonexisting.arb' not found");
1659 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_new =
GB_open(
"nonexisting.arb",
"w"));
1664 const char *bin_db =
"TEST_loadsave.arb";
1665 const char *asc_db =
"TEST_loadsave_ascii.arb";
1668 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_asc =
GB_open(asc_db,
"rw"));
1670 #if defined(TEST_AUTO_UPDATE)
1672 #endif // TEST_AUTO_UPDATE
1675 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_bin =
GB_open(bin_db,
"rw"));
1678 SAVE_AND_COMPARE(gb_asc,
"a2a.arb",
"a", asc_db);
1679 SAVE_AND_COMPARE(gb_asc,
"a2b.arb",
"b", bin_db);
1680 SAVE_AND_COMPARE(gb_bin,
"b2a.arb",
"a", asc_db);
1681 SAVE_AND_COMPARE(gb_bin,
"b2b.arb",
"b", bin_db);
1686 int successful_compressed_saves = 0;
1687 for (
int c = 0; compFlag[c]; ++c) {
1688 for (
char dbtype =
'a'; dbtype<=
'b'; ++dbtype) {
1692 char savetype[] =
"??";
1693 savetype[0] = dbtype;
1694 savetype[1] = compFlag[c];
1697 if (error && strstr(error,
"failed with exitcode=127")) {
1698 fprintf(stderr,
"Assuming compression utility for flag '%c' is not installed\n", compFlag[c]);
1708 SAVE_AND_COMPARE(gb_reloaded,
"r2b.arb",
"b", bin_db);
1709 SAVE_AND_COMPARE(gb_reloaded,
"r2a.arb",
"a", asc_db);
1713 successful_compressed_saves++;
1722 #if (MEMORY_TEST == 0)
1725 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_nomap =
GB_open(bin_db,
"rw"));
1734 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_map =
GB_open(
"fast.arb",
"rw"));
1738 SAVE_AND_COMPARE(gb_map,
"fast2a.arb",
"a", asc_db);
1765 #if defined(TEST_AUTO_UPDATE)
1766 TEST_COPY_FILE(
"a2b.a00",
"TEST_loadsave_quick.a00");
1767 #endif // TEST_AUTO_UPDATE
1780 const char *mod_db =
"a2b_modified.arb";
1785 SAVE_AND_COMPARE(gb_quickload,
"a2b_quickloaded.arb",
"a", mod_db);
1834 TEST_loadsave_CLEANUP();
1837 #define TEST_quicksave_CLEANUP() TEST_EXPECT_ZERO(system("rm -f min_bin.a[0-9]* min_bin.ARF"))
1839 inline bool quicksave_exists(
int i) {
1840 const char *qsformat =
"min_bin.a%02i";
1843 inline bool quicksave_missng(
int i) {
return !quicksave_exists(i); }
1844 inline bool is_first_quicksave(
int i) {
return quicksave_exists(i) && !quicksave_exists(i-1); }
1845 inline bool is_last_quicksave(
int i) {
return quicksave_exists(i) && !quicksave_exists(i+1); }
1846 inline bool quicksaves_range(
int from,
int to) {
return is_first_quicksave(from) && is_last_quicksave(to); }
1848 #define TEST_QUICK_RANGE(s,e) TEST_EXPECT(quicksaves_range(s,e))
1849 #define TEST_QUICK_GONE(i) TEST_EXPECT(quicksave_missng(i))
1851 void TEST_SLOW_quicksave_names() {
1853 TEST_quicksave_CLEANUP();
1854 const char *bname =
"min_bin.arb";
1861 const char *aname =
"min_ascii.arb";
1869 for (
int i = 0; i <= 100; ++i) {
1872 case 0: TEST_QUICK_RANGE( 0, 0);
break;
1873 case 1: TEST_QUICK_RANGE( 0, 1);
break;
1874 case 10: TEST_QUICK_RANGE( 1, 10);
break;
1875 case 98: TEST_QUICK_RANGE(89, 98);
break;
1876 case 99: TEST_QUICK_RANGE(90, 99);
1879 case 100: TEST_QUICK_RANGE(0, 9);
1880 TEST_QUICK_GONE((i-8));
1881 TEST_QUICK_GONE((i-1));
1895 TEST_quicksave_CLEANUP();
1898 void TEST_db_filenames() {
1903 void TEST_SLOW_corruptedEntries_saveProtection() {
1907 const char *name_NORMAL[] = {
1911 const char *name_CORRUPTED[] = {
1912 "corrupted_CORRUPTED.arb",
1913 "corrupted2_CORRUPTED.arb",
1916 const char *quickname =
"corrupted.a00";
1917 const char *quickname_CORRUPTED =
"corrupted_CORRUPTED.a00";
1918 const char *quickname_unwanted =
"corrupted_CORRUPTED.a01";
1920 const char **name = name_NORMAL;
1922 const char *INITIAL_VALUE =
"initial value";
1923 const char *CHANGED_VALUE =
"changed";
1928 for (
int corruption = 0; corruption<=3; ++corruption) {
1975 char *illegal_access = (
char*)content;
1976 illegal_access[2] = 0;
1985 int len = strlen(CHANGED_VALUE);
1986 for (
int i = 3; i<len; ++i) {
1987 illegal_access[i] = 0;
1993 #ifdef PERFORM_DELETE
2015 full_error =
GB_save(gb_main, name_CORRUPTED[1],
"b");
2017 name = name_CORRUPTED;
2024 for (
int full = 0; full<2; ++full) {
2025 TEST_ANNOTATE(
GBS_global_string(
"corruption level %i / full=%i", corruption, full));
2040 switch (corruption) {
2063 #if defined(PERFORM_DELETE)
2064 bool deleted = corruption>0;
2065 #else // !defined(PERFORM_DELETE)
2066 bool deleted =
false;
2092 TEST_PUBLISH(TEST_SLOW_corruptedEntries_saveProtection);
2094 #endif // UNIT_TESTS
GB_ERROR GB_begin_transaction(GBDATA *gbd)
long last_main_saved_transaction
void gb_put_number(long b0, FILE *out)
GB_CSTR gb_mapfile_name(GB_CSTR path)
GBDATA * GB_open(const char *path, const char *opent)
GB_ERROR GB_commit_transaction(GBDATA *gbd)
void GB_warning(const char *message)
GB_ERROR GB_save_quick(GBDATA *gbd, const char *refpath)
GB_CSTR GB_path_in_arbprop(const char *relative_path)
#define GB_PUT_OUT(c, out)
#define SUPPORTED_COMPRESSION_FLAGS
long GB_read_int(GBDATA *gbd)
GBDATA * GB_child(GBDATA *father)
GB_MAIN_TYPE * gb_main_array[GB_MAIN_ARRAY_SIZE]
char * dates[ALLOWED_DATES]
unsigned int security_read
static GB_CSTR gb_reffile_name(GB_CSTR path)
static int gb_is_writeable(gb_header_list *header, GBDATA *gbd, long version, long diff_save)
GB_ERROR GB_create_directory(const char *path)
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
static GB_ERROR gb_add_reference(const char *master, const char *changes)
static GB_BUFFER gb_bin_2_ascii(GBENTRY *gbe)
#define INSTALL_SIGHANDLER(sig, handler, context)
gb_data_base_type_union info
long GB_mode_of_link(const char *path)
GB_MAIN_TYPE * GB_MAIN(GBDATA *gbd)
void GB_unlink_or_warn(const char *path, GB_ERROR *error)
long GB_mode_of_file(const char *path)
GB_ERROR GB_save_as(GBDATA *gbd, const char *path, const char *savetype)
GBDATA * GB_nextEntry(GBDATA *entry)
int main(int argc, char **argv)
GB_ERROR GB_symlink(const char *target, const char *link)
void GB_disable_quicksave(GBDATA *gbd, const char *reason)
GB_ERROR GB_IO_error(const char *action, const char *filename)
char * ARB_strdup(const char *str)
static GB_ERROR gb_create_reference(const char *master)
GB_ERROR GB_start_streamed_save_as(GBDATA *gbd, const char *path, const char *savetype, ArbDBWriter *&writer)
const char * GBS_global_string(const char *templat,...)
void warning(int warning_num, const char *warning_message)
long GB_getuid_of_file(const char *path)
static bool seen_corrupt_data
CONSTEXPR_INLINE gb_header_list * GB_DATA_LIST_HEADER(gb_data_list &dl)
void cat(const char *from)
void gb_write_out_uint32(uint32_t data, FILE *out)
int GB_unlink(const char *path)
GB_MAIN_TYPE * GBCONTAINER_MAIN(GBCONTAINER *gbc)
GB_CSTR gb_oldQuicksaveName(GB_CSTR path, int nr)
static bool gb_write_one_child(FILE *out, GBDATA *gb, GBCONTAINER *&gb_writeFrom, GBCONTAINER *gb_writeTill, int indent)
GBCONTAINER * root_container
unsigned int last_updated
FILE * ARB_zfopen(const char *name, const char *mode, FileCompressionMode cmode, GB_ERROR &error, bool hideStderr)
GB_ERROR GB_set_time_of_file(const char *path, unsigned long new_time)
#define ARRAY_ELEMS(array)
char buffer[MESSAGE_BUFFERSIZE]
GB_ERROR GB_save_quick_as(GBDATA *gbd, const char *path)
const char * ARB_float_2_ascii(const float f)
GB_ERROR save_as(const char *as_path, const char *savetype)
GB_ERROR GB_delete(GBDATA *&source)
long GB_last_saved_clock(GBDATA *gb_main)
unsigned int last_updated
GB_ERROR save_quick(const char *refpath)
static GB_CSTR gb_overwriteName(GB_CSTR path)
#define TEST_PUBLISH(testfunction)
#define TEST_EXPECT_CONTAINS(str, part)
GB_ERROR GB_await_error()
GBDATA * GB_create_container(GBDATA *father, const char *key)
#define TEST_EXPECT(cond)
void GB_warningf(const char *templat,...)
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
char * quick_save_disabled
GB_BUFFER GB_give_buffer(size_t size)
void GBS_fwrite_string(const char *strngi, FILE *out)
GB_ERROR startSaveAs(const char *given_path_, const char *savetype)
unsigned long GB_time_of_file(const char *path)
GB_ERROR save_quick_as(const char *as_path)
#define RETURN_ERROR(err)
GB_ERROR GB_move_file(const char *oldpath, const char *newpath)
bool is_container() const
#define TEST_REJECT(cond)
#define TEST_REJECT_NULL(n)
static void error(const char *msg)
long gb_read_bin_error(FILE *in, GBDATA *gbd, const char *text)
GB_ULONG GB_time_of_day(void)
GB_CSTR gb_quicksaveName(GB_CSTR path, int nr)
unsigned int security_delete
float GB_read_float(GBDATA *gbd)
static char * gb_full_path(const char *path)
bool GB_is_fifo(const char *path)
static GB_ERROR gb_delete_reference(const char *master)
GBCONTAINER * as_container() const
void * gbm_get_mem(size_t size, long index)
int GB_read_flag(GBDATA *gbd)
GB_ERROR GB_stream_save_part(ArbDBWriter *writer, GBDATA *from, GBDATA *till)
GB_ERROR GB_set_mode_of_file(const char *path, long mode)
GB_ERROR GB_write_int(GBDATA *gbd, long i)
GB_ERROR GB_save(GBDATA *gb, const char *path, const char *savetype)
GB_ERROR GB_delete_database(GB_CSTR filename)
static GB_ERROR gb_remove_all_but_main(GB_MAIN_TYPE *Main, const char *path)
void GB_disable_path(GBDATA *gbd, const char *path)
GB_ERROR GB_print_error()
int get_transaction_level() const
fputs(TRACE_PREFIX, stderr)
unsigned int security_level
GB_ERROR GB_export_errorf(const char *templat,...)
static GB_ERROR renameQuicksaves(GB_MAIN_TYPE *Main)
static GB_ERROR gb_remove_quick_saved(GB_MAIN_TYPE *Main, const char *path)
#define GBTUM_MAGIC_NUMBER
const int GB_MAX_QUICK_SAVE_INDEX
GB_ERROR ARB_zfclose(FILE *fp)
bool GB_is_directory(const char *path)
#define TEST_EXPECT_FILES_EQUAL(f1, f2)
GB_ERROR GB_failedTo_error(const char *do_something, const char *special, GB_ERROR error)
int GB_read_byte(GBDATA *gbd)
char * STATIC_BUFFER(SmartCharPtr &strvar, int minlen)
const char * GBS_static_string(const char *str)
#define GB_MAIN_ARRAY_SIZE
static bool gb_write_childs(FILE *out, GBCONTAINER *gbc, GBCONTAINER *&gb_writeFrom, GBCONTAINER *gb_writeTill, int indent)
static GB_ERROR protect_corruption_error(const char *savepath)
static GB_ERROR deleteSuperfluousQuicksaves(GB_MAIN_TYPE *Main)
const char * GB_get_db_path(GBDATA *gbd)
#define TEST_EXPECT_NO_ERROR(call)
char * gb_findExtension(char *path)
GBENTRY * as_entry() const
GB_CSTR GB_mapfile(GBDATA *gb_main)
long GB_read_clock(GBDATA *gbd)
char * GBS_eval_env(GB_CSTR p)
void GB_split_full_path(const char *fullpath, char **res_dir, char **res_fullname, char **res_name_only, char **res_suffix)
bool GB_is_regularfile(const char *path)
GB_CSTR GB_read_bits_pntr(GBDATA *gbd, char c_0, char c_1)
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
static int gb_write_bin(FILE *out, GBCONTAINER *gbc, uint32_t version)
long last_saved_transaction
#define UNINSTALL_SIGHANDLER(sig, handler, old_handler, context)
const char * get_data() const
const int GBTUM_SHORT_STRING_SIZE
GBDATA * GB_nextChild(GBDATA *child)
GB_transaction ta(gb_var)
static int gb_write_bin_sub_containers(FILE *out, GBCONTAINER *gbc, long version, long diff_save, int is_root)
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
void gbm_free_mem(void *block, size_t size, long index)
GB_ULONG GB_last_saved_time(GBDATA *gb_main)
bool GBS_string_matches(const char *str, const char *expr, GB_CASE case_sens)
const char * GB_KEY(GBDATA *gbd)
ArbDBWriter(GB_MAIN_TYPE *Main_)
char * GB_follow_unix_link(const char *path)
const char * GB_get_supported_compression_flags(bool verboose)
const int GB_MAX_QUICK_SAVES
static long gb_write_bin_rek(FILE *out, GBDATA *gbd, long version, long diff_save, long index_of_master_file)
GB_ERROR gb_save_mapfile(GB_MAIN_TYPE *Main, GB_CSTR path)
GB_ERROR saveFromTill(GBCONTAINER *gb_from, GBCONTAINER *gb_till)
GB_ERROR GB_create_parent_directory(const char *path)
#define STATIC_ASSERT(const_expression)
GB_ERROR GB_finish_stream_save(ArbDBWriter *&writer)
GB_ERROR GB_save_in_arbprop(GBDATA *gb, const char *path, const char *savetype)
#define TEST_EXPECT_EQUAL(expr, want)
GBDATA * GB_entry(GBDATA *father, const char *key)
unsigned int security_write
GBCONTAINER * get_father()
unsigned int compressed_data
long gb_ascii_2_bin(const char *source, GBENTRY *gbe)
char * GBS_global_string_copy(const char *templat,...)
void GB_close(GBDATA *gbd)
GB_write_int const char s