From 8ccd47e0075a70a897c12dd349108a87fd88fda7 Mon Sep 17 00:00:00 2001 From: didg Date: Sat, 21 Nov 2009 11:12:49 +0000 Subject: [PATCH] fixes for tdb remaining errors vs cdb --- libatalk/cnid/tdb/cnid_tdb_lookup.c | 112 ++++++++++++++++++++++++---- libatalk/cnid/tdb/cnid_tdb_update.c | 3 +- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/libatalk/cnid/tdb/cnid_tdb_lookup.c b/libatalk/cnid/tdb/cnid_tdb_lookup.c index c6933414..ba47e368 100644 --- a/libatalk/cnid/tdb/cnid_tdb_lookup.c +++ b/libatalk/cnid/tdb/cnid_tdb_lookup.c @@ -1,5 +1,5 @@ /* - * $Id: cnid_tdb_lookup.c,v 1.5 2009-11-20 19:25:05 didg Exp $ + * $Id: cnid_tdb_lookup.c,v 1.6 2009-11-21 11:12:49 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -15,9 +15,15 @@ cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t { char *buf; struct _cnid_tdb_private *db; - TDB_DATA key, devdata, diddata; + TDB_DATA key, devdata, diddata, cniddata; int devino = 1, didname = 1; - cnid_t id = 0; + char dev[CNID_DEV_LEN]; + char ino[CNID_INO_LEN]; + 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 = 0, id_didname = 0,id = 0; if (!cdb || !(db = cdb->_private) || !st || !name) { return 0; @@ -27,39 +33,119 @@ cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long"); return 0; } + memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type)); + type = ntohl(type); memset(&key, 0, sizeof(key)); memset(&devdata, 0, sizeof(devdata)); memset(&diddata, 0, sizeof(diddata)); + memset(&cniddata, 0, sizeof(cniddata)); /* Look for a CNID. We have two options: dev/ino or did/name. If we * only get a match in one of them, that means a file has moved. */ + memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN); + memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN); + key.dptr = buf +CNID_DEVINO_OFS; key.dsize = CNID_DEVINO_LEN; - devdata = tdb_fetch(db->tdb_devino, key); - if (!devdata.dptr) { + cniddata = tdb_fetch(db->tdb_devino, key); + if (!cniddata.dptr) { devino = 0; } + else { + + key.dptr = cniddata.dptr; + key.dsize = sizeof(id); + + devdata = tdb_fetch(db->tdb_cnid, key); + free(cniddata.dptr); + if (devdata.dptr) { + memcpy(&id_devino, devdata.dptr, sizeof(cnid_t)); + memcpy(&type_devino, (char *)devdata.dptr +CNID_TYPE_OFS, sizeof(type_devino)); + type_devino = ntohl(type_devino); + } + else { + devino = 0; + } + } + /* did/name now */ key.dptr = buf + CNID_DID_OFS; key.dsize = CNID_DID_LEN + len + 1; - diddata = tdb_fetch(db->tdb_didname, key); - if (!diddata.dptr) { + cniddata = tdb_fetch(db->tdb_didname, key); + if (!cniddata.dptr) { didname = 0; } + else { + + key.dptr = cniddata.dptr; + key.dsize = sizeof(id); + + diddata = tdb_fetch(db->tdb_cnid, key); + free(cniddata.dptr); + if (diddata.dptr) { + memcpy(&id_didname, diddata.dptr, sizeof(cnid_t)); + memcpy(&type_didname, (char *)diddata.dptr +CNID_TYPE_OFS, sizeof(type_didname)); + type_didname = ntohl(type_didname); + } + else { + didname = 0; + } + } /* Set id. Honor did/name over dev/ino as dev/ino isn't necessarily * 1-1. */ + if (!devino && !didname) { + free(devdata.dptr); + free(diddata.dptr); + return 0; + } + + if (devino && didname && id_devino == id_didname && type_devino == type) { + /* the same */ + free(devdata.dptr); + free(diddata.dptr); + return id_didname; + } + if (didname) { - memcpy(&id, diddata.dptr, sizeof(id)); + 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.dptr + CNID_DEV_OFS, CNID_DEV_LEN) || + type_didname != type) { + if (cnid_tdb_delete(cdb, id) < 0) { + free(devdata.dptr); + free(diddata.dptr); + return 0; + } + } + else { + update = 1; + } } - else if (devino) { - memcpy(&id, devdata.dptr, sizeof(id)); + + 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_tdb_delete(cdb, id) < 0) { + free(devdata.dptr); + free(diddata.dptr); + return 0; + } + } + else { + update = 1; + } } free(devdata.dptr); free(diddata.dptr); - /* Either entries are in both databases or neither of them. */ - if ((devino && didname) || !(devino || didname)) { - return id; + if (!update) { + return 0; } /* Fix up the database. */ diff --git a/libatalk/cnid/tdb/cnid_tdb_update.c b/libatalk/cnid/tdb/cnid_tdb_update.c index 44873ac9..8c4d35e3 100644 --- a/libatalk/cnid/tdb/cnid_tdb_update.c +++ b/libatalk/cnid/tdb/cnid_tdb_update.c @@ -1,5 +1,5 @@ /* - * $Id: cnid_tdb_update.c,v 1.5 2009-11-20 19:25:05 didg Exp $ + * $Id: cnid_tdb_update.c,v 1.6 2009-11-21 11:12:49 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -78,6 +78,7 @@ int cnid_tdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st /* Make a new entry. */ data.dptr = make_tdb_data(cdb->flags, st, did, name, len); data.dsize = CNID_HEADER_LEN + len + 1; + memcpy(data.dptr, &id, sizeof(id)); /* Update the old CNID with the new info. */ key.dptr = (char *) &id; -- 2.39.2