]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/cmd_dbd_lookup.c
remove trivial warnings
[netatalk.git] / etc / cnid_dbd / cmd_dbd_lookup.c
1 /*
2  * $Id: cmd_dbd_lookup.c,v 1.2 2009-07-12 09:21:34 franklahm Exp $
3  *
4  * Copyright (C) Frank Lahm 2009
5  * All Rights Reserved.  See COPYING.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/param.h>
16 #include <errno.h>
17 #include <netatalk/endian.h>
18 #include <atalk/logger.h>
19 #include <atalk/cnid_dbd_private.h>
20
21 #include "pack.h"
22 #include "dbif.h"
23 #include "dbd.h"
24 #include "cmd_dbd.h"
25
26 /* 
27    ATTENTION:
28    whatever you change here, also change cmd_dbd_lookup.c !
29    cmd_dbd_lookup has an read-only mode, but besides that it's the same.
30  */
31
32
33 /* Pull these in from dbd_add.c */
34 extern int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply);
35 extern int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply);
36
37 /*
38  *  This returns the CNID corresponding to a particular file and logs any inconsitencies.
39  *  If roflags == 1 we only scan, if roflag == 0, we modify i.e. call dbd_update
40  *  FIXME: realign this wih dbd_lookup.
41  */
42
43 int cmd_dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int roflag)
44 {
45     unsigned char *buf;
46     DBT key, devdata, diddata;
47     uint64_t dev = 0;
48     int devino = 1, didname = 1; 
49     int rc;
50     cnid_t id_devino, id_didname;
51     u_int32_t type_devino  = (unsigned)-1;
52     u_int32_t type_didname = (unsigned)-1;
53     int update = 0;
54     
55     memset(&key, 0, sizeof(key));
56     memset(&diddata, 0, sizeof(diddata));
57     memset(&devdata, 0, sizeof(devdata));
58
59     rply->namelen = 0; 
60     rply->cnid = 0;
61     
62     buf = pack_cnid_data(rqst); 
63
64     /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
65        only get a match in one of them, that means a file has moved. */
66     key.data = buf + CNID_DEVINO_OFS;
67     key.size = CNID_DEVINO_LEN;
68
69     if ((rc = dbif_get(dbd, DBIF_IDX_DEVINO, &key, &devdata, 0))  < 0) {
70         dbd_log( LOGSTD, "dbd_search: Unable to get CNID %u, name %s",
71                 ntohl(rqst->did), rqst->name);
72         rply->result = CNID_DBD_RES_ERR_DB;
73         return -1;
74     }
75     if (rc == 0) {
76         devino = 0;
77     }
78     else {
79         memcpy(&id_devino, devdata.data, sizeof(rply->cnid));
80         memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
81         type_devino = ntohl(type_devino);
82     }
83
84     key.data = buf + CNID_DID_OFS;
85     key.size = CNID_DID_LEN + rqst->namelen + 1;
86
87     if ((rc = dbif_get(dbd, DBIF_IDX_DIDNAME, &key, &diddata, 0))  < 0) {
88         dbd_log( LOGSTD, "dbd_search: Unable to get CNID %u, name %s",
89                 ntohl(rqst->did), rqst->name);
90         rply->result = CNID_DBD_RES_ERR_DB;
91         return -1;
92     }
93     if (rc == 0) {
94         didname = 0;
95     }
96     else {
97         memcpy(&id_didname, diddata.data, sizeof(rply->cnid));
98         memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
99         type_didname = ntohl(type_didname);
100     }
101     
102     if (!devino && !didname) {  
103         /* not found */
104         dbd_log( LOGDEBUG, "name: '%s/%s', did: %u, dev/ino: 0x%llx/0x%llx is not in the CNID database", 
105                  cwdbuf, rqst->name, ntohl(rqst->did), (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
106         rply->result = CNID_DBD_RES_NOTFOUND;
107         return 1;
108     }
109
110     if (devino && didname && id_devino == id_didname && type_devino == rqst->type) {
111         /* the same */
112         rply->cnid = id_didname;
113         rply->result = CNID_DBD_RES_OK;
114         return 1;
115     }
116
117     /* 
118        Order matters for the next 2 ifs because both found a CNID but they didn't match.
119        So in order to pick the CNID from "didname" it must come after devino.
120        See test cases laid out in dbd_lookup.c.
121     */
122     if (devino) {
123         dbd_log( LOGSTD, "CNID resolve problem: server side rename oder reused inode for '%s/%s'", cwdbuf, rqst->name);
124         rqst->cnid = id_devino;
125         if (type_devino != rqst->type) {
126             /* same dev/inode but not same type: it's an inode reused, delete the record */
127             if (! roflag)
128                 if (dbd_delete(dbd, rqst, rply, DBIF_CNID) < 0)
129                     return -1;
130         }
131         else {
132             update = 1;
133         }
134     }
135     if (didname) {
136         dbd_log( LOGSTD, "CNID resolve problem: changed dev/ino for '%s/%s'", cwdbuf, rqst->name);
137         rqst->cnid = id_didname;
138         /* we have a did/name.
139            If it's the same dev or not the same type, e.g. a remove followed by a new file
140            with the same name */
141         if (!memcmp(&dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) ||
142             type_didname != rqst->type) {
143             if (! roflag)
144                 if (dbd_delete(dbd, rqst, rply, DBIF_CNID) < 0)
145                     return -1;
146         }
147         else {
148             update = 1;
149         }
150     }
151
152     if (!update || roflag) {
153         rply->result = CNID_DBD_RES_NOTFOUND;
154         return 1;
155     }
156     /* Fix up the database. assume it was a file move and rename */
157     rc = dbd_update(dbd, rqst, rply);
158     if (rc >0) {
159         rply->cnid = rqst->cnid;
160     }
161
162     dbd_log( LOGSTD, "CNID database needed update: dev/ino: 0x%llx/0x%llx, did: %u, name: '%s/%s' --> CNID: %u", 
163              (unsigned long long)rqst->dev, (unsigned long long)rqst->ino,
164              ntohl(rqst->did), cwdbuf, rqst->name, ntohl(rply->cnid));
165
166     return rc;
167 }
168
169 /* 
170    This is taken from dbd_add.c, but this func really is only "add", dbd_add calls dbd_lookup
171    before adding.
172    FIXME: realign with dbd_add using e.g. using a new arg like "int lookup".
173 */
174 int cmd_dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
175 {
176     if (get_cnid(dbd, rply) < 0) {
177         if (rply->result == CNID_DBD_RES_ERR_MAX) {
178             dbd_log( LOGSTD, "FATAL: CNID database has reached its limit.");
179             /* This will cause an abort/rollback if transactions are used */
180             return 0;
181         } else {
182             dbd_log( LOGSTD, "Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
183             return -1;
184         }
185     }
186     
187     if (add_cnid(dbd, rqst, rply) < 0) {
188         if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
189             dbd_log( LOGSTD, "Cannot add CNID %u. Corrupt/invalid Rootkey?.", ntohl(rply->cnid));
190             /* abort/rollback, see above */
191             return 0;
192         } else {
193             dbd_log( LOGSTD, "Failed to add CNID for %s to database", rqst->name);
194             return -1;
195         }
196     }
197     dbd_log( LOGDEBUG, "Add to CNID database: did: %u, cnid: %u, name: '%s', dev/ino: 0x%llx/0x%llx",
198              ntohl(rqst->did), ntohl(rply->cnid), rqst->name,
199              (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
200
201     rply->result = CNID_DBD_RES_OK;
202     return 1;
203 }