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