2 * $Id: cnid_cdb_add.c,v 1.2 2005-04-28 20:49:59 bfernhomberg 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"
22 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
24 buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
25 buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
26 buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
27 buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
28 buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
29 buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
30 buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
31 buf[CNID_DEV_LEN - 8] = dev;
33 buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
34 buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
35 buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
36 buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
37 buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
38 buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
39 buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
40 buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;
43 char *make_cnid_data(const struct stat *st,const cnid_t did,
44 const char *name, const int len)
46 static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
47 char *buf = start +CNID_LEN;
53 make_devino_data(buf, st->st_dev, st->st_ino);
54 buf += CNID_DEVINO_LEN;
56 i = S_ISDIR(st->st_mode)?1:0;
58 memcpy(buf, &i, sizeof(i));
61 /* did is already in network byte order */
62 memcpy(buf, &did, sizeof(did));
65 memcpy(buf, name, len);
72 extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
73 const cnid_t did, char *name, const int len);
76 int db_stamp(void *buffer, size_t size)
79 memset(buffer, 0, size);
80 /* return the current time. */
81 if (size < sizeof(time_t))
84 memcpy(buffer,&t, sizeof(time_t));
90 /* ----------------------------- */
91 static cnid_t get_cnid(CNID_private *db)
93 DBT rootinfo_key, rootinfo_data;
98 char buf[ROOTINFO_DATALEN];
99 char stamp[CNID_DEV_LEN];
101 if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
102 LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
106 memset(&rootinfo_key, 0, sizeof(rootinfo_key));
107 memset(&rootinfo_data, 0, sizeof(rootinfo_data));
108 rootinfo_key.data = ROOTINFO_KEY;
109 rootinfo_key.size = ROOTINFO_KEYLEN;
111 switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
113 memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
115 /* If we've hit the max CNID allowed, we return a fatal error. CNID
116 * needs to be recycled before proceding. */
117 if (++id == CNID_INVALID) {
118 LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
119 errno = CNID_ERR_MAX;
126 hint = htonl(CNID_START);
131 LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
136 memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
137 rootinfo_data.data = buf;
138 rootinfo_data.size = ROOTINFO_DATALEN;
139 memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
141 if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
144 memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
148 switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
152 LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
156 if ((rc = cursor->c_close(cursor)) != 0) {
157 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
163 if ((rc = cursor->c_close(cursor)) != 0) {
164 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
170 /* ------------------------ */
171 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
172 const cnid_t did, char *name, const int len,
180 if (!cdb || !(db = cdb->_private) || !st || !name) {
181 errno = CNID_ERR_PARAM;
186 id = cnid_cdb_lookup(cdb, st, did, name, len);
187 /* ... Return id if it is valid, or if Rootinfo is read-only. */
188 if (id || (db->flags & CNIDFLAG_DB_RO)) {
190 LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
195 /* Initialize our DBT data structures. */
196 memset(&key, 0, sizeof(key));
197 memset(&data, 0, sizeof(data));
199 if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
200 LOG(log_error, logtype_default, "cnid_add: Path name is too long");
201 errno = CNID_ERR_PATH;
204 data.size = CNID_HEADER_LEN + len + 1;
206 if ((hint = get_cnid(db)) == 0) {
210 memcpy(data.data, &hint, sizeof(hint));
213 key.size = sizeof(hint);
215 /* Now we need to add the CNID data to the databases. */
216 if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
218 /* if we have a duplicate
219 * on cnid it's a fatal error.
221 * - leftover should have been delete before.
222 * - a second process already updated the db
223 * - it's a new file eg our file is already deleted and replaced
224 * on did:name leftover
226 if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
232 LOG(log_error, logtype_default
233 , "cnid_add: Failed to add CNID for %s to database using hint %u: %s",
234 name, ntohl(hint), db_strerror(rc));
241 LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
247 /* cnid_cbd_getstamp */
248 /*-----------------------*/
249 int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
255 if (!cdb || !(db = cdb->_private) || !buffer || !len) {
256 errno = CNID_ERR_PARAM;
260 memset(buffer, 0, len);
261 memset(&key, 0, sizeof(key));
262 memset(&data, 0, sizeof(data));
264 key.data = ROOTINFO_KEY;
265 key.size = ROOTINFO_KEYLEN;
267 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
268 if (rc != DB_NOTFOUND) {
269 LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
274 /* we waste a single ID here... */
276 memset(&key, 0, sizeof(key));
277 memset(&data, 0, sizeof(data));
278 key.data = ROOTINFO_KEY;
279 key.size = ROOTINFO_KEYLEN;
280 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
281 LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s",
288 memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
290 LOG(log_info, logtype_cnid, "cnid_getstamp: Returning stamp");
296 #endif /* CNID_BACKEND_CDB */