/* ------------------------ */ cnid_t cnid_cdb_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, char *name, const size_t len, cnid_t hint) { CNID_private *db; DBT key, data; int rc; if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) { errno = CNID_ERR_PARAM; return CNID_INVALID; } #if 0 /* FIXME: Bjoern does a lookup. Should we not overwrite unconditionally? */ /* Do a lookup. */ id = cnid_cdb_lookup(cdb, st, did, name, len); /* ... Return id if it is valid, or if Rootinfo is read-only. */ if (id || (db->flags & CNIDFLAG_DB_RO)) { #ifdef DEBUG LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id)); #endif return id; } #endif /* Initialize our DBT data structures. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) { LOG(log_error, logtype_default, "cnid_add: Path name is too long"); errno = CNID_ERR_PATH; return CNID_INVALID; } data.size = CNID_HEADER_LEN + len + 1; memcpy(data.data, &hint, sizeof(hint)); key.data = &hint; key.size = sizeof(hint); /* Now we need to add the CNID data to the databases. */ if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) { LOG(log_error, logtype_default , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", name, ntohl(hint), db_strerror(rc)); errno = CNID_ERR_DB; goto cleanup; } if (set_max_cnid(db, hint) == CNID_INVALID) { errno = CNID_ERR_DB; goto cleanup; } #ifdef DEBUG LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint)); #endif return hint; cleanup: return CNID_INVALID; }
/* cnid_update: takes the given cnid and updates the metadata. To * handle the did/name data, there are a bunch of functions to get * and set the various fields. */ int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st, const cnid_t did, char *name, const size_t len /*, const char *info, const int infolen*/) { unsigned char *buf; CNID_private *db; DBT key, pkey, data; int rc; int notfound = 0; char getbuf[CNID_HEADER_LEN + MAXPATHLEN +1]; if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) { return -1; } memset(&key, 0, sizeof(key)); memset(&pkey, 0, sizeof(pkey)); memset(&data, 0, sizeof(data)); buf = make_cnid_data(cdb->flags, st, did, name, len); key.data = buf +CNID_DEVINO_OFS; key.size = CNID_DEVINO_LEN; data.data = getbuf; data.size = CNID_HEADER_LEN + MAXPATHLEN + 1; if (0 != (rc = db->db_devino->pget(db->db_devino, tid, &key, &pkey, &data, 0)) ) { #if DB_VERSION_MAJOR >= 4 if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) { #else if (rc != DB_NOTFOUND) { #endif LOG(log_error, logtype_default, "cnid_update: Unable to get devino CNID %u, name %s: %s", ntohl(did), name, db_strerror(rc)); goto fin; } notfound = 1; } else { if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) { LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s", ntohl(id), db_strerror(rc)); } } memset(&pkey, 0, sizeof(pkey)); buf = make_cnid_data(cdb->flags, st, did, name, len); key.data = buf + CNID_DID_OFS; key.size = CNID_DID_LEN + len + 1; if (0 != (rc = db->db_didname->pget(db->db_didname, tid, &key, &pkey, &data, 0)) ) { #if DB_VERSION_MAJOR >= 4 if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) { #else if (rc != DB_NOTFOUND) { #endif LOG(log_error, logtype_default, "cnid_update: Unable to get didname CNID %u, name %s: %s", ntohl(did), name, db_strerror(rc)); goto fin; } notfound |= 2; } else { if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) { LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s", ntohl(id), db_strerror(rc)); } } memset(&key, 0, sizeof(key)); key.data = (cnid_t *)&id; key.size = sizeof(id); memset(&data, 0, sizeof(data)); /* Make a new entry. */ buf = make_cnid_data(cdb->flags, st, did, name, len); data.data = buf; memcpy(data.data, &id, sizeof(id)); data.size = CNID_HEADER_LEN + len + 1; /* Update the old CNID with the new info. */ if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) { LOG(log_error, logtype_default, "cnid_update: (%d) Unable to update CNID %u:%s: %s", notfound, ntohl(id), name, db_strerror(rc)); goto fin; } return 0; fin: return -1; }
/* ------------------------ */ cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len, cnid_t hint) { CNID_private *db; DBT key, data; cnid_t id; int rc; if (!cdb || !(db = cdb->_private) || !st || !name) { errno = CNID_ERR_PARAM; return CNID_INVALID; } /* Do a lookup. */ id = cnid_cdb_lookup(cdb, st, did, name, len); /* ... Return id if it is valid, or if Rootinfo is read-only. */ if (id || (db->flags & CNIDFLAG_DB_RO)) { #ifdef DEBUG LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id)); #endif return id; } /* Initialize our DBT data structures. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) { LOG(log_error, logtype_default, "cnid_add: Path name is too long"); errno = CNID_ERR_PATH; return CNID_INVALID; } data.size = CNID_HEADER_LEN + len + 1; if ((hint = get_cnid(db)) == 0) { errno = CNID_ERR_DB; return CNID_INVALID; } memcpy(data.data, &hint, sizeof(hint)); key.data = &hint; key.size = sizeof(hint); /* Now we need to add the CNID data to the databases. */ if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) { if (rc == EINVAL) { /* if we have a duplicate * on cnid it's a fatal error. * on dev:inode * - leftover should have been delete before. * - a second process already updated the db * - it's a new file eg our file is already deleted and replaced * on did:name leftover */ if (cnid_cdb_update(cdb, hint, st, did, name, len)) { errno = CNID_ERR_DB; return CNID_INVALID; } } else { LOG(log_error, logtype_default , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", name, ntohl(hint), db_strerror(rc)); errno = CNID_ERR_DB; return CNID_INVALID; } } #ifdef DEBUG LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint)); #endif return hint; }
/* This returns the CNID corresponding to a particular file. It will * also fix up the various databases if there's a problem. */ cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len) { unsigned char *buf; CNID_private *db; DBT key, devdata, diddata; char dev[CNID_DEV_LEN]; char ino[CNID_INO_LEN]; int devino = 1, didname = 1; u_int32_t type_devino = (unsigned)-1; u_int32_t type_didname = (unsigned)-1; u_int32_t type; int update = 0; cnid_t id_devino, id_didname,id = 0; int rc; if (!cdb || !(db = cdb->_private) || !st || !name) { return 0; } if ((buf = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) { LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long"); return 0; } memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type)); type = ntohl(type); memset(&key, 0, sizeof(key)); memset(&diddata, 0, sizeof(diddata)); memset(&devdata, 0, sizeof(devdata)); /* Look for a CNID for our did/name */ key.data = buf +CNID_DEVINO_OFS; key.size = CNID_DEVINO_LEN; memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN); memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN); if (0 != (rc = db->db_didname->get(db->db_devino, NULL, &key, &devdata, 0 )) ) { if (rc != DB_NOTFOUND) { LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s", did, name, db_strerror(rc)); return 0; } devino = 0; } else { memcpy(&id_devino, devdata.data, sizeof(cnid_t)); memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino)); type_devino = ntohl(type_devino); } buf = make_cnid_data(cdb->flags, st, did, name, len); key.data = buf +CNID_DID_OFS; key.size = CNID_DID_LEN + len + 1; if (0 != (rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0 ) ) ) { if (rc != DB_NOTFOUND) { LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s", did, name, db_strerror(rc)); return 0; } didname = 0; } else { memcpy(&id_didname, diddata.data, sizeof(cnid_t)); memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname)); type_didname = ntohl(type_didname); } if (!devino && !didname) { return 0; } if (devino && didname && id_devino == id_didname && type_devino == type) { /* the same */ return id_didname; } if (didname) { id = id_didname; /* we have a did:name * if it's the same dev or not the same type * just delete it */ if (!memcmp(dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) || type_didname != type) { if (cnid_cdb_delete(cdb, id) < 0) { return 0; } } else { update = 1; } } if (devino) { id = id_devino; if (type_devino != type) { /* same dev:inode but not same type one is a folder the other * is a file,it's an inode reused, delete the record */ if (cnid_cdb_delete(cdb, id) < 0) { return 0; } } else { update = 1; } } if (!update) { return 0; } /* Fix up the database. assume it was a file move and rename */ cnid_cdb_update(cdb, id, st, did, name, len); #ifdef DEBUG LOG(log_debug9, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id)); #endif return id; }