mirror of
https://github.com/samba-team/samba.git
synced 2025-01-15 23:24:37 +03:00
7d9e09f527
- tdb_open api changed so that you now pass an error handling callback when opening the file, so that errors detected during opening have somewhere to go. (All calls from the body of Samba to this function go through a wrapper in tdbutil, which has been updated.) - Clean up logic for deciding how to open tdb. Emit log messages if something goes wrong (e.g. bad magic.) - tdbtool now logs errors to stderr. (This used to be commit 0aa800618eab1043d802c04fb1d125cd07936769)
363 lines
7.5 KiB
C
363 lines
7.5 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 3.0
|
|
tdb utility functions
|
|
Copyright (C) Andrew Tridgell 1992-1998
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
/* these are little tdb utility functions that are meant to make
|
|
dealing with a tdb database a little less cumbersome in Samba */
|
|
|
|
/* lock a chain by string */
|
|
int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
|
|
{
|
|
TDB_DATA key;
|
|
|
|
key.dptr = keyval;
|
|
key.dsize = strlen(keyval)+1;
|
|
|
|
return tdb_chainlock(tdb, key);
|
|
}
|
|
|
|
/* unlock a chain by string */
|
|
void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
|
|
{
|
|
TDB_DATA key;
|
|
|
|
key.dptr = keyval;
|
|
key.dsize = strlen(keyval)+1;
|
|
|
|
tdb_chainunlock(tdb, key);
|
|
}
|
|
|
|
/* fetch a value by a arbitrary blob key, return -1 if not found */
|
|
int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
|
|
{
|
|
TDB_DATA key, data;
|
|
int ret;
|
|
|
|
key.dptr = keyval;
|
|
key.dsize = len;
|
|
data = tdb_fetch(tdb, key);
|
|
if (!data.dptr || data.dsize != sizeof(int)) return -1;
|
|
|
|
memcpy(&ret, data.dptr, sizeof(int));
|
|
free(data.dptr);
|
|
return ret;
|
|
}
|
|
|
|
/* fetch a value by string key, return -1 if not found */
|
|
int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
|
|
{
|
|
return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
|
|
}
|
|
|
|
/* store a value by an arbitary blob key, return 0 on success, -1 on failure */
|
|
int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
|
|
{
|
|
TDB_DATA key, data;
|
|
|
|
key.dptr = keystr;
|
|
key.dsize = len;
|
|
data.dptr = (void *)&v;
|
|
data.dsize = sizeof(int);
|
|
|
|
return tdb_store(tdb, key, data, TDB_REPLACE);
|
|
}
|
|
|
|
/* store a value by string key, return 0 on success, -1 on failure */
|
|
int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
|
|
{
|
|
return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
|
|
}
|
|
|
|
/* Store a buffer by a null terminated string key. Return 0 on success, -1
|
|
on failure */
|
|
int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
|
|
{
|
|
TDB_DATA key, data;
|
|
|
|
key.dptr = keystr;
|
|
key.dsize = strlen(keystr) + 1;
|
|
|
|
data.dptr = buffer;
|
|
data.dsize = len;
|
|
|
|
return tdb_store(tdb, key, data, TDB_REPLACE);
|
|
}
|
|
|
|
/* Fetch a buffer using a null terminated string key. Don't forget to call
|
|
free() on the result dptr. */
|
|
|
|
TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
|
|
{
|
|
TDB_DATA key;
|
|
|
|
key.dptr = keystr;
|
|
key.dsize = strlen(keystr) + 1;
|
|
|
|
return tdb_fetch(tdb, key);
|
|
}
|
|
|
|
/* Atomic integer change. Returns old value. To create, set initial value in *oldval. */
|
|
|
|
int tdb_change_int_atomic(TDB_CONTEXT *tdb, char *keystr, int *oldval, int change_val)
|
|
{
|
|
int val;
|
|
int ret = -1;
|
|
|
|
if (tdb_lock_bystring(tdb, keystr) == -1)
|
|
return -1;
|
|
|
|
if ((val = tdb_fetch_int(tdb, keystr)) == -1) {
|
|
if (tdb_error(tdb) != TDB_ERR_NOEXIST)
|
|
goto err_out;
|
|
|
|
val = *oldval;
|
|
|
|
} else {
|
|
*oldval = val;
|
|
val += change_val;
|
|
}
|
|
|
|
if (tdb_store_int(tdb, keystr, val) == -1)
|
|
goto err_out;
|
|
|
|
ret = 0;
|
|
|
|
err_out:
|
|
|
|
tdb_unlock_bystring(tdb, keystr);
|
|
return ret;
|
|
}
|
|
|
|
/* useful pair of routines for packing/unpacking data consisting of
|
|
integers and strings */
|
|
size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
uint16 w;
|
|
uint32 d;
|
|
int i;
|
|
void *p;
|
|
int len;
|
|
char *s;
|
|
char c;
|
|
char *buf0 = buf;
|
|
char *fmt0 = fmt;
|
|
int bufsize0 = bufsize;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
while (*fmt) {
|
|
switch ((c = *fmt++)) {
|
|
case 'w':
|
|
len = 2;
|
|
w = (uint16)va_arg(ap, int);
|
|
if (bufsize >= len) {
|
|
SSVAL(buf, 0, w);
|
|
}
|
|
break;
|
|
case 'd':
|
|
len = 4;
|
|
d = va_arg(ap, uint32);
|
|
if (bufsize >= len) {
|
|
SIVAL(buf, 0, d);
|
|
}
|
|
break;
|
|
case 'p':
|
|
len = 4;
|
|
p = va_arg(ap, void *);
|
|
d = p?1:0;
|
|
if (bufsize >= len) {
|
|
SIVAL(buf, 0, d);
|
|
}
|
|
break;
|
|
case 'P':
|
|
s = va_arg(ap,char *);
|
|
w = strlen(s);
|
|
len = w + 1;
|
|
if (bufsize >= len) {
|
|
memcpy(buf, s, len);
|
|
}
|
|
break;
|
|
case 'f':
|
|
s = va_arg(ap,char *);
|
|
w = strlen(s);
|
|
len = w + 1;
|
|
if (bufsize >= len) {
|
|
memcpy(buf, s, len);
|
|
}
|
|
break;
|
|
case 'B':
|
|
i = va_arg(ap, int);
|
|
s = va_arg(ap, char *);
|
|
len = 4+i;
|
|
if (bufsize >= len) {
|
|
SIVAL(buf, 0, i);
|
|
memcpy(buf+4, s, i);
|
|
}
|
|
break;
|
|
default:
|
|
DEBUG(0,("Unknown tdb_pack format %c in %s\n",
|
|
c, fmt));
|
|
len = 0;
|
|
break;
|
|
}
|
|
|
|
buf += len;
|
|
bufsize -= len;
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
DEBUG(8,("tdb_pack(%s, %d) -> %d\n",
|
|
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
|
|
|
|
return PTR_DIFF(buf, buf0);
|
|
}
|
|
|
|
|
|
|
|
/* useful pair of routines for packing/unpacking data consisting of
|
|
integers and strings */
|
|
|
|
int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
uint16 *w;
|
|
uint32 *d;
|
|
int len;
|
|
int *i;
|
|
void **p;
|
|
char *s, **b;
|
|
char c;
|
|
char *buf0 = buf;
|
|
char *fmt0 = fmt;
|
|
int bufsize0 = bufsize;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
while (*fmt) {
|
|
switch ((c=*fmt++)) {
|
|
case 'w':
|
|
len = 2;
|
|
w = va_arg(ap, uint16 *);
|
|
if (bufsize < len) goto no_space;
|
|
*w = SVAL(buf, 0);
|
|
break;
|
|
case 'd':
|
|
len = 4;
|
|
d = va_arg(ap, uint32 *);
|
|
if (bufsize < len) goto no_space;
|
|
*d = IVAL(buf, 0);
|
|
break;
|
|
case 'p':
|
|
len = 4;
|
|
p = va_arg(ap, void **);
|
|
if (bufsize < len) goto no_space;
|
|
*p = (void *)IVAL(buf, 0);
|
|
break;
|
|
case 'P':
|
|
s = va_arg(ap,char *);
|
|
len = strlen(buf) + 1;
|
|
if (bufsize < len || len > sizeof(pstring)) goto no_space;
|
|
memcpy(s, buf, len);
|
|
break;
|
|
case 'f':
|
|
s = va_arg(ap,char *);
|
|
len = strlen(buf) + 1;
|
|
if (bufsize < len || len > sizeof(fstring)) goto no_space;
|
|
memcpy(s, buf, len);
|
|
break;
|
|
case 'B':
|
|
i = va_arg(ap, int *);
|
|
b = va_arg(ap, char **);
|
|
len = 4;
|
|
if (bufsize < len) goto no_space;
|
|
*i = IVAL(buf, 0);
|
|
if (! *i) {
|
|
*b = NULL;
|
|
break;
|
|
}
|
|
len += *i;
|
|
if (bufsize < len) goto no_space;
|
|
*b = (char *)malloc(*i);
|
|
if (! *b) goto no_space;
|
|
memcpy(*b, buf+4, *i);
|
|
break;
|
|
default:
|
|
DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
|
|
c, fmt));
|
|
|
|
len = 0;
|
|
break;
|
|
}
|
|
|
|
buf += len;
|
|
bufsize -= len;
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
DEBUG(8,("tdb_unpack(%s, %d) -> %d\n",
|
|
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
|
|
|
|
return PTR_DIFF(buf, buf0);
|
|
|
|
no_space:
|
|
return -1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
log tdb messages via DEBUG()
|
|
****************************************************************************/
|
|
static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
char *ptr = NULL;
|
|
|
|
va_start(ap, format);
|
|
vasprintf(&ptr, format, ap);
|
|
va_end(ap);
|
|
|
|
if (!ptr || !*ptr) return;
|
|
|
|
DEBUG(level, ("tdb(%s): %s", tdb->name, ptr));
|
|
free(ptr);
|
|
}
|
|
|
|
|
|
|
|
/* like tdb_open() but also setup a logging function that redirects to
|
|
the samba DEBUG() system */
|
|
TDB_CONTEXT *tdb_open_log(char *name, int hash_size, int tdb_flags,
|
|
int open_flags, mode_t mode)
|
|
{
|
|
TDB_CONTEXT *tdb;
|
|
|
|
if (!lp_use_mmap()) tdb_flags |= TDB_NOMMAP;
|
|
|
|
tdb = tdb_open(name, hash_size, tdb_flags,
|
|
open_flags, mode, tdb_log);
|
|
if (!tdb) return NULL;
|
|
|
|
return tdb;
|
|
}
|