summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pool <mbp@samba.org>2001-12-04 02:58:42 +0000
committerMartin Pool <mbp@samba.org>2001-12-04 02:58:42 +0000
commit6c3163cc9715188ee8087c6dbf63776f0dc9f1f5 (patch)
treecfcadaf2ef65789212e413ae77b6635963aca95b
parentc2e3d8ba018221c0a0b22a91fdb361dd740482b9 (diff)
downloadsamba-6c3163cc9715188ee8087c6dbf63776f0dc9f1f5.tar.gz
samba-6c3163cc9715188ee8087c6dbf63776f0dc9f1f5.tar.bz2
samba-6c3163cc9715188ee8087c6dbf63776f0dc9f1f5.zip
Set errno in tdb_open in cases where we detect an error in opening the
database, but no underlying system call sets errno. The particular case I had was a mangled .tdb, but there are others. For this one, set EIO. It's a shame Unix messages aren't more detailed -- "bad data format" would be better. (This used to be commit 5630a988be05c21b60aba6304d4aaadce6024817)
-rw-r--r--source3/tdb/README3
-rw-r--r--source3/tdb/tdb.c44
2 files changed, 35 insertions, 12 deletions
diff --git a/source3/tdb/README b/source3/tdb/README
index fac3eacb4d..3715c685c2 100644
--- a/source3/tdb/README
+++ b/source3/tdb/README
@@ -60,7 +60,8 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
The hash size is advisory, use zero for a default value.
- return is NULL on error
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno).
possible tdb_flags are:
TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c
index 69e36ebd3e..31733e9ece 100644
--- a/source3/tdb/tdb.c
+++ b/source3/tdb/tdb.c
@@ -149,7 +149,10 @@ struct list_struct {
};
/* a byte range locking function - return 0 on success
- this functions locks/unlocks 1 byte at the specified offset */
+ this functions locks/unlocks 1 byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open(). */
static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
int rw_type, int lck_type, int probe)
{
@@ -157,8 +160,10 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
if (tdb->flags & TDB_NOLOCK)
return 0;
- if (tdb->read_only)
+ if (tdb->read_only) {
+ errno = EACCES;
return -1;
+ }
fl.l_type = rw_type;
fl.l_whence = SEEK_SET;
@@ -171,6 +176,7 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
TDB_LOG((tdb, 5,"tdb_brlock failed at offset %d rw_type=%d lck_type=%d\n",
offset, rw_type, lck_type));
}
+ /* errno set by fcntl */
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
return 0;
@@ -1369,7 +1375,8 @@ int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
database file. A flags value of O_WRONLY is invalid. The hash size
is advisory, use zero for a default value.
- return is NULL on error */
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno). */
TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode)
{
@@ -1385,8 +1392,11 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
tdb.flags = tdb_flags;
tdb.open_flags = open_flags;
- if ((open_flags & O_ACCMODE) == O_WRONLY)
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ errno = EINVAL;
goto fail;
+ }
+
if (hash_size == 0)
hash_size = DEFAULT_HASH_SIZE;
if ((open_flags & O_ACCMODE) == O_RDONLY) {
@@ -1405,18 +1415,18 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
}
if ((tdb.fd = open(name, open_flags, mode)) == -1)
- goto fail;
+ goto fail; /* errno set by open(2) */
/* ensure there is only one process initialising at once */
if (tdb_brlock(&tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1)
- goto fail;
+ goto fail; /* errno set by tdb_brlock */
/* we need to zero database if we are the only one with it open */
if ((locked = (tdb_brlock(&tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))
&& (tdb_flags & TDB_CLEAR_IF_FIRST)) {
open_flags |= O_CREAT;
if (ftruncate(tdb.fd, 0) == -1)
- goto fail;
+ goto fail; /* errno set by ftruncate */
}
if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header)
@@ -1424,8 +1434,10 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
|| (tdb.header.version != TDB_VERSION
&& !(rev = (tdb.header.version==TDB_BYTEREV(TDB_VERSION))))) {
/* its not a valid database - possibly initialise it */
- if (!(open_flags & O_CREAT) || tdb_new_database(&tdb, hash_size) == -1)
+ if (!(open_flags & O_CREAT) || tdb_new_database(&tdb, hash_size) == -1) {
+ errno = EIO; /* ie bad format or something */
goto fail;
+ }
rev = (tdb.flags & TDB_CONVERT);
}
if (!rev)
@@ -1448,14 +1460,18 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
/* map the database and fill in the return structure */
tdb.name = (char *)strdup(name);
- if (!tdb.name)
+ if (!tdb.name) {
+ errno = ENOMEM;
goto fail;
+ }
tdb.map_size = st.st_size;
tdb.device = st.st_dev;
tdb.inode = st.st_ino;
tdb.locked = calloc(tdb.header.hash_size+1, sizeof(tdb.locked[0]));
- if (!tdb.locked)
+ if (!tdb.locked) {
+ errno = ENOMEM;
goto fail;
+ }
tdb_mmap(&tdb);
if (locked) {
if (!tdb.read_only)
@@ -1468,8 +1484,10 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
goto fail;
internal:
- if (!(ret = malloc(sizeof(tdb))))
+ if (!(ret = malloc(sizeof(tdb)))) {
+ errno = ENOMEM;
goto fail;
+ }
*ret = tdb;
if (tdb_brlock(&tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
goto fail;
@@ -1478,6 +1496,8 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
return ret;
fail:
+ { int save_errno = errno;
+
if (tdb.map_ptr) {
if (tdb.flags & TDB_INTERNAL)
free(tdb.map_ptr);
@@ -1490,7 +1510,9 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
close(tdb.fd);
if (tdb.locked)
free(tdb.locked);
+ errno = save_errno;
return NULL;
+ }
}
/* close a database */