]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/dbd_add.c
osx adouble format . files are invalid if usedots is not set
[netatalk.git] / etc / cnid_dbd / dbd_add.c
1 /*
2  * $Id: dbd_add.c,v 1.1.4.7 2004-02-07 19:46:08 didg 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 /*                         cnid   - dev        - inode     - type  - did  - name */
38 #define ROOTINFO_DATA    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0RootInfo"
39 #define ROOTINFO_DATALEN (3*4 +2*8  +9)
40 #define CNID_START        17 /*  0x80000000L */
41
42 static int add_cnid(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
43 {
44     DBT key, data;
45     int rc;
46
47     memset(&key, 0, sizeof(key));
48     memset(&data, 0, sizeof(data));
49
50     key.data = &rply->cnid;
51     key.size = sizeof(rply->cnid);
52
53     data.data = pack_cnid_data(rqst);
54     data.size = CNID_HEADER_LEN + rqst->namelen + 1;
55     memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
56
57     /* main database */
58     if ((rc = dbif_put(DBIF_IDX_CNID, &key, &data, DB_NOOVERWRITE))) {
59         /* This could indicate a database error or that the key already exists
60          (because of DB_NOOVERWRITE). In that case we still look at some sort of
61          database corruption since that is not supposed to happen. */
62         
63         switch (rc) {
64         case 1:
65             rply->result = CNID_DBD_RES_ERR_DUPLCNID;
66             break;
67         case -1:
68             /* FIXME: Should that not be logged for case 1:? */
69             LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
70              , (char *)data.data + CNID_NAME_OFS);
71             
72             rqst->cnid = rply->cnid;
73             rc = dbd_update(rqst, rply);
74             if (rc < 0) {
75                 rply->result = CNID_DBD_RES_ERR_DB;
76                 return -1;
77             }
78             else 
79                return 0;
80             break;
81         }
82         return -1;
83     }
84
85     return 0;
86 }
87
88 /* ---------------------- */
89 static int get_cnid(struct cnid_dbd_rply *rply)
90 {
91     DBT rootinfo_key, rootinfo_data;
92     int rc;
93     cnid_t hint, id;
94      
95     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
96     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
97     rootinfo_key.data = ROOTINFO_KEY;
98     rootinfo_key.size = ROOTINFO_KEYLEN;
99
100     if ((rc = dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
101         rply->result = CNID_DBD_RES_ERR_DB;
102         return -1;
103     }
104     memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
105     id = ntohl(hint);
106     /* If we've hit the max CNID allowed, we return an error. CNID
107      * needs to be recycled before proceding. */
108     if (++id == CNID_INVALID) {
109         rply->result = CNID_DBD_RES_ERR_MAX;
110         return -1;
111     }
112
113 #if 0
114     memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
115 #endif    
116     rootinfo_data.size = ROOTINFO_DATALEN;
117     hint = htonl(id);
118     memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
119
120     if (dbif_put(DBIF_IDX_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 */
130 int dbd_stamp(void) 
131 {
132     DBT rootinfo_key, rootinfo_data;
133     cnid_t hint;
134     char buf[ROOTINFO_DATALEN];
135     char stamp[CNID_DEV_LEN];
136      
137     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
138     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
139     rootinfo_key.data = ROOTINFO_KEY;
140     rootinfo_key.size = ROOTINFO_KEYLEN;
141
142     switch (dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) {
143     case 0:
144         hint = htonl(CNID_START);
145         memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
146         rootinfo_data.data = buf;
147         rootinfo_data.size = ROOTINFO_DATALEN;
148         if (dbif_stamp(stamp, CNID_DEV_LEN) < 0) {
149             return -1;
150         }
151         memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
152         memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
153         if (dbif_put(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
154             return -1;
155         }
156         return 0;
157     
158     case 1: /* we already have one */
159         return 0;
160     default:
161         return -1;
162     }
163     return -1;
164 }
165
166 /* ------------------------ */
167 int dbd_add(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
168 {
169     rply->namelen = 0;
170
171     /* See if we have an entry already and return it if yes */
172     if (dbd_lookup(rqst, rply) < 0)
173         return -1;
174
175     if (rply->result == CNID_DBD_RES_OK) {
176         /* Found it. rply->cnid is the correct CNID now. */
177 #ifdef DEBUG
178         LOG(log_info, logtype_cnid, "dbd_add: dbd_lookup success, cnid %u", ntohl(rply->cnid));
179 #endif
180         return 1;
181     }
182
183     if (get_cnid(rply) < 0) {
184         if (rply->result == CNID_DBD_RES_ERR_MAX) {
185             LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
186             /* This will cause an abort/rollback if transactions are used */
187             return 0;
188         } else {
189             LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
190             return -1;
191         }
192     }
193     
194     if (add_cnid(rqst, rply) < 0) {
195         if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
196             LOG(log_error, logtype_cnid, "dbd_add: Cannot add CNID %u. Corrupt/invalid Rootkey?.", ntohl(rply->cnid));
197             /* abort/rollback, see above */
198             return 0;
199         } else {
200             LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
201             return -1;
202         }
203     }
204 #ifdef DEBUG
205     LOG(log_info, logtype_cnid, "dbd_add: Added dev/ino %s did %u name %s cnid %u",
206         stringify_devino(rqst->dev, rqst->ino),
207         ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
208 #endif
209     rply->result = CNID_DBD_RES_OK;
210     return 1;
211 }