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