1/* 2 * $Id: cnid_tdb_lookup.c,v 1.6 2009-11-21 11:12:49 didg Exp $ 3 */ 4 5#ifdef HAVE_CONFIG_H 6#include "config.h" 7#endif 8 9#ifdef CNID_BACKEND_TDB 10 11#include "cnid_tdb.h" 12#include <atalk/logger.h> 13 14cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, char *name, const size_t len) 15{ 16 char *buf; 17 struct _cnid_tdb_private *db; 18 TDB_DATA key, devdata, diddata, cniddata; 19 int devino = 1, didname = 1; 20 char dev[CNID_DEV_LEN]; 21 char ino[CNID_INO_LEN]; 22 u_int32_t type_devino = (unsigned)-1; 23 u_int32_t type_didname = (unsigned)-1; 24 u_int32_t type; 25 int update = 0; 26 cnid_t id_devino = 0, id_didname = 0,id = 0; 27 28 if (!cdb || !(db = cdb->_private) || !st || !name) { 29 return 0; 30 } 31 32 if ((buf = make_tdb_data(cdb->flags, st, did, name, len)) == NULL) { 33 LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long"); 34 return 0; 35 } 36 memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type)); 37 type = ntohl(type); 38 39 memset(&key, 0, sizeof(key)); 40 memset(&devdata, 0, sizeof(devdata)); 41 memset(&diddata, 0, sizeof(diddata)); 42 memset(&cniddata, 0, sizeof(cniddata)); 43 44 /* Look for a CNID. We have two options: dev/ino or did/name. If we 45 * only get a match in one of them, that means a file has moved. */ 46 memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN); 47 memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN); 48 49 key.dptr = buf +CNID_DEVINO_OFS; 50 key.dsize = CNID_DEVINO_LEN; 51 cniddata = tdb_fetch(db->tdb_devino, key); 52 if (!cniddata.dptr) { 53 devino = 0; 54 } 55 else { 56 57 key.dptr = cniddata.dptr; 58 key.dsize = sizeof(id); 59 60 devdata = tdb_fetch(db->tdb_cnid, key); 61 free(cniddata.dptr); 62 if (devdata.dptr) { 63 memcpy(&id_devino, devdata.dptr, sizeof(cnid_t)); 64 memcpy(&type_devino, (char *)devdata.dptr +CNID_TYPE_OFS, sizeof(type_devino)); 65 type_devino = ntohl(type_devino); 66 } 67 else { 68 devino = 0; 69 } 70 } 71 72 /* did/name now */ 73 key.dptr = buf + CNID_DID_OFS; 74 key.dsize = CNID_DID_LEN + len + 1; 75 cniddata = tdb_fetch(db->tdb_didname, key); 76 if (!cniddata.dptr) { 77 didname = 0; 78 } 79 else { 80 81 key.dptr = cniddata.dptr; 82 key.dsize = sizeof(id); 83 84 diddata = tdb_fetch(db->tdb_cnid, key); 85 free(cniddata.dptr); 86 if (diddata.dptr) { 87 memcpy(&id_didname, diddata.dptr, sizeof(cnid_t)); 88 memcpy(&type_didname, (char *)diddata.dptr +CNID_TYPE_OFS, sizeof(type_didname)); 89 type_didname = ntohl(type_didname); 90 } 91 else { 92 didname = 0; 93 } 94 } 95 /* Set id. Honor did/name over dev/ino as dev/ino isn't necessarily 96 * 1-1. */ 97 if (!devino && !didname) { 98 free(devdata.dptr); 99 free(diddata.dptr); 100 return 0; 101 } 102 103 if (devino && didname && id_devino == id_didname && type_devino == type) { 104 /* the same */ 105 free(devdata.dptr); 106 free(diddata.dptr); 107 return id_didname; 108 } 109 110 if (didname) { 111 id = id_didname; 112 /* we have a did:name 113 * if it's the same dev or not the same type 114 * just delete it 115 */ 116 if (!memcmp(dev, (char *)diddata.dptr + CNID_DEV_OFS, CNID_DEV_LEN) || 117 type_didname != type) { 118 if (cnid_tdb_delete(cdb, id) < 0) { 119 free(devdata.dptr); 120 free(diddata.dptr); 121 return 0; 122 } 123 } 124 else { 125 update = 1; 126 } 127 } 128 129 if (devino) { 130 id = id_devino; 131 if (type_devino != type) { 132 /* same dev:inode but not same type one is a folder the other 133 * is a file,it's an inode reused, delete the record 134 */ 135 if (cnid_tdb_delete(cdb, id) < 0) { 136 free(devdata.dptr); 137 free(diddata.dptr); 138 return 0; 139 } 140 } 141 else { 142 update = 1; 143 } 144 } 145 free(devdata.dptr); 146 free(diddata.dptr); 147 if (!update) { 148 return 0; 149 } 150 151 /* Fix up the database. */ 152 cnid_tdb_update(cdb, id, st, did, name, len); 153 return id; 154} 155 156#endif 157