dbwrap: Add code to marshall a db_context's db
authorVolker Lendecke <vl@samba.org>
Wed, 5 Nov 2014 13:02:38 +0000 (13:02 +0000)
committerJeremy Allison <jra@samba.org>
Tue, 16 Dec 2014 17:56:03 +0000 (18:56 +0100)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
lib/dbwrap/dbwrap.h
lib/dbwrap/dbwrap_util.c

index e56e036c4c4f18fd589683547f4c14d9380e6c15..00c7672a9054d3587823c5c5206ffc9fe5331670 100644 (file)
@@ -155,6 +155,15 @@ NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
                                     const char *key, TDB_DATA *value);
 
+size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize);
+NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
+                                  bool (*fn)(TDB_DATA key, TDB_DATA value,
+                                             void *private_data),
+                                  void *private_data);
+NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
+                          size_t buflen);
+
+
 /**
  * This opens an ntdb or tdb file: you can hand it a .ntdb or .tdb extension
  * and it will decide (based on parameter settings, or else what exists) which
index 4185fff9dd35407926226ba13ef01b38f710ed78..901ef564ab7b4cb4b605be46dfdec62abdbb8c85 100644 (file)
@@ -595,3 +595,169 @@ NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
        talloc_free(key_upper);
        return status;
 }
+
+struct dbwrap_marshall_state {
+       uint8_t *buf;
+       size_t bufsize;
+       size_t dbsize;
+};
+
+static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
+{
+       struct dbwrap_marshall_state *state = private_data;
+       TDB_DATA key, value;
+       size_t new_dbsize;
+
+       key = dbwrap_record_get_key(rec);
+       value = dbwrap_record_get_value(rec);
+
+       new_dbsize = state->dbsize;
+       new_dbsize += 8 + key.dsize;
+       new_dbsize += 8 + value.dsize;
+
+       if (new_dbsize <= state->bufsize) {
+               uint8_t *p = state->buf + state->dbsize;
+
+               SBVAL(p, 0, key.dsize);
+               p += 8;
+               memcpy(p, key.dptr, key.dsize);
+               p += key.dsize;
+
+               SBVAL(p, 0, value.dsize);
+               p += 8;
+               memcpy(p, value.dptr, value.dsize);
+       }
+       state->dbsize = new_dbsize;
+       return 0;
+}
+
+size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
+{
+       struct dbwrap_marshall_state state;
+
+       state.bufsize = bufsize;
+       state.buf = buf;
+       state.dbsize = 0;
+
+       dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
+
+       return state.dbsize;
+}
+
+static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
+                                         size_t ofs, TDB_DATA *pdata)
+{
+       uint64_t space, len;
+       const uint8_t *p;
+
+       if (ofs == buflen) {
+               return 0;
+       }
+       if (ofs > buflen) {
+               return -1;
+       }
+
+       space = buflen - ofs;
+       if (space < 8) {
+               return -1;
+       }
+
+       p = buf + ofs;
+       len = BVAL(p, 0);
+
+       p += 8;
+       space -= 8;
+
+       if (len > space) {
+               return -1;
+       }
+
+       *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
+                             .dsize = len };
+       return len + 8;
+}
+
+NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
+                                  bool (*fn)(TDB_DATA key, TDB_DATA value,
+                                             void *private_data),
+                                  void *private_data)
+{
+       size_t ofs = 0;
+
+       while (true) {
+               ssize_t len;
+               TDB_DATA key, value;
+               bool ok;
+
+               len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
+               if (len == 0) {
+                       break;
+               }
+               if (len == -1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               ofs += len;
+
+               len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
+               if (len == 0) {
+                       break;
+               }
+               if (len == -1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               ofs += len;
+
+               ok = fn(key, value, private_data);
+               if (!ok) {
+                       break;
+               }
+       }
+
+       return NT_STATUS_OK;
+}
+
+struct dbwrap_unmarshall_state {
+       struct db_context *db;
+       NTSTATUS ret;
+};
+
+static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
+                                void *private_data)
+{
+       struct dbwrap_unmarshall_state *state = private_data;
+       struct db_record *rec;
+       NTSTATUS status;
+
+       rec = dbwrap_fetch_locked(state->db, state->db, key);
+       if (rec == NULL) {
+               DEBUG(10, ("%s: dbwrap_fetch_locked failed\n",
+                          __func__));
+               state->ret = NT_STATUS_NO_MEMORY;
+               return false;
+       }
+
+       status = dbwrap_record_store(rec, value, 0);
+       TALLOC_FREE(rec);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("%s: dbwrap_record_store failed: %s\n",
+                          __func__, nt_errstr(status)));
+               state->ret = status;
+               return false;
+       }
+
+       return true;
+}
+
+NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
+                          size_t buflen)
+{
+       struct dbwrap_unmarshall_state state = { .db = db };
+       NTSTATUS status;
+
+       status = dbwrap_parse_marshall_buf(buf, buflen,
+                                          dbwrap_unmarshall_fn, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       return state.ret;
+}