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