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