2 * $Id: cnid_cdb_add.c,v 1.8 2009-11-20 17:22:11 didg Exp $
4 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
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.
14 #endif /* HAVE_CONFIG_H */
16 #ifdef CNID_BACKEND_CDB
17 #include "cnid_cdb_private.h"
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);
25 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
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;
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;
46 unsigned char *make_cnid_data(u_int32_t flags, const struct stat *st, const cnid_t did,
47 const char *name, const size_t len)
49 static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
50 unsigned char *buf = start +CNID_LEN;
56 make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
57 buf += CNID_DEVINO_LEN;
59 i = S_ISDIR(st->st_mode)?1:0;
61 memcpy(buf, &i, sizeof(i));
64 /* did is already in network byte order */
65 memcpy(buf, &did, sizeof(did));
68 memcpy(buf, name, len);
75 static int db_stamp(void *buffer, size_t size)
78 memset(buffer, 0, size);
79 /* return the current time. */
80 if (size < sizeof(time_t))
83 memcpy(buffer,&t, sizeof(time_t));
89 /* ----------------------------- */
90 static cnid_t get_cnid(CNID_private *db)
92 DBT rootinfo_key, rootinfo_data;
97 char buf[ROOTINFO_DATALEN];
98 char stamp[CNID_DEV_LEN];
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));
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;
110 switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
112 memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(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;
125 hint = htonl(CNID_START);
130 LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
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));
140 if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
143 memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
147 switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
151 LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
155 if ((rc = cursor->c_close(cursor)) != 0) {
156 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
162 if ((rc = cursor->c_close(cursor)) != 0) {
163 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
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,
179 if (!cdb || !(db = cdb->_private) || !st || !name) {
180 errno = CNID_ERR_PARAM;
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)) {
189 LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
194 /* Initialize our DBT data structures. */
195 memset(&key, 0, sizeof(key));
196 memset(&data, 0, sizeof(data));
198 if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
199 LOG(log_error, logtype_default, "cnid_add: Path name is too long");
200 errno = CNID_ERR_PATH;
203 data.size = CNID_HEADER_LEN + len + 1;
205 if ((hint = get_cnid(db)) == 0) {
209 memcpy(data.data, &hint, sizeof(hint));
212 key.size = sizeof(hint);
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))) {
217 /* if we have a duplicate
218 * on cnid it's a fatal error.
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
225 if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
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));
240 LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
246 /* cnid_cbd_getstamp */
247 /*-----------------------*/
248 int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
254 if (!cdb || !(db = cdb->_private) || !buffer || !len) {
255 errno = CNID_ERR_PARAM;
259 memset(buffer, 0, len);
260 memset(&key, 0, sizeof(key));
261 memset(&data, 0, sizeof(data));
263 key.data = ROOTINFO_KEY;
264 key.size = ROOTINFO_KEYLEN;
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",
273 /* we waste a single ID here... */
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",
287 memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
289 LOG(log_debug9, logtype_cnid, "cnid_getstamp: Returning stamp");
295 #endif /* CNID_BACKEND_CDB */