]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/dbd_add.c
New MySQL CNID backend
[netatalk.git] / etc / cnid_dbd / dbd_add.c
1 /*
2  * Copyright (C) Joerg Lenneis 2003
3  * Copyright (C) Frank Lahm 2010
4  * All Rights Reserved.  See COPYING.
5  */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif /* HAVE_CONFIG_H */
10
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <sys/time.h>
16
17 #include <atalk/logger.h>
18 #include <atalk/cnid_bdb_private.h>
19 #include <atalk/cnid.h>
20 #include <db.h>
21
22 #include "dbif.h"
23 #include "pack.h"
24 #include "dbd.h"
25
26 int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
27 {
28     DBT key, data;
29     int rc;
30
31     memset(&key, 0, sizeof(key));
32     memset(&data, 0, sizeof(data));
33
34     key.data = &rply->cnid;
35     key.size = sizeof(rply->cnid);
36
37     data.data = pack_cnid_data(rqst);
38     data.size = CNID_HEADER_LEN + rqst->namelen + 1;
39     memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
40
41     /* main database */
42     if ((rc = dbif_put(dbd, DBIF_CNID, &key, &data, DB_NOOVERWRITE))) {
43         /* This could indicate a database error or that the key already exists
44          (because of DB_NOOVERWRITE). In that case we still look at some sort of
45          database corruption since that is not supposed to happen. */
46         
47         switch (rc) {
48         case 1:
49             rply->result = CNID_DBD_RES_ERR_DUPLCNID;
50             break;
51         case -1:
52             /* FIXME: Should that not be logged for case 1:? */
53             LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
54              , (char *)data.data + CNID_NAME_OFS);
55             
56             rqst->cnid = rply->cnid;
57             rc = dbd_update(dbd, rqst, rply);
58             if (rc < 0) {
59                 rply->result = CNID_DBD_RES_ERR_DB;
60                 return -1;
61             }
62             else 
63                return 0;
64             break;
65         }
66         return -1;
67     }
68
69     return 0;
70 }
71
72 /* ---------------------- */
73 int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
74 {
75     static cnid_t id;
76     static char buf[ROOTINFO_DATALEN];
77     DBT rootinfo_key, rootinfo_data, key, data;
78     int rc;
79     cnid_t hint;
80
81     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
82     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
83     rootinfo_key.data = ROOTINFO_KEY;
84     rootinfo_key.size = ROOTINFO_KEYLEN;
85
86     memset(&key, 0, sizeof(key));
87     memset(&data, 0, sizeof(data));
88
89     if (id == 0) {
90         if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) != 1) {
91             rply->result = CNID_DBD_RES_ERR_DB;
92             return -1;
93         }
94         memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
95         memcpy(&hint, buf + CNID_TYPE_OFS, sizeof(hint));
96         id = ntohl(hint);
97         if (id < CNID_START - 1)
98             id = CNID_START - 1;
99     }
100
101     cnid_t trycnid, tmp;
102
103     while (true) {
104         if (rply->cnid != CNID_INVALID) {
105             trycnid = ntohl(rply->cnid);
106             rply->cnid = CNID_INVALID;
107         } else {
108             if (++id == CNID_INVALID)
109                 id = CNID_START;
110             trycnid = id;
111         }
112         tmp = htonl(trycnid);
113         key.data = &tmp;
114         key.size = sizeof(cnid_t);
115         rc = dbif_get(dbd, DBIF_CNID, &key, &data, 0);
116         if (rc == 0) {
117             break;
118         } else if (rc == -1) {
119             rply->result = CNID_DBD_RES_ERR_DB;
120             return -1;
121         }
122     }
123
124     if (trycnid == id) {
125         rootinfo_data.data = buf;
126         rootinfo_data.size = ROOTINFO_DATALEN;
127         hint = htonl(id);
128         memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
129
130         if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
131             rply->result = CNID_DBD_RES_ERR_DB;
132             return -1;
133         }
134     }
135
136     rply->cnid = htonl(trycnid);
137     return 0;
138 }
139
140 /* ------------------------ */
141 /* We need a nolookup version for `dbd` */
142 int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
143 {
144     rply->namelen = 0;
145
146     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx) {start}",
147         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
148
149     /* See if we have an entry already and return it if yes */
150     if (dbd_lookup(dbd, rqst, rply) < 0) {
151         LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): error in dbd_lookup",
152             ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
153         return -1;
154     }
155
156     if (rply->result == CNID_DBD_RES_OK) {
157         /* Found it. rply->cnid is the correct CNID now. */
158         LOG(log_debug, logtype_cnid, "dbd_add: dbd_lookup success --> CNID: %u", ntohl(rply->cnid));
159         return 1;
160     }
161
162     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): {adding to database ...}",
163         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
164
165     if (rqst->cnid) {
166         /* rqst->cnid is the cnid "hint"/backup from the adouble file */
167         rply->cnid = rqst->cnid;
168     }
169     if (get_cnid(dbd, rply) < 0) {
170         if (rply->result == CNID_DBD_RES_ERR_MAX) {
171             LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
172             /* This will cause an abort/rollback if transactions are used */
173             return 0;
174         } else {
175             LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
176             return -1;
177         }
178     }
179     
180     if (add_cnid(dbd, rqst, rply) < 0) {
181         if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
182             LOG(log_error, logtype_cnid, "dbd_add(DID: %u/\"%s\", dev/ino 0x%llx/0x%llx): Cannot add CNID: %u",
183                 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
184             /* abort/rollback, see above */
185             return 0;
186         } else {
187             LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
188             return -1;
189         }
190     }
191     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): Added with CNID: %u",
192         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
193
194     rply->result = CNID_DBD_RES_OK;
195     return 1;
196 }