2 * $Id: dbd_lookup.c,v 1.9 2009-07-12 09:21:34 franklahm Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * All Rights Reserved. See COPYING.
10 whatever you change here, also change cmd_dbd_lookup.c !
11 cmd_dbd_lookup has an read-only mode but besides that it's the same.
17 Id Did T Dev Inode Name
18 ============================
23 ...are the expected results of certain operations.
28 Name is changed but inode stays the same. We should try to keep the CNID.
34 Result in dbd_lookup (-: not found, +: found):
44 Changes inode and name. Result is just a new file which will get a fresh CNID.
45 Unfortunately the old one gets orphaned.
55 Possible fixup solution:
56 Not possible. Only dbd -re can delete the orphaned CNID 15
59 3) Restore from backup
60 ----------------------
69 Possible fixup solution:
76 emacs uses a backup file (file~). When saving because of inode reusage of the fs,
77 both files exchange inodes. This should just be treated like 1).
89 Possible fixup solution:
90 Update CNID entry found via "didname"(!).
95 #endif /* HAVE_CONFIG_H */
100 #include <sys/param.h>
102 #include <netatalk/endian.h>
103 #include <atalk/logger.h>
104 #include <atalk/cnid_dbd_private.h>
111 * This returns the CNID corresponding to a particular file. It will also fix
112 * up the database if there's a problem.
115 int dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
118 DBT key, devdata, diddata;
119 char dev[CNID_DEV_LEN];
120 int devino = 1, didname = 1;
122 cnid_t id_devino, id_didname;
123 u_int32_t type_devino = (unsigned)-1;
124 u_int32_t type_didname = (unsigned)-1;
128 memset(&key, 0, sizeof(key));
129 memset(&diddata, 0, sizeof(diddata));
130 memset(&devdata, 0, sizeof(devdata));
135 buf = pack_cnid_data(rqst);
136 memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN);
138 /* Look for a CNID. We have two options: dev/ino or did/name. If we
139 only get a match in one of them, that means a file has moved. */
140 key.data = buf + CNID_DEVINO_OFS;
141 key.size = CNID_DEVINO_LEN;
143 if ((rc = dbif_get(dbd, DBIF_IDX_DEVINO, &key, &devdata, 0)) < 0) {
144 LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
145 ntohl(rqst->did), rqst->name);
146 rply->result = CNID_DBD_RES_ERR_DB;
153 memcpy(&id_devino, devdata.data, sizeof(rply->cnid));
154 memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
155 type_devino = ntohl(type_devino);
158 key.data = buf + CNID_DID_OFS;
159 key.size = CNID_DID_LEN + rqst->namelen + 1;
161 if ((rc = dbif_get(dbd, DBIF_IDX_DIDNAME, &key, &diddata, 0)) < 0) {
162 LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
163 ntohl(rqst->did), rqst->name);
164 rply->result = CNID_DBD_RES_ERR_DB;
171 memcpy(&id_didname, diddata.data, sizeof(rply->cnid));
172 memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
173 type_didname = ntohl(type_didname);
176 if (!devino && !didname) {
179 LOG(log_debug, logtype_cnid, "cnid_lookup: dev/ino 0x%llx/0x%llx did %u name %s neither in devino nor didname",
180 (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rqst->did), rqst->name);
182 rply->result = CNID_DBD_RES_NOTFOUND;
186 if (devino && didname && id_devino == id_didname && type_devino == rqst->type) {
189 LOG(log_debug, logtype_cnid, "cnid_lookup: Looked up dev/ino 0x%llx/0x%llx did %u name %s as %u",
190 (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rqst->did), rqst->name, ntohl(id_didname));
192 rply->cnid = id_didname;
193 rply->result = CNID_DBD_RES_OK;
198 Order matters for the next 2 ifs because both found a CNID but they do not match.
199 So in order to pick the CNID from "didname" it must come after devino.
200 See test cases laid out in dbd_lookup.c.
203 LOG(log_maxdebug, logtype_cnid, "CNID resolve problem: server side rename oder reused inode for '%s'", rqst->name);
204 rqst->cnid = id_devino;
205 if (type_devino != rqst->type) {
206 /* same dev:inode but not same type one is a folder the other
207 * is a file,it's an inode reused, delete the record
209 if (dbd_delete(dbd, rqst, rply, DBIF_CNID) < 0) {
218 LOG(log_maxdebug, logtype_cnid, "CNID resolve problem: changed dev/ino for '%s'", rqst->name);
219 rqst->cnid = id_didname;
220 /* we have a did:name
221 * if it's the same dev or not the same type
224 if (!memcmp(dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) ||
225 type_didname != rqst->type) {
226 if (dbd_delete(dbd, rqst, rply, DBIF_CNID) < 0) {
235 rply->result = CNID_DBD_RES_NOTFOUND;
238 /* Fix up the database. assume it was a file move and rename */
239 rc = dbd_update(dbd, rqst, rply);
241 rply->cnid = rqst->cnid;
244 LOG(log_debug, logtype_cnid, "cnid_lookup: Looked up dev/ino 0x%llx/0x%llx did %u name %s as %u (needed update)",
245 (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rqst->did), rqst->name, ntohl(rply->cnid));