]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/dbd_add.c
7f66ca30b387b0d9a101bd5f0e480487482f95b4
[netatalk.git] / etc / cnid_dbd / dbd_add.c
1 /*
2  * $Id: dbd_add.c,v 1.6 2009-05-14 13:46:08 franklahm Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * All Rights Reserved.  See COPYING.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <string.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif /* HAVE_UNISTD_H */
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif /* HAVE_FCNTL_H */
19 #include <errno.h>
20 #ifdef HAVE_SYS_TIME_H
21 #include <sys/time.h>
22 #endif /* HAVE_SYS_TIME_H */
23
24 #include <atalk/logger.h>
25 #include <atalk/cnid_dbd_private.h>
26 #include <atalk/cnid.h>
27 #ifdef HAVE_DB4_DB_H
28 #include <db4/db.h>
29 #else
30 #include <db.h>
31 #endif
32
33 #include "dbif.h"
34 #include "pack.h"
35 #include "dbd.h"
36
37 int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
38 {
39     DBT key, data;
40     int rc;
41
42     memset(&key, 0, sizeof(key));
43     memset(&data, 0, sizeof(data));
44
45     key.data = &rply->cnid;
46     key.size = sizeof(rply->cnid);
47
48     data.data = pack_cnid_data(rqst);
49     data.size = CNID_HEADER_LEN + rqst->namelen + 1;
50     memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
51
52     /* main database */
53     if ((rc = dbif_put(dbd, DBIF_CNID, &key, &data, DB_NOOVERWRITE))) {
54         /* This could indicate a database error or that the key already exists
55          (because of DB_NOOVERWRITE). In that case we still look at some sort of
56          database corruption since that is not supposed to happen. */
57         
58         switch (rc) {
59         case 1:
60             rply->result = CNID_DBD_RES_ERR_DUPLCNID;
61             break;
62         case -1:
63             /* FIXME: Should that not be logged for case 1:? */
64             LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
65              , (char *)data.data + CNID_NAME_OFS);
66             
67             rqst->cnid = rply->cnid;
68             rc = dbd_update(dbd, rqst, rply);
69             if (rc < 0) {
70                 rply->result = CNID_DBD_RES_ERR_DB;
71                 return -1;
72             }
73             else 
74                return 0;
75             break;
76         }
77         return -1;
78     }
79
80     return 0;
81 }
82
83 /* ---------------------- */
84 int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
85 {
86     DBT rootinfo_key, rootinfo_data;
87     int rc;
88     cnid_t hint, id;
89      
90     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
91     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
92     rootinfo_key.data = ROOTINFO_KEY;
93     rootinfo_key.size = ROOTINFO_KEYLEN;
94
95     if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
96         rply->result = CNID_DBD_RES_ERR_DB;
97         return -1;
98     }
99     memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
100     id = ntohl(hint);
101     /* If we've hit the max CNID allowed, we return an error. CNID
102      * needs to be recycled before proceding. */
103     if (++id == CNID_INVALID) {
104         rply->result = CNID_DBD_RES_ERR_MAX;
105         return -1;
106     }
107
108 #if 0
109     memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
110 #endif    
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 int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
163 {
164     rply->namelen = 0;
165
166     /* See if we have an entry already and return it if yes */
167     if (dbd_lookup(dbd, rqst, rply) < 0)
168         return -1;
169
170     if (rply->result == CNID_DBD_RES_OK) {
171         /* Found it. rply->cnid is the correct CNID now. */
172         LOG(log_debug, logtype_cnid, "dbd_add: dbd_lookup success, cnid %u", ntohl(rply->cnid));
173         return 1;
174     }
175
176     if (get_cnid(dbd, rply) < 0) {
177         if (rply->result == CNID_DBD_RES_ERR_MAX) {
178             LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
179             /* This will cause an abort/rollback if transactions are used */
180             return 0;
181         } else {
182             LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
183             return -1;
184         }
185     }
186     
187     if (add_cnid(dbd, rqst, rply) < 0) {
188         if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
189             LOG(log_error, logtype_cnid, "dbd_add: Cannot add CNID %u. Corrupt/invalid Rootkey?.", ntohl(rply->cnid));
190             /* abort/rollback, see above */
191             return 0;
192         } else {
193             LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
194             return -1;
195         }
196     }
197     LOG(log_debug, logtype_cnid, "dbd_add: Added dev/ino 0x%llx/0x%llx did %u name %s cnid %u",
198         (unsigned long long)rqst->dev, (unsigned long long)rqst->ino,
199         ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
200
201     rply->result = CNID_DBD_RES_OK;
202     return 1;
203 }