+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ if ((rc = dbif_get(srcdbd, DBIF_CNID, &key, &data, 0)) <= 0) {
+ LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error getting rootinfo record");
+ return -1;
+ }
+
+ memset(&key, 0, sizeof(key));
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ if ((rc = dbif_put(destdbd, DBIF_CNID, &key, &data, 0))) {
+ LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error writing rootinfo key");
+ return -1;
+ }
+
+ return 0;
+}
+
+int dbif_dump(DBD *dbd, int dumpindexes)
+{
+ int rc;
+ uint32_t max = 0, count = 0, cnid, type, did, lastid, version;
+ uint64_t dev, ino;
+ time_t stamp;
+ DBC *cur;
+ DBT key = { 0 }, data = { 0 };
+ DB *db = dbd->db_table[DBIF_CNID].db;
+ char *typestring[2] = {"f", "d"};
+ char timebuf[64];
+
+ printf("CNID database dump:\n");
+
+ rc = db->cursor(db, NULL, &cur, 0);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(rc));
+ return -1;
+ }
+
+ cur->c_get(cur, &key, &data, DB_FIRST);
+ while (rc == 0) {
+ /* Parse and print data */
+ memcpy(&cnid, key.data, 4);
+ cnid = ntohl(cnid);
+ if (cnid > max)
+ max = cnid;
+
+ /* Rootinfo node ? */
+ if (cnid == 0) {
+ memcpy(&stamp, (char *)data.data + CNID_DEV_OFS, sizeof(time_t));
+ memcpy(&lastid, (char *)data.data + CNID_TYPE_OFS, CNID_TYPE_LEN);
+ lastid = ntohl(lastid);
+ memcpy(&version, (char *)data.data + CNID_DID_OFS, CNID_DID_LEN);
+ version = ntohl(version);
+
+ strftime(timebuf, sizeof(timebuf), "%b %d %Y %H:%M:%S", localtime(&stamp));
+ printf("CNID db version: %u, dbd stamp: 0x%08x (%s), next free CNID: %u\n",
+ version, (unsigned int)stamp, timebuf, lastid + 1);
+ } else {
+ /* dev */
+ memcpy(&dev, (char *)data.data + CNID_DEV_OFS, 8);
+ dev = ntoh64(dev);
+ /* ino */
+ memcpy(&ino, (char *)data.data + CNID_INO_OFS, 8);
+ ino = ntoh64(ino);
+ /* type */
+ memcpy(&type, (char *)data.data + CNID_TYPE_OFS, 4);
+ type = ntohl(type);
+ /* did */
+ memcpy(&did, (char *)data.data + CNID_DID_OFS, 4);
+ did = ntohl(did);
+
+ count++;
+ printf("id: %10u, did: %10u, type: %s, dev: 0x%llx, ino: 0x%016llx, name: %s\n",
+ cnid, did, typestring[type],
+ (long long unsigned int)dev, (long long unsigned int)ino,
+ (char *)data.data + CNID_NAME_OFS);
+
+ }
+
+ rc = cur->c_get(cur, &key, &data, DB_NEXT);
+ }
+
+ if (rc != DB_NOTFOUND) {
+ LOG(log_error, logtype_cnid, "Error iterating over btree: %s", db_strerror(rc));
+ return -1;
+ }
+
+ rc = cur->c_close(cur);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't close cursor: %s", db_strerror(rc));
+ return -1;
+ }
+ printf("%u CNIDs in database. Max CNID: %u.\n", count, max);
+
+ /* Dump indexes too ? */
+ if (dumpindexes) {
+ /* DBIF_IDX_DEVINO */
+ printf("\ndev/inode index:\n");
+ count = 0;
+ db = dbd->db_table[DBIF_IDX_DEVINO].db;
+ rc = db->cursor(db, NULL, &cur, 0);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(rc));
+ return -1;
+ }
+
+ cur->c_get(cur, &key, &data, DB_FIRST);
+ while (rc == 0) {
+ /* Parse and print data */
+
+ /* cnid */
+ memcpy(&cnid, data.data, CNID_LEN);
+ cnid = ntohl(cnid);
+ if (cnid == 0) {
+ /* Rootinfo node */
+ } else {
+ /* dev */
+ memcpy(&dev, key.data, CNID_DEV_LEN);
+ dev = ntoh64(dev);
+ /* ino */
+ memcpy(&ino, (char *)key.data + CNID_DEV_LEN, CNID_INO_LEN);
+ ino = ntoh64(ino);
+
+ printf("id: %10u <== dev: 0x%llx, ino: 0x%016llx\n",
+ cnid, (unsigned long long int)dev, (unsigned long long int)ino);
+ count++;
+ }
+ rc = cur->c_get(cur, &key, &data, DB_NEXT);
+ }
+ if (rc != DB_NOTFOUND) {
+ LOG(log_error, logtype_cnid, "Error iterating over btree: %s", db_strerror(rc));
+ return -1;
+ }
+
+ rc = cur->c_close(cur);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't close cursor: %s", db_strerror(rc));
+ return -1;
+ }
+ printf("%u items\n", count);
+
+ /* Now dump DBIF_IDX_DIDNAME */
+ printf("\ndid/name index:\n");
+ count = 0;
+ db = dbd->db_table[DBIF_IDX_DIDNAME].db;
+ rc = db->cursor(db, NULL, &cur, 0);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(rc));
+ return -1;
+ }
+
+ cur->c_get(cur, &key, &data, DB_FIRST);
+ while (rc == 0) {
+ /* Parse and print data */
+
+ /* cnid */
+ memcpy(&cnid, data.data, CNID_LEN);
+ cnid = ntohl(cnid);
+ if (cnid == 0) {
+ /* Rootinfo node */
+ } else {
+ /* did */
+ memcpy(&did, key.data, CNID_LEN);
+ did = ntohl(did);
+
+ printf("id: %10u <== did: %10u, name: %s\n", cnid, did, (char *)key.data + CNID_LEN);
+ count++;
+ }
+ rc = cur->c_get(cur, &key, &data, DB_NEXT);
+ }
+ if (rc != DB_NOTFOUND) {
+ LOG(log_error, logtype_cnid, "Error iterating over btree: %s", db_strerror(rc));
+ return -1;
+ }
+
+ rc = cur->c_close(cur);
+ if (rc) {
+ LOG(log_error, logtype_cnid, "Couldn't close cursor: %s", db_strerror(rc));
+ return -1;
+ }
+ printf("%u items\n", count);
+ }
+
+ return 0;
+}
+
+/*
+ Iterates over dbd, returning cnids.
+ Uses in-value of cnid to seek to that cnid, then gets next and return that in cnid.
+ If close=1, close cursor.
+ Return -1 on error, 0 on EOD (end-of-database), 1 if returning cnid.
+*/
+int dbif_idwalk(DBD *dbd, cnid_t *cnid, int close)
+{
+ int rc;
+ int flag;
+ cnid_t id;
+
+ static DBT key = { 0 }, data = { 0 };
+ DB *db = dbd->db_table[DBIF_CNID].db;
+
+ if (close) {
+ if (dbd->db_cur) {
+ dbd->db_cur->close(dbd->db_cur);
+ dbd->db_cur = NULL;
+ }
+ return 0;
+ }
+
+ /* An dbif_del will have closed our cursor too */
+ if ( ! dbd->db_cur ) {
+ if ((rc = db->cursor(db, NULL, &dbd->db_cur, 0)) != 0) {
+ LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(rc));
+ return -1;
+ }
+ flag = DB_SET_RANGE; /* This will seek to next cnid after the one just deleted */
+ id = htonl(*cnid);
+ key.data = &id;
+ key.size = sizeof(cnid_t);
+ } else
+ flag = DB_NEXT;
+
+ if ((rc = dbd->db_cur->get(dbd->db_cur, &key, &data, flag)) == 0) {
+ memcpy(cnid, key.data, sizeof(cnid_t));
+ *cnid = ntohl(*cnid);
+ return 1;
+ }
+
+ if (rc != DB_NOTFOUND) {
+ LOG(log_error, logtype_cnid, "Error iterating over btree: %s", db_strerror(rc));
+ dbd->db_cur->close(dbd->db_cur);
+ dbd->db_cur = NULL;
+ return -1;
+ }
+
+ if (dbd->db_cur) {
+ dbd->db_cur->close(dbd->db_cur);
+ dbd->db_cur = NULL;
+ }
+
+ return 0;
+}