]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/dbd_add.c
Merge remote branch 'sf/product-2-2' into develop
[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 #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;
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     if (id == 0) {
87         if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) < 0) {
88             rply->result = CNID_DBD_RES_ERR_DB;
89             return -1;
90         }
91         if (rc == 0) {
92             /* no rootinfo key yet */
93             memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
94             id = CNID_START - 1;
95         } else {
96             memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
97             memcpy(&hint, buf + CNID_TYPE_OFS, sizeof(hint));
98             id = ntohl(hint);
99             if (id < CNID_START - 1)
100                 id = CNID_START - 1;
101         }
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.data = buf;
112     rootinfo_data.size = ROOTINFO_DATALEN;
113     hint = htonl(id);
114     memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
115
116     if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
117         rply->result = CNID_DBD_RES_ERR_DB;
118         return -1;
119     }
120     rply->cnid = hint;
121     return 0;
122 }
123
124 /* ------------------------ */
125 /* We need a nolookup version for `dbd` */
126 int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int nolookup)
127 {
128     rply->namelen = 0;
129
130     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx) {start}",
131         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
132
133     /* See if we have an entry already and return it if yes */
134     if (! nolookup) {
135         if (dbd_lookup(dbd, rqst, rply, 0) < 0) {
136             LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): error in dbd_lookup",
137                 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
138             return -1;
139         }
140
141         if (rply->result == CNID_DBD_RES_OK) {
142             /* Found it. rply->cnid is the correct CNID now. */
143             LOG(log_debug, logtype_cnid, "dbd_add: dbd_lookup success --> CNID: %u", ntohl(rply->cnid));
144             return 1;
145         }
146     }
147
148     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): {adding to database ...}",
149         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
150
151
152     if (get_cnid(dbd, rply) < 0) {
153         if (rply->result == CNID_DBD_RES_ERR_MAX) {
154             LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
155             /* This will cause an abort/rollback if transactions are used */
156             return 0;
157         } else {
158             LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
159             return -1;
160         }
161     }
162     
163     if (add_cnid(dbd, rqst, rply) < 0) {
164         if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
165             LOG(log_error, logtype_cnid, "dbd_add(DID: %u/\"%s\", dev/ino 0x%llx/0x%llx): Cannot add CNID: %u",
166                 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
167             /* abort/rollback, see above */
168             return 0;
169         } else {
170             LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
171             return -1;
172         }
173     }
174     LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): Added with CNID: %u",
175         ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
176
177     rply->result = CNID_DBD_RES_OK;
178     return 1;
179 }