13 #include <netinet/in.h>
35 #define FILESIZE_GRANULARITY 1024 // progress will work with DB files up to 2Tb
50 (*line) += strcspn(*line,
" \t");
55 (*line) += strspn(*line,
" \t");
62 int secr, secw, secd, lu;
65 secr = secw = secd = 0;
68 if (p && p[0] ==
':') {
75 if (secd<0 || secd>7) error =
GBS_global_string(
"Illegal protection level %i", secd);
76 else if (secw<0 || secw>7) error =
GBS_global_string(
"Illegal protection level %i", secw);
77 else if (secr<0 || secr>7) error =
GBS_global_string(
"Illegal protection level %i", secr);
104 while (!error && !done) {
108 char *
line = (
char*)(LINE.c_str());
111 line += strspn(line,
" \t");
114 if (line[0] ==
'/' && line[1] ==
'*') {
115 char *eoc = strstr(line+2,
"*/");
120 error =
"expected '*/'";
125 if (name[0] ==
'%' && name[1] ==
')' && !name[2]) {
127 error =
"Unexpected '%)' (not allowed outside container)";
130 if (line[0] ==
'/' && line[1] ==
'*') {
131 char *eoc = strstr(line+2,
"*/");
133 error =
"expected '*/'";
138 if (strcmp(line, parent_name) != 0) {
140 "Warning: comment at end of container ('%s') does not match name of container ('%s').\n"
141 " (might be harmless if you've edited the file and did not care about these comments)\n",
151 const char *protection =
NULp;
152 if (line[0] ==
':') {
156 bool readAsString =
true;
157 if (line[0] ==
'%') {
158 readAsString =
false;
162 if (type[1] == 0 || type[2] != 0) {
163 error =
GBS_global_string(
"Syntax error in type '%s' (expected %% and 1 more character)", type);
166 if (type[1] ==
'%' || type[1] ==
'$') {
167 if (line[0] ==
'(' && line[1] ==
'%') {
171 char *protection_copy = nulldup(protection);
172 bool marked = type[1] ==
'$';
179 free(protection_copy);
183 error =
"Expected '(%' after '%%'";
190 case 'i': gb_type =
GB_INT;
break;
192 case 'y': gb_type =
GB_BYTE;
break;
193 case 'f': gb_type =
GB_FLOAT;
break;
194 case 'I': gb_type =
GB_BITS;
break;
196 case 'Y': gb_type =
GB_BYTES;
break;
197 case 'N': gb_type =
GB_INTS;
break;
199 case 's': gb_type =
GB_STRING; readAsString =
true;
break;
206 if (!error && !readAsString) {
210 fputs(
"Skipped entry (obsolete type GB_LINK)\n", stderr);
217 case 'i': error =
GB_write_int(gb_new, atoi(line));
break;
221 int len = strlen(line);
227 case 'Y':
if (
gb_ascii_2_bin(line, gb_new)) error =
"syntax error in byte-array";
break;
228 case 'N':
if (
gb_ascii_2_bin(line, gb_new)) error =
"syntax error in int-array";
break;
229 case 'F':
if (
gb_ascii_2_bin(line, gb_new)) error =
"syntax error in float-array";
break;
243 if (line[0] !=
'\"') {
247 char *string_start = line+1;
250 if (!end) error =
"Cannot convert string (contains zero char)";
317 static FILE *old_in =
NULp;
318 static unsigned char *file =
NULp;
319 static long size = 0;
326 if (loading_quick_save) {
331 "(parts of your database might be recoverable using 'arb_repair yourDB.arb newName.arb')\n",
339 GB_export_error(
"Unable to recover from corrupt file (Reason: cannot recover from stream)\n"
340 "Note: if the file is a compressed arb-file, uncompress it manually and retry.");
344 long pos = ftell(in);
350 for (; pos<size-10; pos ++) {
354 for (s = pos + 4; s<size && file[
s]; s++) {
356 if (! (isalnum(c) || isspace(c) || strchr(
"._;:,", c)))
break;
358 if (s< size && s > pos+11 && !file[s]) {
360 return fseek(in, pos, 0);
369 #if defined(DEBUG_READ)
372 printf(
"%*s%s\n", (
int)deep,
"", s);
376 #define DEBUG_DUMP_INDENTED(d, s)
395 GB_warning(
"Now reading to end of file (trying to recover data from broken database)");
399 bool is_quicksave = version != 1;
401 for (
long item = 0; item<nitems; item++) {
402 long type = getc(in);
445 long security = getc(in);
446 long type2 = (type>>4)&0xf;
450 const char *reason =
GBS_global_string(
"database entry with unknown field quark %i", key);
477 if (type2 ==
GB_DB) {
490 if (type2 == (
long)
GB_DB) {
524 if (!fread((
char*)&buffer,
sizeof(
GB_UINT4), 1, in)) {
528 gbe->
info.
i = ntohl(buffer);
533 if (!fread((
char*)&gbe->
info.
i,
sizeof(
float), 1, in)) {
545 for (; size<i; size++) {
546 if (!(*(p++) = getc(in)))
goto shrtstring_fully_loaded;
552 shrtstring_fully_loaded :
569 long i = fread(storage, 1, (
size_t)memsize, in);
587 gbe->
info.
i = getc(in);
608 if (type !=
GB_DB)
continue;
625 if (gb_system)
return;
635 if (!error) error =
GB_delete(gb_oldsystem);
641 gb_assert(strlen(expected_keyword) == 4);
644 bool as_expected = strncmp((
char*)&val, expected_keyword, 4) == 0;
664 while (c && c != EOF) {
678 case 0x01020304: reversed =
false;
break;
679 case 0x04030201: reversed =
true;
break;
687 gb_read_bin_error(in, gbc,
"ARB Database version 0 no longer supported (rev [9647])");
695 if (version == 2 && !allowed_to_load_diff) {
696 GB_export_error(
"This is not a primary arb file, please select the master"
727 printf(
"Warning: Key '%s' exceeds maximum keylength (%i)\n"
728 " Please do NOT create such long keys!\n",
731 if (p == buffer)
break;
740 first_free_key = index;
755 for (k=0; k<256; k++) {
765 if (p == buffer)
break;
766 freedup(Main->
dates[j], buffer);
782 unsigned long time_of_db;
800 case -1: map_fail_reason =
GBS_global_string(
"no FastLoad File '%s' found", map_path);
break;
805 if (time_of_map != time_of_db) {
806 unsigned long diff = time_of_map>time_of_db ? time_of_map-time_of_db : time_of_db-time_of_map;
807 fprintf(stderr,
"Warning: modification times of DB and fastload file differ (DB=%lu fastload=%lu diff=%lu)\n",
808 time_of_db, time_of_map, diff);
811 map_fail_reason =
"modification times of DB and fastload file differ (too much)";
814 fprintf(stderr,
"(accepting modification time difference of %lu seconds)\n", diff);
818 if (!map_fail_reason) {
827 long gbc_index = gbc->
index;
877 for (i=1; i < Main->
keycnt; i++) {
889 GB_internal_errorf(
"Sorry: This ARB Version does not support database format V%li", version);
900 for (i=1; i < Main->
keycnt; i++) {
919 gb_next_main_idx_for_mapfile = idx;
930 if (gb_next_main_idx_for_mapfile<=0) {
937 idx = (
short)gb_next_main_idx_for_mapfile;
938 gb_next_main_idx_for_mapfile = 0;
961 error =
GBS_global_string(
"There is no ARBDB server '%s', please start one or add a filename", db_path);
967 error = initial_client_transaction();
983 return (
id == 0x56430176)
991 const int ASC_HEADER_SIZE = 15;
992 char buffer[ASC_HEADER_SIZE+1];
994 size_t read_bytes = fread(buffer+4, 1, ASC_HEADER_SIZE-4, in);
995 if (read_bytes == (ASC_HEADER_SIZE-4)) {
996 buffer[ASC_HEADER_SIZE] = 0;
998 const char *ascii_header =
"/*ARBDB ASCII*/";
999 uint32_t *ui_buffer = (uint32_t*)buffer;
1001 *ui_buffer = bin_id;
1002 if (strcmp(buffer, ascii_header) == 0)
return true;
1005 if (strcmp(buffer, ascii_header) == 0)
return true;
1053 int ignoreMissingMaster = 0;
1054 int loadedQuickIndex = -1;
1057 bool dbCreated =
false;
1063 if (strchr(path,
':')) {
1069 if (isdigit(ext[6])) {
1070 loadedQuickIndex = atoi(ext+6);
1071 strcpy(ext,
".arb");
1073 if (strchr(opent,
'R')) ignoreMissingMaster = 1;
1080 if (isdigit(extension[2]) && isdigit(extension[3])) {
1081 loadedQuickIndex = atoi(extension+2);
1082 strcpy(extension,
".arb");
1084 if (strchr(opent,
'R')) ignoreMissingMaster = 1;
1097 GB_warning(
"The QuickSave-File with the highest index-number\n"
1098 "is not the NEWEST of your QuickSave-Files.\n"
1099 "If you didn't restore old QuickSave-File from a backup\n"
1100 "please inform your system-administrator - \n"
1101 "this may be a serious bug and you may loose your data.");
1115 if (gb_verbose_mode) {
1116 GB_informationf(
"ARB: Loading '%s'%s%s", path, quickFile ?
" + Changes-File " :
"", null2empty(quickFile));
1146 if (path && (strchr(opent,
'r'))) {
1147 if (strchr(path,
':')) {
1151 int read_from_stdin = strcmp(path,
"-") == 0;
1153 GB_ULONG time_of_main_file = 0;
long i;
1160 if (!input && ignoreMissingMaster) {
1162 goto load_quick_save_file_only;
1166 if (strchr(opent,
'c')) {
1170 if (strchr(opent,
'D')) {
1177 fprintf(stderr,
"file %s not found\n", path);
1181 freeset(path, found_path);
1191 fprintf(stderr,
"Created new database \"%s\".\n", path);
1201 if (strchr(opent,
'D')) {
1202 fprintf(stderr,
"Using properties from '%s'\n", path);
1231 if (gbc && quickFile) {
1234 load_quick_save_file_only :
1238 input = fopen(quickFile,
"rb");
1242 if (time_of_main_file && time_of_quick_file < time_of_main_file) {
1244 " the changes file '%s'\n"
1245 " That is very strange and happens only if files where\n"
1246 " moved/copied by hand\n"
1247 " Your file '%s' may be an old relict,\n"
1248 " if you ran into problems now,delete it",
1249 path, quickFile, quickFile);
1263 "[Fail-Reason: '%s']",
1268 err_msg =
"Wrong file format (not a quicksave file)";
1273 err_msg =
"Can't open file";
1281 "Note: you MAY restore an older version by running arb with:\n"
1282 " arb <name of quicksave-file>",
1283 quickFile, err_msg);
1293 GB_disable_quicksave(gbc,
"Couldn't load last quicksave (your latest changes are NOT included)");
1302 if (input != stdin) {
1304 if (!error) error = close_error;
1307 "Sorry, I cannot save differences to ascii files\n"
1308 " Save whole database in binary mode first");
1340 if (!strchr(opent,
'N')) {
1357 if (gb_verbose_mode && !dbCreated)
GB_informationf(
"ARB: Loading '%s' done\n", path);
1366 return GB_login(path, opent, user);
1376 if (!strchr(name,
':')) {
1408 void TEST_io_number() {
1447 const char *numbers =
"numbers.test";
1452 FILE *out = fopen(numbers,
"wb");
1461 long pos = ftell(out);
1462 long bytes_written = pos-lastPos;
1465 writeSize += bytes_written;
1469 TEST_ANNOTATE(
NULp);
1475 FILE *in = fopen(numbers,
"rb");
1487 long pos = ftell(in);
1488 long bytes_read = pos-lastPos;
1491 readSize += bytes_read;
1495 TEST_ANNOTATE(
NULp);
1506 void TEST_GBDATA_size() {
1520 #else // !defined(ARB_64)
1534 #endif // UNIT_TESTS
GB_ERROR GB_begin_transaction(GBDATA *gbd)
static long gb_recover_corrupt_file(GBCONTAINER *gbc, FILE *in, GB_ERROR recovery_reason, bool loading_quick_save)
GB_ERROR GB_copy_dropProtectMarksAndTempstate(GBDATA *dest, GBDATA *source)
void gb_put_number(long b0, FILE *out)
int allow_corrupt_file_recovery
long GB_size_of_FILE(FILE *in)
GB_CSTR gb_mapfile_name(GB_CSTR path)
GB_ERROR GB_write_bits(GBDATA *gbd, const char *bits, long size, const char *c_0)
GBDATA * GB_open(const char *path, const char *opent)
GB_ERROR GB_commit_transaction(GBDATA *gbd)
void GB_warning(const char *message)
GBDATA * GB_child(GBDATA *father)
GB_MAIN_TYPE * gb_main_array[GB_MAIN_ARRAY_SIZE]
#define implicated(hypothesis, conclusion)
char * dates[ALLOWED_DATES]
unsigned int security_read
bool getLine(string &line)
void GB_set_next_main_idx(long idx)
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
const char * quark2key(GB_MAIN_TYPE *Main, GBQUARK key_quark)
long gb_get_number(FILE *in)
gb_data_base_type_union info
long GB_mode_of_link(const char *path)
GB_MAIN_TYPE * GB_MAIN(GBDATA *gbd)
void insert_data(const char *Data, long Size, long Memsize)
bool search_system_folder
static long gb_read_bin(FILE *in, GBCONTAINER *gbc, bool allowed_to_load_diff, arb_progress &progress)
unsigned int folded_container
long gb_create_key(GB_MAIN_TYPE *Main, const char *key, bool create_gb_key)
void GB_disable_quicksave(GBDATA *gbd, const char *reason)
#define ASSERT_RESULT(Type, Expected, Expr)
char * ARB_strdup(const char *str)
GB_ERROR gb_convert_V2_to_V3(GBDATA *gb_main)
void GB_internal_errorf(const char *templat,...)
const char * GBS_global_string(const char *templat,...)
void warning(int warning_num, const char *warning_message)
GB_NUMHASH * GBS_create_numhash(size_t estimated_elements)
void GBK_terminatef(const char *templat,...)
static void gb_search_system_folder(GBDATA *gb_main)
CONSTEXPR_INLINE gb_header_list * GB_DATA_LIST_HEADER(gb_data_list &dl)
static long gb_next_main_idx_for_mapfile
static GB_ERROR gb_read_ascii_beyond_header(FILE *in, const char *path, GBCONTAINER *gbc)
int GB_unlink(const char *path)
GB_MAIN_TYPE * GBCONTAINER_MAIN(GBCONTAINER *gbc)
GB_CSTR gb_oldQuicksaveName(GB_CSTR path, int nr)
GB_MAIN_IDX gb_make_main_idx(GB_MAIN_TYPE *Main)
GBCONTAINER * root_container
long GB_size_of_file(const char *path)
unsigned int last_updated
FILE * ARB_zfopen(const char *name, const char *mode, FileCompressionMode cmode, GB_ERROR &error, bool hideStderr)
#define ARRAY_ELEMS(array)
static void gb_delete_entry(GBCONTAINER *&gbc)
char buffer[MESSAGE_BUFFERSIZE]
static GB_ERROR init_tmp_branch(GBDATA *gb_main)
GB_ERROR error_if_aborted()
static GBDATA * gb_search_system_folder_rek(GBDATA *gbd)
static int gb_verbose_mode
GB_ERROR GB_delete(GBDATA *&source)
void GBT_install_message_handler(GBDATA *gb_main)
unsigned int last_updated
#define TEST_PUBLISH(testfunction)
#define DEBUG_DUMP_INDENTED(d, s)
const int GB_REMOTE_HASH_SIZE
GB_ERROR GB_export_error(const char *error)
static GB_ERROR gb_parse_ascii_rek(LineReader &r, GBCONTAINER *gb_parent, const char *parent_name)
size_t getLineNumber() const
GB_ERROR GB_await_error()
uint32_t reverse_byteorder(uint32_t val)
static int diff(int v1, int v2, int v3, int v4, int st, int en)
GB_ERROR gb_unfold(GBCONTAINER *gbc, long deep, int index_pos)
GB_TYPES GB_read_type(GBDATA *gbd)
bool has_ascii_db_id(uint32_t bin_id, FILE *in)
GB_ERROR GB_install_pid(int mode)
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
char * GB_property_file(bool warn_when_not_found, const char *filename)
char * GB_map_FILE(FILE *in, int writeable)
GB_HASH * key_2_index_hash
GB_BUFFER GB_give_buffer(size_t size)
unsigned long GB_time_of_file(const char *path)
GB_ERROR login_remote(const char *db_path, const char *opent) __ATTR__USERESULT
gb_scan_quicks_types type
#define TEST_REJECT_NULL(n)
static void error(const char *msg)
GB_ERROR gb_scan_directory(char *basename, gb_scandir *sd)
long gb_read_bin_error(FILE *in, GBDATA *gbd, const char *text)
int gb_is_valid_mapfile(const char *path, gb_map_header *mheader, int verbose)
GB_CSTR gb_quicksaveName(GB_CSTR path, int nr)
#define GBTUM_MAGIC_REVERSED
unsigned int security_delete
bool GB_is_fifo(const char *path)
GBCONTAINER * as_container() const
#define TEST_EXPECT_ZERO_OR_SHOW_ERRNO(iocond)
void gb_create_header_array(GBCONTAINER *gbc, int size)
static long gb_read_bin_rek_V2(FILE *in, GBCONTAINER *gbc_dest, long nitems, long version, long reversed, long deep, arb_progress &progress)
CONSTEXPR_INLINE GBCONTAINER * GB_FATHER(GBDATA *gbd)
GB_ERROR GB_write_float(GBDATA *gbd, float f)
GB_ERROR GB_write_int(GBDATA *gbd, long i)
GB_ERROR GB_print_error()
GBENTRY * gb_make_entry(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq, GB_TYPES type)
static GBDATA * GB_login(const char *cpath, const char *opent, const char *user)
GB_ERROR GB_set_temporary(GBDATA *gbd) __ATTR__USERESULT
fputs(TRACE_PREFIX, stderr)
unsigned int security_level
GB_ERROR GB_export_errorf(const char *templat,...)
BufferedPipeReader(const string &pipename, FILE *in)
void GB_internal_error(const char *message)
CONSTEXPR_INLINE_Cxx14 void SET_GB_FATHER(GBDATA *gbd, GBCONTAINER *father)
GBCONTAINER * gb_make_container(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq)
#define FILESIZE_GRANULARITY
#define GBTUM_MAGIC_NUMBER
void GB_write_flag(GBDATA *gbd, long flag)
static const char * getToken(char **line)
GB_BUFFER GB_increase_buffer(size_t size)
GB_ERROR ARB_zfclose(FILE *fp)
GB_CSTR GB_getenvUSER(void)
void touch_creation_and_update(long date)
long quark2gbmindex(GB_MAIN_TYPE *Main, GBQUARK key_quark)
GB_ERROR GB_write_byte(GBDATA *gbd, int i)
GB_ERROR gbcm_logout(GB_MAIN_TYPE *Main, const char *loginname)
GB_ERROR gb_resort_system_folder_to_top(GBCONTAINER *gb_main)
#define GB_MAIN_ARRAY_SIZE
float GB_atof(const char *str)
const char * GB_get_db_path(GBDATA *gbd)
bool read_keyword(const char *expected_keyword, FILE *in, GBCONTAINER *gbc)
char * GBS_fconvert_string(char *buffer)
char * gb_findExtension(char *path)
NOT4PERL int GB_give_buffer_size(void)
static GB_ERROR gb_parse_ascii(LineReader &r, GBCONTAINER *gb_parent)
GBENTRY * as_entry() const
bool GB_is_regularfile(const char *path)
bool is_binary_db_id(int id)
void GB_informationf(const char *templat,...)
gbcmc_comm * gbcmc_open(const char *path)
bool ARB_strBeginsWith(const char *str, const char *with)
const int GBTUM_SHORT_STRING_SIZE
GBDATA * GB_nextChild(GBDATA *child)
void gbm_free_mem(void *block, size_t size, long index)
bool GBS_string_matches(const char *str, const char *expr, GB_CASE case_sens)
GB_ERROR GBT_check_arb_file(const char *name)
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
char * GB_follow_unix_link(const char *path)
GBDATA * gb_map_mapfile(const char *path)
#define TEST_EXPECT_EQUAL(expr, want)
uint32_t gb_read_in_uint32(FILE *in, bool reversed)
GBDATA * GB_entry(GBDATA *father, const char *key)
unsigned int security_write
static GB_ERROR set_protection_level(GB_MAIN_TYPE *Main, GBDATA *gbd, const char *p)
GB_ERROR gbcm_login(GBCONTAINER *gb_main, const char *loginname)
unsigned int compressed_data
long gb_ascii_2_bin(const char *source, GBENTRY *gbe)
GBCONTAINER * dummy_father
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
void gb_delete_dummy_father(GBCONTAINER *&gbc)
GB_ERROR gb_load_key_data_and_dictionaries(GB_MAIN_TYPE *Main)
GB_write_int const char s