]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/open.c
tdb2: save openhook, allow tdb_get_attribute() on it.
[ccan] / ccan / tdb2 / open.c
index e88c9e694c531b67bf4a6ff33d113a3b4078ad59..277a95f9e8ba7bb72caed6ac434f7ccb798ebc1c 100644 (file)
@@ -270,11 +270,11 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
                attr->seed.seed = tdb->hash_seed;
                break;
        case TDB_ATTRIBUTE_OPENHOOK:
-               return tdb->last_error
-                       = tdb_logerr(tdb, TDB_ERR_EINVAL,
-                                    TDB_LOG_USE_ERROR,
-                                    "tdb_get_attribute:"
-                                    " cannot get TDB_ATTRIBUTE_OPENHOOK");
+               if (!tdb->openhook)
+                       return tdb->last_error = TDB_ERR_NOEXIST;
+               attr->openhook.fn = tdb->openhook;
+               attr->openhook.data = tdb->openhook_data;
+               break;
        case TDB_ATTRIBUTE_STATS: {
                size_t size = attr->stats.size;
                if (size > tdb->stats.size)
@@ -306,16 +306,16 @@ void tdb_unset_attribute(struct tdb_context *tdb,
        case TDB_ATTRIBUTE_LOG:
                tdb->log_fn = NULL;
                break;
+       case TDB_ATTRIBUTE_OPENHOOK:
+               tdb->openhook = NULL;
+               break;
        case TDB_ATTRIBUTE_HASH:
        case TDB_ATTRIBUTE_SEED:
-       case TDB_ATTRIBUTE_OPENHOOK:
                tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
                           "tdb_unset_attribute: cannot unset %s after opening",
                           type == TDB_ATTRIBUTE_HASH
                           ? "TDB_ATTRIBUTE_HASH"
-                          : type == TDB_ATTRIBUTE_SEED
-                          ? "TDB_ATTRIBUTE_SEED"
-                          : "TDB_ATTRIBUTE_OPENHOOK");
+                          : "TDB_ATTRIBUTE_SEED");
                break;
        case TDB_ATTRIBUTE_STATS:
                tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -347,7 +347,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        ssize_t rlen;
        struct tdb_header hdr;
        struct tdb_attribute_seed *seed = NULL;
-       struct tdb_attribute_openhook *openhook = NULL;
        tdb_bool_err berr;
        enum TDB_ERROR ecode;
        int openlock;
@@ -369,8 +368,10 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        tdb->log_fn = NULL;
        tdb->transaction = NULL;
        tdb->access = NULL;
+       tdb->open_flags = open_flags;
        tdb->last_error = TDB_SUCCESS;
        tdb->file = NULL;
+       tdb->openhook = NULL;
        tdb->lock_fn = tdb_fcntl_lock;
        tdb->unlock_fn = tdb_fcntl_unlock;
        tdb->hash_fn = jenkins_hash;
@@ -389,7 +390,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                        seed = &attr->seed;
                        break;
                case TDB_ATTRIBUTE_OPENHOOK:
-                       openhook = &attr->openhook;
+                       tdb->openhook = attr->openhook.fn;
+                       tdb->openhook_data = attr->openhook.data;
                        break;
                default:
                        /* These are set as normal. */
@@ -401,7 +403,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        }
 
        if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT
-                         | TDB_NOSYNC | TDB_SEQNUM | TDB_ALLOW_NESTING)) {
+                         | TDB_NOSYNC | TDB_SEQNUM | TDB_ALLOW_NESTING
+                         | TDB_RDONLY)) {
                ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
                                   "tdb_open: unknown flags %u", tdb_flags);
                goto fail;
@@ -415,12 +418,16 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        }
 
        if ((open_flags & O_ACCMODE) == O_RDONLY) {
-               tdb->read_only = true;
-               tdb->mmap_flags = PROT_READ;
                openlock = F_RDLCK;
+               tdb->flags |= TDB_RDONLY;
        } else {
-               tdb->read_only = false;
-               tdb->mmap_flags = PROT_READ | PROT_WRITE;
+               if (tdb_flags & TDB_RDONLY) {
+                       ecode = tdb_logerr(tdb, TDB_ERR_EINVAL,
+                                          TDB_LOG_USE_ERROR,
+                                          "tdb_open: can't use TDB_RDONLY"
+                                          " without O_RDONLY");
+                       goto fail;
+               }
                openlock = F_WRLCK;
        }
 
@@ -492,8 +499,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        }
 
        /* call their open hook if they gave us one. */
-       if (openhook) {
-               ecode = openhook->fn(tdb->file->fd, openhook->data);
+       if (tdb->openhook) {
+               ecode = tdb->openhook(tdb->file->fd, tdb->openhook_data);
                if (ecode != TDB_SUCCESS) {
                        tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
                                   "tdb_open: open hook failed");
@@ -532,6 +539,12 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                                           name, (long long)hdr.version);
                        goto fail;
                }
+       } else if (tdb->flags & TDB_CONVERT) {
+               ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+                                  "tdb_open:"
+                                  " %s does not need TDB_CONVERT",
+                                  name);
+               goto fail;
        }
 
        tdb_convert(tdb, &hdr, sizeof(hdr));
@@ -550,17 +563,20 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        /* Clear any features we don't understand. */
        if ((open_flags & O_ACCMODE) != O_RDONLY) {
                hdr.features_used &= TDB_FEATURE_MASK;
-               if (tdb_write_convert(tdb, offsetof(struct tdb_header,
-                                                   features_used),
-                                     &hdr.features_used,
-                                     sizeof(hdr.features_used)) == -1)
+               ecode = tdb_write_convert(tdb, offsetof(struct tdb_header,
+                                                       features_used),
+                                         &hdr.features_used,
+                                         sizeof(hdr.features_used));
+               if (ecode != TDB_SUCCESS)
                        goto fail;
        }
 
        tdb_unlock_open(tdb, openlock);
 
        /* This make sure we have current map_size and mmap. */
-       tdb->methods->oob(tdb, tdb->file->map_size + 1, true);
+       ecode = tdb->methods->oob(tdb, tdb->file->map_size + 1, true);
+       if (unlikely(ecode != TDB_SUCCESS))
+               goto fail;
 
        /* Now it's fully formed, recover if necessary. */
        berr = tdb_needs_recovery(tdb);