1 #ifdef COPYRIGHT_INFORMATION
2 #include "gplv3.h"
3 #endif
4 /*
5  * Copyright (C) 2002-2016 Edscott Wilson Garcia
6  * EMail: edscott@imp.mx
7  *
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation.
22  */
23 
24 // This file contains definitions of static functions
25 // No exported functions or symbols should be in this file.
26 
27 
28 static int open_timeout = 0;
29 static pthread_mutex_t new_mutex = PTHREAD_MUTEX_INITIALIZER;
30 
31 static int sdbh_writeheader (DBHashTable * dbh, int flush);
32 static int sdbh_updateBranch (DBHashTable *, FILE_POINTER);
33 static unsigned char sdbh_readBranches (DBHashTable *, FILE_POINTER);
34 
35 static FILE_POINTER *sdbh_locate (DBHashTable *, FILE_POINTER *);
36 static FILE_POINTER *sdbh_locateTop (DBHashTable *, FILE_POINTER *, int);
37 static FILE_POINTER *sdbh_locateFind (DBHashTable *, FILE_POINTER *, int);
38 static void sdbh_cuenta (unsigned char *, unsigned char, FILE_POINTER);
39 static FILE_POINTER sdbh_write (char, DBHashTable *, unsigned char);
40 static int sdbh_read (char, DBHashTable *, unsigned char);
41 static int sdbh_readheader (DBHashTable *);
42 
43 #ifdef TURN
44 static FILE_POINTER sdbh_turnaround (FILE_POINTER);
45 #endif
46 static FILE_POINTER sdbh_z (unsigned char, unsigned char);
47 static unsigned char sdbh_cuantumR (FILE_POINTER, unsigned char, FILE_POINTER *);
48 static unsigned char sdbh_cuantum (FILE_POINTER, unsigned char, FILE_POINTER *);
49 static void sdbh_cifra (unsigned char *, unsigned char, unsigned char, FILE_POINTER *);
50 
51 static int sdbh_reversebarre (DBHashTable *, FILE_POINTER, int);
52 static int sdbh_barre (DBHashTable *, FILE_POINTER, int);
53 
54 static void sdbh_transfer (DBHashTable *);
55 static DBHashTable *sdbh_open_S (const char *, int, int);
56 
57 static int sdbh_size (DBHashTable *, FILE_POINTER);
58 
59 #ifdef PARALLEL_SAFE
60 static char *lock_name(const char *archivo);
61 #endif
62 
63 /*************************************************************************/
my_open(const char * filename,int flags)64 static int my_open(const char *filename, int flags){
65 #ifndef HAVE_WINDOWS_H
66     if (flags & O_CREAT) return open(filename, flags, 0640);
67     return open(filename, flags);
68 #else
69     if (flags & O_CREAT) return open(filename, flags|_O_BINARY, 0640);
70     return open(filename, flags|_O_BINARY);
71 #endif
72 }
73 
74 #if 0
75 // Faster without this.
76 static int
77 sync_fd (int fd) {
78     /*if (fsync(fd) < 0) {
79        // this should not happen, really.
80        ERR("fsync(): %s\n", strerror(errno));
81        return 0;
82        } */
83     return 1;
84 }
85 #endif
86 
87 static int
advance_fp(DBHashTable * dbh,FILE_POINTER offset)88 advance_fp (DBHashTable * dbh, FILE_POINTER offset) {
89     //if (!sync_fd(dbh->fd)) return 0;
90     if(lseek (dbh->fd, (off_t) offset, SEEK_CUR) < 0) {
91         errno = EBADF;
92         ERR( "Error: advance_fp failed to advance fp %lld\n", (long long)offset);
93         return 0;
94     }
95     return 1;
96 }
97 
98 static int
place_fp_at(DBHashTable * dbh,off_t seek)99 place_fp_at (DBHashTable * dbh, off_t seek) {
100     //if (!sync_fd(dbh->fd)) return 0;
101     if(lseek (dbh->fd, (off_t) seek, SEEK_SET) != seek) {
102         // this should not happen...
103         errno = EBADF;
104 	ERR( "Error: sdbh_locate() cannot place file pointer at bof=0x%llu\n", (long long unsigned)seek);
105         return 0;
106     }
107     return 1;
108 }
109 
110 static FILE_POINTER
place_eof(DBHashTable * dbh)111 place_eof (DBHashTable * dbh) {
112     //if (!sync_fd(dbh->fd)) return 0;
113     FILE_POINTER eof;
114     eof = (FILE_POINTER) lseek (dbh->fd, (off_t) 0L, SEEK_END);
115     if(eof < sizeof (dbh_header_t)) {
116         errno = EBADF;
117         ERR( "Error: tell_eof() <  sizeof (dbh_header_t)\n");
118         eof = -1;
119     }
120     if(eof < 0) {
121         // this should not happen...
122         errno = EBADF;
123         ERR( "Error: tell_eof() cannot place file pointer at eof\n");
124     }
125     return eof;
126 }
127 
128   /* Funciones nivel 0: */
129 static void
sdbh_operate(DBHashTable * dbh)130 sdbh_operate (DBHashTable * dbh) {
131     if(dbh == NULL) {
132         ERR ("Must define function operate(place*) before doing a sweep\n");
133     }
134 }
135 
136 static char *
sdbh_randomfilename(DBHashTable * dbh,char code)137 sdbh_randomfilename (DBHashTable * dbh, char code) {
138     time_t segundos;
139     FILE_POINTER divisor;
140     char *archivo;
141     const char *tmpdir;
142     if(!dbh) return NULL;
143     // determine best tmp directory
144     if(dbh->head_info->user_tmpdir == 0) {
145         struct stat dbh_st, tmp_st;
146         if (stat (dbh->path, &dbh_st) < 0){
147             ERR("Unable to stat: %s\n", dbh->path);
148             return NULL;
149         }
150 #ifdef HAVE_WINDOWS_H
151         const char * tmp = getenv("TEMP");
152 	if (!tmp || access(tmp,W_OK) < 0) tmp ="c:\\";
153 #else
154         const char *tmp = "/tmp";
155 #endif
156 
157         if (stat (tmp, &tmp_st) < 0){
158             ERR("Unable to stat: %s\n", tmp);
159             return NULL;
160         }
161 	if (dbh->tmpdir) {
162                 free(dbh->tmpdir);
163         }
164         dbh->tmpdir = NULL;
165         // Make sure tmp dir is on same device.
166         DBG("system temp dir is %s \n", tmp);
167         if(dbh_st.st_dev == tmp_st.st_dev) {
168             dbh->tmpdir = (char *)malloc (strlen (tmp) + 1);
169 	    if (dbh->tmpdir == NULL) {
170 		 ERR( "malloc dbh->tmpdir: %s\n", strerror(errno));
171                  return NULL;
172 	    }
173 	    strcpy (dbh->tmpdir, tmp);
174         } else {
175             // system tmp dir is not on the same device.
176 #ifdef HAVE_WINDOWS_H
177             dbh->tmpdir = (char *)malloc (strlen (tmp) + 1);
178 	    strcpy (dbh->tmpdir, tmp);
179 #else
180             if (*(dbh->path) =='/') {
181                 dbh->tmpdir = (char *)malloc (strlen (dbh->path) + 1);
182 	        if (dbh->tmpdir == NULL) {
183 		   ERR( "malloc dbh->tmpdir: %s\n", strerror(errno));
184                    return NULL;
185                 }
186         	strcpy (dbh->tmpdir, dbh->path);
187                 *(strrchr(dbh->tmpdir, '/')) = 0;
188             } else {
189                 dbh->tmpdir = (char *)malloc (1024);
190 	        if (dbh->tmpdir == NULL) {
191 		   ERR( "malloc dbh->tmpdir: %s\n", strerror(errno));
192                    return NULL;
193                 }
194                 if (!getcwd(dbh->tmpdir, 1024)){
195 		   ERR( "!getcwd: %s\n", strerror(errno));
196                    return NULL;
197                 }
198             }
199 #endif
200         }
201     }
202     tmpdir = dbh->tmpdir;
203 
204     time (&segundos);
205     int try=0;
206 retry:
207     srand ((unsigned)segundos);
208     divisor = RAND_MAX / 10000;
209     // Usage of rand is not security related. Just to get a random temporary file name.
210     // coverity[dont_call : FALSE]
211     if((segundos = rand () / divisor) > 100000L)
212         segundos = 50001;
213     archivo = (char *)malloc (strlen (tmpdir) + 1 + 1 + 6 + 4 + 1);
214     if (archivo == NULL) {
215 	 ERR( "malloc filename: %s\n", strerror(errno));
216          return NULL;
217     }
218 #ifdef HAVE_WINDOWS_H
219     sprintf (archivo, "%s%c%c%ld.tmp", tmpdir, '\\', code, (long)segundos);
220 #else
221     sprintf (archivo, "%s/%c%ld.tmp", tmpdir, code, (long)segundos);
222 #endif
223 
224     // if the file exists (fat chance), retry with a different random number...
225     struct stat st;
226     if (stat(archivo, &st)==0){
227 	if (segundos > 0) segundos--;
228 	else segundos++;
229 	if (try++ < 3) {
230 	    free(archivo);
231             goto retry;
232         }
233 	free(archivo);
234 	return NULL;
235     }
236 
237     return archivo;
238 }  /*******************************************************************************/
239 
240 #if 0
241 this is unreliable in Linux...
242 //mode=1 --> write lock
243 static void
244 lock_fd (int fd, int mode, const char *archivo) {
245     //  return;
246     // get the file lock, wait if necesary:
247     struct flock lock;
248 
249     lock.l_whence = SEEK_SET;
250     lock.l_start = 0;
251     lock.l_len = 0;             // to eof
252 
253     if(mode) {
254         lock.l_type = F_WRLCK;
255     } else {
256         lock.l_type = F_RDLCK;
257     }
258 
259     int try=0;
260 retry:
261     if(fcntl (fd, F_SETLKW, &lock) < 0) {
262 	if (try++ < 3) {
263 	    sleep(1);
264 	    goto retry;
265 	}
266         DBG( "fcntl(F_SETLKW)(%s): %s\n", archivo, strerror (errno));
267     }
268 }
269 
270 static void
271 unlock (int fd) {
272 
273 
274     // release the lock:
275     struct flock lock;
276 
277     lock.l_whence = SEEK_SET;
278     lock.l_start = 0;
279     lock.l_len = 0;             // to eof
280 
281     lock.l_type = F_UNLCK;
282     int try=0;
283 retry:
284     if(fcntl (fd, F_SETLKW, &lock) < 0) {
285 	if (try++ < 3) {
286 	    sleep(1);
287 	    goto retry;
288 	}
289         DBG( "fcntl(F_SETLKW): %s\n", strerror (errno));
290     }
291 }
292 #endif
293 
294 
295   /* Functions: ************************************************************** */
296 static unsigned char
sdbh_readBranches(DBHashTable * dbh,FILE_POINTER seek)297 sdbh_readBranches (DBHashTable * dbh, FILE_POINTER seek) {
298     FILE_POINTER *rama;
299     unsigned char ramas;
300     rama = dbh->newbranch;
301     TRACE ("sdbh_readBranches\n");
302 
303     if(!place_fp_at (dbh, (off_t)seek)){
304         return 0;
305     }
306     if(read (dbh->fd, &ramas, 1) != 1) {
307         ERR ("sdbh_readBranches error 3.1\n");
308         return 0;
309     }
310     if (ramas > dbh->head_info->n_limit){
311         ERR ("Corrupted loop boundary \"ramas\"\n");
312         return 0;
313     }
314     DBG ("sdbh_readBranches ramas=%lld\n", (long long)ramas);
315     if(!advance_fp (dbh, 1L + sizeof (FILE_POINTER))) {
316         return 0;
317     }
318 
319     if(read (dbh->fd, rama, sizeof (FILE_POINTER) * ramas) != sizeof (FILE_POINTER) * ramas) {
320         ERR ("sdbh_readBranches error 3.2\n");
321         return 0;
322     }
323     DBG ("read:");
324     int i;
325     for(i = 0; i < ramas; i++){
326         DBG (" rama[%d]=0x%llu\n", i, (long long unsigned)(rama[i]));
327     }
328 #ifdef TURN
329     {
330         int i;
331         for(i = 0; i < ramas; i++)
332             rama[i] = sdbh_turnaround (rama[i]);
333     }
334 #endif
335     return ramas;
336 } /***************************************************/
337 
338 static int
sdbh_updateBranch(DBHashTable * dbh,FILE_POINTER seek)339 sdbh_updateBranch (DBHashTable * dbh, FILE_POINTER seek) {
340     TRACE ("sdbh_updateBranch\n");
341     FILE_POINTER *rama;
342     unsigned char ramas;
343     rama = dbh->newbranch;
344     if(!place_fp_at (dbh, (off_t)seek)) {
345         return 0;
346     }
347     if(read (dbh->fd, &ramas, 1) != 1) {
348         ERR ("sdbh_updateBranch read error 4.1\n");
349         return 0;
350     }
351 
352     if(!advance_fp (dbh, 1L + sizeof (FILE_POINTER))){
353         return 0;
354     }
355 
356 #ifdef TURN
357     {
358         int i;
359         for(i = 0; i < ramas; i++)
360             rama[i] = sdbh_turnaround (rama[i]);
361     }
362 #endif
363     DBG ("Updating branch information for new record:");
364     int i;
365     if (ramas > dbh->head_info->n_limit){
366         ERR ("Corrupted loop boundary \"ramas\"\n");
367         return 0;
368     }
369     for(i = 0; i < ramas; i++){
370         DBG (" rama[%d]=0x%llu\n", i, (long long unsigned)(rama[i]));
371     }
372 
373     if(write (dbh->fd, rama, sizeof (FILE_POINTER) * ramas) != sizeof (FILE_POINTER) * ramas) {
374         ERR ("sdbh_updateBranch write error 4.2\n");
375         return 0;
376     }
377 #ifdef TURN
378     {
379         int i;
380         for(i = 0; i < ramas; i++)
381             rama[i] = sdbh_turnaround (rama[i]);
382     }
383 #endif
384     return 1;
385 }  /*****************************************************/
386 
387 #define BRANCHOFF (dbh->head_info->n_limit-dbh->newbranches)
388 #define CURRENTSEEK fp[0]
389 #define LASTSEEK fp[1]
390 #define CURR_BRANCH fp[2]
391 #define SWITCHED (dbh->head_info->reservedD)
392 //FILE_POINTER *fp must have size = 3
393 static FILE_POINTER *
sdbh_locate(DBHashTable * dbh,FILE_POINTER * fp)394 sdbh_locate (DBHashTable * dbh, FILE_POINTER * fp) {
395     TRACE ("sdbh_locate\n");
396     FILE_POINTER currentseek,
397       lastseek;
398     int i;                      /*,offset; */
399     lastseek = currentseek = 0;
400     CURRENTSEEK = LASTSEEK = CURR_BRANCH = 0;   /* ERROR value assigned */
401     currentseek = dbh->head_info->bof;
402 
403     if(!place_fp_at (dbh, (off_t)currentseek)) {
404         return NULL;
405     }
406 
407     if(!sdbh_read (NEW, dbh, 1)) {
408         return fp;
409     }
410   loop:
411 #define OFFSET (i+(dbh->head_info->n_limit-dbh->newbranches))
412     for(i = 0; i < dbh->newbranches; i++) {
413         if(*(dbh->key + OFFSET) != *(dbh->newkey + OFFSET))
414         {
415             lastseek = currentseek;
416             if((currentseek = *(dbh->newbranch + i)) == 0) {
417                 CURR_BRANCH = i;
418                 break;
419             }
420             if(!place_fp_at (dbh, (off_t)currentseek)) {
421                 return NULL;
422             }
423             if(!sdbh_read (NEW, dbh, 1)) {
424                 return fp;
425             }
426             goto loop;
427         }
428     }
429     CURRENTSEEK = currentseek;
430     LASTSEEK = lastseek;
431     return fp;
432 }
433 
434 static FILE_POINTER *
sdbh_locateTop(DBHashTable * dbh,FILE_POINTER * fp,int key_length)435 sdbh_locateTop (DBHashTable * dbh, FILE_POINTER * fp, int key_length) {
436     TRACE ("sdbh_locateFind\n");
437     FILE_POINTER currentseek,
438       lastseek;
439     int i;
440     lastseek = currentseek = 0;
441     CURRENTSEEK = LASTSEEK = CURR_BRANCH = 0;   /* ERROR value assigned */
442     currentseek = dbh->head_info->bof;
443 
444     if(!place_fp_at (dbh, (off_t)currentseek)) {
445         return NULL;
446     }
447 
448     if(!sdbh_read (NEW, dbh, 1)) {
449         return fp;
450     }
451     if (key_length > dbh->newbranches) key_length = dbh->newbranches;
452 //        fprintf(stderr, "*branch %d: newkey=%s branches=%d\n", 0, dbh->newkey, dbh->newbranches);
453 //        fprintf(stderr, "looking for %s ...\n", dbh->key);
454 
455     FILE_POINTER addr[key_length];
456     memcpy(addr, dbh->newbranch, key_length*sizeof(FILE_POINTER));
457     if (memcmp((void *)(dbh->key), (void *)(dbh->newkey), key_length) == 0){
458         CURRENTSEEK = currentseek;
459         return fp;
460     }
461 
462     int j=0;
463 loop:
464     for (i=0; i<key_length; i++){
465 //        fprintf(stderr, "%d) %c ?= %c\n", j, *(dbh->key + j),*(dbh->newkey + OFFSET));
466         if (*(dbh->key + j) != *(dbh->newkey + OFFSET)){
467             if (!dbh->newbranch[i]) return NULL; // no next node
468             // otherwise, read next node:
469 //            fprintf(stderr, "next branch %d: (addr:%p)\n", i, dbh->newbranch[i]);
470             lastseek = currentseek;
471             currentseek = dbh->newbranch[i];
472             if(!place_fp_at (dbh, (off_t)currentseek)) {
473                 return NULL;
474             }
475             if(!sdbh_read (NEW, dbh, 1)) {
476                 return NULL;
477             }
478             if (memcmp((void *)(dbh->key), (void *)(dbh->newkey), key_length) == 0) {
479                 //fprintf(stderr, "branch %d: (addr:%p) newkey=%s newbranches=%d\n", i,  dbh->newbranch[i], dbh->newkey, dbh->newbranches);
480                 CURRENTSEEK = currentseek;
481                 //fprintf(stderr, "fp: %p %p %p\n", fp[0], fp[1], fp[2]);
482                 return fp;
483             }
484             goto loop;
485         }
486         j++;
487     }
488     return NULL;
489 }
490 
491 static FILE_POINTER *
sdbh_locateFind(DBHashTable * dbh,FILE_POINTER * fp,int keys)492 sdbh_locateFind (DBHashTable * dbh, FILE_POINTER * fp, int keys) {
493     TRACE ("sdbh_locateFind\n");
494     FILE_POINTER currentseek,
495       lastseek;
496     int i;
497     lastseek = currentseek = 0;
498     CURRENTSEEK = LASTSEEK = CURR_BRANCH = 0;   /* ERROR value assigned */
499     currentseek = dbh->head_info->bof;
500 
501     if(!place_fp_at (dbh, (off_t)currentseek)) {
502         return NULL;
503     }
504 
505     if(!sdbh_read (NEW, dbh, 1)) {
506         return fp;
507     }
508     if(keys > dbh->head_info->n_limit)
509         keys = dbh->head_info->n_limit;
510   loop:
511     for(i = 0; i < dbh->newbranches - (dbh->head_info->n_limit - keys); i++) {
512         /*  offset=i+(dbh->head_info->n_limit-dbh->newbranches); */
513         if(*(dbh->key + OFFSET) != *(dbh->newkey + OFFSET)) {
514             lastseek = currentseek;
515             if((currentseek = *(dbh->newbranch + i)) == 0) {
516                 CURR_BRANCH = i;
517                 break;
518             }
519             if(!place_fp_at (dbh, (off_t)currentseek)) {
520                 return NULL;
521             }
522             if(!sdbh_read (NEW, dbh, 1)) {
523                 return fp;
524             }
525             goto loop;
526         }
527     }
528     CURRENTSEEK = currentseek;
529     LASTSEEK = lastseek;
530     return fp;
531 }
532 
533 #ifdef PARALLEL_SAFE
lock_name(const char * archivo)534 static char *lock_name(const char *archivo){
535     if (!archivo || strlen(archivo)==0){
536  	ERR("Cannot determine lock name for %s\n",
537 		(archivo)?archivo:"NULL");
538 	return NULL;
539    }
540 
541     char *path;
542 
543 #ifdef HAVE_REALPATH
544     path = realpath(archivo, NULL);
545     if (!path) {
546         ERR( "realpath(%s): %s\n", archivo, strerror(errno));
547     }
548 #else
549     path = (char *)malloc(strlen(archivo)+1);
550     if (path) strcpy(path, archivo);
551 #endif
552 
553     if (!path){
554         ERR( "1.malloc path %s: %s\n", path, strerror(errno));
555         return NULL;
556     }
557 
558 
559     // Get inode information:
560     struct stat st;
561     if (stat(path, &st) < 0){
562 	// This is a valid return value.
563 	NOOP("Cannot stat %s: %s\n", path, strerror(errno));
564 	free(path);
565 	return NULL;
566     }
567 
568     // Build shm_name
569     char buffer[1024];
570     memset(buffer, 0, 1024);
571     sprintf(buffer, "/%d-%d", (int)st.st_dev, (int)st.st_ino);
572 
573     char *shm_name = (char *)malloc((strlen(buffer)+1)*sizeof(char));
574     if (!shm_name) {
575  	ERR("Cannot malloc lock name for %s\n", path);
576 	return NULL;
577    }
578     memset(shm_name, 0, strlen(buffer)+1);
579     sprintf(shm_name, "%s", buffer);
580     free(path);
581     return shm_name;
582 }
583 
sem_name(const char * archivo)584 static char *sem_name(const char *archivo){
585     char *untagged_name = lock_name(archivo);
586     if (!untagged_name) return NULL;
587     char *name = (char *)malloc((strlen(untagged_name)+strlen("-ns")+1)*sizeof(char));
588     if (!name){
589         errno=ENOMEM;
590         free(untagged_name);
591         return NULL;
592     }
593     sprintf(name, "%s-ns", untagged_name);
594     free(untagged_name);
595     return name;
596 }
597 
598 
599 
600 
601 
602 #endif
603 
604 static dbh_lock_t *
open_shm_lock(const char * archivo)605 open_shm_lock(const char *archivo){
606 #ifndef PARALLEL_SAFE
607     return NULL;
608 #else
609     char *shm_name=lock_name(archivo);
610     if (!shm_name){
611 	// This would indicate something is wrong...
612 	ERR("Cannot get lock name for %s\n",
613 		archivo);
614 	return NULL;
615     }
616 
617     int fd = shm_open (shm_name, O_RDWR, S_IRUSR | S_IWUSR);
618     if (fd > 0){
619 	NOOP("Lockfile exists %s -> %s\n", archivo, shm_name);
620     } else {
621 	fd = shm_open (shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
622     }
623     if(fd < 0) {
624 	ERR("Cannot open shared memory file descriptor for %s (%s): %s\n",
625 		shm_name, archivo, strerror (errno));
626 	free(shm_name);
627 	return NULL;
628     } else {
629 	if(ftruncate (fd, sizeof(dbh_lock_t)) < 0) {
630 	    ERR("Cannot ftruncate shared memory item for %s: %s\n",
631 		    archivo, strerror (errno));
632 	    free(shm_name);
633 	    close(fd);
634 	    return NULL;
635 	}
636     }
637     dbh_lock_t *lock_p = (dbh_lock_t *) mmap (NULL, sizeof(dbh_lock_t),
638 	PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
639     if (lock_p == MAP_FAILED){
640 	ERR("Cannot mmap shared memory item for %s: %s\n",
641 	    archivo, strerror (errno));
642 	close (fd);
643 	shm_unlink (shm_name);
644         char *nsem_name = sem_name(archivo);
645 	if (nsem_name){
646             sem_unlink (nsem_name);
647             free(nsem_name);
648         }
649 	free(shm_name);
650 	return NULL;
651     }
652 
653 
654     free(shm_name);
655     close (fd);
656     return lock_p;
657 #endif
658 }
659 
660 static void
destroy_shm_lock(char * archivo,dbh_lock_t * lock_p)661 destroy_shm_lock(char *archivo, dbh_lock_t *lock_p){
662 #ifdef PARALLEL_SAFE
663     if (!lock_p) return;
664     char *shm_name=lock_name(archivo);
665     if (!shm_name) {
666 	// Nothing to destroy.
667 	return;
668     }
669     munmap (lock_p, sizeof(dbh_lock_t));
670     shm_unlink (shm_name);
671     free(shm_name);
672 #endif
673 }
674 
675 static void
clear_shm_lock(const char * archivo)676 clear_shm_lock(const char *archivo){
677 #ifndef PARALLEL_SAFE
678     return;
679 #else
680     char *shm_name=lock_name(archivo);
681     if (!shm_name){
682 	// Nothing to clear.
683 	return;
684     }
685     // open it.
686     dbh_lock_t *lock_p = open_shm_lock(archivo);
687     // clear it.
688 
689     lock_p->write_lock_count = 0;
690     lock_p->write_lock = 0;
691     lock_p->read_lock_count = 0;
692 
693     if(msync (lock_p,  sizeof(dbh_lock_t), MS_ASYNC) < 0){
694             ERR("(1) Cannot msync shared memory item for %s: %s\n",
695                 archivo, strerror (errno));
696     }
697 
698     munmap (lock_p, sizeof(dbh_lock_t));
699     // erase it (if not open elsewhere)
700     shm_unlink (shm_name);
701     free(shm_name);
702     char *nsem_name = sem_name(archivo);
703     if (nsem_name){
704         sem_unlink(nsem_name);
705         free(nsem_name);
706     }
707     return;
708 #endif
709 }
710 
711 
712 static DBHashTable *
sdbh_create(const char * path,unsigned char key_length,int flags)713 sdbh_create (const char *path, unsigned char key_length, int flags) {
714     DBHashTable *dbh;
715     if (key_length > 254){
716         ERR("sdbh_create(%s): key_length is limited to 254 bytes...\n", path);
717         return NULL;
718     }
719     dbh = (DBHashTable *) malloc (sizeof (DBHashTable));
720     if(dbh == NULL){
721 	ERR( "malloc(%ld): %s\n", (long)sizeof (DBHashTable), strerror(errno));
722 	return NULL;
723     }
724     memset (dbh, 0, sizeof (DBHashTable));
725     dbh->lock_attempt_limit = open_timeout;
726     /////////////////////////////////////////////
727 
728     unlink (path);
729     dbh->fd = my_open (path, O_CREAT | O_RDWR | O_TRUNC);
730     if(dbh->fd < 0) {
731         free (dbh);
732         ERR("sdbh_create(%s): %s\n", path, strerror (errno));
733         return NULL;
734     }
735 
736     dbh->head_info = (dbh_header_t *) malloc (sizeof (dbh_header_t));
737      if (dbh->head_info == NULL) {
738         free (dbh);
739 	ERR( "malloc(%ld): %s\n", (long)sizeof (dbh_header_t), strerror(errno));
740         return NULL;
741      }
742 
743     memset ((void *)(dbh->head_info), 0, sizeof (dbh_header_t));
744 #ifdef PARALLEL_SAFE
745     if (flags & DBH_PARALLEL_SAFE){
746         char *nsem_name = sem_name(path);
747         if (!nsem_name) {
748 	    ERR( "malloc(%ld): %s\n", (long)strlen(path), strerror(errno));
749             free (dbh);
750             return NULL;
751         }
752         dbh->sem = sem_open(nsem_name, O_CREAT, 0700, 1);
753         free(nsem_name);
754 
755         clear_shm_lock(path);
756         dbh->lock_p = open_shm_lock(path);
757     }
758 #endif
759 
760     dbh->head_info->bof = sizeof (dbh_header_t);
761     dbh->head_info->n_limit = key_length;
762     dbh->head_info->user_tmpdir = 0;
763     dbh->head_info->sweep_erased = 0;
764     dbh->head_info->total_space = dbh->head_info->data_space = dbh->head_info->erased_space = 0;
765     strncpy (dbh->head_info->version, DBH_FILE_VERSION, 15);
766     dbh->head_info->records = 0;
767     dbh->operate = sdbh_operate;
768     dbh->branch = (FILE_POINTER *) malloc (dbh->head_info->n_limit * sizeof (FILE_POINTER));
769      if (dbh->branch == NULL) {
770 	 ERR( "malloc dbh->branch: %s\n", strerror(errno));
771          dbh_close(dbh);
772         return NULL;
773      }
774      dbh->newbranch = (FILE_POINTER *) malloc (dbh->head_info->n_limit * sizeof (FILE_POINTER));
775       if (dbh->newbranch == NULL) {
776 	 ERR( "malloc dbh->newbranch: %s\n", strerror(errno));
777          dbh_close(dbh);
778         return NULL;
779      }
780      dbh->key = (unsigned char *)malloc (key_length);
781      if (dbh->key == NULL) {
782 	 ERR( "malloc dbh->key: %s\n", strerror(errno));
783          dbh_close(dbh);
784         return NULL;
785      }
786      dbh->newkey = (unsigned char *)malloc (key_length);
787      if (dbh->newkey == NULL) {
788 	 ERR( "malloc dbh->newkey: %s\n", strerror(errno));
789          dbh_close(dbh);
790         return NULL;
791      }
792      dbh->path = (char *)malloc (strlen (path) + 1);
793      if (dbh->path == NULL || dbh->newbranch == NULL ||
794 	    dbh->key == NULL || dbh->newkey == NULL || dbh->path == NULL) {
795 	 ERR( "malloc dbh->path: %s\n", strerror(errno));
796          dbh_close(dbh);
797         return NULL;
798      }
799 
800     strcpy (dbh->path, path);
801 
802     dbh->head_info->record_length = 0;
803     dbh->head_info->writeOK = 1;
804     sdbh_size (dbh, DEFAULT_DBH_DATASIZE);
805     dbh->bytes_userdata = 0;
806 
807     sdbh_writeheader (dbh, 1);
808     DBG (" created %s \n", path);
809     return dbh;
810 }
811 
812 static DBHashTable *
sdbh_open_S(const char * archivo,int mode,int flags)813 sdbh_open_S (const char *archivo, int mode, int flags) {
814     TRACE ("sdbh_open_S: %s\n", archivo);
815     DBHashTable *dbh;
816     int fd;
817     if(mode) {
818         fd = my_open (archivo, O_RDWR);
819     } else {
820         fd = my_open (archivo, O_RDONLY);
821     }
822 
823 
824 
825     if(fd < 0) {
826         DBG ("open(%s) %s failed: %s\n", archivo, (mode)?"O_RDWR":"O_RDONLY", strerror (errno));
827         return NULL;
828     }
829     dbh = (DBHashTable *) malloc (sizeof (DBHashTable));
830      if (dbh == NULL) {
831 	DBG( "malloc(%ld) failed: %s\n", (long)sizeof (DBHashTable), strerror(errno));
832         close(fd);
833         return NULL;
834      }
835     memset (dbh, 0, sizeof (DBHashTable));
836     dbh->lock_attempt_limit = open_timeout;
837     dbh->fd = fd;
838 
839     /////////////////////////////////////////////
840 #ifdef PARALLEL_SAFE
841     if (flags & DBH_PARALLEL_SAFE){
842         char *nsem_name = sem_name(archivo);
843         if (!nsem_name) {
844 	    DBG( "sem_name(%s) failed: %s\n", archivo, strerror(errno));
845             dbh_close(dbh);
846             return NULL;
847         }
848         dbh->sem = sem_open(nsem_name, O_CREAT, 0700, 1);
849         free(nsem_name);
850         dbh->lock_p = open_shm_lock(archivo);
851     }
852 #endif
853 
854     dbh->head_info = (dbh_header_t *) malloc (sizeof (dbh_header_t));
855      if (dbh->head_info == NULL) {
856 	DBG( "malloc(%ld) failed: %s\n", (long)sizeof (dbh_header_t), strerror(errno));
857         dbh_close(dbh);
858         return NULL;
859      }
860     FILE_POINTER eof = place_eof (dbh);
861     if(eof < 0) {
862 	DBG( "place_eof(%s) failed: %s\n", archivo, strerror(errno));
863         dbh_close(dbh);
864         return NULL;
865     }
866 
867     dbh->path = (char *)malloc (strlen (archivo) + 1);
868      if (dbh->path == NULL) {
869 	DBG( "malloc(%ld) failed: %s\n", (long)(strlen (archivo) + 1), strerror(errno));
870         dbh_close(dbh);
871         return NULL;
872      }
873      strcpy (dbh->path, archivo);
874 
875     if(!sdbh_readheader (dbh)) {
876         dbh_close(dbh);
877 	DBG( "readheader(%s) failed: %s\n", archivo, strerror(errno));
878         return NULL;
879     }
880     dbh->operate = sdbh_operate;
881     dbh->branch = (FILE_POINTER *) malloc (dbh->head_info->n_limit * sizeof (FILE_POINTER));
882      if (dbh->branch  == NULL) {
883 	ERR( "malloc dbh->branch: %s\n", strerror(errno));
884         dbh_close(dbh);
885         return NULL;
886      }
887     dbh->newbranch = (FILE_POINTER *) malloc (dbh->head_info->n_limit * sizeof (FILE_POINTER));
888      if (dbh->newbranch  == NULL) {
889 	ERR( "malloc dbh->newbranch: %s\n", strerror(errno));
890         dbh_close(dbh);
891         return NULL;
892      }
893     dbh->key = (unsigned char *)malloc (dbh->head_info->n_limit);
894       if (dbh->key == NULL) {
895 	 ERR( "malloc dbh->key: %s\n", strerror(errno));
896         dbh_close(dbh);
897         return NULL;
898      }
899    dbh->newkey = (unsigned char *)malloc (dbh->head_info->n_limit);
900      if (dbh->newkey  == NULL) {
901 	 ERR( "malloc dbh->newkey: %s\n", strerror(errno));
902         dbh_close(dbh);
903         return NULL;
904      }
905     if(mode == WRITE)
906         dbh->head_info->writeOK = 1;
907     else
908         dbh->head_info->writeOK = 0;
909     sdbh_size (dbh, (int)dbh->head_info->record_length);
910     DBG (" opened %s \n", archivo);
911     return dbh;
912 }  /****************************************************************************/
913 
914 static void
sdbh_cuenta(unsigned char * numero,unsigned char orden,FILE_POINTER cuanto)915 sdbh_cuenta (unsigned char *numero, unsigned char orden, FILE_POINTER cuanto) {
916     unsigned char q;
917     FILE_POINTER m;
918     if(orden == 0)
919         numero[0] = 0;
920     if(orden == 1)
921         numero[0] = (unsigned char)cuanto;
922     q = sdbh_cuantumR (cuanto, orden, &m);       /* en que cuantum estamos */
923     orden--;
924     sdbh_cifra (numero, q, orden, &m);
925 /* sdbh_cifra(numero,q,orden-1,&m);*/
926 } /***********************************************************************/
927 
928 #define RECORD_EXTENT  ( 2 + sizeof(FILE_POINTER)*(*how_many_branches+1) + dbh->head_info->n_limit + the_user_databytes )
929 static FILE_POINTER
sdbh_write(char newinfo,DBHashTable * dbh,unsigned char write_branches)930 sdbh_write (char newinfo, DBHashTable * dbh, unsigned char write_branches) {
931     TRACE ("sdbh_write\n");
932     int i;
933     void *the_data;
934     unsigned char *how_many_branches;
935     FILE_POINTER the_user_databytes;
936     FILE_POINTER *the_branches;
937     unsigned char *the_key;
938     if(newinfo) {
939         the_branches = dbh->newbranch;
940     } else {
941         the_branches = dbh->branch;
942     }
943     the_data = dbh->data;
944     how_many_branches = &(dbh->newbranches);
945     the_user_databytes = dbh->bytes_userdata;
946     the_key = dbh->key;
947 
948     if(the_user_databytes > dbh->head_info->record_length) {
949         ERR(
950                  "dbh->bytes_userdata (%lld) is greater than dbh->head_info->record_length (%lld). This is wrong and I stubbornly refuse to write\n",
951                  (long long)dbh->bytes_userdata, (long long)dbh->head_info->record_length);
952         ERR("*** sdbh_write() error 1\n");
953         return 0;
954     }
955     DBG("Starting write at offset %lld\n", (long long)lseek(dbh->fd, 0, SEEK_CUR));
956     if(write (dbh->fd, how_many_branches, 1) != 1){
957         ERR("*** sdbh_write() error 2\n");
958         return 0;
959     }
960     if(write (dbh->fd, &(dbh->flag), 1) != 1){
961         ERR("*** sdbh_write() error 3\n");
962         return 0;
963     }
964 
965     i = write (dbh->fd, &the_user_databytes, sizeof (FILE_POINTER));
966     if(i != sizeof (FILE_POINTER)){
967         ERR("*** sdbh_write() error 4\n");
968         return 0;
969     }
970 
971     if(write_branches) {
972 #ifdef TURN
973         for(i = 0; i < *how_many_branches; i++)
974             the_branches[i] = sdbh_turnaround (the_branches[i]);
975 #endif
976         i = write (dbh->fd, the_branches, sizeof (FILE_POINTER) * (*how_many_branches));
977         if(i != sizeof (FILE_POINTER) * (*how_many_branches)){
978                 ERR("*** sdbh_write() error 5\n");
979                 return 0;
980         }
981 
982 #ifdef TURN
983         for(i = 0; i < *how_many_branches; i++)
984             the_branches[i] = sdbh_turnaround (the_branches[i]);
985 #endif
986     } else {
987         if(!advance_fp (dbh, *how_many_branches * sizeof (FILE_POINTER))){
988         ERR("*** sdbh_write() error 6\n");
989         return 0;
990     }
991 
992 
993     }
994     if(write (dbh->fd, the_key, dbh->head_info->n_limit) != dbh->head_info->n_limit) {
995         ERR( "fwrite: %s\n", strerror (errno));
996         return 0;
997     }
998     if(the_user_databytes) {
999         if(dbh->head_info->reservedC){
1000             the_user_databytes = write (dbh->fd, the_data, dbh->head_info->record_length);
1001 	} else {
1002             the_user_databytes = write (dbh->fd, the_data, the_user_databytes);
1003 	}
1004         return (the_user_databytes);
1005     }
1006         NOOP("*** sdbh_write() Data length for record is zero.\n");
1007     return (0);
1008 
1009 }  /************************************************************************************/
1010 
1011 static int
sdbh_read(char newinfo,DBHashTable * dbh,unsigned char read_data)1012 sdbh_read (char newinfo, DBHashTable * dbh, unsigned char read_data) {
1013     TRACE ("sdbh_read\n");
1014     unsigned char keylength;
1015     void *the_data;
1016     unsigned char *how_many_branches;
1017     FILE_POINTER *the_user_databytes;
1018     FILE_POINTER *the_branches;
1019     unsigned char *the_key;
1020     if(newinfo) {
1021         the_branches = dbh->newbranch;
1022         the_data = dbh->newdata;
1023         how_many_branches = &(dbh->newbranches);
1024         the_user_databytes = &(dbh->newbytes_userdata);
1025         the_key = dbh->newkey;
1026     } else {
1027         the_branches = dbh->branch;
1028         the_data = dbh->data;
1029         how_many_branches = &(dbh->branches);
1030         the_user_databytes = &(dbh->bytes_userdata);
1031         the_key = dbh->key;
1032     }
1033     keylength = dbh->head_info->n_limit;
1034 
1035     if (DBH_MAXIMUM_RECORD_SIZE(dbh) < 16 * 4096) {
1036         /* new code: reduce read() call count from 3 to 1,
1037          *  but only with reasonable maximum data size (stack size is limited)
1038          *  the value 16 * 4096 is arbitrary, but sounds OK. */
1039         /*
1040          * Minimum bytes to read: 2+sizeof(FILE_POINTER)
1041          *   (unsigned char, unsigned char, FILE_POINTER)
1042          * Maximum bytes to read: 2+sizeof(FILE_POINTER) + 256 + 256 * sizeof(FILE_POINTER)
1043          *   (add 256 FILE_POINTERs and 256 unsigned chars for the key and maximum data size)
1044          *    */
1045         int min_bytes = 2+sizeof(FILE_POINTER);
1046         int max_bytes = min_bytes + 256 + (256 * sizeof(FILE_POINTER)) + DBH_MAXIMUM_RECORD_SIZE(dbh);
1047         unsigned char buffer[max_bytes];
1048         int bytes = read (dbh->fd, buffer, max_bytes);
1049         if (bytes < min_bytes){
1050             DBG ("read error 2.1.1 (on empty dbh file this is OK)\n");
1051             return 0;
1052         }
1053         memcpy(how_many_branches, buffer, 1);
1054         memcpy(&(dbh->flag), buffer+1, 1);
1055         memcpy (the_user_databytes, buffer+2, sizeof(FILE_POINTER));
1056 #ifdef TURN
1057             *the_user_databytes = sdbh_turnaround (*the_user_databytes);
1058 #endif
1059 
1060         if(*the_user_databytes > dbh->head_info->record_length) {
1061             ERR("sdbh_read(): user databytes is greater than head_info->record_length. This should not happen.\n");
1062             return 0;
1063         }
1064         if(*the_user_databytes == 0) {
1065             DBG ( "dbh_RECORD_SIZE() == 0. If this is not intentional, use dbh_set_recordsize() to set record size for %s.\n",
1066                     dbh->path);
1067             return 0;
1068         }
1069         int structure_buffer_size = (sizeof (FILE_POINTER) * (*how_many_branches)) + keylength;
1070         int correct_bytes = min_bytes + structure_buffer_size + *the_user_databytes;
1071         if(bytes < correct_bytes) {
1072             ERR ("fread error 2.4\n");
1073             return 0;
1074         }
1075         void *structure_buffer = buffer + min_bytes;
1076         memcpy(the_branches, structure_buffer, structure_buffer_size - keylength);
1077         memcpy(the_key, structure_buffer + (structure_buffer_size - keylength), keylength);
1078 #ifdef TURN
1079         {
1080             int i; for(i = 0; i < *how_many_branches; i++)
1081                 the_branches[i] = sdbh_turnaround (the_branches[i]);
1082         }
1083 #endif
1084         if(read_data) {
1085             memcpy(the_data, structure_buffer + structure_buffer_size, *the_user_databytes);
1086         }
1087     } else {
1088         int buffer_size = 2+sizeof(FILE_POINTER);
1089         unsigned char buffer[buffer_size];
1090         if(read (dbh->fd, buffer, buffer_size) != buffer_size) {
1091             DBG ("read error 2.1.1 (on empty dbh file this is OK)\n");
1092             return 0;
1093         }
1094         memcpy(how_many_branches, buffer, 1);
1095         memcpy(&(dbh->flag), buffer+1, 1);
1096         memcpy (the_user_databytes, buffer+2, sizeof(FILE_POINTER));
1097 #ifdef TURN
1098             *the_user_databytes = sdbh_turnaround (*the_user_databytes);
1099 #endif
1100 
1101         if(*the_user_databytes > dbh->head_info->record_length) {
1102             ERR("sdbh_read(): user databytes is greater than head_info->record_length. This should not happen.\n");
1103             return 0;
1104         }
1105         if(*the_user_databytes == 0) {
1106             ERR ( "dbh_RECORD_SIZE() == 0. If this is not intentional, use dbh_set_recordsize() to set record size for %s.\n", dbh->path);
1107             return 0;
1108         }
1109 
1110         int structure_buffer_size = (sizeof (FILE_POINTER) * (*how_many_branches)) + keylength;
1111         unsigned char structure_buffer[structure_buffer_size];
1112         if(read (dbh->fd, structure_buffer, structure_buffer_size) != structure_buffer_size) {
1113             ERR ("fread error 2.4\n");
1114             return 0;
1115         }
1116         memcpy(the_branches, structure_buffer, structure_buffer_size - keylength);
1117         memcpy(the_key, structure_buffer + (structure_buffer_size - keylength), keylength);
1118 #ifdef TURN
1119         {
1120             int i; for(i = 0; i < *how_many_branches; i++)
1121                 the_branches[i] = sdbh_turnaround (the_branches[i]);
1122         }
1123 #endif
1124         // This may be a very big read, better left by itself.
1125         if(read_data) {
1126             // if data is tainted, there will be no overrun since value is checked against
1127             // dbh->head_info->record_length above.
1128             // coverity[tainted_data : FALSE]
1129             if(read (dbh->fd, the_data, *the_user_databytes) != *the_user_databytes) {
1130                 ERR ("fread error 2.51: blocksize=%lld\n", (long long)(*the_user_databytes));
1131 
1132                 return 0;
1133             }
1134         }
1135     }
1136 //
1137     return 1;
1138 } /************************************************************************************/
1139 
1140 static int
sdbh_readheader(DBHashTable * dbh)1141 sdbh_readheader (DBHashTable * dbh) {
1142     TRACE ("sdbh_readheader\n");
1143     if(!place_fp_at (dbh, (off_t)0)) {
1144             ERR("*** sdbh_readheader() error 1; !place_fp_at (dbh, 0)\n");
1145         return 0;
1146     }
1147     // dbh->head_info is *not* a string. It is a fixed length structure
1148     // coverity[string_null_argument : FALSE]
1149     size_t bytes = read (dbh->fd, (void *)(dbh->head_info), sizeof (dbh_header_t));
1150 
1151     if (bytes != sizeof (dbh_header_t)) {
1152         ERR( "Failed to read header for %s: %s\nsizeof (dbh_header_t)=%ld read=%ld\n",
1153                 dbh->path, strerror (errno),
1154                  (long)sizeof (dbh_header_t), (long)bytes);
1155         return 0;
1156     }
1157     if(strncmp (dbh->head_info->version, DBH_FILE_VERSION, 15) != 0) {
1158         ERR(
1159                  "Failed to read header for %s at sdbh_readheader(): strncmp (\"%s\",\"%s\")\n",
1160                  dbh->path, dbh->head_info->version, DBH_FILE_VERSION);
1161         return 0;
1162     }
1163     /* volatile values: */
1164     dbh->head_info->user_tmpdir = 0;
1165 
1166 #ifdef TURN
1167     dbh->head_info->bof = sdbh_turnaround (dbh->head_info->bof);
1168     dbh->head_info->record_length = sdbh_turnaround (dbh->head_info->record_length);
1169     dbh->head_info->total_space = sdbh_turnaround (dbh->head_info->total_space);
1170     dbh->head_info->data_space = sdbh_turnaround (dbh->head_info->data_space);
1171     dbh->head_info->erased_space = sdbh_turnaround (dbh->head_info->erased_space);
1172     dbh->head_info->records = sdbh_turnaround (dbh->head_info->records);
1173 #endif
1174     return 1;
1175 }  /************************************************************************************/
1176 
1177 #ifdef TURN
1178 static FILE_POINTER
sdbh_turnaround(FILE_POINTER x)1179 sdbh_turnaround (FILE_POINTER x) {
1180     char *where,
1181       temp;
1182     where = (char *)&x;
1183     temp = where[0];
1184     where[0] = where[3];
1185     where[3] = temp;
1186     temp = where[1];
1187     where[1] = where[2];
1188     where[2] = temp;
1189     return x;
1190 } /************************************************************************************/
1191 #endif
1192 
1193 static FILE_POINTER
sdbh_z(unsigned char n,unsigned char m)1194 sdbh_z (unsigned char n, unsigned char m) {      /* n=cuantum m=orden */
1195     FILE_POINTER s = 0;
1196     unsigned char i;
1197     if(m < 2)
1198         return 1;
1199     if(m == 2)
1200         return (n + 1);
1201     m--;
1202     for(i = n; i > 0; i--)
1203         s += sdbh_z (i, m);
1204 /* for (i=n;i>0;i--) s += sdbh_z(i,m-1);*/
1205     return (s + 1);
1206 }  /************************************************************************************/
1207 
1208 static unsigned char
sdbh_cuantumR(FILE_POINTER cuanto,unsigned char orden,FILE_POINTER * m)1209 sdbh_cuantumR (FILE_POINTER cuanto, unsigned char orden, FILE_POINTER * m) {
1210     unsigned char i;
1211     FILE_POINTER ztotal,
1212       grandtotal = 0;
1213     for(i = 0; 1; i++) {
1214         if(i == orden)
1215             ztotal = grandtotal;
1216         else
1217             ztotal = sdbh_z (i, orden);
1218         grandtotal += ztotal;
1219         if(cuanto <= grandtotal) {
1220             if(m)
1221                 *m = grandtotal - cuanto + 1;
1222             break;
1223         }
1224     }
1225     return i;
1226 }  /************************************************************************************/
1227 
1228 static unsigned char
sdbh_cuantum(FILE_POINTER cuanto,unsigned char orden,FILE_POINTER * m)1229 sdbh_cuantum (FILE_POINTER cuanto, unsigned char orden, FILE_POINTER * m) {
1230     unsigned char i;
1231     FILE_POINTER ztotal,
1232       grandtotal = 0;
1233     for(i = 0; 1; i++) {
1234         if(i == orden)
1235             ztotal = grandtotal;
1236         else
1237             ztotal = sdbh_z (i, orden);
1238         grandtotal += ztotal;
1239         if(cuanto <= grandtotal)
1240             break;
1241         if(m)
1242             *m = cuanto - grandtotal;
1243     }
1244     return i;
1245 }  /************************************************************************************/
1246 
1247 static void
sdbh_cifra(unsigned char * numero,unsigned char q,unsigned char orden,FILE_POINTER * m)1248 sdbh_cifra (unsigned char *numero, unsigned char q, unsigned char orden, FILE_POINTER * m) {
1249     unsigned char subcuantum;
1250     int t;
1251     if(orden == 1) {
1252         t = q - (*m - 1);
1253         numero[0] = (unsigned char)t;
1254 /*  numero[0]=q - (*m-1);*/
1255         t = *m - 1;
1256         numero[1] = (unsigned char)t;
1257 /*  numero[1]= *m-1;*/
1258         return;
1259     }
1260     subcuantum = sdbh_cuantum (*m, orden, m);
1261     t = q - subcuantum;
1262     numero[0] = (unsigned char)t;
1263 /* numero[0]=q-subcuantum;*/
1264     orden--;
1265     sdbh_cifra (numero + 1, subcuantum, orden, m);
1266     /* sdbh_cifra(numero+1,subcuantum,orden-1,m); */
1267     return;
1268 }  /************************************************************************************/
1269 
1270 #if 0
1271 // legacy code
1272 static int
1273 sdbh_barrelong (DBHashTable * dbh, FILE_POINTER startadd, int ramas) {
1274     unsigned char i;
1275     if(dbh_load_address (dbh, startadd) == 0)
1276         return 0;
1277     if(dbh->head_info->dbh_exit)
1278         return 2;
1279     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1280         (*(dbh->operate)) (dbh);
1281     if(ramas) {
1282         if((ramas = dbh->branches - ramas) < 0)
1283             ramas = 0;
1284     }
1285     for(i = dbh->branches; i > ramas; i--) {
1286         if(dbh->branch[i - 1])
1287             sdbh_barrelong (dbh, dbh->branch[i - 1], 0);
1288         dbh_load_address (dbh, startadd);
1289     }
1290     return 1;
1291 }    /**********************************************************************/
1292 
1293 static int
1294 sdbh_reversebarrelong (DBHashTable * dbh, FILE_POINTER startadd, int ramas) {
1295     int i;
1296     if(dbh_load_address (dbh, startadd) == 0)
1297         return 0;
1298     if(dbh->head_info->dbh_exit)
1299         return 2;
1300     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1301         (*(dbh->operate)) (dbh);
1302 /* if (!ERASED) (*(dbh->operate))(dbh);*/
1303     if(ramas) {
1304         if((ramas = dbh->branches - ramas) < 0)
1305             ramas = 0;
1306     }
1307     for(i = ramas; i < dbh->branches; i++) {
1308         if(dbh->branch[i])
1309             sdbh_reversebarrelong (dbh, dbh->branch[i], 0);
1310         dbh_load_address (dbh, startadd);
1311     }
1312     return 1;
1313 }   /******************************************************************************/
1314 #endif
1315 
1316 static int
sdbh_reversebarre(DBHashTable * dbh,FILE_POINTER startadd,int ramas)1317 sdbh_reversebarre (DBHashTable * dbh, FILE_POINTER startadd, int ramas) {
1318     int i;
1319     unsigned char oldbranches;
1320     FILE_POINTER *oldbranch;
1321     if(dbh_load_address (dbh, startadd) == 0)
1322         return 0;
1323     if(dbh->head_info->dbh_exit)
1324         return 2;
1325     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1326         (*(dbh->operate)) (dbh);
1327 /* if (!ERASED) (*(dbh->operate))(dbh);*/
1328     oldbranch = (FILE_POINTER *) malloc (dbh->branches * sizeof (FILE_POINTER));
1329      if (oldbranch == NULL) {
1330 	 ERR( "malloc oldbranch: %s\n", strerror(errno));
1331         return 0;
1332      }
1333     oldbranches = dbh->branches;
1334     if(ramas) {
1335         if((ramas = dbh->branches - ramas) < 0)
1336             ramas = 0;
1337     }
1338 #if 1
1339     for(i = 0; i < oldbranches; i++)
1340         oldbranch[i] = dbh->branch[i];
1341     for(i = ramas; i < oldbranches; i++)
1342         if(oldbranch[i])
1343             sdbh_reversebarre (dbh, oldbranch[i], 0);
1344     free (oldbranch);
1345 #else
1346 // legacy code
1347     if(oldbranch == NULL) fullmemory = 1;
1348     char fullmemory = 0;
1349     if(!fullmemory) {
1350         for(i = 0; i < oldbranches; i++)
1351             oldbranch[i] = dbh->branch[i];
1352         for(i = ramas; i < oldbranches; i++)
1353             if(oldbranch[i])
1354                 sdbh_reversebarre (dbh, oldbranch[i], 0);
1355         free (oldbranch);
1356     } else
1357         for(i = ramas; i < oldbranches; i++) {
1358             if(dbh->branch[i])
1359                 sdbh_reversebarrelong (dbh, dbh->branch[i], 0);
1360             dbh_load_address (dbh, startadd);
1361         }
1362 #endif
1363     return 1;
1364 }  /******************************************************************************/
1365 
1366 static int
sdbh_barre(DBHashTable * dbh,FILE_POINTER startadd,int ramas)1367 sdbh_barre (DBHashTable * dbh, FILE_POINTER startadd, int ramas) {
1368     unsigned char i;
1369     FILE_POINTER *oldbranch;
1370     if(dbh_load_address (dbh, startadd) == 0)
1371         return 0;
1372     if(dbh->head_info->dbh_exit)
1373         return 2;
1374 #if 0
1375     printf ("barre: currentseek at %lu\n", (long unsigned)startadd);
1376     printf ("record is erased? -> %d\n", ERASED);
1377 #endif
1378     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1379         (*(dbh->operate)) (dbh);
1380 /* if (!ERASED) (*(dbh->operate))(dbh);*/
1381     oldbranch = (FILE_POINTER *) malloc (dbh->branches * sizeof (FILE_POINTER));
1382       if (oldbranch == NULL) {
1383 	 ERR( "malloc oldbranch: %s\n", strerror(errno));
1384         return 0;
1385      }
1386     if(ramas) {
1387         if((ramas = dbh->branches - ramas) < 0)
1388             ramas = 0;
1389     }
1390 #if 1
1391     for(i = 0; i < dbh->branches; i++)
1392         oldbranch[i] = dbh->branch[i];
1393     for(i = dbh->branches; i > ramas; i--)
1394         if(oldbranch[i - 1])
1395             sdbh_barre (dbh, oldbranch[i - 1], 0);
1396     free (oldbranch);
1397 #else
1398 // legacy code
1399     char fullmemory = 0;
1400     if(!fullmemory) {
1401         for(i = 0; i < dbh->branches; i++)
1402             oldbranch[i] = dbh->branch[i];
1403         for(i = dbh->branches; i > ramas; i--)
1404             if(oldbranch[i - 1])
1405                 sdbh_barre (dbh, oldbranch[i - 1], 0);
1406         free (oldbranch);
1407     } else
1408         for(i = dbh->branches; i > ramas; i--) {
1409             if(dbh->branch[i - 1])
1410                 sdbh_barrelong (dbh, dbh->branch[i - 1], 0);
1411             dbh_load_address (dbh, startadd);
1412         }
1413 #endif
1414     return 1;
1415 }   /************************************************************************/
1416 
1417   /* Functions: */
1418 static void
sdbh_transfer(DBHashTable * srcdbh)1419 sdbh_transfer (DBHashTable * srcdbh) {
1420     DBHashTable *dbh_desdbh = srcdbh->dbh_desdbh;
1421     dbh_desdbh->bytes_userdata = srcdbh->bytes_userdata;
1422     dbh_update (dbh_desdbh);
1423 /* if ((count++ % 100)==0) printf("\n %ld registros procesados",count);*/
1424     return;
1425 } /***************************************************************************/
1426 
1427 /*****************************************************************************/
1428 /***    old   non static functions ***/
1429 /*****************************************************************************/
1430 
1431 static int
sdbh_size(DBHashTable * dbh,FILE_POINTER record_length)1432 sdbh_size (DBHashTable * dbh, FILE_POINTER record_length) {
1433 
1434     /* despues de abrir DBHashTable */
1435     if(dbh == NULL) {
1436         ERR( "sdbh_size(): dbh != NULL not met\n");
1437         return 0;
1438     }
1439     if(dbh->head_info == NULL) {
1440         ERR( "sdbh_size(): dbh->head_info != NULL not met\n");
1441         return 0;
1442     }
1443 
1444     if(record_length < dbh->head_info->record_length) {
1445         /*
1446         ERR ("sdbh_size(): may not shrink! current size=%lld requested size=%ld\n",
1447                (long long)dbh->head_info->record_length, (long)record_length);
1448                */
1449         return 0;
1450     }
1451 
1452     void *data = malloc (record_length);
1453      if (data == NULL) {
1454 	 ERR( "malloc data: %s\n", strerror(errno));
1455         return 0;
1456      }
1457     void *newdata = malloc (record_length);
1458      if (newdata == NULL) {
1459          free(data);
1460 	 ERR( "malloc newdata: %s\n", strerror(errno));
1461         return 0;
1462      }
1463     memset (data, 0, record_length);
1464     memset (newdata, 0, record_length);
1465     if(dbh->data != NULL) {
1466         memcpy (data, dbh->data, dbh->head_info->record_length);
1467         free (dbh->data);
1468     }
1469     if(dbh->newdata != NULL) {
1470         memcpy (newdata, dbh->newdata, dbh->head_info->record_length);
1471         free (dbh->newdata);
1472     }
1473     dbh->data = data;
1474     dbh->newdata = newdata;
1475 
1476     if (dbh->head_info->record_length != record_length) {
1477 	dbh->head_info->record_length = record_length;
1478         if(dbh->head_info->writeOK) sdbh_writeheader (dbh, 1);
1479     }
1480     return 1;
1481 } /****************************************************************************************/
1482 
1483 #if 0
1484 // legacy code
1485 static int
1486 sdbh_barrelong2 (DBHashTable * dbh, DBHashFunc2 operate, void *data,
1487 	    FILE_POINTER startadd, int ramas) {
1488     unsigned char i;
1489     if(dbh_load_address (dbh, startadd) == 0)
1490         return 0;
1491     if(dbh->head_info->dbh_exit)
1492         return 2;
1493     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1494         (*(dbh->operate)) (dbh);
1495     if(ramas) {
1496         if((ramas = dbh->branches - ramas) < 0)
1497             ramas = 0;
1498     }
1499     for(i = dbh->branches; i > ramas; i--) {
1500         if(dbh->branch[i - 1])
1501             sdbh_barrelong2 (dbh, operate, data, dbh->branch[i - 1], 0);
1502         dbh_load_address (dbh, startadd);
1503     }
1504     return 1;
1505 }    /**********************************************************************/
1506 #endif
1507 
1508 static int
sdbh_barre2(DBHashTable * dbh,DBHashFunc2 operate,void * data,FILE_POINTER startadd,int ramas)1509 sdbh_barre2 (DBHashTable * dbh, DBHashFunc2 operate, void *data,
1510 	FILE_POINTER startadd, int ramas) {
1511     unsigned char i;
1512     FILE_POINTER *oldbranch;
1513     if(dbh_load_address (dbh, startadd) == 0)
1514         return 0;
1515     if(dbh->head_info->dbh_exit)
1516         return 2;
1517 #if 0
1518     printf ("barre: currentseek at %lu\n", (long unsigned)startadd);
1519     printf ("record is erased? -> %d\n", ERASED);
1520 #endif
1521     if(!ERASED || (ERASED && dbh->head_info->sweep_erased))
1522         (operate) (dbh, data);
1523 /* if (!ERASED) (*(dbh->operate))(dbh);*/
1524     oldbranch = (FILE_POINTER *) malloc (dbh->branches * sizeof (FILE_POINTER));
1525       if (oldbranch == NULL) {
1526 	 ERR( "malloc oldbranch: %s\n", strerror(errno));
1527         return 0;
1528      }
1529     if(ramas) {
1530         if((ramas = dbh->branches - ramas) < 0)
1531             ramas = 0;
1532     }
1533 #if 1
1534     for(i = 0; i < dbh->branches; i++)
1535         oldbranch[i] = dbh->branch[i];
1536     for(i = dbh->branches; i > ramas; i--)
1537         if(oldbranch[i - 1])
1538             sdbh_barre2 (dbh, operate, data, oldbranch[i - 1], 0);
1539     free (oldbranch);
1540 #else
1541 // legacy code
1542     char fullmemory = 0;
1543     if(!fullmemory)
1544     {
1545         for(i = 0; i < dbh->branches; i++)
1546             oldbranch[i] = dbh->branch[i];
1547         for(i = dbh->branches; i > ramas; i--)
1548             if(oldbranch[i - 1])
1549                 sdbh_barre2 (dbh, operate, data, oldbranch[i - 1], 0);
1550         free (oldbranch);
1551     } else
1552         for(i = dbh->branches; i > ramas; i--) {
1553             if(dbh->branch[i - 1])
1554                 sdbh_barrelong2 (dbh, operate, data, dbh->branch[i - 1], 0);
1555             dbh_load_address (dbh, startadd);
1556         }
1557 #endif
1558     return 1;
1559 }   /************************************************************************/
1560 
1561 
1562 static int
sdbh_newbarre2(DBHashTable * dbh,DBHashFunc2 operate,void * data)1563 sdbh_newbarre2 (DBHashTable * dbh, DBHashFunc2 operate, void *data) {
1564     if(!dbh) {
1565         ERR( "sdbh_newbarre(): %s\n", strerror (EBADF));
1566         return 0;
1567     }
1568 
1569     dbh->head_info->dbh_exit = 0;
1570     sdbh_barre2 (dbh, operate, data, dbh->head_info->bof, 0);
1571 
1572 
1573 
1574     return 1;
1575 } /***************************************************************************************/
1576 
1577 static int
sdbh_newbarre(DBHashTable * dbh,unsigned char * key1,unsigned char * key2,unsigned char keylength)1578 sdbh_newbarre (DBHashTable * dbh, unsigned char *key1, unsigned char *key2, unsigned char keylength) {
1579     int i;
1580     FILE_POINTER pointer;
1581     if(!dbh) {
1582         ERR( "sdbh_newbarre(): %s\n", strerror (EBADF));
1583 
1584         return 0;
1585     }
1586 
1587     dbh->head_info->dbh_exit = 0;
1588     if(key1 == NULL) {
1589         sdbh_barre (dbh, dbh->head_info->bof, 0);
1590         return 1;
1591     }
1592     if(key2 != NULL) {
1593         memcpy ((void *)(dbh->key), (void *)key1, dbh->head_info->n_limit);
1594 
1595         for(i = 0; i < dbh->head_info->n_limit; i++)
1596             if(key1[i] != key2[i])
1597                 break;
1598         /* que pedo con ERASED?? (load returns errorvalue on ERASED */
1599         pointer = dbh_load (dbh);
1600         if((pointer == 0) && !(ERASED))
1601             return 0;
1602 /*  if ((pointer=dbh_load(dbh)) == 0) return 0;*/
1603         /* aqui hay que considerar que el nodo puede estar marcado como ERASED */
1604         else {
1605             pointer = dbh_find (dbh, i);
1606             sdbh_barre (dbh, pointer, dbh->head_info->n_limit - i);
1607         }
1608     } else if(keylength) {
1609         memcpy ((void *)(dbh->key), (void *)key1, keylength);
1610         pointer = dbh_find (dbh, keylength);
1611         if(pointer == 0)
1612             return 0;
1613         sdbh_barre (dbh, pointer, dbh->head_info->n_limit - keylength);
1614     }
1615     return 1;
1616 } /***************************************************************************************/
1617 
1618 static int
sdbh_newreversebarre(DBHashTable * dbh,unsigned char * key1,unsigned char * key2,unsigned char keylength)1619 sdbh_newreversebarre (DBHashTable * dbh, unsigned char *key1, unsigned char *key2, unsigned char keylength) {
1620     int i;
1621     FILE_POINTER pointer;
1622     if(!dbh) {
1623         ERR( "sdbh_newreversebarre(): %s\n", strerror (EBADF));
1624 
1625         return 0;
1626     }
1627 
1628     dbh->head_info->dbh_exit = 0;
1629     if(key1 == NULL) {
1630         sdbh_reversebarre (dbh, dbh->head_info->bof, 0);
1631         return 1;
1632     }
1633     if(key2 != NULL) {
1634         memcpy ((void *)(dbh->key), (void *)key1, dbh->head_info->n_limit);
1635         for(i = 0; i < dbh->head_info->n_limit; i++)
1636             if(key1[i] != key2[i])
1637                 break;
1638         /* que pedo con ERASED?? (load returns errorvalue on ERASED */
1639         pointer = dbh_load (dbh);
1640         if((pointer == 0) && !(ERASED))
1641             return 0;
1642 /*  if ((pointer=dbh_load(dbh)) == 0) return 0;*/
1643         else {
1644             pointer = dbh_find (dbh, i);
1645             sdbh_reversebarre (dbh, pointer, i);
1646         }
1647     } else if(keylength != 0) {
1648         memcpy ((void *)dbh->key, (void *)key1, keylength);
1649 
1650         pointer = dbh_find (dbh, keylength);
1651         if(pointer == 0)
1652             return 0;
1653         sdbh_reversebarre (dbh, pointer, keylength);
1654     }
1655     return 1;
1656 }  /************************************************************************************/
1657 
1658 static DBHashTable *
sdbh_regen(DBHashTable * dbh,int sweep)1659 sdbh_regen (DBHashTable * dbh, int sweep) {
1660     void *temp, *newtemp;
1661     char *archivo2, *archivo;
1662     DBHashTable *newdbh;
1663     unsigned char *tempkey, *newtempkey;
1664     void (*fun) (DBHashTable *);
1665 
1666     if(!dbh) {
1667         ERR( "sdbh_regen(): %s\n", strerror (EBADF));
1668         return NULL;
1669     }
1670     if (dbh->protection_flags & DBH_READ_ONLY){
1671         ERR( "DBH table is read only: %s\n", dbh->path);
1672         return NULL;
1673     }
1674     dbh_lock_write (dbh);
1675 
1676     archivo2 = sdbh_randomfilename (dbh, 's');
1677     if (!archivo2){
1678         ERR( "Cannot open temporary file: DBHashtable will not be regenerated\n");
1679 	return NULL;
1680     }
1681 
1682     archivo = (char *)malloc (strlen (dbh->path) + 1);
1683     if (archivo == NULL) {
1684 	 ERR( "malloc(%ld): %s\n", (long)(strlen (dbh->path) + 1), strerror(errno));
1685 	free(archivo2);
1686         return NULL;
1687     }
1688     strcpy (archivo, dbh->path);
1689     struct stat  st_old;
1690     // No problem with TOCTOU, since at TOU, rename will return error
1691     // if synchronization mismatch occurs.
1692     // coverity[fs_check_call : FALSE]
1693     if (stat (archivo, &st_old) < 0){
1694         ERR( "unable to stat: %s\n", archivo);
1695 	free(archivo);
1696 	free(archivo2);
1697         return NULL;
1698     }
1699 
1700     char *archivobak = (char *)malloc (strlen (archivo) + strlen (".bak") + 1);
1701     if (archivobak == NULL) {
1702 	free(archivo);
1703 	free(archivo2);
1704 	 ERR( "malloc archivobak: %s\n", strerror(errno));
1705         return NULL;
1706     }
1707     sprintf (archivobak, "%s.bak", archivo);
1708 
1709     // Set thread safe characteristics to new table.
1710     int flags = dbh->protection_flags & (DBH_PARALLEL_SAFE|DBH_THREAD_SAFE);
1711     DBHashTable *dbh_desdbh = sdbh_create (archivo2, dbh->head_info->n_limit, flags);
1712     if(!dbh_desdbh) {
1713         ERR( "Cannot open for write: %s\n", archivo2);
1714 	free(archivo);
1715 	free(archivo2);
1716 	free(archivobak);
1717         return NULL;
1718     }
1719 
1720     struct stat  st_new;
1721     // No problem with TOCTOU, since at TOU, rename will return error
1722     // if synchronization mismatch occurs.
1723     // coverity[fs_check_call : FALSE]
1724     if (stat (archivo2, &st_new) < 0){
1725         ERR( "unable to stat: %s\n", archivo2);
1726 	free(archivo);
1727 	free(archivo2);
1728 	free(archivobak);
1729         dbh_close(dbh_desdbh);
1730         return NULL;
1731     }
1732     dbh_lock_write (dbh_desdbh);
1733 
1734 
1735     dbh->dbh_desdbh = dbh_desdbh;
1736 
1737     tempkey = dbh_desdbh->key;
1738     newtempkey = dbh_desdbh->newkey;
1739     temp = dbh_desdbh->data;
1740     newtemp = dbh_desdbh->newdata;
1741     dbh_desdbh->key = dbh->key;
1742     dbh_desdbh->newkey = dbh->newkey;
1743     dbh_desdbh->data = dbh->data;
1744     dbh_desdbh->newdata = dbh->newdata;
1745 
1746 
1747 
1748     dbh_desdbh->head_info->record_length = dbh->head_info->record_length;
1749     fun = dbh->operate;
1750 
1751     dbh->operate = sdbh_transfer;
1752     if(sweep) {
1753         sdbh_newbarre (dbh, NULL, NULL, 0);
1754     } else {
1755         sdbh_newreversebarre (dbh, NULL, NULL, 0);
1756     }
1757 
1758     dbh_desdbh->data = temp;
1759     dbh_desdbh->newdata = newtemp;
1760     dbh_desdbh->key = tempkey;
1761     dbh_desdbh->newkey = newtempkey;
1762 
1763     dbh_unlock_write (dbh_desdbh);
1764     dbh_close (dbh_desdbh);
1765     dbh_unlock_write (dbh);
1766     dbh_close (dbh);
1767 
1768 
1769 
1770 
1771     if(unlink (archivobak) < 0 && errno != ENOENT) {
1772             ERR( "cannot remove old backup file: %s (%s)\n",
1773                             archivobak, strerror(errno));
1774     }
1775 
1776     DBG ("rename %s %s\n", archivo, archivobak);
1777     if(rename (archivo, archivobak) < 0) {
1778             ERR( "*** DBH: cannot rename %s to %s (%s)\n",
1779                             archivo, archivobak, strerror (errno));            ;
1780     }
1781     free (archivobak);
1782 
1783     if(st_old.st_dev == st_new.st_dev) {
1784         DBG (" rename %s %s\n", archivo2, archivo);
1785         if(rename (archivo2, archivo) < 0) {
1786             ERR( "*** DBH: cannot rename %s to %s (%s)\n",
1787                             archivo2, archivo, strerror (errno));
1788         }
1789     } else {
1790         DBG (" mv %s %s\n", archivo2, archivo);
1791 #ifdef HAVE_FORK
1792         pid_t pid = fork ();
1793         if(!pid) {
1794             execlp ("mv", "mv", archivo2, archivo, NULL);
1795             _exit (123);
1796         } else {
1797             int status;
1798             waitpid (pid, &status, 0);
1799         }
1800 #else
1801 # ifdef HAVE__SPAWNVP
1802 	const int mode = P_WAIT; // also P_NOWAIT
1803 	const char *_argv[]={"copy", archivo2, archivo, NULL};
1804 	const char *argv0 = _argv[0];
1805 	_spawnvp (mode, argv0, _argv);
1806 # else
1807         ERR( "Cannot regenerate %s\n", archivo);
1808         free (archivo);
1809         free (archivo2);
1810         return NULL;
1811 # endif
1812 #endif
1813     }
1814 
1815     newdbh = dbh_new (archivo, NULL, flags);
1816     free (archivo);
1817     free (archivo2);
1818     newdbh->operate = fun;
1819     return newdbh;
1820 }
1821 
1822 static void
prune_mark_erased(DBHashTable * dbh)1823 prune_mark_erased (DBHashTable * dbh) {
1824     SET_ERASED;
1825     /* set file pointer at record flag byte */
1826     if(place_fp_at (dbh, (off_t)((dbh->reservedB) + 1)) < 0) {
1827         return;
1828     }
1829     /* write the flag to the file */
1830     /* printf("flag for erase=0x%x\n",dbh->flag); */
1831     if(write (dbh->fd, &(dbh->flag), 1) != 1) {
1832         ERR( "unable to erase: %s\n", strerror (errno));
1833         return;
1834     }
1835     /*printf("erasing %s flag at %lu\n",(char *)dbh->data,
1836        (long unsigned)(dbh->reservedB+1)); */
1837     /* update file header information */
1838     dbh->head_info->data_space -= dbh->bytes_userdata;
1839     dbh->head_info->erased_space += (dbh->bytes_userdata);
1840     return;
1841 }
1842 
1843 static void
prune_mark_unerased(DBHashTable * dbh)1844 prune_mark_unerased (DBHashTable * dbh) {
1845     SET_UNERASED;
1846     /* set file pointer at record flag byte */
1847     if(place_fp_at (dbh, (off_t)(dbh->reservedB + 1)) < 0){
1848         return;
1849     }
1850     /* write the flag to the file */
1851     if(write (dbh->fd, &(dbh->flag), 1) != 1) {
1852         ERR( "unable to unerase: %s\n", strerror (errno));
1853         return;
1854     }
1855     /* update file header information */
1856     dbh->head_info->data_space += dbh->bytes_userdata;
1857     dbh->head_info->erased_space -= (dbh->bytes_userdata);
1858     return;
1859 }
1860 
1861 
sdbh_writeheader(DBHashTable * dbh,int flush)1862 static int sdbh_writeheader (DBHashTable * dbh, int flush) {
1863         TRACE("sdbh_writeheader\n");
1864     if(!dbh || !(dbh->head_info)) {
1865         ERR("sdbh_writeheader(): %s\n", strerror (EBADF));
1866         return 0;
1867     }
1868     if(!(dbh->head_info->writeOK)){
1869 	ERR("sdbh_writeheader() is invalid in a read only DBH Table\n");
1870 	return 0;
1871     }
1872 
1873     if(strlen (COPYRIGHT) > 127) {
1874         ERR("This should never happen, strlen(\"%s\")>127\n", COPYRIGHT);
1875         return 0;
1876     }
1877     if (!strlen(dbh->head_info->copyright)){
1878             strcpy ((char *)(dbh->head_info->copyright), COPYRIGHT);
1879     }
1880 
1881 #ifdef TURN
1882     dbh->head_info->bof = sdbh_turnaround (dbh->head_info->bof);
1883     dbh->head_info->record_length = sdbh_turnaround (dbh->head_info->record_length);
1884     dbh->head_info->total_space = sdbh_turnaround (dbh->head_info->total_space);
1885     dbh->head_info->data_space = sdbh_turnaround (dbh->head_info->data_space);
1886     dbh->head_info->erased_space = sdbh_turnaround (dbh->head_info->erased_space);
1887     dbh->head_info->records = sdbh_turnaround (dbh->head_info->records);
1888 #endif
1889 
1890 
1891     dbh_lock_write (dbh);
1892     if(!place_fp_at (dbh, (off_t)0)){
1893         dbh_unlock_write (dbh);
1894         ERR("*** sdbh_writeheader(): error 1; cannot place at 0L\n");
1895         return 0;
1896     }
1897 
1898 
1899     size_t bytes = write (dbh->fd, (void *)dbh->head_info, sizeof (dbh_header_t));
1900     if(bytes != sizeof (dbh_header_t)) {
1901         dbh_unlock_write (dbh);
1902         ERR("*** sdbh_writeheader(): error 2; write count %lu != %lu\n",
1903                         (long unsigned)sizeof (dbh_header_t),
1904                         (long unsigned)bytes);
1905         return 0;
1906     }
1907     dbh_unlock_write (dbh);
1908 
1909 
1910 #ifdef TURN
1911     dbh->head_info->bof = sdbh_turnaround (dbh->head_info->bof);
1912     dbh->head_info->record_length = sdbh_turnaround (dbh->head_info->record_length);
1913     dbh->head_info->total_space = sdbh_turnaround (dbh->head_info->total_space);
1914     dbh->head_info->data_space = sdbh_turnaround (dbh->head_info->data_space);
1915     dbh->head_info->erased_space = sdbh_turnaround (dbh->head_info->erased_space);
1916     dbh->head_info->records = sdbh_turnaround (dbh->head_info->records);
1917 #endif
1918     if (!flush) return 1;
1919 
1920 #if HAVE_FSYNC
1921     fsync(dbh->fd);
1922 #endif
1923 #if HAVE_WINDOWS_H
1924     FlushFileBuffers ((HANDLE) _get_osfhandle (dbh->fd));
1925 #endif
1926 
1927 #ifdef DEBUG_TRACE
1928     dbh_header_t tmp;
1929     lseek(dbh->fd, 0, SEEK_SET);
1930     DBG("--- > testing written header... got %ld bytes\n",
1931                     (long)read(dbh->fd, (void *)(&tmp), sizeof(dbh_header_t)));
1932 #endif
1933     return 1;
1934 }
1935 
1936 #ifdef PARALLEL_SAFE
1937 static int
lock_it(DBHashTable * dbh,int for_write)1938 lock_it (DBHashTable * dbh, int for_write){
1939     TRACE("DBH: locking file %s (write = %d)\n", dbh->path, for_write);
1940     if (for_write) {
1941         dbh->lock_p->write_lock_count++;
1942         dbh->lock_p->write_lock = getpid();
1943     } else {
1944         dbh->lock_p->read_lock_count++;
1945     }
1946     if(msync (dbh->lock_p,  sizeof(dbh_lock_t), MS_ASYNC) < 0){
1947             ERR("(2:lock_p=%p) Cannot msync shared memory item for %s: %s\n",
1948                 dbh->lock_p, dbh->path, strerror (errno));
1949     }
1950     return 1;
1951 }
1952 
1953 static int
lock_ok(DBHashTable * dbh,int for_write)1954 lock_ok (DBHashTable * dbh, int for_write){
1955     int lock_condition;
1956     if (for_write){
1957         lock_condition = (dbh->lock_p->read_lock_count ||
1958 	    (dbh->lock_p->write_lock_count && dbh->lock_p->write_lock != getpid()));
1959     } else {
1960         lock_condition = dbh->lock_p->write_lock_count;
1961     }
1962     if (lock_condition) return 0;
1963     return 1;
1964 }
1965 
1966 static int
sdbh_lock(DBHashTable * dbh,int for_write)1967 sdbh_lock (DBHashTable * dbh, int for_write){
1968     if (!(dbh->protection_flags & DBH_PARALLEL_SAFE)){
1969         return 0;
1970     }
1971     if (dbh->lock_attempt_limit == 0) sem_wait(dbh->sem);
1972     else {
1973         struct timespec timeout;
1974         timeout.tv_sec = time(NULL) + dbh->lock_attempt_limit;
1975         timeout.tv_nsec = 0;
1976         if (sem_timedwait(dbh->sem, &timeout) < 0){
1977             ERR("DBH: sdbh_lock() unable to unlock semaphore for %s (%s), proceeding on timeout...\n", dbh->path, strerror(errno));
1978         }
1979     }
1980     if (lock_ok(dbh, for_write)){
1981         lock_it(dbh, for_write);
1982         sem_post(dbh->sem);
1983         return 1;
1984     }
1985     sem_post(dbh->sem);
1986     return 0;
1987 }
1988 
1989 static int
sdbh_unlock(DBHashTable * dbh,int for_write)1990 sdbh_unlock (DBHashTable * dbh, int for_write){
1991     if (!(dbh->protection_flags & DBH_PARALLEL_SAFE)){
1992         return 0;
1993     }
1994     if (dbh->lock_attempt_limit == 0) sem_wait(dbh->sem);
1995     else {
1996         struct timespec timeout;
1997         timeout.tv_sec = time(NULL) + dbh->lock_attempt_limit;
1998         timeout.tv_nsec = 0;
1999         if (sem_timedwait(dbh->sem, &timeout) < 0){
2000             ERR("DBH: sdbh_unlock() unable to unlock semaphore for %s (%s), proceeding on timeout...\n", dbh->path, strerror(errno));
2001         }
2002     }
2003     if (for_write){
2004         dbh->lock_p->write_lock_count = 0;
2005         dbh->lock_p->write_lock = 0;
2006     } else {
2007         if (dbh->lock_p->read_lock_count > 0) dbh->lock_p->read_lock_count--;
2008     }
2009     if(msync (dbh->lock_p,  sizeof(dbh_lock_t), MS_ASYNC) < 0){
2010             ERR("(3:lock_p=%p) Cannot msync shared memory item for %s: %s\n",
2011                 dbh->lock_p, dbh->path, strerror (errno));
2012     }
2013     sem_post(dbh->sem);
2014     return 1;
2015 }
2016 #endif
2017 
2018