]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cdb/cnid_cdb_add.c
use log_debug rather than log_info for LOG inside ifdef DEBUG
[netatalk.git] / libatalk / cnid / cdb / cnid_cdb_add.c
1 /*
2  * $Id: cnid_cdb_add.c,v 1.6 2009-10-29 13:17:29 didg Exp $
3  *
4  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5  * All Rights Reserved. See COPYRIGHT.
6  *
7  * cnid_add (db, dev, ino, did, name, hint):
8  * add a name to the CNID database. we use both dev/ino and did/name
9  * to keep track of things.
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif /* HAVE_CONFIG_H */
15
16 #ifdef CNID_BACKEND_CDB
17 #include "cnid_cdb_private.h"
18
19 extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
20                 const cnid_t did, char *name, const size_t len);
21
22
23 #define tid    NULL
24
25 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
26 {
27     buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
28     buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
29     buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
30     buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
31     buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
32     buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
33     buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
34     buf[CNID_DEV_LEN - 8] = dev;
35
36     buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
37     buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
38     buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
39     buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
40     buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
41     buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
42     buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
43     buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;    
44 }
45
46 unsigned char *make_cnid_data(const struct stat *st,const cnid_t did,
47                      const char *name, const size_t len)
48 {
49     static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
50     unsigned char *buf = start  +CNID_LEN;
51     u_int32_t i;
52
53     if (len > MAXPATHLEN)
54         return NULL;
55
56     make_devino_data(buf, st->st_dev, st->st_ino);
57     buf += CNID_DEVINO_LEN;
58
59     i = S_ISDIR(st->st_mode)?1:0;
60     i = htonl(i);
61     memcpy(buf, &i, sizeof(i));
62     buf += sizeof(i);
63     
64     /* did is already in network byte order */
65     memcpy(buf, &did, sizeof(did));
66     buf += sizeof(did);
67
68     memcpy(buf, name, len);
69     *(buf + len) = '\0';
70
71     return start;
72 }    
73
74 /* --------------- */
75 static int db_stamp(void *buffer, size_t size)
76 {
77 time_t t;
78     memset(buffer, 0, size);
79     /* return the current time. */
80     if (size < sizeof(time_t))
81         return -1;
82     t = time(NULL);
83     memcpy(buffer,&t, sizeof(time_t));
84     return 0;
85
86 }
87
88
89 /* ----------------------------- */
90 static cnid_t get_cnid(CNID_private *db)
91 {
92     DBT rootinfo_key, rootinfo_data;
93     DBC  *cursor;
94     int rc;
95     int flag, setstamp=0;
96     cnid_t hint,id;
97     char buf[ROOTINFO_DATALEN];
98     char stamp[CNID_DEV_LEN];
99      
100     if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
101         LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
102         return CNID_INVALID;
103     }
104
105     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
106     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
107     rootinfo_key.data = ROOTINFO_KEY;
108     rootinfo_key.size = ROOTINFO_KEYLEN;
109
110     switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
111     case 0:
112         memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
113         id = ntohl(hint);
114         /* If we've hit the max CNID allowed, we return a fatal error.  CNID
115          * needs to be recycled before proceding. */
116         if (++id == CNID_INVALID) {
117             LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
118             errno = CNID_ERR_MAX;
119             goto cleanup;
120         }
121         hint = htonl(id);
122         flag = DB_CURRENT;
123         break;
124     case DB_NOTFOUND:
125         hint = htonl(CNID_START);
126         flag = DB_KEYFIRST;
127         setstamp = 1;
128         break;
129     default:
130         LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
131         errno = CNID_ERR_DB; 
132         goto cleanup;
133     }
134     
135     memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
136     rootinfo_data.data = buf;
137     rootinfo_data.size = ROOTINFO_DATALEN;
138     memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
139     if (setstamp) {
140         if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
141             goto cleanup;
142         }
143         memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
144     }
145
146     
147     switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
148     case 0:
149         break;
150     default:
151         LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
152         errno = CNID_ERR_DB; 
153         goto cleanup;
154     }
155     if ((rc = cursor->c_close(cursor)) != 0) {
156         LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
157         errno = CNID_ERR_DB; 
158         return CNID_INVALID;
159     }
160     return hint;
161 cleanup:
162     if ((rc = cursor->c_close(cursor)) != 0) {
163         LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
164         return CNID_INVALID;
165     }
166     return CNID_INVALID;
167 }
168
169 /* ------------------------ */
170 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
171                 const cnid_t did, char *name, const size_t len,
172                 cnid_t hint)
173 {
174     CNID_private *db;
175     DBT key, data;
176     cnid_t id;
177     int rc;
178
179     if (!cdb || !(db = cdb->_private) || !st || !name) {
180         errno = CNID_ERR_PARAM;
181         return CNID_INVALID;
182     }
183
184     /* Do a lookup. */
185     id = cnid_cdb_lookup(cdb, st, did, name, len);
186     /* ... Return id if it is valid, or if Rootinfo is read-only. */
187     if (id || (db->flags & CNIDFLAG_DB_RO)) {
188 #ifdef DEBUG
189         LOG(log_debug, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
190 #endif
191         return id;
192     }
193
194     /* Initialize our DBT data structures. */
195     memset(&key, 0, sizeof(key));
196     memset(&data, 0, sizeof(data));
197
198     if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
199         LOG(log_error, logtype_default, "cnid_add: Path name is too long");
200         errno = CNID_ERR_PATH;
201         return CNID_INVALID;
202     }
203     data.size = CNID_HEADER_LEN + len + 1;
204
205     if ((hint = get_cnid(db)) == 0) {
206          errno = CNID_ERR_DB;
207          return CNID_INVALID;
208     }
209     memcpy(data.data, &hint, sizeof(hint));
210     
211     key.data = &hint;
212     key.size = sizeof(hint);
213
214     /* Now we need to add the CNID data to the databases. */
215     if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
216         if (rc == EINVAL) {
217             /* if we have a duplicate
218              * on cnid it's a fatal error.
219              * on dev:inode
220              *   - leftover should have been delete before.
221              *   - a second process already updated the db
222              *   - it's a new file eg our file is already deleted and replaced
223              * on did:name leftover
224             */
225             if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
226                 errno = CNID_ERR_DB;
227                 return CNID_INVALID;
228             }
229         }
230         else {
231             LOG(log_error, logtype_default
232                    , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", 
233                    name, ntohl(hint), db_strerror(rc));  
234             errno = CNID_ERR_DB;
235             return CNID_INVALID;
236         }
237     }
238
239 #ifdef DEBUG
240     LOG(log_debug, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
241 #endif
242
243     return hint;
244 }
245
246 /* cnid_cbd_getstamp */
247 /*-----------------------*/
248 int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
249 {
250     DBT key, data;
251     int rc;
252     CNID_private *db;
253
254     if (!cdb || !(db = cdb->_private) || !buffer || !len) {
255         errno = CNID_ERR_PARAM;
256         return -1;
257     }
258
259     memset(buffer, 0, len);
260     memset(&key, 0, sizeof(key));
261     memset(&data, 0, sizeof(data));
262
263     key.data = ROOTINFO_KEY;
264     key.size = ROOTINFO_KEYLEN;
265
266     if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
267         if (rc != DB_NOTFOUND) {
268             LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
269                db_strerror(rc));
270             errno = CNID_ERR_DB;
271             return -1;
272         }
273         /* we waste a single ID here... */
274         get_cnid(db);
275         memset(&key, 0, sizeof(key));
276         memset(&data, 0, sizeof(data));
277         key.data = ROOTINFO_KEY;
278         key.size = ROOTINFO_KEYLEN;
279         if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
280             LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s", 
281                db_strerror(rc));
282             errno = CNID_ERR_DB;
283             return -1;
284         }
285     }
286
287     memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
288 #ifdef DEBUG
289     LOG(log_debug, logtype_cnid, "cnid_getstamp: Returning stamp");
290 #endif
291    return 0;
292 }
293
294
295 #endif /* CNID_BACKEND_CDB */